summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-11-28 03:58:46 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-11-28 03:58:46 +0000
commitb63ad0882a16a5d28003e57f2b0b81dee3fb322b (patch)
tree0a343ce219e2b8b38a5d702d66032c57b83d9720
parenta9d7bff9a84dba79609a0002e5321b74c4d64c64 (diff)
Merge with 2.4.0-test11.
-rw-r--r--CREDITS40
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/Configure.help55
-rw-r--r--Documentation/cachetlb.txt30
-rw-r--r--Documentation/dnotify.txt92
-rw-r--r--Documentation/fb/matroxfb.txt2
-rw-r--r--Documentation/isdn/README.act20002
-rw-r--r--Documentation/isdn/README.eicon2
-rw-r--r--Documentation/isdn/README.icn2
-rw-r--r--Documentation/kbuild/makefiles.txt6
-rw-r--r--Documentation/networking/bridge.txt12
-rw-r--r--Documentation/networking/ip-sysctl.txt4
-rw-r--r--Documentation/networking/lapb-module.txt10
-rw-r--r--Documentation/networking/netdevices.txt42
-rw-r--r--Documentation/networking/sis900.txt711
-rw-r--r--Documentation/networking/tulip.txt29
-rw-r--r--Documentation/networking/x25-iface.txt59
-rw-r--r--Documentation/usb/hotplug.txt124
-rw-r--r--Documentation/usb/ov511.txt62
-rw-r--r--Documentation/usb/usb-serial.txt31
-rw-r--r--Documentation/video4linux/bttv/CARDLIST6
-rw-r--r--Documentation/video4linux/bttv/Insmod-options27
-rw-r--r--Documentation/video4linux/bttv/README11
-rw-r--r--Documentation/video4linux/bttv/Sound-FAQ74
-rw-r--r--Documentation/video4linux/bttv/Specs3
-rw-r--r--MAINTAINERS31
-rw-r--r--Makefile97
-rw-r--r--arch/alpha/config.in5
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c23
-rw-r--r--arch/alpha/kernel/irq.c9
-rw-r--r--arch/alpha/kernel/semaphore.c498
-rw-r--r--arch/alpha/kernel/time.c3
-rw-r--r--arch/alpha/lib/Makefile2
-rw-r--r--arch/alpha/lib/semaphore.S348
-rw-r--r--arch/arm/config.in2
-rw-r--r--arch/arm/kernel/semaphore.c12
-rw-r--r--arch/i386/Makefile6
-rw-r--r--arch/i386/config.in15
-rw-r--r--arch/i386/defconfig17
-rw-r--r--arch/i386/kernel/acpi.c19
-rw-r--r--arch/i386/kernel/apic.c69
-rw-r--r--arch/i386/kernel/apm.c18
-rw-r--r--arch/i386/kernel/bluesmoke.c13
-rw-r--r--arch/i386/kernel/entry.S7
-rw-r--r--arch/i386/kernel/i386_ksyms.c2
-rw-r--r--arch/i386/kernel/i387.c2
-rw-r--r--arch/i386/kernel/i8259.c12
-rw-r--r--arch/i386/kernel/mpparse.c42
-rw-r--r--arch/i386/kernel/msr.c2
-rw-r--r--arch/i386/kernel/mtrr.c327
-rw-r--r--arch/i386/kernel/pci-irq.c65
-rw-r--r--arch/i386/kernel/semaphore.c12
-rw-r--r--arch/i386/kernel/setup.c880
-rw-r--r--arch/i386/kernel/smpboot.c2
-rw-r--r--arch/i386/kernel/traps.c9
-rw-r--r--arch/i386/lib/mmx.c70
-rw-r--r--arch/i386/mm/fault.c15
-rw-r--r--arch/ia64/config.in2
-rw-r--r--arch/ia64/ia32/sys_ia32.c2
-rw-r--r--arch/ia64/kernel/semaphore.c12
-rw-r--r--arch/m68k/config.in2
-rw-r--r--arch/m68k/kernel/semaphore.c4
-rw-r--r--arch/mips/config.in4
-rw-r--r--arch/mips/defconfig2
-rw-r--r--arch/mips/defconfig-atlas2
-rw-r--r--arch/mips/defconfig-ddb54767
-rw-r--r--arch/mips/defconfig-decstation2
-rw-r--r--arch/mips/defconfig-ev961009
-rw-r--r--arch/mips/defconfig-ip222
-rw-r--r--arch/mips/defconfig-malta2
-rw-r--r--arch/mips/defconfig-orion2
-rw-r--r--arch/mips/defconfig-rm2002
-rw-r--r--arch/mips/kernel/semaphore.c6
-rw-r--r--arch/mips64/config.in4
-rw-r--r--arch/mips64/defconfig2
-rw-r--r--arch/mips64/defconfig-ip222
-rw-r--r--arch/mips64/defconfig-ip272
-rw-r--r--arch/mips64/kernel/linux32.c2
-rw-r--r--arch/mips64/kernel/semaphore.c6
-rw-r--r--arch/mips64/ld.script.elf32123
-rw-r--r--arch/mips64/mm/fault.c16
-rw-r--r--arch/ppc/8xx_io/commproc.c2
-rw-r--r--arch/ppc/config.in4
-rw-r--r--arch/ppc/configs/apus_defconfig430
-rw-r--r--arch/ppc/configs/bseip_defconfig88
-rw-r--r--arch/ppc/configs/common_defconfig46
-rw-r--r--arch/ppc/configs/est8260_defconfig21
-rw-r--r--arch/ppc/configs/gemini_defconfig150
-rw-r--r--arch/ppc/configs/mbx_defconfig333
-rw-r--r--arch/ppc/configs/oak_defconfig185
-rw-r--r--arch/ppc/configs/rpxcllf_defconfig22
-rw-r--r--arch/ppc/configs/rpxlite_defconfig87
-rw-r--r--arch/ppc/configs/walnut_defconfig190
-rw-r--r--arch/ppc/defconfig51
-rw-r--r--arch/ppc/kernel/entry.S6
-rw-r--r--arch/ppc/kernel/hashtable.S22
-rw-r--r--arch/ppc/kernel/head.S27
-rw-r--r--arch/ppc/kernel/irq.c5
-rw-r--r--arch/ppc/kernel/misc.S4
-rw-r--r--arch/ppc/kernel/pci.c5
-rw-r--r--arch/ppc/kernel/ppc8260_pic.c2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c4
-rw-r--r--arch/ppc/kernel/process.c13
-rw-r--r--arch/ppc/kernel/semaphore.c4
-rw-r--r--arch/ppc/mm/init.c2
-rw-r--r--arch/s390/config.in3
-rw-r--r--arch/s390/kernel/semaphore.c12
-rw-r--r--arch/sh/config.in2
-rw-r--r--arch/sh/kernel/semaphore.c4
-rw-r--r--arch/sparc/config.in4
-rw-r--r--arch/sparc/kernel/ebus.c24
-rw-r--r--arch/sparc/kernel/pcic.c19
-rw-r--r--arch/sparc/kernel/semaphore.c6
-rw-r--r--arch/sparc/mm/init.c7
-rw-r--r--arch/sparc/mm/srmmu.c4
-rw-r--r--arch/sparc/mm/sun4c.c7
-rw-r--r--arch/sparc/vmlinux.lds3
-rw-r--r--arch/sparc64/config.in2
-rw-r--r--arch/sparc64/kernel/dtlb_base.S26
-rw-r--r--arch/sparc64/kernel/dtlb_prot.S50
-rw-r--r--arch/sparc64/kernel/ebus.c29
-rw-r--r--arch/sparc64/kernel/ioctl32.c22
-rw-r--r--arch/sparc64/kernel/itlb_base.S30
-rw-r--r--arch/sparc64/kernel/pci.c8
-rw-r--r--arch/sparc64/kernel/process.c17
-rw-r--r--arch/sparc64/kernel/semaphore.c6
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c52
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c6
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c4
-rw-r--r--arch/sparc64/lib/Makefile5
-rw-r--r--arch/sparc64/lib/U3copy_from_user.S500
-rw-r--r--arch/sparc64/lib/U3copy_in_user.S531
-rw-r--r--arch/sparc64/lib/U3copy_to_user.S528
-rw-r--r--arch/sparc64/lib/U3memcpy.S409
-rw-r--r--arch/sparc64/lib/VIScopy.S34
-rw-r--r--arch/sparc64/mm/init.c16
-rw-r--r--arch/sparc64/mm/ultra.S67
-rw-r--r--arch/sparc64/solaris/ioctl.c4
-rw-r--r--arch/sparc64/solaris/socket.c2
-rw-r--r--arch/sparc64/vmlinux.lds3
-rw-r--r--drivers/acorn/net/etherh.c7
-rw-r--r--drivers/acpi/driver.c2
-rw-r--r--drivers/atm/atmtcp.c1
-rw-r--r--drivers/atm/nicstar.c18
-rw-r--r--drivers/block/cpqarray.c8
-rw-r--r--drivers/block/ll_rw_blk.c51
-rw-r--r--drivers/block/loop.c6
-rw-r--r--drivers/block/rd.c64
-rw-r--r--drivers/char/Config.in6
-rw-r--r--drivers/char/agp/agp.h2
-rw-r--r--drivers/char/agp/agpgart_be.c26
-rw-r--r--drivers/char/console.c1
-rw-r--r--drivers/char/cyclades.c2
-rw-r--r--drivers/char/drm/agpsupport.c120
-rw-r--r--drivers/char/drm/dma.c1
-rw-r--r--drivers/char/drm/drmP.h18
-rw-r--r--drivers/char/drm/ffb_drv.c10
-rw-r--r--drivers/char/drm/gamma_drv.c4
-rw-r--r--drivers/char/drm/i810_drv.c7
-rw-r--r--drivers/char/drm/memory.c64
-rw-r--r--drivers/char/drm/mga_drv.c7
-rw-r--r--drivers/char/drm/mga_state.c2
-rw-r--r--drivers/char/drm/r128_drm.h6
-rw-r--r--drivers/char/drm/r128_drv.c7
-rw-r--r--drivers/char/drm/tdfx_drv.c6
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ctl.c21
-rw-r--r--drivers/char/generic_serial.c58
-rw-r--r--drivers/char/joystick/adi.c4
-rw-r--r--drivers/char/joystick/analog.c5
-rw-r--r--drivers/char/joystick/iforce.c23
-rw-r--r--drivers/char/joystick/ns558.c18
-rw-r--r--drivers/char/joystick/sidewinder.c2
-rw-r--r--drivers/char/mem.c7
-rw-r--r--drivers/char/mxser.c2
-rw-r--r--drivers/char/n_hdlc.c196
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/rio/rio_linux.c3
-rw-r--r--drivers/char/rtc.c8
-rw-r--r--drivers/char/sx.c8
-rw-r--r--drivers/char/synclink.c603
-rw-r--r--drivers/i2o/i2o_block.c2
-rw-r--r--drivers/i2o/i2o_core.c2
-rw-r--r--drivers/i2o/i2o_proc.c6
-rw-r--r--drivers/ide/Makefile2
-rw-r--r--drivers/ide/alim15x3.c2
-rw-r--r--drivers/ide/amd7409.c2
-rw-r--r--drivers/ide/hd.c2
-rw-r--r--drivers/ide/hpt366.c2
-rw-r--r--drivers/ide/icside.c8
-rw-r--r--drivers/ide/ide-pci.c5
-rw-r--r--drivers/ide/opti621.c2
-rw-r--r--drivers/ide/sis5513.c4
-rw-r--r--drivers/ide/sl82c105.c4
-rw-r--r--drivers/ide/via82cxxx.c2
-rw-r--r--drivers/input/evdev.c4
-rw-r--r--drivers/input/input.c6
-rw-r--r--drivers/input/joydev.c4
-rw-r--r--drivers/input/mousedev.c7
-rw-r--r--drivers/isdn/Config.in2
-rw-r--r--drivers/isdn/act2000/Makefile2
-rw-r--r--drivers/isdn/act2000/act2000.h27
-rw-r--r--drivers/isdn/act2000/act2000_isa.c39
-rw-r--r--drivers/isdn/act2000/act2000_isa.h13
-rw-r--r--drivers/isdn/act2000/capi.c30
-rw-r--r--drivers/isdn/act2000/capi.h21
-rw-r--r--drivers/isdn/act2000/module.c71
-rw-r--r--drivers/isdn/avmb1/Makefile35
-rw-r--r--drivers/isdn/avmb1/avmcard.h11
-rw-r--r--drivers/isdn/avmb1/b1.c2
-rw-r--r--drivers/isdn/avmb1/b1dma.c29
-rw-r--r--drivers/isdn/avmb1/b1isa.c28
-rw-r--r--drivers/isdn/avmb1/b1pci.c56
-rw-r--r--drivers/isdn/avmb1/b1pcmcia.c28
-rw-r--r--drivers/isdn/avmb1/c4.c50
-rw-r--r--drivers/isdn/avmb1/capi.c4
-rw-r--r--drivers/isdn/avmb1/capidrv.c18
-rw-r--r--drivers/isdn/avmb1/capifs.c7
-rw-r--r--drivers/isdn/avmb1/t1isa.c55
-rw-r--r--drivers/isdn/avmb1/t1pci.c28
-rw-r--r--drivers/isdn/divert/divert_init.c18
-rw-r--r--drivers/isdn/divert/divert_procfs.c34
-rw-r--r--drivers/isdn/divert/isdn_divert.c21
-rw-r--r--drivers/isdn/divert/isdn_divert.h15
-rw-r--r--drivers/isdn/hisax/config.c2
-rw-r--r--drivers/isdn/hisax/hfc_pci.c46
-rw-r--r--drivers/isdn/hisax/nj_s.c5
-rw-r--r--drivers/isdn/hisax/nj_u.c5
-rw-r--r--drivers/isdn/hisax/w6692.c5
-rw-r--r--drivers/isdn/hysdn/boardergo.c14
-rw-r--r--drivers/isdn/hysdn/boardergo.h8
-rw-r--r--drivers/isdn/hysdn/hycapi.c24
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c14
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h14
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c22
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c31
-rw-r--r--drivers/isdn/hysdn/hysdn_pof.h8
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c31
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c29
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c14
-rw-r--r--drivers/isdn/icn/icn.c224
-rw-r--r--drivers/isdn/icn/icn.h106
-rw-r--r--drivers/isdn/isdn_cards.c5
-rw-r--r--drivers/isdn/isdn_common.c4
-rw-r--r--drivers/isdn/isdn_net.c14
-rw-r--r--drivers/isdn/isdn_ppp.c345
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c40
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h17
-rw-r--r--drivers/isdn/pcbit/drv.c12
-rw-r--r--drivers/isdn/sc/debug.c9
-rw-r--r--drivers/macintosh/via-pmu.c139
-rw-r--r--drivers/md/lvm.c2
-rw-r--r--drivers/md/md.c6
-rw-r--r--drivers/md/raid1.c23
-rw-r--r--drivers/md/raid5.c31
-rw-r--r--drivers/md/xor.c2721
-rw-r--r--drivers/media/radio/radio-aimslab.c17
-rw-r--r--drivers/media/radio/radio-aztech.c17
-rw-r--r--drivers/media/radio/radio-cadet.c80
-rw-r--r--drivers/media/radio/radio-gemtek.c17
-rw-r--r--drivers/media/radio/radio-maestro.c28
-rw-r--r--drivers/media/radio/radio-miropcm20.c17
-rw-r--r--drivers/media/radio/radio-rtrack2.c17
-rw-r--r--drivers/media/radio/radio-sf16fmi.c17
-rw-r--r--drivers/media/radio/radio-terratec.c17
-rw-r--r--drivers/media/radio/radio-trust.c17
-rw-r--r--drivers/media/radio/radio-typhoon.c26
-rw-r--r--drivers/media/radio/radio-zoltrix.c17
-rw-r--r--drivers/media/video/Makefile4
-rw-r--r--drivers/media/video/audiochip.h10
-rw-r--r--drivers/media/video/bttv-cards.c1181
-rw-r--r--drivers/media/video/bttv-driver.c611
-rw-r--r--drivers/media/video/bttv-if.c53
-rw-r--r--drivers/media/video/bttv.h321
-rw-r--r--drivers/media/video/bttvp.h226
-rw-r--r--drivers/media/video/buz.c30
-rw-r--r--drivers/media/video/bw-qcam.c27
-rw-r--r--drivers/media/video/c-qcam.c27
-rw-r--r--drivers/media/video/cpia.c24
-rw-r--r--drivers/media/video/cpia_usb.c35
-rw-r--r--drivers/media/video/id.h26
-rw-r--r--drivers/media/video/msp3400.c216
-rw-r--r--drivers/media/video/planb.c32
-rw-r--r--drivers/media/video/pms.c27
-rw-r--r--drivers/media/video/saa5249.c17
-rw-r--r--drivers/media/video/stradis.c28
-rw-r--r--drivers/media/video/tda7432.c30
-rw-r--r--drivers/media/video/tda8425.c330
-rw-r--r--drivers/media/video/tda985x.c542
-rw-r--r--drivers/media/video/tda9875.c30
-rw-r--r--drivers/media/video/tea6300.c350
-rw-r--r--drivers/media/video/tea6420.c273
-rw-r--r--drivers/media/video/tuner.c42
-rw-r--r--drivers/media/video/tuner.h2
-rw-r--r--drivers/media/video/tvaudio.c1107
-rw-r--r--drivers/media/video/tvaudio.h13
-rw-r--r--drivers/media/video/tvmixer.c20
-rw-r--r--drivers/media/video/vino.c21
-rw-r--r--drivers/media/video/zr36120.c55
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/cfi_cmdset_0001.c40
-rw-r--r--drivers/mtd/cfi_cmdset_0002.c34
-rw-r--r--drivers/mtd/cfi_probe.c44
-rw-r--r--drivers/mtd/doc2000.c23
-rw-r--r--drivers/mtd/doc2001.c21
-rw-r--r--drivers/mtd/docprobe.c47
-rw-r--r--drivers/mtd/map_ram.c30
-rw-r--r--drivers/net/3c501.c24
-rw-r--r--drivers/net/3c503.c65
-rw-r--r--drivers/net/3c505.c63
-rw-r--r--drivers/net/3c507.c17
-rw-r--r--drivers/net/3c509.c19
-rw-r--r--drivers/net/3c515.c25
-rw-r--r--drivers/net/3c523.c28
-rw-r--r--drivers/net/3c527.c32
-rw-r--r--drivers/net/3c59x.c58
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/82596.c2
-rw-r--r--drivers/net/Config.in95
-rw-r--r--drivers/net/Space.c68
-rw-r--r--drivers/net/a2065.c44
-rw-r--r--drivers/net/ac3200.c33
-rw-r--r--drivers/net/acenic.c16
-rw-r--r--drivers/net/aironet4500_card.c24
-rw-r--r--drivers/net/aironet4500_core.c2
-rw-r--r--drivers/net/am79c961a.c14
-rw-r--r--drivers/net/apne.c24
-rw-r--r--drivers/net/appletalk/cops.c11
-rw-r--r--drivers/net/ariadne2.c22
-rw-r--r--drivers/net/arlan.c9
-rw-r--r--drivers/net/at1700.c61
-rw-r--r--drivers/net/atari_bionet.c15
-rw-r--r--drivers/net/atari_pamsnet.c16
-rw-r--r--drivers/net/atarilance.c17
-rw-r--r--drivers/net/atp.c22
-rw-r--r--drivers/net/bagetlance.c27
-rw-r--r--drivers/net/bmac.c52
-rw-r--r--drivers/net/cs89x0.c75
-rw-r--r--drivers/net/de4x5.c39
-rw-r--r--drivers/net/de600.c18
-rw-r--r--drivers/net/de620.c15
-rw-r--r--drivers/net/e2100.c5
-rw-r--r--drivers/net/es3210.c5
-rw-r--r--drivers/net/eth16i.c47
-rw-r--r--drivers/net/fc/iph5526.c3
-rw-r--r--drivers/net/fmv18x.c58
-rw-r--r--drivers/net/gmac.c33
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hamradio/soundmodem/sm.h4
-rw-r--r--drivers/net/hp-plus.c16
-rw-r--r--drivers/net/hp.c18
-rw-r--r--drivers/net/ibmlana.c38
-rw-r--r--drivers/net/irda/irport.c17
-rw-r--r--drivers/net/irda/irtty.c17
-rw-r--r--drivers/net/irda/nsc-ircc.c27
-rw-r--r--drivers/net/irda/smc-ircc.c36
-rw-r--r--drivers/net/irda/toshoboe.c13
-rw-r--r--drivers/net/irda/w83977af_ir.c19
-rw-r--r--drivers/net/lance.c91
-rw-r--r--drivers/net/lne390.c5
-rw-r--r--drivers/net/ne.c241
-rw-r--r--drivers/net/ne2.c34
-rw-r--r--drivers/net/ne2k-pci.c186
-rw-r--r--drivers/net/ne3210.c65
-rw-r--r--drivers/net/oaknet.c18
-rw-r--r--drivers/net/pcmcia/Config.in3
-rw-r--r--drivers/net/pcmcia/xircom_tulip_cb.c4
-rw-r--r--drivers/net/pppoe.c43
-rw-r--r--drivers/net/rrunner.c79
-rw-r--r--drivers/net/seeq8005.c49
-rw-r--r--drivers/net/sis900.c219
-rw-r--r--drivers/net/sis900.h10
-rw-r--r--drivers/net/smc-mca.c21
-rw-r--r--drivers/net/smc-ultra.c52
-rw-r--r--drivers/net/smc-ultra32.c5
-rw-r--r--drivers/net/smc9194.c47
-rw-r--r--drivers/net/stnic.c7
-rw-r--r--drivers/net/sunhme.c152
-rw-r--r--drivers/net/sunhme.h5
-rw-r--r--drivers/net/tulip/21142.c2
-rw-r--r--drivers/net/tulip/ChangeLog29
-rw-r--r--drivers/net/tulip/interrupt.c41
-rw-r--r--drivers/net/tulip/timer.c9
-rw-r--r--drivers/net/tulip/tulip.h6
-rw-r--r--drivers/net/tulip/tulip_core.c196
-rw-r--r--drivers/net/wan/comx-proto-lapb.c7
-rw-r--r--drivers/net/wan/comx.c5
-rw-r--r--drivers/net/wan/lapbether.c14
-rw-r--r--drivers/net/wan/x25_asy.c7
-rw-r--r--drivers/net/wd.c30
-rw-r--r--drivers/nubus/proc.c2
-rw-r--r--drivers/pci/pci.c54
-rw-r--r--drivers/pci/pci.ids3
-rw-r--r--drivers/pci/proc.c2
-rw-r--r--drivers/pcmcia/Config.in22
-rw-r--r--drivers/pcmcia/cardbus.c2
-rw-r--r--drivers/pcmcia/cs.c2
-rw-r--r--drivers/pcmcia/i82365.c31
-rw-r--r--drivers/pcmcia/pci_socket.c2
-rw-r--r--drivers/pcmcia/pci_socket.h4
-rw-r--r--drivers/pcmcia/tcic.c30
-rw-r--r--drivers/pcmcia/yenta.c84
-rw-r--r--drivers/s390/char/con3215.c1
-rw-r--r--drivers/sbus/char/aurora.c19
-rw-r--r--drivers/sbus/char/bpp.c13
-rw-r--r--drivers/sbus/char/display7seg.c15
-rw-r--r--drivers/sbus/char/envctrl.c131
-rw-r--r--drivers/sbus/char/flash.c15
-rw-r--r--drivers/sbus/char/openprom.c13
-rw-r--r--drivers/sbus/char/sab82532.c5
-rw-r--r--drivers/sbus/char/su.c5
-rw-r--r--drivers/sbus/char/uctrl.c16
-rw-r--r--drivers/sbus/sbus.c29
-rw-r--r--drivers/scsi/3w-xxxx.c9
-rw-r--r--drivers/scsi/53c7xx.c16
-rw-r--r--drivers/scsi/AM53C974.c70
-rw-r--r--drivers/scsi/AM53C974.h18
-rw-r--r--drivers/scsi/BusLogic.c5
-rw-r--r--drivers/scsi/Config.in2
-rw-r--r--drivers/scsi/a2091.c4
-rw-r--r--drivers/scsi/a3000.c2
-rw-r--r--drivers/scsi/advansys.c3
-rw-r--r--drivers/scsi/aha152x.c115
-rw-r--r--drivers/scsi/aha152x.h4
-rw-r--r--drivers/scsi/aha1542.c2
-rw-r--r--drivers/scsi/aha1740.c5
-rw-r--r--drivers/scsi/atari_scsi.c6
-rw-r--r--drivers/scsi/atp870u.c2
-rw-r--r--drivers/scsi/cpqfcTSinit.c3
-rw-r--r--drivers/scsi/dmx3191d.c5
-rw-r--r--drivers/scsi/dtc.c3
-rw-r--r--drivers/scsi/eata_dma.c25
-rw-r--r--drivers/scsi/eata_dma_proc.c11
-rw-r--r--drivers/scsi/eata_pio.c6
-rw-r--r--drivers/scsi/esp.c6
-rw-r--r--drivers/scsi/fcal.c6
-rw-r--r--drivers/scsi/fdomain.c2
-rw-r--r--drivers/scsi/g_NCR5380.c12
-rw-r--r--drivers/scsi/gdth.c37
-rw-r--r--drivers/scsi/gdth_proc.c10
-rw-r--r--drivers/scsi/gvp11.c2
-rw-r--r--drivers/scsi/ibmmca.c4
-rw-r--r--drivers/scsi/imm.c2
-rw-r--r--drivers/scsi/in2000.c4
-rw-r--r--drivers/scsi/ini9100u.c5
-rw-r--r--drivers/scsi/inia100.c4
-rw-r--r--drivers/scsi/ips.c2
-rw-r--r--drivers/scsi/mac53c94.c4
-rw-r--r--drivers/scsi/mac_scsi.c2
-rw-r--r--drivers/scsi/megaraid.c20
-rw-r--r--drivers/scsi/pas16.c3
-rw-r--r--drivers/scsi/pci2000.c2
-rw-r--r--drivers/scsi/pci2220i.c3
-rw-r--r--drivers/scsi/pluto.c6
-rw-r--r--drivers/scsi/ppa.c2
-rw-r--r--drivers/scsi/psi240i.c2
-rw-r--r--drivers/scsi/scsi_debug.c17
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/scsi_ioctl.c76
-rw-r--r--drivers/scsi/scsi_obsolete.c2
-rw-r--r--drivers/scsi/seagate.c3
-rw-r--r--drivers/scsi/sgiwd93.c37
-rw-r--r--drivers/scsi/sr_ioctl.c2
-rw-r--r--drivers/scsi/st.c12
-rw-r--r--drivers/scsi/sun3_scsi.c3
-rw-r--r--drivers/scsi/sym53c416.c2
-rw-r--r--drivers/scsi/t128.c3
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/sound/724hwmcode.h6
-rw-r--r--drivers/sound/aci.c2
-rw-r--r--drivers/sound/ad1816.c2
-rw-r--r--drivers/sound/awe_wave.c2
-rw-r--r--drivers/sound/cmpci.c14
-rw-r--r--drivers/sound/cs4232.c12
-rw-r--r--drivers/sound/cs4281.c3121
-rw-r--r--drivers/sound/cs461x_image.h2
-rw-r--r--drivers/sound/cs46xx.c10
-rw-r--r--drivers/sound/dmasound/dmasound.h1
-rw-r--r--drivers/sound/dmasound/dmasound_atari.c5
-rw-r--r--drivers/sound/dmasound/dmasound_core.c6
-rw-r--r--drivers/sound/emu10k1/emu_wrapper.h4
-rw-r--r--drivers/sound/es1370.c6
-rw-r--r--drivers/sound/esssolo1.c6
-rw-r--r--drivers/sound/gus_midi.c8
-rw-r--r--drivers/sound/gus_wave.c13
-rw-r--r--drivers/sound/i810_audio.c103
-rw-r--r--drivers/sound/ics2101.c5
-rw-r--r--drivers/sound/iwmem.h7
-rw-r--r--drivers/sound/maestro.c6
-rw-r--r--drivers/sound/maui.c4
-rw-r--r--drivers/sound/mpu401.c13
-rw-r--r--drivers/sound/msnd.c2
-rw-r--r--drivers/sound/msnd_pinnacle.c2
-rw-r--r--drivers/sound/nm256_audio.c12
-rw-r--r--drivers/sound/pas2_midi.c5
-rw-r--r--drivers/sound/pas2_mixer.c4
-rw-r--r--drivers/sound/pas2_pcm.c4
-rw-r--r--drivers/sound/pss.c8
-rw-r--r--drivers/sound/sgalaxy.c8
-rw-r--r--drivers/sound/sonicvibes.c6
-rw-r--r--drivers/sound/sscape.c3
-rw-r--r--drivers/sound/trident.c236
-rw-r--r--drivers/sound/vwsnd.c27
-rw-r--r--drivers/sound/waveartist.c7
-rw-r--r--drivers/sound/wavfront.c16
-rw-r--r--drivers/sound/ymf_sb.c12
-rw-r--r--drivers/sound/yss225.c36
-rw-r--r--drivers/telephony/ixj.c4
-rw-r--r--drivers/usb/Config.in3
-rw-r--r--drivers/usb/acm.c164
-rw-r--r--drivers/usb/audio.c40
-rw-r--r--drivers/usb/bluetooth.c28
-rw-r--r--drivers/usb/dabusb.c28
-rw-r--r--drivers/usb/dc2xx.c18
-rw-r--r--drivers/usb/devio.c25
-rw-r--r--drivers/usb/dsbr100.c39
-rw-r--r--drivers/usb/hid.c16
-rw-r--r--drivers/usb/hub.c41
-rw-r--r--drivers/usb/ibmcam.c69
-rw-r--r--drivers/usb/mdc800.c26
-rw-r--r--drivers/usb/microtek.c90
-rw-r--r--drivers/usb/net1080.c18
-rw-r--r--drivers/usb/ov511.c380
-rw-r--r--drivers/usb/pegasus.c306
-rw-r--r--drivers/usb/pegasus.h198
-rw-r--r--drivers/usb/plusb.c794
-rw-r--r--drivers/usb/plusb.h48
-rw-r--r--drivers/usb/printer.c30
-rw-r--r--drivers/usb/rio500.c34
-rw-r--r--drivers/usb/scanner.c95
-rw-r--r--drivers/usb/scanner.h75
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/belkin_sa.c576
-rw-r--r--drivers/usb/serial/belkin_sa.h113
-rw-r--r--drivers/usb/serial/digi_acceleport.c75
-rw-r--r--drivers/usb/serial/ftdi_sio.c368
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/keyspan.h121
-rw-r--r--drivers/usb/serial/keyspan_pda.c28
-rw-r--r--drivers/usb/serial/omninet.c16
-rw-r--r--drivers/usb/serial/usb-serial.h7
-rw-r--r--drivers/usb/serial/usbserial.c38
-rw-r--r--drivers/usb/serial/visor.c18
-rw-r--r--drivers/usb/serial/whiteheat.c39
-rw-r--r--drivers/usb/storage/scsiglue.c30
-rw-r--r--drivers/usb/storage/transport.c11
-rw-r--r--drivers/usb/storage/usb.c15
-rw-r--r--drivers/usb/usb-ohci.c2
-rw-r--r--drivers/usb/usb.c325
-rw-r--r--drivers/usb/usbkbd.c27
-rw-r--r--drivers/usb/usbmouse.c28
-rw-r--r--drivers/usb/uss720.c28
-rw-r--r--drivers/usb/wacom.c113
-rw-r--r--drivers/video/Makefile11
-rw-r--r--drivers/video/S3triofb.c2
-rw-r--r--drivers/video/amifb.c4
-rw-r--r--drivers/video/atafb.c4
-rw-r--r--drivers/video/clgenfb.c8
-rw-r--r--drivers/video/cyberfb.c4
-rw-r--r--drivers/video/fm2fb.c2
-rw-r--r--drivers/video/g364fb.c2
-rw-r--r--drivers/video/hpfb.c4
-rw-r--r--drivers/video/retz3fb.c4
-rw-r--r--drivers/video/riva/fbdev.c51
-rw-r--r--drivers/video/sis/Makefile12
-rw-r--r--drivers/video/sis/initdef.h138
-rw-r--r--drivers/video/sis/sis.h64
-rw-r--r--drivers/video/sis/sis_300.c1524
-rw-r--r--drivers/video/sis/sis_300.h163
-rw-r--r--drivers/video/sis/sis_301.c2868
-rw-r--r--drivers/video/sis/sis_301.h224
-rw-r--r--drivers/video/sis/sis_main.c2374
-rw-r--r--drivers/video/sisfb.c3619
-rw-r--r--drivers/video/tgafb.c4
-rw-r--r--drivers/video/vfb.c3
-rw-r--r--drivers/video/vgacon.c40
-rw-r--r--drivers/video/virgefb.c4
-rw-r--r--fs/Config.in1
-rw-r--r--fs/adfs/inode.c4
-rw-r--r--fs/affs/inode.c7
-rw-r--r--fs/affs/symlink.c2
-rw-r--r--fs/autofs/inode.c1
-rw-r--r--fs/autofs4/inode.c8
-rw-r--r--fs/bfs/dir.c4
-rw-r--r--fs/buffer.c13
-rw-r--r--fs/coda/symlink.c2
-rw-r--r--fs/cramfs/inode.c14
-rw-r--r--fs/devfs/base.c7
-rw-r--r--fs/devpts/inode.c9
-rw-r--r--fs/dnotify.c11
-rw-r--r--fs/dquot.c2
-rw-r--r--fs/efs/dir.c3
-rw-r--r--fs/efs/symlink.c2
-rw-r--r--fs/exec.c4
-rw-r--r--fs/ext2/ialloc.c9
-rw-r--r--fs/fat/inode.c10
-rw-r--r--fs/fcntl.c4
-rw-r--r--fs/file_table.c7
-rw-r--r--fs/hpfs/namei.c2
-rw-r--r--fs/isofs/dir.c100
-rw-r--r--fs/isofs/inode.c249
-rw-r--r--fs/isofs/joliet.c3
-rw-r--r--fs/isofs/namei.c197
-rw-r--r--fs/isofs/rock.c2
-rw-r--r--fs/jffs/inode-v23.c7
-rw-r--r--fs/jffs/intrep.c141
-rw-r--r--fs/lockd/clntlock.c4
-rw-r--r--fs/lockd/clntproc.c4
-rw-r--r--fs/lockd/svclock.c2
-rw-r--r--fs/locks.c115
-rw-r--r--fs/minix/bitmap.c8
-rw-r--r--fs/namei.c7
-rw-r--r--fs/ncpfs/dir.c6
-rw-r--r--fs/ncpfs/file.c9
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/ioctl.c10
-rw-r--r--fs/ncpfs/mmap.c7
-rw-r--r--fs/ncpfs/ncplib_kernel.c2
-rw-r--r--fs/ncpfs/symlink.c2
-rw-r--r--fs/nfs/dir.c8
-rw-r--r--fs/nfs/inode.c7
-rw-r--r--fs/nfs/read.c4
-rw-r--r--fs/nfs/symlink.c4
-rw-r--r--fs/nfs/write.c23
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/ntfs/fs.c8
-rw-r--r--fs/ntfs/inode.c6
-rw-r--r--fs/ntfs/super.c2
-rw-r--r--fs/pipe.c4
-rw-r--r--fs/proc/array.c2
-rw-r--r--fs/proc/base.c32
-rw-r--r--fs/proc/generic.c10
-rw-r--r--fs/proc/inode.c15
-rw-r--r--fs/proc/proc_misc.c174
-rw-r--r--fs/proc/root.c14
-rw-r--r--fs/ramfs/inode.c15
-rw-r--r--fs/select.c9
-rw-r--r--fs/smbfs/cache.c8
-rw-r--r--fs/smbfs/inode.c4
-rw-r--r--fs/sysv/ialloc.c8
-rw-r--r--fs/udf/dir.c6
-rw-r--r--fs/udf/file.c4
-rw-r--r--fs/udf/ialloc.c10
-rw-r--r--fs/udf/inode.c7
-rw-r--r--fs/udf/symlink.c2
-rw-r--r--fs/ufs/ialloc.c10
-rw-r--r--fs/umsdos/dir.c2
-rw-r--r--fs/umsdos/emd.c8
-rw-r--r--include/asm-alpha/atomic.h4
-rw-r--r--include/asm-alpha/compiler.h9
-rw-r--r--include/asm-alpha/module.h11
-rw-r--r--include/asm-alpha/param.h4
-rw-r--r--include/asm-alpha/pgtable.h3
-rw-r--r--include/asm-alpha/semaphore-helper.h128
-rw-r--r--include/asm-alpha/semaphore.h482
-rw-r--r--include/asm-alpha/spinlock.h2
-rw-r--r--include/asm-alpha/xor.h855
-rw-r--r--include/asm-arm/module.h11
-rw-r--r--include/asm-arm/pgtable.h3
-rw-r--r--include/asm-arm/xor.h1
-rw-r--r--include/asm-generic/xor.h322
-rw-r--r--include/asm-i386/bugs.h204
-rw-r--r--include/asm-i386/cpufeature.h73
-rw-r--r--include/asm-i386/elf.h6
-rw-r--r--include/asm-i386/highmem.h17
-rw-r--r--include/asm-i386/i387.h1
-rw-r--r--include/asm-i386/module.h11
-rw-r--r--include/asm-i386/pgtable.h3
-rw-r--r--include/asm-i386/processor.h135
-rw-r--r--include/asm-i386/xor.h858
-rw-r--r--include/asm-ia64/xor.h283
-rw-r--r--include/asm-m68k/module.h11
-rw-r--r--include/asm-m68k/pgtable.h3
-rw-r--r--include/asm-m68k/xor.h1
-rw-r--r--include/asm-mips/module.h11
-rw-r--r--include/asm-mips/pgtable.h3
-rw-r--r--include/asm-mips/resource.h9
-rw-r--r--include/asm-mips/xor.h1
-rw-r--r--include/asm-mips64/module.h11
-rw-r--r--include/asm-mips64/pgtable.h3
-rw-r--r--include/asm-mips64/sn/ioc3.h13
-rw-r--r--include/asm-mips64/xor.h1
-rw-r--r--include/asm-ppc/8xx_immap.h2
-rw-r--r--include/asm-ppc/amigahw.h2
-rw-r--r--include/asm-ppc/amigaints.h2
-rw-r--r--include/asm-ppc/amigappc.h2
-rw-r--r--include/asm-ppc/backlight.h2
-rw-r--r--include/asm-ppc/bitops.h2
-rw-r--r--include/asm-ppc/board.h2
-rw-r--r--include/asm-ppc/bootinfo.h2
-rw-r--r--include/asm-ppc/byteorder.h9
-rw-r--r--include/asm-ppc/cache.h2
-rw-r--r--include/asm-ppc/checksum.h2
-rw-r--r--include/asm-ppc/cpm_8260.h2
-rw-r--r--include/asm-ppc/current.h2
-rw-r--r--include/asm-ppc/dbdma.h2
-rw-r--r--include/asm-ppc/delay.h2
-rw-r--r--include/asm-ppc/dma.h3
-rw-r--r--include/asm-ppc/elf.h42
-rw-r--r--include/asm-ppc/feature.h2
-rw-r--r--include/asm-ppc/floppy.h2
-rw-r--r--include/asm-ppc/gemini.h2
-rw-r--r--include/asm-ppc/gemini_serial.h2
-rw-r--r--include/asm-ppc/hardirq.h2
-rw-r--r--include/asm-ppc/highmem.h17
-rw-r--r--include/asm-ppc/hw_irq.h2
-rw-r--r--include/asm-ppc/ide.h4
-rw-r--r--include/asm-ppc/immap_8260.h2
-rw-r--r--include/asm-ppc/init.h2
-rw-r--r--include/asm-ppc/io.h9
-rw-r--r--include/asm-ppc/ipcbuf.h24
-rw-r--r--include/asm-ppc/irq.h5
-rw-r--r--include/asm-ppc/kgdb.h2
-rw-r--r--include/asm-ppc/kmap_types.h2
-rw-r--r--include/asm-ppc/linux_logo.h2
-rw-r--r--include/asm-ppc/machdep.h3
-rw-r--r--include/asm-ppc/mbx.h3
-rw-r--r--include/asm-ppc/mc146818rtc.h2
-rw-r--r--include/asm-ppc/md.h2
-rw-r--r--include/asm-ppc/mediabay.h4
-rw-r--r--include/asm-ppc/mmu.h2
-rw-r--r--include/asm-ppc/mmu_context.h2
-rw-r--r--include/asm-ppc/module.h11
-rw-r--r--include/asm-ppc/mpc8260.h2
-rw-r--r--include/asm-ppc/mpc8xx.h2
-rw-r--r--include/asm-ppc/msgbuf.h1
-rw-r--r--include/asm-ppc/namei.h2
-rw-r--r--include/asm-ppc/nvram.h2
-rw-r--r--include/asm-ppc/oak.h2
-rw-r--r--include/asm-ppc/page.h12
-rw-r--r--include/asm-ppc/param.h4
-rw-r--r--include/asm-ppc/pci-bridge.h2
-rw-r--r--include/asm-ppc/pci.h2
-rw-r--r--include/asm-ppc/pgalloc.h29
-rw-r--r--include/asm-ppc/pgtable.h5
-rw-r--r--include/asm-ppc/pnp.h2
-rw-r--r--include/asm-ppc/prep_nvram.h2
-rw-r--r--include/asm-ppc/processor.h2
-rw-r--r--include/asm-ppc/prom.h2
-rw-r--r--include/asm-ppc/ptrace.h38
-rw-r--r--include/asm-ppc/raven.h2
-rw-r--r--include/asm-ppc/residual.h2
-rw-r--r--include/asm-ppc/rpxclassic.h2
-rw-r--r--include/asm-ppc/rpxlite.h2
-rw-r--r--include/asm-ppc/scatterlist.h2
-rw-r--r--include/asm-ppc/semaphore-helper.h2
-rw-r--r--include/asm-ppc/sembuf.h1
-rw-r--r--include/asm-ppc/serial.h2
-rw-r--r--include/asm-ppc/setup.h2
-rw-r--r--include/asm-ppc/shmbuf.h12
-rw-r--r--include/asm-ppc/siginfo.h2
-rw-r--r--include/asm-ppc/signal.h2
-rw-r--r--include/asm-ppc/smp.h2
-rw-r--r--include/asm-ppc/smplock.h2
-rw-r--r--include/asm-ppc/softirq.h2
-rw-r--r--include/asm-ppc/spinlock.h2
-rw-r--r--include/asm-ppc/stat.h2
-rw-r--r--include/asm-ppc/string.h4
-rw-r--r--include/asm-ppc/system.h2
-rw-r--r--include/asm-ppc/termbits.h2
-rw-r--r--include/asm-ppc/time.h2
-rw-r--r--include/asm-ppc/timex.h2
-rw-r--r--include/asm-ppc/tqm860.h2
-rw-r--r--include/asm-ppc/tqm8xxL.h2
-rw-r--r--include/asm-ppc/types.h8
-rw-r--r--include/asm-ppc/uaccess.h2
-rw-r--r--include/asm-ppc/unaligned.h2
-rw-r--r--include/asm-ppc/uninorth.h4
-rw-r--r--include/asm-ppc/user.h2
-rw-r--r--include/asm-ppc/vga.h2
-rw-r--r--include/asm-ppc/walnut.h2
-rw-r--r--include/asm-ppc/xor.h1
-rw-r--r--include/asm-s390/module.h11
-rw-r--r--include/asm-s390/pgtable.h3
-rw-r--r--include/asm-s390/xor.h1
-rw-r--r--include/asm-sh/module.h11
-rw-r--r--include/asm-sh/pgtable.h3
-rw-r--r--include/asm-sh/xor.h1
-rw-r--r--include/asm-sparc/bpp.h9
-rw-r--r--include/asm-sparc/ethtool.h79
-rw-r--r--include/asm-sparc/highmem.h17
-rw-r--r--include/asm-sparc/module.h11
-rw-r--r--include/asm-sparc/openpromio.h6
-rw-r--r--include/asm-sparc/pgtable.h4
-rw-r--r--include/asm-sparc/xor.h273
-rw-r--r--include/asm-sparc64/bpp.h9
-rw-r--r--include/asm-sparc64/envctrl.h4
-rw-r--r--include/asm-sparc64/ethtool.h79
-rw-r--r--include/asm-sparc64/module.h11
-rw-r--r--include/asm-sparc64/openpromio.h6
-rw-r--r--include/asm-sparc64/pgalloc.h13
-rw-r--r--include/asm-sparc64/pgtable.h8
-rw-r--r--include/asm-sparc64/xor.h396
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/agp_backend.h20
-rw-r--r--include/linux/blk.h1
-rw-r--r--include/linux/byteorder/swabb.h2
-rw-r--r--include/linux/divert.h2
-rw-r--r--include/linux/dn.h19
-rw-r--r--include/linux/ethtool.h97
-rw-r--r--include/linux/fb.h3
-rw-r--r--include/linux/fs.h10
-rw-r--r--include/linux/highmem.h44
-rw-r--r--include/linux/irda.h20
-rw-r--r--include/linux/isdn.h5
-rw-r--r--include/linux/iso_fs.h5
-rw-r--r--include/linux/kernel.h4
-rw-r--r--include/linux/kernelcapi.h2
-rw-r--r--include/linux/kmod.h36
-rw-r--r--include/linux/lapb.h2
-rw-r--r--include/linux/mm.h12
-rw-r--r--include/linux/module.h55
-rw-r--r--include/linux/mtd/cfi.h1
-rw-r--r--include/linux/mtd/map.h17
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/linux/netfilter_decnet.h20
-rw-r--r--include/linux/netlink.h1
-rw-r--r--include/linux/nfs_page.h16
-rw-r--r--include/linux/pci_ids.h6
-rw-r--r--include/linux/proc_fs.h2
-rw-r--r--include/linux/raid/md.h3
-rw-r--r--include/linux/raid/md_compatible.h4
-rw-r--r--include/linux/raid/md_k.h2
-rw-r--r--include/linux/raid/md_p.h2
-rw-r--r--include/linux/raid/md_u.h2
-rw-r--r--include/linux/raid/xor.h19
-rw-r--r--include/linux/rtnetlink.h1
-rw-r--r--include/linux/sched.h19
-rw-r--r--include/linux/sisfb.h89
-rw-r--r--include/linux/sockios.h1
-rw-r--r--include/linux/soundcard.h6
-rw-r--r--include/linux/sunrpc/debug.h2
-rw-r--r--include/linux/sunrpc/sched.h22
-rw-r--r--include/linux/synclink.h5
-rw-r--r--include/linux/sysctl.h4
-rw-r--r--include/linux/time.h4
-rw-r--r--include/linux/usb.h14
-rw-r--r--include/linux/wait.h6
-rw-r--r--include/linux/wrapper.h7
-rw-r--r--include/net/ax25.h10
-rw-r--r--include/net/dn_nsp.h24
-rw-r--r--include/net/irda/discovery.h6
-rw-r--r--include/net/irda/ircomm_core.h2
-rw-r--r--include/net/irda/ircomm_tty.h2
-rw-r--r--include/net/irda/irda.h32
-rw-r--r--include/net/irda/irda_device.h4
-rw-r--r--include/net/irda/iriap.h2
-rw-r--r--include/net/irda/irias_object.h18
-rw-r--r--include/net/irda/irlan_client.h2
-rw-r--r--include/net/irda/irlan_common.h27
-rw-r--r--include/net/irda/irlap.h6
-rw-r--r--include/net/irda/irlmp.h43
-rw-r--r--include/net/irda/irmod.h8
-rw-r--r--include/net/irda/irqueue.h29
-rw-r--r--include/net/irda/irttp.h4
-rw-r--r--include/net/irda/irtty.h2
-rw-r--r--include/net/irda/qos.h11
-rw-r--r--include/net/irda/timer.h2
-rw-r--r--include/net/x25.h6
-rw-r--r--init/main.c10
-rw-r--r--ipc/shm.c15
-rw-r--r--kernel/Makefile6
-rw-r--r--kernel/context.c60
-rw-r--r--kernel/exit.c8
-rw-r--r--kernel/fork.c6
-rw-r--r--kernel/kmod.c28
-rw-r--r--kernel/ksyms.c26
-rw-r--r--kernel/module.c343
-rw-r--r--kernel/ptrace.c6
-rw-r--r--kernel/resource.c2
-rw-r--r--kernel/sched.c79
-rw-r--r--kernel/sysctl.c13
-rw-r--r--mm/filemap.c27
-rw-r--r--mm/highmem.c25
-rw-r--r--mm/memory.c31
-rw-r--r--mm/mlock.c14
-rw-r--r--mm/mmap.c80
-rw-r--r--mm/mprotect.c14
-rw-r--r--mm/mremap.c4
-rw-r--r--mm/oom_kill.c18
-rw-r--r--mm/swap_state.c2
-rw-r--r--mm/vmalloc.c22
-rw-r--r--mm/vmscan.c3
-rw-r--r--net/Makefile2
-rw-r--r--net/README2
-rw-r--r--net/atm/pvc.c2
-rw-r--r--net/atm/signaling.c1
-rw-r--r--net/atm/svc.c1
-rw-r--r--net/ax25/sysctl_net_ax25.c27
-rw-r--r--net/bridge/br_fdb.c3
-rw-r--r--net/bridge/br_if.c6
-rw-r--r--net/bridge/br_ioctl.c12
-rw-r--r--net/core/datagram.c2
-rw-r--r--net/core/dev.c89
-rw-r--r--net/core/scm.c8
-rw-r--r--net/core/sock.c4
-rw-r--r--net/decnet/Config.in4
-rw-r--r--net/decnet/TODO20
-rw-r--r--net/decnet/af_decnet.c27
-rw-r--r--net/decnet/dn_dev.c6
-rw-r--r--net/decnet/dn_nsp_in.c179
-rw-r--r--net/decnet/dn_nsp_out.c6
-rw-r--r--net/decnet/dn_route.c6
-rw-r--r--net/decnet/sysctl_net_decnet.c1
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/tcp.c4
-rw-r--r--net/ipv4/tcp_ipv4.c147
-rw-r--r--net/ipv6/ndisc.c3
-rw-r--r--net/ipv6/route.c14
-rw-r--r--net/ipx/Config.in6
-rw-r--r--net/irda/Config.in1
-rw-r--r--net/irda/Makefile13
-rw-r--r--net/irda/af_irda.c713
-rw-r--r--net/irda/compressors/irda_deflate.c56
-rw-r--r--net/irda/discovery.c154
-rw-r--r--net/irda/ircomm/ircomm_core.c5
-rw-r--r--net/irda/ircomm/ircomm_tty.c15
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c15
-rw-r--r--net/irda/irda_device.c8
-rw-r--r--net/irda/iriap.c13
-rw-r--r--net/irda/irias_object.c55
-rw-r--r--net/irda/irlan/irlan_client.c90
-rw-r--r--net/irda/irlan/irlan_common.c253
-rw-r--r--net/irda/irlan/irlan_eth.c41
-rw-r--r--net/irda/irlan/irlan_provider.c79
-rw-r--r--net/irda/irlap.c49
-rw-r--r--net/irda/irlap_comp.c2
-rw-r--r--net/irda/irlap_event.c212
-rw-r--r--net/irda/irlap_frame.c64
-rw-r--r--net/irda/irlmp.c168
-rw-r--r--net/irda/irlmp_event.c15
-rw-r--r--net/irda/irlmp_frame.c67
-rw-r--r--net/irda/irnet/Config.in1
-rw-r--r--net/irda/irnet/Makefile22
-rw-r--r--net/irda/irnet/irnet.h453
-rw-r--r--net/irda/irnet/irnet_irda.c1481
-rw-r--r--net/irda/irnet/irnet_irda.h169
-rw-r--r--net/irda/irnet/irnet_ppp.c1052
-rw-r--r--net/irda/irnet/irnet_ppp.h130
-rw-r--r--net/irda/irqueue.c126
-rw-r--r--net/irda/irsyms.c (renamed from net/irda/irmod.c)299
-rw-r--r--net/irda/irsysctl.c27
-rw-r--r--net/irda/irttp.c34
-rw-r--r--net/irda/parameters.c10
-rw-r--r--net/irda/qos.c86
-rw-r--r--net/irda/timer.c32
-rw-r--r--net/irda/wrapper.c10
-rw-r--r--net/khttpd/README11
-rw-r--r--net/khttpd/datasending.c6
-rw-r--r--net/khttpd/main.c9
-rw-r--r--net/lapb/lapb_iface.c10
-rw-r--r--net/lapb/lapb_in.c16
-rw-r--r--net/netlink/af_netlink.c4
-rw-r--r--net/socket.c6
-rw-r--r--net/sunrpc/sched.c31
-rw-r--r--net/unix/af_unix.c4
-rw-r--r--net/unix/garbage.c2
-rw-r--r--net/x25/af_x25.c41
-rw-r--r--net/x25/x25_dev.c11
-rw-r--r--net/x25/x25_in.c17
-rw-r--r--net/x25/x25_out.c30
960 files changed, 36409 insertions, 22745 deletions
diff --git a/CREDITS b/CREDITS
index ced88f564..7f8a8c70c 100644
--- a/CREDITS
+++ b/CREDITS
@@ -765,11 +765,10 @@ S: D-57250 Netphen
S: Germany
N: Rik Faith
-E: faith@cs.unc.edu
E: faith@acm.org
-D: Author: Future Domain TMC-16x0 SCSI driver
-D: Debugging: SCSI code; Cyclades serial driver; APM driver
-D: Debugging: XFree86 Mach 32 server, accelerated server code
+D: Future Domain TMC-16x0 SCSI driver (author)
+D: APM driver (early port)
+D: DRM drivers (author of several)
N: János Farkas
E: chexum@shadow.banki.hu
@@ -912,6 +911,15 @@ S: 8124 Constitution Apt. 7
S: Sterling Heights, Michigan 48313
S: USA
+N: William Greathouse
+E: wgreathouse@smva.com
+E: wgreathouse@myfavoritei.com
+D: Current Belkin USB Serial Adapter F5U103 hacker
+D: Kernel hacker, embedded systems
+S: 7802 Fitzwater Road
+S: Brecksville, OH 44141-1334
+S: USA
+
N: Tristan Greaves
E: Tristan.Greaves@icl.com
E: tmg296@ecs.soton.ac.uk
@@ -1425,9 +1433,10 @@ D: bits and pieces of USB core code.
N: Russell Kroll
E: rkroll@exploits.org
W: http://www.exploits.org/
-D: V4L Aztech radio card driver, mods to Aimslab driver
-S: Post Office Box 49458
-S: Colorado Springs, Colorado 80949-9458
+D: V4L radio cards: radio-aztech (new), others (bugfixes/features)
+D: Loopback block device: dynamic sizing ("max_loop" as module)
+S: Post Office Box 691886
+S: San Antonio, Texas 78269-1886
S: USA
N: Andrzej M. Krzysztofowicz
@@ -1590,7 +1599,8 @@ N: Robert M. Love
E: rml@tech9.net
E: rml@ufl.edu
D: misc. kernel hacking and debugging
-S: FL, USA
+S: Gainesville, Florida 32608
+S: USA
N: Martin von Löwis
E: loewis@informatik.hu-berlin.de
@@ -2239,11 +2249,12 @@ S: D-68789 St.Leon-Rot
S: Germany
N: Stephen Rothwell
-E: sfr@linuxcare.com
+E: sfr@linuxcare.com.au
W: http://linuxcare.com.au/sfr
P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02
D: Boot/setup/build work for setup > 2K
D: Author, APM driver
+D: Directory notification
S: 66 Maltby Circuit
S: Wanniassa ACT 2903
S: Australia
@@ -2624,17 +2635,14 @@ S: Rockville, Maryland 20853
S: USA
N: Stephen Tweedie
-E: sct@dcs.ed.ac.uk
+E: sct@redhat.com
P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69
+P: 1024D/43BE7544 D2A4 8556 08E6 90E7 076C BA3F 243F 20A4 43BE 7544
D: Second extended file system developer
D: General filesystem hacker
D: kswap vm management code
-S: Dept. of Computer Science
-S: University of Edinburgh
-S: JCMB, The King's Buildings
-S: Mayfield Road
-S: Edinburgh
-S: EH9 3JZ
+S: 44 Campbell Park Crescent
+S: Edinburgh EH13 0HT
S: United Kingdom
N: Thomas Uhl
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 93386cb2e..a7bca2f14 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -43,6 +43,8 @@ digiboard.txt
- info on the Digiboard PC/X{i,e,eve} multiport boards.
digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
+dnotify.txt
+ - info about directory notification in Linux.
exception.txt
- how Linux v2.2 handles exceptions without verify_area etc.
fb/
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 4927cd8b7..76c55c43c 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -77,7 +77,7 @@ CONFIG_EXPERIMENTAL
in some special cases. Detailed bug reports from people familiar
with the kernel internals are usually welcomed by the developers
(before submitting bug reports, please read the documents README,
- MAINTAINERS, REPORTING_BUGS, Documentation/BUG-HUNTING, and
+ MAINTAINERS, REPORTING-BUGS, Documentation/BUG-HUNTING, and
Documentation/oops-tracing.txt in the kernel source).
This option will also make obsoleted drivers available. These are
@@ -113,7 +113,7 @@ CONFIG_SMP
Management" code will be disabled if you say Y here.
See also the files Documentation/smp.tex, Documentation/smp.txt,
- Documentation/IO-APIC.txt, Documentation/nmi_watchdog.txt and the
+ Documentation/i386/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.
@@ -2069,6 +2069,23 @@ CONFIG_IP_NF_COMPAT_IPFWADM
If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say `N'.
+TCP Explicit Congestion Notification support
+CONFIG_INET_ECN
+ Explicit Congestion Notification (ECN) allows routers to notify
+ clients about network congestion, resulting in fewer dropped packets
+ and increased network performance. This option adds ECN support to the
+ Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn) which
+ allows ECN support to be disabled at runtime.
+
+ Note that, on the Internet, there are many broken firewalls which
+ refuse connections from ECN-enabled machines, and it may be a while
+ before these firewalls are fixed. Until then, to access a site behind
+ such a firewall (some of which are major sites, at the time of this
+ writing) you will have to disable this option, either by saying N now
+ or by using the sysctl.
+
+ If in doubt, say N.
+
SYN flood protection
CONFIG_SYN_COOKIES
Normal TCP/IP networking is open to an attack known as "SYN
@@ -2355,7 +2372,7 @@ CONFIG_AGP
Intel 440LX/BX/GX support
CONFIG_AGP_INTEL
This option gives you AGP support for the GLX component of the
- XFree86 4.x on Intel 440LX/BX/GX chipsets.
+ XFree86 4.x on Intel 440LX/BX/GX, 815, and 840 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
@@ -2363,9 +2380,9 @@ CONFIG_AGP_INTEL
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.
+ This option gives you AGP support for the Xserver on the Intel 810
+ and 815 chipset boards for their on-board integrated graphics. This
+ is required to do any useful video modes with these boards.
VIA chipset support
CONFIG_AGP_VIA
@@ -2482,6 +2499,20 @@ CONFIG_MCA
Documentation/mca.txt (and especially the web page given there)
before attempting to build an MCA bus kernel.
+EISA support
+CONFIG_EISA
+ The Extended Industry Standard Architecture (EISA) bus was
+ developed as an open alternative to the IBM MicroChannel bus.
+
+ The EISA bus provided some of the features of the IBM MicroChannel
+ bus while maintaining backward compatibility with cards made for
+ the older ISA bus. The EISA bus saw limited use between 1988 and 1995
+ when it was made obsolete by the PCI bus.
+
+ Say Y here if you are building a kernel for an EISA-based machine.
+
+ Otherwise, say N.
+
SGI Visual Workstation support
CONFIG_VISWS
The SGI Visual Workstation series is an IA32-based workstation
@@ -2855,6 +2886,7 @@ CONFIG_M386
- "Pentium-MMX" for the Intel Pentium MMX.
- "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II.
- "Pentium-III" for the Intel Pentium III.
+ - "Pentium-4" for the Intel Pentium 4
- "K6" for the AMD K6, K6-II and K6-III (aka K6-3D).
- "Athlon" for the AMD Athlon (K7).
- "Crusoe" for the Transmeta Crusoe series.
@@ -3488,7 +3520,7 @@ CONFIG_PARPORT
The module will be called parport.o. If you have more than one
parallel port and want to specify which port and IRQ to be used by
this driver at module load time, take a look at
- Documentation/networking/parport.txt.
+ Documentation/parport.txt.
If unsure, say Y.
@@ -3631,7 +3663,7 @@ CONFIG_INET
"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.
+ Documentation/networking/ip-sysctl.txt.
Short answer: say Y.
@@ -5012,7 +5044,7 @@ Compaq Smart Array support
CONFIG_BLK_CPQ_CISS_DA
This is the driver for Compaq Smart Array controllers.
Everyone using these boards should say Y here.
- See "linux/Documentation/cciss.txt" for the current list of
+ See Documentation/cciss.txt for the current list of
boards supported by this driver, and for further information
on the use of this driver.
@@ -14012,7 +14044,7 @@ CONFIG_SOUND_MSS
SGI Visual Workstation on-board audio
CONFIG_SOUND_VWSND
Say Y or M if you have an SGI Visual Workstation and you want to
- be able to use its on-board audio. Read Documentation/sound/visws
+ be able to use its on-board audio. Read Documentation/sound/vwsnd
for more info on this driver's capabilities.
Ensoniq Soundscape support
@@ -14045,8 +14077,7 @@ CONFIG_TRIX_BOOT_FILE
Support for OPTi MAD16 and/or Mozart based cards
CONFIG_SOUND_MAD16
Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
- 82C928 or 82C929 or 82C931) audio interface chip. For the 82C931,
- please read drivers/sound/README.C931. These chips are currently
+ 82C928 or 82C929 or 82C931) audio interface chip. These chips are
quite common so it's possible that many no-name cards have one of
them. In addition the MAD16 chip is used in some cards made by known
manufacturers such as Turtle Beach (Tropez), Reveal (some models)
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index 952dbc652..5201a2f54 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -305,19 +305,23 @@ Here is the new interface:
If D-cache aliasing is not an issue, this routine may
simply be defined as a nop on that architecture.
- TODO: If we set aside a few bits in page->flags as
- "architecture private", these interfaces could
- be implemented much more efficiently. This would
- allow one to "defer" (perhaps indefinitely) the
- actual flush if there are currently no user processes
- mapping this page.
-
- The idea is, first at flush_dcache_page() time, if
- page->mapping->i_mmap is an empty list, just mark
- one of the architecture private page flag bits.
- Later, in update_mmu_cache(), a check could be made
- of this flag bit, and if set the flush is done
- and the flag bit is cleared.
+ There is a bit set aside in page->flags (PG_arch_1) as
+ "architecture private". The kernel guarentees that,
+ for pagecache pages, it will clear this bit when such
+ a page first enters the pagecache.
+
+ This allows these interfaces to be implemented much more
+ efficiently. It allows one to "defer" (perhaps indefinitely)
+ the actual flush if there are currently no user processes
+ mapping this page. See sparc64's flush_dcache_page and
+ update_mmu_cache implementations for an example of how to go
+ about doing this.
+
+ The idea is, first at flush_dcache_page() time, if
+ page->mapping->i_mmap{,_shared} are empty lists, just mark the
+ architecture private page flag bit. Later, in
+ update_mmu_cache(), a check is made of this flag bit, and if
+ set the flush is done and the flag bit is cleared.
XXX Not documented: flush_icache_page(), need to talk to Paul
Mackerras, David Mosberger-Tang, et al.
diff --git a/Documentation/dnotify.txt b/Documentation/dnotify.txt
new file mode 100644
index 000000000..9f8611803
--- /dev/null
+++ b/Documentation/dnotify.txt
@@ -0,0 +1,92 @@
+ Linux Directory Notification
+ ============================
+
+ Stephen Rothwell <sfr@linuxcare.com.au>
+
+The intention of directory notification is to allow user applications
+to be notified when a directory, or any of the files in it, are changed.
+The basic mechanism involves the application registering for notification
+on a directory using a fcntl(2) call and the notifications themselves
+being delivered using signals.
+
+The application decides which "events" it wants to be notified about.
+The currently defined events are:
+
+ DN_ACCESS A file in the directory was accessed (read)
+ DN_MODIFY A file in the directory was modified (write,truncate)
+ DN_CREATE A file was created in the directory
+ DN_DELETE A file was unlinked from directory
+ DN_RENAME A file in the directory was renamed
+ DN_ATTRIB A file in the directory had its attributes
+ changed (chmod,chown)
+
+Usually, the application must reregister after each notification, but
+if DN_MULTISHOT is or'ed with the event mask, then the registration will
+remain until explicitly removed (by registering for no events).
+
+By default, SIGIO will be delivered to the process and no other useful
+information. However, if the F_SETSIG fcntl(2) call is used to let the
+kernel know which signal to deliver, a siginfo structure will be passed to
+the signal handler and the si_fd member of that structure will contain the
+file descriptor associated with the direcory in which the event occured.
+
+Preferably the application will choose one of the real time signals
+(SIGRTMIN + <n>) so that the notifications may be queued. This is
+especially important if DN_MULTISHOT is specified.
+
+Implementation expectations (features and bugs :-))
+---------------------------
+
+The notification should work for any local access to files even if the
+actual file system is on a remote server. This implies that remote
+access to files served by local user mode servers should be notified.
+Also, remote accesses to files served by a local kernel NFS server should
+be notified.
+
+In order to make the impact on the file system code as small as possible,
+the problem of hard links to files has been ignored. So if a file (x)
+exists in two directories (a and b) then a change to the file using the
+name "a/x" should be notified to a program expecting notifications on
+directory "a", but will not be notified to one expecting notifications on
+directory "b".
+
+Also, files that are unlinked, will still cause notifications in the
+last directory that they were linked to.
+
+Example
+-------
+
+ #define _GNU_SOURCE /* needed to get the defines */
+ #include <fcntl.h> /* in glibc 2.2 this has the needed
+ values defined */
+ #include <signal.h>
+ #include <stdio.h>
+ #include <unistd.h>
+
+ static volatile int event_fd;
+
+ static void handler(int sig, siginfo_t *si, void *data)
+ {
+ event_fd = si->si_fd;
+ }
+
+ int main(void)
+ {
+ struct sigaction act;
+ int fd;
+
+ act.sa_sigaction = handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ sigaction(SIGRTMIN, &act, NULL);
+
+ fd = open(".", O_RDONLY);
+ fcntl(fd, F_SETSIG, SIGRTMIN);
+ fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
+ /* we will now be notified if any of the files
+ in "." is modified or new files are created */
+ while (1) {
+ pause();
+ printf("Got event on fd=%d\n", event_fd);
+ }
+ }
diff --git a/Documentation/fb/matroxfb.txt b/Documentation/fb/matroxfb.txt
index 0b8068dc5..a3bbe6b92 100644
--- a/Documentation/fb/matroxfb.txt
+++ b/Documentation/fb/matroxfb.txt
@@ -253,7 +253,7 @@ depth:X - Bits per pixel: 0=text, 4,8,15,16,24 or 32. Default depends on
`vesa'.
If you know capabilities of your monitor, you can specify some (or all) of
-`pixclk', `fh' and `fv'. In this case, `pixclock' is computed so that
+`maxclk', `fh' and `fv'. In this case, `pixclock' is computed so that
pixclock <= maxclk, real_fh <= fh and real_fv <= fv.
maxclk:X - maximum dotclock. X can be specified in MHz, kHz or Hz. Default is
diff --git a/Documentation/isdn/README.act2000 b/Documentation/isdn/README.act2000
index 0846d96b3..ce7115e7f 100644
--- a/Documentation/isdn/README.act2000
+++ b/Documentation/isdn/README.act2000
@@ -1,4 +1,4 @@
-$Id: README.act2000,v 1.2 1998/04/29 19:49:06 he Exp $
+$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
This document describes the ACT2000 driver for the
IBM Active 2000 ISDN card.
diff --git a/Documentation/isdn/README.eicon b/Documentation/isdn/README.eicon
index a77542a67..16dd09eb9 100644
--- a/Documentation/isdn/README.eicon
+++ b/Documentation/isdn/README.eicon
@@ -1,4 +1,4 @@
-$Id: README.eicon,v 1.9 2000/06/08 08:50:25 armin Exp $
+$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $
(c) 1999,2000 Armin Schindler (mac@melware.de)
(c) 1999,2000 Cytronics & Melware (info@melware.de)
diff --git a/Documentation/isdn/README.icn b/Documentation/isdn/README.icn
index 37aa7f3d0..a5f55eadb 100644
--- a/Documentation/isdn/README.icn
+++ b/Documentation/isdn/README.icn
@@ -1,4 +1,4 @@
-$Id: README.icn,v 1.6 1998/04/29 19:49:08 he Exp $
+$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
You can get the ICN-ISDN-card from:
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 13a663e3e..1b63892c6 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -640,6 +640,12 @@ The public interface of Rules.make consists of the following variables:
but then you will notice a lot of extra compiles when you edit
any source file. Blame CONFIG_MODVERSIONS for this.]
+ Data that is passed to other objects via registration functions
+ (e.g. pci_register_driver, pm_register) does not need to be marked
+ as EXPORT_SYMBOL. The objects that pass data via registration
+ functions do not need to be marked as OX_OBJS, unless they also have
+ exported symbols.
+
Rules.make compiles all the $(O_OBJS) and $(OX_OBJS) files.
It then calls "$(LD) -r" to merge these files into one .o file
with the name $(O_TARGET). This $(O_TARGET) name also appears
diff --git a/Documentation/networking/bridge.txt b/Documentation/networking/bridge.txt
index 043a14b16..66ffb4c1f 100644
--- a/Documentation/networking/bridge.txt
+++ b/Documentation/networking/bridge.txt
@@ -1,11 +1,11 @@
In order to use the ethernet bridging functionality you'll need the
-userspace tools available at ftp://openrock.net/bridge. The tarball
-available there contains extensive documentation, but if you still have
-questions, don't hesitate to post to the mailing list (more info at
-http://openrock.net/mailman/listinfo/bridge). You can also mail me at
-buytenh@openrock.net.
+userspace tools available at http://www.math.leidenuniv.nl/~buytenh/bridge.
+The tarball available there contains extensive documentation, but if you
+still have questions, don't hesitate to post to the mailing list (more info
+at http://www.math.leidenuniv.nl/mailman/listinfo/bridge). You can also
+mail me at buytenh@gnu.org.
Lennert Buytenhek
-<buytenh@openrock.net>
+<buytenh@gnu.org>
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index aade6928c..419906891 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -203,7 +203,7 @@ tcp_fack - BOOLEAN
tcp_dsack - BOOLEAN
Allows TCP to send "duplicate" SACKs.
-tcp_ecn - BOOLEN
+tcp_ecn - BOOLEAN
Enable Explicit Congestion Notification in TCP.
tcp_reordering - INTEGER
@@ -376,4 +376,4 @@ kuznet@ms2.inr.ac.ru
Updated by:
Andi Kleen
ak@muc.de
-$Id: ip-sysctl.txt,v 1.16 2000/08/13 18:24:11 davem Exp $
+$Id: ip-sysctl.txt,v 1.17 2000/11/06 07:15:36 davem Exp $
diff --git a/Documentation/networking/lapb-module.txt b/Documentation/networking/lapb-module.txt
index 28a000838..d4fc8f221 100644
--- a/Documentation/networking/lapb-module.txt
+++ b/Documentation/networking/lapb-module.txt
@@ -2,6 +2,8 @@
Jonathan Naylor 29.12.96
+Changed (Henner Eisen, 2000-10-29): int return value for data_indication()
+
The LAPB module will be a separately compiled module for use by any parts of
the Linux operating system that require a LAPB service. This document
defines the interfaces to, and the services provided by this module. The
@@ -37,7 +39,7 @@ struct lapb_register_struct {
void (*connect_indication)(int token, int reason);
void (*disconnect_confirmation)(int token, int reason);
void (*disconnect_indication)(int token, int reason);
- void (*data_indication)(int token, struct sk_buff *skb);
+ int (*data_indication)(int token, struct sk_buff *skb);
void (*data_transmit)(int token, struct sk_buff *skb);
};
@@ -240,7 +242,7 @@ LAPB_TIMEDOUT No response was received in N2 tries from the remote
system.
-void (*data_indication)(void *token, struct sk_buff *skb);
+int (*data_indication)(void *token, struct sk_buff *skb);
This is called by the LAPB module when data has been received from the
remote system that should be passed onto the next layer in the protocol
@@ -248,6 +250,10 @@ stack. The skbuff becomes the property of the device driver and the LAPB
module will not perform any more actions on it. The skb->data pointer will
be pointing to the first byte of data after the LAPB header.
+This method should return NET_RX_DROP (as defined in the header
+file include/linux/netdevice.h) if and only if the frame was dropped
+before it could be delivered to the upper layer.
+
void (*data_transmit)(void *token, struct sk_buff *skb);
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
new file mode 100644
index 000000000..8769040b3
--- /dev/null
+++ b/Documentation/networking/netdevices.txt
@@ -0,0 +1,42 @@
+
+Network Devices, the Kernel, and You!
+
+
+Introduction
+============
+The following is a random collection of documentation regarding
+network devices.
+
+
+
+struct net_device synchronization rules
+=======================================
+dev->open:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->stop:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->do_ioctl:
+ Locking: Inside rtnl_lock() semaphore.
+ Sleeping: OK
+
+dev->get_stats:
+ Locking: Inside dev_base_lock spinlock.
+ Sleeping: NO
+
+dev->hard_start_xmit:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+dev->tx_timeout:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+dev->set_multicast_list:
+ Locking: Inside dev->xmit_lock spinlock.
+ Sleeping: NO
+
+
diff --git a/Documentation/networking/sis900.txt b/Documentation/networking/sis900.txt
index 6c26c9927..b6de27947 100644
--- a/Documentation/networking/sis900.txt
+++ b/Documentation/networking/sis900.txt
@@ -1,468 +1,245 @@
- SiS 900/7016 Fast Ethernet Device Driver
- by Ollie Lho (ollie@sis.com.tw)
- November 4, 1999. Document Revision: 0.2
-
- This document gives some information on installation and usage of SiS
- 900/7016 device driver under Linux.
- ______________________________________________________________________
-
- Table of Contents
-
-
- 1. Introduction
-
- 2. License
-
- 3. Changes
-
- 4. Tested Environment
-
- 5. Files in This Package
-
- 6. Installation
-
- 6.1 Kernel version later than 2.2.11 and 2.3.15
- 6.1.1 Building the driver as loadable module
- 6.1.2 Building the driver into kernel
- 6.2 Earlier Kernel Version in 2.2.x and 2.3.x Series
-
- 7. Known Problems and Bugs
-
- 8. Revision History
-
- 9. Acknowledgements
-
-
-
- ______________________________________________________________________
-
- 1. Introduction
-
- This document describes the revision 1.06 of SiS 900/7016 Fast
- Ethernet device driver under Linux. The driver is developed by Silicon
- Integrated System Corp. and distributed freely under the GNU General
- Public License (GPL). The driver can be compiled as a loadable module
- and used under Linux kernel version 2.2.x. With minimal changes, the
- driver can also be used under 2.3.x kernel, please see section
- ``Installation''. If you are intended to use the driver for earlier
- kernels, you are on your own.
-
- The driver is tested with usual TCP/IP applications including FTP,
- Telnet, Netscape etc. and is used constantly by the developers.
-
- Please send all comments/fixes/questions to Ollie Lho.
-
-
- 2. License
-
-
-
-
-
-
-
-
-
-
- Copyright (C) 1999 Silicon Integrated System Corp.
-
- 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
-
-
-
-
-
- 3. Changes
-
- Changes made in Revision 1.06
-
- 1. Separation of sis900.c and sis900.h in order to move most constant
- definition to sis900.h (many of those constants were corrected)
-
- 2. Clean up PCI detection, the pci-scan from Donald Becker were not
- used, just simple pci_find_*.
-
- 3. MII detection is modified to support multiple mii transceiver.
-
- 4. Bugs in read_eeprom, mdio_* were removed.
-
- 5. Lot of sis900 irrelevant comments were removed/changed and more
- comments were added to reflect the real situation.
-
- 6. Clean up of physical/virtual address space mess in buffer
- descriptors.
-
- 7. Better transmit/receive error handling.
-
- 8. The driver now uses zero-copy single buffer management scheme to
- improve performance.
-
- 9. Names of variables were changed to be more consistent.
-
- 10.
- Clean up of auo-negotiation and timer code.
-
- 11.
- Automatic detection and change of PHY on the fly.
-
-
- 4. Tested Environment
-
- This driver is developed on the following hardware
-
- o Intel Celeron 336 with SiS 620 (rev 02) chipset
-
- o SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card
-
- and tested with these software environments
-
- o Red Hat Linux version 6.0
-
- o Linux kernel version 2.2.13
-
- o Netscape version 4.6
-
- o NcFTP 3.0.0 beta 18
-
- o Samba version 2.0.3
-
-
- 5. Files in This Package
-
- In the package you can find these files:
-
-
- sis900-2.2.x.c
- Driver source for kernel 2.2.x
-
- sis900-2.3.x.c
- Driver source for kernel 2.3.x
-
- sis900.h
- Header file for both 2.2.x and 2.3.x kernel
-
- sis900.sgml
- Linux-Doc SGML source of the document
-
-
- 6. Installation
-
- Silicon Integrated System Corp. is cooperating closely with core Linux
- Kernel developers. The revisions of SiS 900 driver are distributed by
- the usual channels for kernel tar files and patches. Those kernel tar
- files for official kernel and patches for kernel pre-release can be
- download at official kernel ftp site
- <http://ftp.kernel.org/pub/linux/kernel/> and its mirrors. The 1.06
- revision can be found in kernel version later than 2.3.15 and
- pre-2.2.14. If you have no prior experience in networking under
- Linux, please read Ethernet HOWTO and Networking HOWTO available from
- Linux Documentation Project (LDP).
-
- The installation procedure are different according to your kernel
- versions.
-
-
- 6.1. Kernel version later than 2.2.11 and 2.3.15
-
- The driver is bundled in release later than 2.2.11 and 2.3.15 so this
- is the most easy case. Be sure you have the appropriate packages for
- compiling kernel source. Those packages are listed in
- Document/Changes in kernel source distribution. There are two
- alternative ways to install the driver
-
-
- 6.1.1. Building the driver as loadable module
-
- To build the driver as a loadable kernel module you have to
- reconfigure the kernel to activate network support by
-
-
-
- make config
-
-
-
-
- Choose "Network Device Support" to "Y" and "Ethernet Support" to "Y".
- Then you have to choose "SiS 900 Fast Ethernet Adapter Support" to
- "M".
-
- After reconfiguring the kernel, you can make the driver module by
-
-
- make modules
-
-
-
-
- The driver should be compiled with no errors. After compiling the
- driver, the driver can be installed to proper place by
-
-
-
- make modules_install
-
-
-
-
- Load the driver into kernel by
-
-
-
- insmod sis900
-
-
-
-
- When loading the driver into memory, some information message can be
- view by
-
-
-
- dmesg
-
-
-
-
- or
-
-
- cat /var/log/message
-
-
-
-
- If the driver is loaded properly you will have messages similar to
- this:
-
-
-
- sis900.c: v1.06 11/04/99
- eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
- eth0: SiS 900 Internal MII PHY transceiver found at address 1.
- eth0: Using SiS 900 Internal MII PHY as default
-
-
-
-
- showing the version of the driver and the results of probing routine.
-
- Once the driver is loaded, network can be brought up by
-
-
-
- /sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK
-
-
-
-
-
- where IPADDR, BROADCAST, NETMASK are your IP address, broadcast
- address and netmask respectively. For more information on how to
- configure network interface, please refer to Networking HOWTO.
-
- The link status is also shown by kernel messages. For example, after
- the network interface is activated, you may have the message:
-
-
-
- eth0: Media Link On 100mbps full-duplex
-
-
-
-
- If you try to unplug the twist pair (TP) cable you will get
-
-
-
- eth0: Media Link Off
-
-
-
-
- indicating that the link is failed.
-
-
- 6.1.2. Building the driver into kernel
-
- If you want to make the driver into kernel, choose "Y" rather than "M"
- on "SiS 900 Fast Ethernet Adapter Support" when configuring the
- kernel. Build the kernel image in the usual way
-
-
-
- make dep
-
- make clean
-
- make bzlilo
-
-
-
-
- Next time the system reboot, you have the driver in memory.
-
-
- 6.2. Earlier Kernel Version in 2.2.x and 2.3.x Series
-
- Installing the driver for earlier kernels in 2.2.x and 2.3.x series
- requires a little bit more work. First you have to copy sis900-2.x.x.c
- to /usr/src/linux/drivers/net/ and you have to modify some files
- manually (sorry !! no patch available !!)
-
- in Space.c, add
-
-
- extern int sis900_probe(struct device *dev);
-
- ...
-
- #ifdef CONFIG_SIS900
- {sis900_probe,0},
- #endif
-
-
- in Config.in add
-
-
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- ... //other adapter drivers
- tristate 'SiS 900 PCI Fast Ethernet Adapter Support' CONFIG_SIS900
- ... //other adapter drivers
- fi
-
-
-
-
- in Makefile add
-
-
- ifeq ($(CONFIG_SIS900),y)
- L_OBJS += sis900.o
- else
- ifeq ($(CONFIG_SIS900),m)
- M_OBJS += sis900.o
- endif
- endif
-
-
-
-
- After modifying these files, the driver can be build as described in
- the previous section.
-
-
- 7. Known Problems and Bugs
-
- There are some known problems and bugs. If you find any other bugs
- please mail to ollie@sis.com.tw
-
- 1. AM79C901 HomePNA PHY is not thoroughly tested, there may be some
- bugs in the "on the fly" change of transceiver.
-
- 2. A bug is hidden somewhere in the receive buffer management code,
- the bug causes NULL pointer reference in the kernel. This fault is
- caught before bad things happen and reported with the message:
-
-
- eth0: NULL pointer encountered in Rx ring, skipping
-
-
-
-
- which can be viewed with dmesg or cat /var/log/message.
-
-
- 8. Revision History
-
-
- o November 4, 1999, Revision 1.06, Second release, lots of clean up
- and optimization.
-
- o August 8, 1999, Revision 1.05, Initial Public Release
-
-
- 9. Acknowledgements
-
- This driver was originally derived form Donald Becker's pci-skeleton
- and rtl8139 drivers. Donald also provided various suggestion regarded
- with improvements made in revision 1.06.
-
- The 1.05 revision was created by Jim Huang, AMD 79c901 support was
- added by Chin-Shan Li.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+SiS 900/7016 Fast Ethernet Device Driver
+
+Ollie Lho
+
+Lei Chun Chang
+
+ November 16, 2000. Document Revision: 0.3
+
+ This document gives some information on installation and usage of SiS
+ 900/7016 device driver under Linux.
+ _________________________________________________________________
+ _________________________________________________________________
+
+Introduction
+
+ This document describes the revision 1.06 and 1.07 of SiS 900/7016
+ Fast Ethernet device driver under Linux. The driver is developed by
+ Silicon Integrated System Corp. and distributed freely under the GNU
+ General Public License (GPL). The driver can be compiled as a loadable
+ module and used under Linux kernel version 2.2.x. (rev. 1.06) With
+ minimal changes, the driver can also be used under 2.3.x and 2.4.x
+ kernel (rev. 1.07), please see the section called Installation. If you
+ are intended to use the driver for earlier kernels, you are on your
+ own.
+
+ The driver is tested with usual TCP/IP applications including FTP,
+ Telnet, Netscape etc. and is used constantly by the developers.
+
+ Please send all comments/fixes/questions to Lei-Chun Chang.
+ _________________________________________________________________
+
+License
+
+ Copyright (C) 1999 Silicon Integrated System Corp.
+
+ 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 U
+SA
+ _________________________________________________________________
+
+Changes
+
+ Changes made in Revision 1.07
+
+ 1. Separation of sis900.c and sis900.h in order to move most constant
+ definition to sis900.h (many of those constants were corrected)
+ 2. Clean up PCI detection, the pci-scan from Donald Becker were not
+ used, just simple pci_find_*.
+ 3. MII detection is modified to support multiple mii transceiver.
+ 4. Bugs in read_eeprom, mdio_* were removed.
+ 5. Lot of sis900 irrelevant comments were removed/changed and more
+ comments were added to reflect the real situation.
+ 6. Clean up of physical/virtual address space mess in buffer
+ descriptors.
+ 7. Better transmit/receive error handling.
+ 8. The driver now uses zero-copy single buffer management scheme to
+ improve performance.
+ 9. Names of variables were changed to be more consistent.
+ 10. Clean up of auo-negotiation and timer code.
+ 11. Automatic detection and change of PHY on the fly.
+ 12. Bug in mac probing fixed.
+ 13. Fix 630E equalier problem by modifying the equalizer workaround
+ rule.
+ 14. Support for ICS1893 10/100 Interated PHYceiver.
+ 15. Support for media select by ifconfig.
+ _________________________________________________________________
+
+Tested Environment
+
+ This driver is developed on the following hardware
+
+ * Intel Celeron 500 with SiS 630 (rev 02) chipset
+ * SiS 900 (rev 01) and SiS 7016/7014 Fast Ethernet Card
+
+ and tested with these software environments
+
+ * Red Hat Linux version 6.2
+ * Linux kernel version 2.4.0
+ * Netscape version 4.6
+ * NcFTP 3.0.0 beta 18
+ * Samba version 2.0.3
+ _________________________________________________________________
+
+Files in This Package
+
+ In the package you can find these files:
+
+ sis900.c
+ Driver source file in C
+
+ sis900.h
+ Header file for sis900.c
+
+ sis900.sgml
+ DocBook SGML source of the document
+
+ sis900.txt
+ Driver document in plain text
+ _________________________________________________________________
+
+Installation
+
+ Silicon Integrated System Corp. is cooperating closely with core Linux
+ Kernel developers. The revisions of SiS 900 driver are distributed by
+ the usuall channels for kernel tar files and patches. Those kernel tar
+ files for official kernel and patches for kernel pre-release can be
+ download at official kernel ftp site and its mirrors. The 1.06
+ revision can be found in kernel version later than 2.3.15 and
+ pre-2.2.14, and 1.07 revision can be found in kernel version 2.4.0. If
+ you have no prior experience in networking under Linux, please read
+ Ethernet HOWTO and Networking HOWTO available from Linux Documentation
+ Project (LDP).
+
+ The driver is bundled in release later than 2.2.11 and 2.3.15 so this
+ is the most easy case. Be sure you have the appropriate packages for
+ compiling kernel source. Those packages are listed in Document/Changes
+ in kernel source distribution. If you have to install the driver other
+ than those bundled in kernel release, you should have your driver file
+ sis900.c and sis900.h copied into /usr/src/linux/drivers/net/ first.
+ There are two alternative ways to install the driver
+ _________________________________________________________________
+
+Building the driver as loadable module
+
+ To build the driver as a loadable kernel module you have to
+ reconfigure the kernel to activate network support by
+
+make menuconfig
+
+ Choose "Loadable module support --->", then select "Enable loadable
+ module support".
+
+ Choose "Network Device Support --->", select "Ethernet (10 or
+ 100Mbit)". Then select "EISA, VLB, PCI and on board controllers", and
+ choose "SiS 900/7016 PCI Fast Ethernet Adapter support" to "M".
+
+ After reconfiguring the kernel, you can make the driver module by
+
+make modules
+
+ The driver should be compiled with no errors. After compiling the
+ driver, the driver can be installed to proper place by
+
+make modules_install
+
+ Load the driver into kernel by
+
+insmod sis900
+
+ When loading the driver into memory, some information message can be
+ view by
+
+dmesg
+
+ or
+cat /var/log/message
+
+ If the driver is loaded properly you will have messages similar to
+ this:
+
+sis900.c: v1.07.06 11/07/2000
+eth0: SiS 900 PCI Fast Ethernet at 0xd000, IRQ 10, 00:00:e8:83:7f:a4.
+eth0: SiS 900 Internal MII PHY transceiver found at address 1.
+eth0: Using SiS 900 Internal MII PHY as default
+
+ showing the version of the driver and the results of probing routine.
+
+ Once the driver is loaded, network can be brought up by
+
+/sbin/ifconfig eth0 IPADDR broadcast BROADCAST netmask NETMASK
+
+ where IPADDR, BROADCAST, NETMASK are your IP address, broadcast
+ address and netmask respectively. For more information on how to
+ configure network interface, please refer to Networking HOWTO.
+
+ The link status is also shown by kernel messages. For example, after
+ the network interface is activated, you may have the message:
+
+eth0: Media Link On 100mbps full-duplex
+
+ If you try to unplug the twist pair (TP) cable you will get
+
+eth0: Media Link Off
+
+ indicating that the link is failed.
+ _________________________________________________________________
+
+Building the driver into kernel
+
+ If you want to make the driver into kernel, choose "Y" rather than "M"
+ on "SiS 900/7016 PCI Fast Ethernet Adapter support" when configuring
+ the kernel. Build the kernel image in the usual way
+
+make dep
+
+make clean
+
+make bzlilo
+
+ Next time the system reboot, you have the driver in memory.
+ _________________________________________________________________
+
+Known Problems and Bugs
+
+ There are some known problems and bugs. If you find any other bugs
+ please mail to lcchang@sis.com.tw
+
+ 1. AM79C901 HomePNA PHY is not thoroughly tested, there may be some
+ bugs in the "on the fly" change of transceiver.
+ 2. A bug is hidden somewhere in the receive buffer management code,
+ the bug causes NULL pointer reference in the kernel. This fault is
+ caught before bad things happen and reported with the message:
+ eth0: NULL pointer encountered in Rx ring, skipping which can be
+ viewed with dmesg or cat /var/log/message.
+ _________________________________________________________________
+
+Revision History
+
+ * November 13, 2000, Revision 1.07, seventh release, 630E problem
+ fixed and furthur clean up.
+ * November 4, 1999, Revision 1.06, Second release, lots of clean up
+ and optimization.
+ * August 8, 1999, Revision 1.05, Initial Public Release
+ _________________________________________________________________
+
+Acknowledgements
+
+ This driver was originally derived form Donald Becker's pci-skeleton
+ and rtl8139 drivers. Donald also provided various suggestion regarded
+ with improvements made in revision 1.06.
+
+ The 1.05 revision was created by Jim Huang, AMD 79c901 support was
+ added by Chin-Shan Li.
diff --git a/Documentation/networking/tulip.txt b/Documentation/networking/tulip.txt
index 5363811cb..bd104e11d 100644
--- a/Documentation/networking/tulip.txt
+++ b/Documentation/networking/tulip.txt
@@ -1,20 +1,26 @@
Tulip Ethernet Card Driver
Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-The Tulip driver is developed by Donald Becker and changed by
+The Tulip driver was developed by Donald Becker and changed by
Takashi Manabe and a cast of thousands.
+For 2.4.x and later kernels, the Linux Tulip driver is available at
+http://sourceforge.net/projects/tulip/
+
This driver is for the Digital "Tulip" Ethernet adapter interface.
It should work with most DEC 21*4*-based chips/ethercards, as well as
with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ The author may be reached as becker@scyld.com, or C/O
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- Additional information available at
- http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
-
+ Additional information on Donald Becker's tulip.c
+ is available at http://www.scyld.com/network/tulip.html
+
+
+
+
Theory of Operation
Board Compatibility
@@ -24,7 +30,7 @@ This device driver is designed for the DECchip "Tulip", Digital's
single-chip ethernet controllers for PCI. Supported members of the family
are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
-supported.
+supported.
These chips are used on at least 140 unique PCI board designs. The great
number of chips and board designs supported is the reason for the
@@ -43,7 +49,7 @@ Some boards have EEPROMs tables with default media entry. The factory default
is usually "autoselect". This should only be overridden when using
transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
for forcing full-duplex when used with old link partners that do not do
-autonegotiation.
+autonegotiation.
Driver operation
================
@@ -142,6 +148,15 @@ tulip_core.c - Driver core (a.k.a. where "everything else" goes)
Version history
===============
+0.9.11 (November 3, 2000):
+* Eliminate extra bus accesses when sharing interrupts (prumpf)
+* Barrier following ownership descriptor bit flip (prumpf)
+* Endianness fixes for >14 addresses in setup frames (prumpf)
+* Report link beat to kernel/userspace via netif_carrier_*. (kuznet)
+* Better spinlocking in set_rx_mode.
+* Fix I/O resource request failure error messages (DaveM catch)
+* Handle DMA allocation failure.
+
0.9.10 (September 6, 2000):
* Simple interrupt mitigation (via jamal)
* More PCI ids
diff --git a/Documentation/networking/x25-iface.txt b/Documentation/networking/x25-iface.txt
index 14af1b886..975cc87eb 100644
--- a/Documentation/networking/x25-iface.txt
+++ b/Documentation/networking/x25-iface.txt
@@ -62,3 +62,62 @@ link disconnect_confirmation and a disconnect_indication.
First Byte = 0x03
LAPB parameters. To be defined.
+
+
+
+Possible Problems
+=================
+
+(Henner Eisen, 2000-10-28)
+
+The X.25 packet layer protocol depends on a reliable datalink service.
+The LAPB protocol provides such reliable service. But this reliability
+is not preserved by the Linux network device driver interface:
+
+- With Linux 2.4.x (and above) SMP kernels, packet ordering is not
+ preserved. Even if a device driver calls netif_rx(skb1) and later
+ netif_rx(skb2), skb2 might be delivered to the network layer
+ earlier that skb1.
+- Data passed upstream by means of netif_rx() might be dropped by the
+ kernel if the backlog queue is congested.
+
+The X.25 packet layer protocol will detect this and reset the virtual
+call in question. But many upper layer protocols are not designed to
+handle such N-Reset events gracefully. And frequent N-Reset events
+will always degrade performance.
+
+Thus, driver authors should make netif_rx() as reliable as possible:
+
+SMP re-ordering will not occur if the driver's interrupt handler is
+always executed on the same CPU. Thus,
+
+- Driver authors should use irq affinity for the interrupt handler.
+
+The probability of packet loss due to backlog congestion can be
+reduced by the following measures or a combination thereof:
+
+(1) Drivers for kernel versions 2.4.x and above should always check the
+ return value of netif_rx(). If it returns NET_RX_DROP, the
+ driver's LAPB protocol must not confirm reception of the frame
+ to the peer.
+ This will reliably suppress packet loss. The LAPB protocol will
+ automatically cause the peer to re-transmit the dropped packet
+ later.
+ The lapb module interface was modified to support this. Its
+ data_indication() method should now transparently pass the
+ netif_rx() return value to the (lapb mopdule) caller.
+(2) Drivers for kernel versions 2.2.x should always check the global
+ variable netdev_dropping when a new frame is received. The driver
+ should only call netif_rx() if netdev_dropping is zero. Otherwise
+ the driver should not confirm delivery of the frame and drop it.
+ Alternatively, the driver can queue the frame internally and call
+ netif_rx() later when netif_dropping is 0 again. In that case, delivery
+ confirmation should also be deferred such that the internal queue
+ cannot grow to much.
+ This will not reliably avoid packet loss, but the probability
+ of packet loss in netif_rx() path will be significantly reduced.
+(3) Additionally, driver authors might consider to support
+ CONFIG_NET_HW_FLOWCONTROL. This allows the driver to be woken up
+ when a previously congested backlog queue becomes empty again.
+ The driver could uses this for flow-controlling the peer by means
+ of the LAPB protocol's flow-control service.
diff --git a/Documentation/usb/hotplug.txt b/Documentation/usb/hotplug.txt
new file mode 100644
index 000000000..a526ffc67
--- /dev/null
+++ b/Documentation/usb/hotplug.txt
@@ -0,0 +1,124 @@
+USB HOTPLUGGING
+
+In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices
+into the bus with power on. In most cases, users expect the devices to become
+immediately usable. That means the system must do many things, including:
+
+ - Find a driver that can handle the device. That may involve
+ loading a kernel module; newer drivers can use modutils to
+ publish their device (and class) support to user utilities.
+
+ - Bind a driver to that device. That's done using the USB
+ device driver's probe() routine.
+
+ - Tell other subsystems to configure the new device. Print
+ queues may need to be enabled, networks brought up, disk
+ partitions mounted, and so on. In some cases these will
+ be driver-specific actions.
+
+This involves a mix of kernel mode and user mode actions. Making devices
+be immediately usable means that any user mode actions can't wait for an
+administrator to do them: the kernel must trigger them, either passively
+(triggering some monitoring daemon to invoke a helper program) or
+actively (calling such a user mode helper program directly).
+
+Those triggered actions must support a system's administrative policies;
+such programs are called "policy agents" here. Typically they involve
+shell scripts that dispatch to more familiar administration tools.
+
+
+KERNEL HOTPLUG HELPER (/sbin/hotplug)
+
+When you compile with CONFIG_HOTPLUG, you get a new kernel parameter:
+/proc/sys/kernel/hotplug, which normally holds the pathname "/sbin/hotplug".
+That parameter names a program which the kernel may invoke at various times.
+
+The /sbin/hotplug program can be invoked by any subsystem as part of its
+reaction to a configuration change, from a thread in that subsystem.
+Only one parameter is required: the name of a subsystem being notified of
+some kernel event. That name is used as the first key for further event
+dispatch; any other argument and environment parameters are specified by
+the subsystem making that invocation.
+
+A reference implementation of a /sbin/hotplug script is available at the
+http://www.linux-usb.org website, which works USB for but also knows how to
+delegate to any /etc/hotplug/$TYPE.agent policy agent present.
+
+
+USB POLICY AGENT
+
+The USB subsystem currently invokes /sbin/hotplug when USB devices
+are added or removed from system. The invocation is done by the kernel
+hub daemon thread [khubd], or else as part of root hub initialization
+(done by init, modprobe, kapmd, etc). Its single command line parameter
+is the string "usb", and it passes these environment variables:
+
+ ACTION ... "add", "remove"
+ PRODUCT ... USB vendor, product, and version codes (hex)
+ TYPE ... device class codes (decimal)
+ INTERFACE ... interface 0 class codes (decimal)
+
+If "usbdevfs" is configured, DEVICE and DEVFS are also passed. DEVICE is
+the pathname of the device, and is useful for devices with multiple and/or
+alternate interfaces that complicate driver selection.
+
+Currently available policy agent implementations can load drivers for
+modules, and can invoke driver-specific setup scripts. The newest ones
+leverage USB modutils support. Later agents might unload drivers.
+
+
+USB MODUTILS SUPPORT
+
+Current versions of modutils will create a "modules.usbmap" file which
+contains the entries from each driver's MODULE_DEVICE_TABLE. Such files
+can be used by various user mode policy agents to make sure all the right
+driver modules get loaded, either at boot time or later.
+
+See <linux/usb.h> for full information about such table entries; or look
+at existing drivers. Each table entry describes one or more criteria to
+be used when matching a driver to a device or class of devices.
+
+A short example, for a driver that supports several specific USB devices
+and their quirks, might have a MODULE_DEVICE_TABLE like this:
+
+ static const struct usb_device_id mydriver_id_table = {
+ { idVendor: 0x9999, idProduct 0xaaaa, driver_info: QUIRK_X },
+ { idVendor: 0xbbbb, idProduct 0x8888, driver_info: QUIRK_Y|QUIRK_Z },
+ ...
+ { } /* end with an all-zeroes entry */
+ }
+ MODULE_DEVICE_TABLE (usb, mydriver_id_table);
+
+Most USB device drivers should pass these tables to the USB subsystem as
+well as to the module management subsystem. Not all, though: some driver
+frameworks connect using interfaces layered over USB, and so they won't
+need such a "struct usb_driver".
+
+Drivers that connect directly to the USB subsystem should be declared
+something like this:
+
+ static struct usb_driver mydriver = {
+ name: "mydriver",
+ id_table: mydriver_id_table,
+ probe: my_probe,
+ disconnect: my_disconnect,
+
+ /*
+ if using the usb chardev framework:
+ minor: MY_USB_MINOR_START,
+ fops: my_file_ops,
+ if exposing any operations through usbdevfs:
+ ioctl: my_ioctl,
+ */
+ }
+
+When the USB subsystem knows about a driver's device ID table, it's used when
+choosing drivers to probe(). The thread doing new device processing checks
+drivers' device ID entries from the MODULE_DEVICE_TABLE against interface and
+device descriptors for the device. It will only call probe() if there is a
+match, and the third argument to probe() will be the entry that matched.
+
+If you don't provide an id_table for your driver, then your driver may get
+probed for each new device; the third parameter to probe() will be null.
+
+
diff --git a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt
index 304a1ec90..bc9cad2ab 100644
--- a/Documentation/usb/ov511.txt
+++ b/Documentation/usb/ov511.txt
@@ -5,22 +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 Stability improvements
- o Support for hue control
- o 160x120 mostly working
- o OV6620 color problems fixed
- o More WebCam 3 detection improvements
-
INTRODUCTION:
This is a driver for the OV511, a USB-only chip used in many "webcam" devices.
Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It
supports streaming and capture of color or monochrome video via the Video4Linux
-API. Most V4L apps are compatible with it, but a few videoconferencing programs
+API. Most V4L apps are compatible with it, but a few video-conferencing programs
do not work yet. The following resolutions are supported: 640x480, 448x336,
384x288, 352x288, and 320x240.
+If you need more information, please visit the OV511 homepage at the above URL.
+
WHAT YOU NEED:
- If you want to help with the development, get the chip's specification docs at
@@ -81,29 +76,6 @@ Now you should be able to run xawtv. Right click for the options dialog. If
you get a scrambled image it is likely that you made a mistake in Xawtv.ad.
Try setting the size to 320x240 if all else fails.
-FAQ:
-Q: "Why does the picture have noise and look grainy"
-A: This is a problem at low light levels, and may be also due to subtle bugs in
- the code. The cause is most likely the OV7610 settings we are currently
- using. I am looking into this problem.
-
-Q: "The driver sometimes says `Failed to read OV7610 ID.' What is the deal?"
-A: The I2C code that allows the OV511 to communicate with the camera chip is a
- bit flaky right now. This message means that the I2C bus never got
- initialized properly, and the camera will most likely not work even if you
- disable this warning. Try unloading/reloading the driver or unplugging/re-
- plugging the camera if this happens. Also try increasing the i2c_detect_tries
- parameter (see below).
-
-Q: "Why do you bother with this phony camera detection crap? It doesn't do
- anything useful!"
-A: The main purpose of only supporting known camera models is to force people
- with new camera models to tell me about them, so I can assemble the list
- above, and so the code can know what CCD chip you have. Right now, nearly all
- of the cameras use the OV7610 and consequently I have not put support for
- other ones in, so the value of the detection code is questionable. Eventually
- though, new CCDs might appear and we will be fortunate to have the detection.
-
MODULE PARAMETERS:
You can set these with: insmod ov511 NAME=VALUE
@@ -136,7 +108,7 @@ MODULE PARAMETERS:
or so lines higher than the red component. This is only apparent in
images with white objects on black backgrounds at 640x480. Setting this
to 1 will realign the color planes correctly. NOTE: This is still
- experimental and very buggy. You will likely need a fast (500 Mhz) CPU.
+ experimental and very buggy. You will likely need a fast (500 MHz) CPU.
NAME: snapshot
TYPE: integer (boolean)
@@ -203,15 +175,21 @@ MODULE PARAMETERS:
DESC: Prevent apps from timing out if frame is not done in time. This is
useful if you are having problems with Xawtv getting "stuck" on a frame
when your system is under heavy load.
-
+
+ NAME: sensor_gbr
+ TYPE: boolean
+ DEFAULT: 0
+ DESC: This makes the sensor output GBR422 instead of YUV420. This saves the
+ driver the trouble of converting YUV to RGB, but it currently does not
+ work very well (the colors are not quite right)
+
WORKING FEATURES:
- o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, 320x240, and
- 160x120
- o RGB24, YUV420, YUV422, YUYV, and YUV422P color
+ o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240
+ o RGB24, RGB565, YUV420, YUV422, YUYV, and YUV422P color
o Monochrome
o Setting/getting of saturation, contrast, brightness, and hue (only some of
them work the OV7620 and OV7620AE)
- o proc status reporting
+ o /proc status reporting
EXPERIMENTAL FEATURES:
o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
@@ -219,6 +197,7 @@ EXPERIMENTAL FEATURES:
o Snapshot mode (only works with some read() based apps; see below for more)
o OV6620 sensor support
o GBR422 parsing
+ o 160x120
TODO:
o Fix the noise / grainy image problem.
@@ -227,18 +206,19 @@ TODO:
so we can't really work on that yet. Please kindly inform OmniVision that you
would like them to release their specifications to the Linux community.
o YUV422
- o Get snapshot mode working with mmap().
o Fix fixFrameRGBoffset(). It is not stable yet with streaming video.
- o Get autoadjust disable working
o V4L2 support (Probably not until it goes into the kernel)
- o Creative WebCam III has problems initializing its sensor. This should be
- fixed now, but if you still have problems let me know.
o Get rid of the memory management functions (put them in videodev.c??)
o Setting of contrast and brightness not working with 7620/7620AE
o Driver/camera state save/restore for when USB supports suspend/resume
o Unstable on SMP systems
o OV7620/OV6620 experience frame corruption with moving objects
o OV6620 is too dark
+ o 176x144 support
+ o Driver sometimes hangs upon close() with OHCI
+ o The image should always be written properly to the mmap'ed buffer as long as
+ the requested image size is at least the minimum size. This will likely
+ require a rewrite of all the parsing code.
HOW TO CONTACT ME:
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 4ffe021a7..a6efeefa5 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -151,6 +151,37 @@ Digi AccelePort Driver
driver.
+Belkin USB Serial Adapter F5U103
+
+ Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
+
+Current status:
+ The following have been tested and work:
+ Baud rate 300-230400
+ Data bits 5-8
+ Stop bits 1-2
+ Parity N,E,O,M,S
+ Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)*
+ Break Set and clear
+ Line contrl Input/Output query and control **
+
+ * Hardware input flow control is only enabled for firmware
+ levels above 2.06. Read source code comments describing Belkin
+ firmware errata. Hardware output flow control is working for all
+ firmware versions.
+ ** Queries of inputs (CTS,DSR,CD,RI) show the last
+ reported state. Queries of outputs (DTR,RTS) show the last
+ requested state and may not reflect current state as set by
+ automatic hardware flow control.
+
+TO DO List:
+ -- Add true modem contol line query capability. Currently tracks the
+ states reported by the interrupt and the states requested.
+ -- Add error reporting back to application for UART error conditions.
+ -- Add support for flush ioctls.
+ -- Add everything else that is missing :)
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
diff --git a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST
index 0d36761d1..f513ebb48 100644
--- a/Documentation/video4linux/bttv/CARDLIST
+++ b/Documentation/video4linux/bttv/CARDLIST
@@ -48,6 +48,11 @@ bttv.o
card=46 - Zoltrix Genie TV
card=47 - Terratec TV/Radio+
card=48 - Dynalink Magic TView
+ card=49 - GV-BCTV3
+ card=50 - Prolink PV-BT878P+4E (PixelView PlayTV PAK)
+ card=51 - Eagle Wireless Capricorn2 (bt878A)
+ card=52 - Pinnacle Studio PCTV Pro
+ card=53 - Typhoon TView RDS
tuner.o
type=0 - Temic PAL
@@ -65,3 +70,4 @@ tuner.o
type=12 - Alps TSBE5
type=13 - Alps TSBC5
type=14 - Temic 4006FH5
+ type=15 - Alps TSCH6
diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
index 68818a532..4cb55586d 100644
--- a/Documentation/video4linux/bttv/Insmod-options
+++ b/Documentation/video4linux/bttv/Insmod-options
@@ -23,11 +23,19 @@ bttv.o
at the hardware). default is 1.
bttv_debug=0/1 debug messages (for capture).
default is 0 (off).
+ irq_debug=0/1 irq handler debug messages.
+ default is 0 (off).
gbuffers=2-64 number of capture buffers for mmap'ed capture.
default is 2.
gbufsize= size of capture buffers. default and
maximum value is 0x208000 (~2MB)
+ bttv_gpio=0/1
+ gpiomask=
+ audioall=
+ audiomux=
+ See Sound-FAQ for a detailed description.
+
remap, card, radio and pll accept up to four comma-separated arguments
(for multiple boards).
@@ -54,6 +62,19 @@ tvaudio.o
new, experimental module which is supported to provide a single
driver for all simple i2c audio control chips (tda/tea*).
+ insmod args:
+ tda8425 = 1 enable/disable the support for the
+ tda9840 = 1 various chips.
+ tda9850 = 1 The tea6300 can't be autodetected and is
+ tda9855 = 1 therefore off by default, if you have
+ tda9873 = 1 this one on your card (STB uses these)
+ tea6300 = 0 you have to enable it explicitly.
+ tea6420 = 1 The two tda985x chips use the same i2c
+ pic16c54 = 1 address and can't be disturgished from
+ each other, you might have to disable
+ the wrong one.
+ debug = 1 print debug messages
+
msp3400.o
The driver for the msp34xx sound processor chips. If you have a
stereo card, you probably want to insmod this one.
@@ -72,7 +93,7 @@ msp3400.o
should improve things for french people, the
carrier autoscan seems to work with FM only...
-tea6300.o
+tea6300.o - OBSOLETE (use tvaudio instead)
The driver for the tea6300 fader chip. If you have a stereo
card and the msp3400.o doesn't work, you might want to try this
one. This chip is seen on most STB TV/FM cards (usually from
@@ -81,7 +102,7 @@ tea6300.o
insmod args:
debug=1 print some debug info to the syslog.
-tda8425.o
+tda8425.o - OBSOLETE (use tvaudio instead)
The driver for the tda8425 fader chip. This driver used to be
part of bttv.c, so if your sound used to work but does not
anymore, try loading this module.
@@ -89,7 +110,7 @@ tda8425.o
insmod args:
debug=1 print some debug info to the syslog.
-tda985x.o
+tda985x.o - OBSOLETE (use tvaudio instead)
The driver for the tda9850/55 audio chips.
insmod args:
diff --git a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README
index 868feedb9..bce7e55ee 100644
--- a/Documentation/video4linux/bttv/README
+++ b/Documentation/video4linux/bttv/README
@@ -1,4 +1,8 @@
+IMPORTANT: Don't send me mails with images attached unless I ask you
+to do so. Mails with images attached will go to /dev/null unseen.
+
+
Release notes for bttv-0.7.x
============================
@@ -17,7 +21,7 @@ CONFIG_I2C=m
CONFIG_I2C_ALGOBIT=m
The latest bttv version is available here:
- http://me.in-berlin.de/~kraxel/bttv.html
+ http://www.strusel007.de/linux/bttv/
You'll find Ralphs original (mostly outdated) documentation in the
ralphs-doc subdirectory.
@@ -38,6 +42,8 @@ kernel at least once, you probably don't have do worry about this. If
not, go to /usr/src/linux and run at least "make config". Even
better, compile your own kernel, you'll never become a real hacker
else ;-)
+Note that you have to turn on video4linux support (CONFIG_VIDEO_DEV)
+in the kernel to get the videodev.o module which is required by bttv.
Make bttv work with your card
@@ -66,7 +72,8 @@ correct card type. If you get video but no sound you've very likely
specified the wrong (or no) card type. A list of supported cards is
in CARDLIST.
-If your card isn't listed in CARDLIST, you should read the Sound-FAQ.
+If your card isn't listed in CARDLIST or if you have trouble making
+audio work, you should read the Sound-FAQ.
Still doesn't work?
diff --git a/Documentation/video4linux/bttv/Sound-FAQ b/Documentation/video4linux/bttv/Sound-FAQ
index ce8895700..64611f497 100644
--- a/Documentation/video4linux/bttv/Sound-FAQ
+++ b/Documentation/video4linux/bttv/Sound-FAQ
@@ -8,12 +8,12 @@ completely by the bt8xx chip, which is common on all boards. But
sound is handled in slightly different ways on each board.
To handle the grabber boards correctly, there is a array tvcards[] in
-bttv.c, which holds the informations required for each board. Sound
-will work only, if the correct entry is used (for video it often makes
-no difference). The bttv driver prints a line to the kernel log,
-telling which card type is used. Like this one:
+bttv-cards.c, which holds the informations required for each board.
+Sound will work only, if the correct entry is used (for video it often
+makes no difference). The bttv driver prints a line to the kernel
+log, telling which card type is used. Like this one:
- bttv0: model: BT848(Hauppauge old)
+ bttv0: model: BT848(Hauppauge old) [autodetected]
You should verify this is correct. If it is'nt, you have to pass the
correct board type as insmod argument, "insmod bttv card=2" for
@@ -32,7 +32,7 @@ you might want to check the video4linux mailing list archive first...
Of course you need a correctly installed soundcard unless you have the
speakers connected directly to the grabber board. Hint: check the
-mixer settings too...
+mixer settings too. ALSA for example has everything muted by default.
How sound works in detail
@@ -48,42 +48,64 @@ bt848 chip. Another one is the data register (BT848_GPIO_DATA), where
you can get/set the status if these pins. They can be used for input
and output.
-All grabber board vendors use these pins to control an external chip
+Most grabber board vendors use these pins to control an external chip
which does the sound routing. But every board is a little different.
These pins are also used by some companies to drive remote control
-receiver chips.
+receiver chips. Some boards use the i2c bus instead of the gpio pins
+to connect the mux chip.
As mentioned above, there is a array which holds the required
informations for each known board. You basically have to create a new
-line for your board. What is in there:
+line for your board. The important fields are these two:
struct tvcard
{
- char *name;
- int inputs; /* number of video inputs */
- int tuner; /* which of them is the tuner */
- int svhs; /* which of them is the svhs input */
+ [ ... ]
u32 gpiomask;
- u32 muxsel[8]; /* video mux */
- u32 audiomux[6]; /* audio mux: Tuner, Radio, external, internal, mute, stereo */
- u32 gpiomask2; /* GPIO MUX mask (this is video) */
+ u32 audiomux[5]; /* audio mux: tuner, radio, external, internal, mute */
};
-gpiomask has all bits set which are used to control the audio mux.
-This value basically goes to the gpio output enable register. It is
-also used to mask bits when switching the audio mux (which is done by
-read-modify-write on the gpio data register).
+gpiomask specifies which pins are used to control the audio mux chip.
+The corresponding bits in the output enable register
+(BT848_GPIO_OUT_EN) will be set as these pins must be driven by the
+bt848 chip.
+
+The audiomux[] array holds the data values for the different inputs
+(i.e. which pins must be high/low for tuner/mute/...). This will be
+written to the data register (BT848_GPIO_DATA) to switch the audio
+mux.
+
What you have to do is figure out the correct values for gpiomask and
the audiomux array. If you have Windows and the drivers four your
card installed, you might to check out if you can read these registers
values used by the windows driver. A tool to do this is available
-from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil. There is
-some #ifdef'ed code in bttv.c (search for "new card") which prints
-these values before board initialization, this might help too: boot
-win, start tv app, softboot (loadlin) into linux and load bttv with
-this enabled. If you hav'nt Windows installed, this is a trial and
-error game...
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil (doesn't
+work with bt878 boards according to some reports I received). You
+might also dig around in the *.ini files of the Windows applications.
+You can have a look at the board to see which of the gpio pins are
+connected at all and then start trial-and-error ...
+
+
+Starting with release 0.7.41 bttv has a number of insmod options to
+make the gpio debugging easier:
+
+bttv_gpio=0/1 enable/disable gpio debug messages
+gpiomask=n set the gpiomask value
+audiomux=i,j,... set the values of the audiomux array
+audioall=a set the values of the audiomux array (one
+ value for all array elements, useful to check
+ out which effect the particular value has).
+
+The messages printed with bttv_gpio=1 look like this:
+
+ bttv0: gpio: en=00000027, out=00000024 in=00ffffd8 [audio: off]
+
+en = output _en_able register (BT848_GPIO_OUT_EN)
+out = _out_put bits of the data register (BT848_GPIO_DATA),
+ i.e. BT848_GPIO_DATA & BT848_GPIO_OUT_EN
+in = _in_put bits of the data register,
+ i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN
Good luck,
diff --git a/Documentation/video4linux/bttv/Specs b/Documentation/video4linux/bttv/Specs
new file mode 100644
index 000000000..79b9e576f
--- /dev/null
+++ b/Documentation/video4linux/bttv/Specs
@@ -0,0 +1,3 @@
+Philips http://www.Semiconductors.COM/pip/
+Conexant http://www.conexant.com/techinfo/default.asp
+Micronas http://www.micronas.de/pages/product_documentation/index.html
diff --git a/MAINTAINERS b/MAINTAINERS
index 4682b40e2..072d1da5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -353,6 +353,12 @@ W: http://www.dgii.com/linux,http://lameter.com/digi
L: digilnux@dgii.com
S: Maintained
+DIRECTORY NOTIFICATION
+P: Stephen Rothwell
+M: sfr@linuxcare.com.au
+L: linux-kernel@vger.kernel.org
+S: Supported
+
DISK GEOMETRY AND PARTITION HANDLING
P: Andries Brouwer
M: aeb@veritas.com
@@ -373,6 +379,12 @@ M: jrv@vanzandt.mv.com
L: blinux-list@redhat.com
S: Maintained
+DRM DRIVERS
+P: Rik Faith
+M: faith@valinux.com
+L: dri-devel@lists.sourceforge.net
+S: Supported
+
EATA-DMA SCSI DRIVER
P: Michael Neuffer
M: mike@i-Connect.Net
@@ -411,9 +423,9 @@ S: Maintained
ETHERNET BRIDGE
P: Lennert Buytenhek
-M: buytenh@openrock.net
-L: bridge@openrock.net
-W: http://openrock.net/bridge
+M: buytenh@gnu.org
+L: bridge@math.leidenuniv.nl
+W: http://www.math.leidenuniv.nl/~buytenh/bridge
S: Maintained
ETHERTEAM 16I DRIVER
@@ -1239,8 +1251,9 @@ W: http://www.kernel.dk
S: Maintained
USB SUBSYSTEM
-P: Randy Dunlap
-M: randy.dunlap@intel.com
+P: Johannes Erdfelt
+M: jerdfelt@valinux.com
+M: johannes@erdfelt.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-usb.org
@@ -1330,6 +1343,14 @@ L: linux-usb-devel@lists.sourceforge.net
S: Maintained
W: http://www.kroah.com/linux-usb/
+USB SERIAL BELKIN F5U103 DRIVER
+P: William Greathouse
+M: wgreathouse@smva.com
+M: wgreathouse@myfavoritei.com
+L: linux-usb-users@lists.sourceforge.net
+L: linux-usb-devel@lists.sourceforge.net
+S: Maintained
+
USB MASS STORAGE DRIVER
P: Matthew Dharm
M: mdharm-usb@one-eyed-alien.net
diff --git a/Makefile b/Makefile
index a7cd5a45b..6de1193ef 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test10
+EXTRAVERSION = -test11
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -180,6 +180,52 @@ DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
DRIVERS += $(DRIVERS-y)
+
+# files removed with 'make clean'
+CLEAN_FILES = \
+ kernel/ksyms.lst include/linux/compile.h \
+ vmlinux System.map \
+ .tmp* \
+ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \
+ drivers/char/conmakehash \
+ drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist \
+ drivers/zorro/devlist.h drivers/zorro/gen-devlist \
+ drivers/sound/bin2hex drivers/sound/hex2hex \
+ drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2} \
+ net/khttpd/make_times_h \
+ net/khttpd/times.h \
+ submenu*
+# directories removed with 'make clean'
+CLEAN_DIRS = \
+ modules
+
+# files removed with 'make mrproper'
+MRPROPER_FILES = \
+ include/linux/autoconf.h include/linux/version.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \
+ drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \
+ drivers/net/hamradio/soundmodem/gentbl \
+ drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h \
+ drivers/sound/*_boot.h drivers/sound/.*.boot \
+ drivers/sound/msndinit.c \
+ drivers/sound/msndperm.c \
+ drivers/sound/pndsperm.c \
+ drivers/sound/pndspini.c \
+ drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \
+ .version .config* config.in config.old \
+ scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \
+ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
+ .menuconfig.log \
+ include/asm \
+ .hdepend scripts/mkdep scripts/split-include scripts/docproc \
+ $(TOPDIR)/include/linux/modversions.h
+# directories removed with 'make mrproper'
+MRPROPER_DIRS = \
+ include/config \
+ $(TOPDIR)/include/linux/modules
+
+
include arch/$(ARCH)/Makefile
export CPPFLAGS CFLAGS AFLAGS
@@ -206,7 +252,7 @@ vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(LIBS) \
--end-group \
-o vmlinux
- $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+ $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
symlinks:
rm -f include/asm
@@ -355,49 +401,18 @@ modules modules_install: dummy
endif
clean: archclean
- rm -f kernel/ksyms.lst include/linux/compile.h
- find . -name '*.[oas]' -type f -print | grep -v lxdialog/ | xargs rm -f
- rm -f core `find . -type f -name 'core' -print`
- rm -f core `find . -type f -name '.*.flags' -print`
- rm -f vmlinux System.map
- rm -f .tmp*
- rm -f drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c
- rm -f drivers/char/conmakehash
- rm -f drivers/pci/devlist.h drivers/pci/classlist.h drivers/pci/gen-devlist
- rm -f drivers/zorro/devlist.h drivers/zorro/gen-devlist
- rm -f drivers/sound/bin2hex drivers/sound/hex2hex
- rm -f drivers/atm/fore200e_mkfirm drivers/atm/{pca,sba}*{.bin,.bin1,.bin2}
- rm -f net/khttpd/make_times_h
- rm -f net/khttpd/times.h
- rm -f submenu*
- rm -rf modules
+ find . \( -name '*.[oas]' -o -name core -o -name '.*.flags' \) -type f -print \
+ | grep -v lxdialog/ | xargs rm -f
+ rm -f $(CLEAN_FILES)
+ rm -rf $(CLEAN_DIRS)
$(MAKE) -C Documentation/DocBook clean
mrproper: clean archmrproper
- rm -f include/linux/autoconf.h include/linux/version.h
- rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
- rm -f drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h
- rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h
- rm -f drivers/net/hamradio/soundmodem/gentbl
- rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
- rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
- rm -f drivers/sound/msndinit.c
- rm -f drivers/sound/msndperm.c
- rm -f drivers/sound/pndsperm.c
- rm -f drivers/sound/pndspini.c
- rm -f drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw
- rm -f .version .config* config.in config.old
- rm -f scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp
- rm -f scripts/lxdialog/*.o scripts/lxdialog/lxdialog
- rm -f .menuconfig.log
- rm -f include/asm
- rm -rf include/config
- rm -f .depend `find . -type f -name .depend -print`
- rm -f core `find . -type f -size 0 -print`
- rm -f .hdepend scripts/mkdep scripts/split-include scripts/docproc
- rm -f $(TOPDIR)/include/linux/modversions.h
- rm -rf $(TOPDIR)/include/linux/modules
+ find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
+ rm -f $(MRPROPER_FILES)
+ rm -rf $(MRPROPER_DIRS)
$(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 '#*#' \
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 18fdcde8a..da5c361c9 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -63,12 +63,13 @@ unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
unset CONFIG_ALPHA_IRONGATE
unset CONFIG_ALPHA_BROKEN_IRQ_MASK
-unset CONFIG_ALPHA_LARGE_VMALLOC
# 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_EISA y
define_bool CONFIG_SBUS n
+define_bool CONFIG_MCA n
if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
then
@@ -214,6 +215,8 @@ if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_DP264" = "y" \
-o "$CONFIG_ALPHA_WILDFIRE" = "y" -o "$CONFIG_ALPHA_TITAN" = "y" ]
then
bool 'Large VMALLOC support' CONFIG_ALPHA_LARGE_VMALLOC
+else
+ define_bool CONFIG_ALPHA_LARGE_VMALLOC n
fi
source drivers/pci/Config.in
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 4ac2e8b0d..17285ac26 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -160,15 +160,20 @@ EXPORT_SYMBOL_NOVERS(__do_clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
-/*
- * The following are specially called from the semaphore assembly stubs.
- */
-EXPORT_SYMBOL_NOVERS(__down_failed);
-EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
-EXPORT_SYMBOL_NOVERS(__up_wakeup);
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
+/* Semaphore helper functions. */
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_failed_interruptible);
+EXPORT_SYMBOL(__up_wakeup);
+EXPORT_SYMBOL(down);
+EXPORT_SYMBOL(down_interruptible);
+EXPORT_SYMBOL(up);
+EXPORT_SYMBOL(__down_read_failed);
+EXPORT_SYMBOL(__down_write_failed);
+EXPORT_SYMBOL(__rwsem_wake);
+EXPORT_SYMBOL(down_read);
+EXPORT_SYMBOL(down_write);
+EXPORT_SYMBOL(up_read);
+EXPORT_SYMBOL(up_write);
/*
* SMP-specific symbols.
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index ac7ca67f8..080e48e43 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -747,7 +747,7 @@ probe_irq_mask(unsigned long val)
unsigned int mask;
mask = 0;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < NR_IRQS; i++) {
irq_desc_t *desc = irq_desc + i;
unsigned int status;
@@ -755,8 +755,11 @@ probe_irq_mask(unsigned long val)
status = desc->status;
if (status & IRQ_AUTODETECT) {
- if (!(status & IRQ_WAITING))
- mask |= 1 << i;
+ /* We only react to ISA interrupts */
+ if (!(status & IRQ_WAITING)) {
+ if (i < 16)
+ mask |= 1 << i;
+ }
desc->status = status & ~IRQ_AUTODETECT;
desc->handler->shutdown(i);
diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
index dc5209531..7c1c9a80c 100644
--- a/arch/alpha/kernel/semaphore.c
+++ b/arch/alpha/kernel/semaphore.c
@@ -1,139 +1,267 @@
/*
- * Generic semaphore code. Buyer beware. Do your own
- * specific changes in <asm/semaphore-helper.h>
+ * Alpha semaphore implementation.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * (C) Copyright 1999, 2000 Richard Henderson
*/
#include <linux/sched.h>
-#include <asm/semaphore-helper.h>
+
/*
* Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to sleep, while the "waking" variable is
- * incremented when the "up()" code goes to wake up waiting
- * processes.
+ *
+ * The "count" variable is decremented for each process that tries to sleep,
+ * while the "waking" variable is incremented when the "up()" code goes to
+ * wake up waiting processes.
*
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
+ * Notably, the inline "up()" and "down()" functions can efficiently test
+ * if they need to do any extra work (up needs to do something only if count
+ * was negative before the increment operation.
*
- * waking_non_zero() (from asm/semaphore.h) must execute
- * atomically.
+ * waking_non_zero() (from asm/semaphore.h) must execute atomically.
*
- * When __up() is called, the count was negative before
- * incrementing it, and we need to wake up somebody.
+ * When __up() is called, the count was negative before incrementing it,
+ * and we need to wake up somebody.
*
- * This routine adds one to the count of processes that need to
- * wake up and exit. ALL waiting processes actually wake up but
- * only the one that gets to the "waking" field first will gate
- * through and acquire the semaphore. The others will go back
- * to sleep.
+ * This routine adds one to the count of processes that need to wake up and
+ * exit. ALL waiting processes actually wake up but only the one that gets
+ * to the "waking" field first will gate through and acquire the semaphore.
+ * The others will go back to sleep.
*
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Note that these functions are only called when there is contention on the
+ * lock, and as such all this is the "non-critical" part of the whole
+ * semaphore business. The critical part is the inline stuff in
+ * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
*/
-void
-__up(struct semaphore *sem)
-{
- wake_one_more(sem);
- wake_up(&sem->wait);
-}
-
/*
* Perform the "down" function. Return zero for semaphore acquired,
* return negative for signalled out of the function.
*
- * If called from __down, the return is ignored and the wait loop is
+ * If called from down, the return is ignored and the wait loop is
* not interruptible. This means that a task waiting on a semaphore
* using "down()" cannot be killed until someone does an "up()" on
* the semaphore.
*
- * If called from __down_interruptible, the return value gets checked
+ * If called from down_interruptible, the return value gets checked
* upon return. If the return value is negative then the task continues
* with the negative value in the return register (it can be tested by
* the caller).
*
* Either form may be used in conjunction with "up()".
- *
*/
-#define DOWN_VAR \
- struct task_struct *tsk = current; \
- wait_queue_t wait; \
- init_waitqueue_entry(&wait, tsk)
-
-#define DOWN_HEAD(task_state) \
- \
- \
- tsk->state = (task_state); \
- add_wait_queue(&sem->wait, &wait); \
- \
- /* \
- * Ok, we're set up. sem->count is known to be less than zero \
- * so we must wait. \
- * \
- * We can let go the lock for purposes of waiting. \
- * We re-acquire it after awaking so as to protect \
- * all semaphore operations. \
- * \
- * If "up()" is called before we call waking_non_zero() then \
- * we will catch it right away. If it is called later then \
- * we will have to go through a wakeup cycle to catch it. \
- * \
- * Multiple waiters contend for the semaphore lock to see \
- * who gets to gate through and who has to wait some more. \
- */ \
- for (;;) {
-
-#define DOWN_TAIL(task_state) \
- tsk->state = (task_state); \
- } \
- tsk->state = TASK_RUNNING; \
- remove_wait_queue(&sem->wait, &wait)
-
void
-__down(struct semaphore * sem)
+__down_failed(struct semaphore *sem)
{
- DOWN_VAR;
- DOWN_HEAD(TASK_UNINTERRUPTIBLE);
+ DECLARE_WAITQUEUE(wait, current);
+
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down failed(%p)\n",
+ current->comm, current->pid, sem);
+#endif
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ wmb();
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ /* At this point we know that sem->count is negative. In order
+ to avoid racing with __up, we must check for wakeup before
+ going to sleep the first time. */
+
+ while (1) {
+ long ret, tmp;
+
+ /* An atomic conditional decrement of sem->waking. */
+ __asm__ __volatile__(
+ "1: ldl_l %1,%2\n"
+ " blt %1,2f\n"
+ " subl %1,1,%0\n"
+ " stl_c %0,%2\n"
+ " beq %0,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=r"(ret), "=&r"(tmp), "=m"(sem->waking)
+ : "0"(0));
+
+ if (ret)
+ break;
- if (waking_non_zero(sem))
- break;
- schedule();
+ schedule();
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
+ }
- DOWN_TAIL(TASK_UNINTERRUPTIBLE);
+ remove_wait_queue(&sem->wait, &wait);
+ current->state = TASK_RUNNING;
+
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down acquired(%p)\n",
+ current->comm, current->pid, sem);
+#endif
}
int
-__down_interruptible(struct semaphore * sem)
+__down_failed_interruptible(struct semaphore *sem)
{
- int ret = 0;
- DOWN_VAR;
- DOWN_HEAD(TASK_INTERRUPTIBLE);
-
- ret = waking_non_zero_interruptible(sem, tsk);
- if (ret)
- {
- if (ret == 1)
- /* ret != 0 only if we get interrupted -arca */
- ret = 0;
- break;
+ DECLARE_WAITQUEUE(wait, current);
+ long ret;
+
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down failed(%p)\n",
+ current->comm, current->pid, sem);
+#endif
+
+ current->state = TASK_INTERRUPTIBLE;
+ wmb();
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ while (1) {
+ long tmp, tmp2, tmp3;
+
+ /* We must undo the sem->count down_interruptible decrement
+ simultaneously and atomicly with the sem->waking
+ adjustment, otherwise we can race with __up. This is
+ accomplished by doing a 64-bit ll/sc on two 32-bit words.
+
+ "Equivalent" C. Note that we have to do this all without
+ (taken) branches in order to be a valid ll/sc sequence.
+
+ do {
+ tmp = ldq_l;
+ ret = 0;
+ if (tmp >= 0) { // waking >= 0
+ tmp += 0xffffffff00000000; // waking -= 1
+ ret = 1;
+ }
+ else if (pending) {
+ // count += 1, but since -1 + 1 carries into the
+ // high word, we have to be more careful here.
+ tmp = (tmp & 0xffffffff00000000)
+ | ((tmp + 1) & 0x00000000ffffffff);
+ ret = -EINTR;
+ }
+ tmp = stq_c = tmp;
+ } while (tmp == 0);
+ */
+
+ __asm__ __volatile__(
+ "1: ldq_l %1,%4\n"
+ " lda %0,0\n"
+ " cmovne %5,%6,%0\n"
+ " addq %1,1,%2\n"
+ " and %1,%7,%3\n"
+ " andnot %2,%7,%2\n"
+ " cmovge %1,1,%0\n"
+ " or %3,%2,%2\n"
+ " addq %1,%7,%3\n"
+ " cmovne %5,%2,%1\n"
+ " cmovge %2,%3,%1\n"
+ " stq_c %1,%4\n"
+ " beq %1,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2),
+ "=&r"(tmp3), "=m"(*sem)
+ : "r"(signal_pending(current)), "r"(-EINTR),
+ "r"(0xffffffff00000000));
+
+ /* At this point we have ret
+ 1 got the lock
+ 0 go to sleep
+ -EINTR interrupted */
+ if (ret != 0)
+ break;
+
+ schedule();
+ set_task_state(current, TASK_INTERRUPTIBLE);
}
- schedule();
- DOWN_TAIL(TASK_INTERRUPTIBLE);
- return ret;
+ remove_wait_queue(&sem->wait, &wait);
+ current->state = TASK_RUNNING;
+ wake_up(&sem->wait);
+
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down %s(%p)\n",
+ current->comm, current->pid,
+ (ret < 0 ? "interrupted" : "acquired"), sem);
+#endif
+
+ /* Convert "got the lock" to 0==success. */
+ return (ret < 0 ? ret : 0);
+}
+
+void
+__up_wakeup(struct semaphore *sem)
+{
+ wake_up(&sem->wait);
+}
+
+void
+down(struct semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down(%p) <count=%d> from %p\n",
+ current->comm, current->pid, sem,
+ atomic_read(&sem->count), __builtin_return_address(0));
+#endif
+ __down(sem);
+}
+
+int
+down_interruptible(struct semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down(%p) <count=%d> from %p\n",
+ current->comm, current->pid, sem,
+ atomic_read(&sem->count), __builtin_return_address(0));
+#endif
+ return __down_interruptible(sem);
}
int
-__down_trylock(struct semaphore * sem)
+down_trylock(struct semaphore *sem)
{
- return waking_non_zero_trylock(sem);
+ int ret;
+
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ ret = __down_trylock(sem);
+
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): down_trylock %s from %p\n",
+ current->comm, current->pid,
+ ret ? "failed" : "acquired",
+ __builtin_return_address(0));
+#endif
+
+ return ret;
+}
+
+void
+up(struct semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+#if DEBUG_SEMAPHORE
+ printk("%s(%d): up(%p) <count=%d> from %p\n",
+ current->comm, current->pid, sem,
+ atomic_read(&sem->count), __builtin_return_address(0));
+#endif
+ __up(sem);
}
@@ -142,124 +270,106 @@ __down_trylock(struct semaphore * sem)
*/
void
-__down_read(struct rw_semaphore *sem, int count)
+__down_read_failed(struct rw_semaphore *sem, int count)
{
- long tmp;
- DOWN_VAR;
+ DECLARE_WAITQUEUE(wait, current);
retry_down:
if (count < 0) {
- /* Wait for the lock to become unbiased. Readers
- are non-exclusive. */
+ /* Waiting on multiple readers and/or writers. */
- /* This takes care of granting the lock. */
- up_read(sem);
+ /* Undo the acquisition we started in down_read. */
+ atomic_inc(&sem->count);
+ current->state = TASK_UNINTERRUPTIBLE;
+ wmb();
add_wait_queue(&sem->wait, &wait);
- while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (sem->count >= 0)
- break;
+ mb();
+ while (atomic_read(&sem->count) < 0) {
schedule();
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
}
remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- __asm __volatile (
- " mb\n"
- "1: ldl_l %0,%1\n"
- " subl %0,1,%2\n"
- " subl %0,1,%0\n"
- " stl_c %2,%1\n"
- " bne %2,2f\n"
- ".subsection 2\n"
- "2: br 1b\n"
- ".previous"
- : "=r"(count), "=m"(sem->count), "=r"(tmp)
- : : "memory");
+ current->state = TASK_RUNNING;
+
+ mb();
+ count = atomic_dec_return(&sem->count);
if (count <= 0)
goto retry_down;
} else {
+ /* Waiting on exactly one writer. */
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ wmb();
add_wait_queue(&sem->wait, &wait);
+ mb();
- while (1) {
- if (test_and_clear_bit(0, &sem->granted))
- break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if ((sem->granted & 1) == 0)
- schedule();
+ while (!test_and_clear_bit(0, &sem->granted)) {
+ schedule();
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
}
remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
+ current->state = TASK_RUNNING;
}
}
void
-__down_write(struct rw_semaphore *sem, int count)
+__down_write_failed(struct rw_semaphore *sem, int count)
{
- long tmp;
- DOWN_VAR;
+ DECLARE_WAITQUEUE(wait, current);
retry_down:
if (count + RW_LOCK_BIAS < 0) {
- up_write(sem);
+ /* Waiting on multiple readers and/or writers. */
+
+ /* Undo the acquisition we started in down_write. */
+ atomic_add(RW_LOCK_BIAS, &sem->count);
+ current->state = TASK_UNINTERRUPTIBLE;
+ wmb();
add_wait_queue_exclusive(&sem->wait, &wait);
+ mb();
- while (sem->count < 0) {
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
- if (sem->count >= RW_LOCK_BIAS)
- break;
+ while (atomic_read(&sem->count) + RW_LOCK_BIAS < 0) {
schedule();
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
}
remove_wait_queue(&sem->wait, &wait);
- tsk->state = TASK_RUNNING;
-
- __asm __volatile (
- " mb\n"
- "1: ldl_l %0,%1\n"
- " ldah %2,%3(%0)\n"
- " ldah %0,%3(%0)\n"
- " stl_c %2,%1\n"
- " bne %2,2f\n"
- ".subsection 2\n"
- "2: br 1b\n"
- ".previous"
- : "=r"(count), "=m"(sem->count), "=r"(tmp)
- : "i"(-(RW_LOCK_BIAS >> 16))
- : "memory");
+ current->state = TASK_RUNNING;
+
+ count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
if (count != 0)
goto retry_down;
} else {
- /* Put ourselves at the end of the list. */
- add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
-
- while (1) {
- if (test_and_clear_bit(1, &sem->granted))
- break;
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
- if ((sem->granted & 2) == 0)
- schedule();
+ /* Waiting on exactly one writer. */
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ wmb();
+ add_wait_queue_exclusive(&sem->wait, &wait);
+ mb();
+
+ while (!test_and_clear_bit(1, &sem->granted)) {
+ schedule();
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
}
remove_wait_queue(&sem->write_bias_wait, &wait);
- tsk->state = TASK_RUNNING;
+ current->state = TASK_RUNNING;
/* If the lock is currently unbiased, awaken the sleepers.
FIXME: This wakes up the readers early in a bit of a
stampede -> bad! */
- if (sem->count >= 0)
+ count = atomic_read(&sem->count);
+ if (__builtin_expect(count >= 0, 0))
wake_up(&sem->wait);
}
}
void
-__do_rwsem_wake(struct rw_semaphore *sem, int readers)
+__rwsem_wake(struct rw_semaphore *sem, int readers)
{
if (readers) {
if (test_and_set_bit(0, &sem->granted))
@@ -271,3 +381,67 @@ __do_rwsem_wake(struct rw_semaphore *sem, int readers)
wake_up(&sem->write_bias_wait);
}
}
+
+void
+down_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+ __down_read(sem);
+#if WAITQUEUE_DEBUG
+ if (sem->granted & 2)
+ BUG();
+ if (atomic_read(&sem->writers))
+ BUG();
+ atomic_inc(&sem->readers);
+#endif
+}
+
+void
+down_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+ __down_write(sem);
+#if WAITQUEUE_DEBUG
+ if (sem->granted & 3)
+ BUG();
+ if (atomic_read(&sem->writers))
+ BUG();
+ if (atomic_read(&sem->readers))
+ BUG();
+ atomic_inc(&sem->writers);
+#endif
+}
+
+void
+up_read(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+ if (sem->granted & 2)
+ BUG();
+ if (atomic_read(&sem->writers))
+ BUG();
+ atomic_dec(&sem->readers);
+#endif
+ __up_read(sem);
+}
+
+void
+up_write(struct rw_semaphore *sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+ if (sem->granted & 3)
+ BUG();
+ if (atomic_read(&sem->readers))
+ BUG();
+ if (atomic_read(&sem->writers) != 1)
+ BUG();
+ atomic_dec(&sem->writers);
+#endif
+ __up_write(sem);
+}
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 0edf60839..bc7beb7be 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -378,6 +378,9 @@ do_settimeofday(struct timeval *tv)
* BUG: This routine does not handle hour overflow properly; it just
* sets the minutes. Usually you won't notice until after reboot!
*/
+
+extern int abs(int);
+
static int
set_rtc_mmss(unsigned long nowtime)
{
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index d22a6f522..913331a95 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -12,7 +12,7 @@ OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \
strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \
strchr.o strrchr.o memchr.o \
copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \
- csum_ipv6_magic.o strcasecmp.o semaphore.o fpreg.o \
+ csum_ipv6_magic.o strcasecmp.o fpreg.o \
callback_srm.o srm_puts.o srm_printk.o
lib.a: $(OBJS)
diff --git a/arch/alpha/lib/semaphore.S b/arch/alpha/lib/semaphore.S
deleted file mode 100644
index 517285ea4..000000000
--- a/arch/alpha/lib/semaphore.S
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * linux/arch/alpha/lib/semaphore.S
- *
- * Copyright (C) 1999, 2000 Richard Henderson
- */
-
-/*
- * The semaphore operations have a special calling sequence that
- * allow us to do a simpler in-line version of them. These routines
- * need to convert that sequence back into the C sequence when
- * there is contention on the semaphore.
- */
-
- .set noat
- .set noreorder
- .align 4
-
-/* __down_failed takes the semaphore in $24, clobbers $24 and $28. */
-
- .globl __down_failed
- .ent __down_failed
-__down_failed:
- ldgp $29,0($27)
- lda $30, -20*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $25, 17*8($30)
- stq $26, 18*8($30)
- .frame $30, 20*8, $28
- .prologue 1
-
- mov $24, $16
- jsr __down
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $25, 17*8($30)
- ldq $26, 18*8($30)
- lda $30, 20*8($30)
- ret $31, ($28), 0
- .end __down_failed
-
-/* __down_failed_interruptible takes the semaphore in $24,
- clobbers $28, returns success in $24. */
-
- .globl __down_failed_interruptible
- .ent __down_failed_interruptible
-__down_failed_interruptible:
- ldgp $29,0($27)
- lda $30, -20*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $25, 17*8($30)
- stq $26, 18*8($30)
- .frame $30, 20*8, $28
- .prologue 1
-
- mov $24, $16
- jsr __down_interruptible
- mov $0, $24
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $25, 17*8($30)
- ldq $26, 18*8($30)
- lda $30, 20*8($30)
- ret $31, ($28), 0
- .end __down_failed_interruptible
-
-/* __up_wakeup takes the semaphore in $24, clobbers $24 and $28. */
-
- .globl __up_wakeup
- .ent __up_wakeup
-__up_wakeup:
- ldgp $29,0($27)
- lda $30, -20*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $25, 17*8($30)
- stq $26, 18*8($30)
- .frame $30, 20*8, $28
- .prologue 1
-
- mov $24, $16
- jsr __up
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $25, 17*8($30)
- ldq $26, 18*8($30)
- lda $30, 20*8($30)
- ret $31, ($28), 0
- .end __up_wakeup
-
-/* __down_read_failed takes the semaphore in $24, count in $25;
- clobbers $24, $25 and $28. */
-
- .globl __down_read_failed
- .ent __down_read_failed
-__down_read_failed:
- ldgp $29,0($27)
- lda $30, -18*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $26, 17*8($30)
- .frame $30, 18*8, $28
- .prologue 1
-
- mov $24, $16
- mov $25, $17
- jsr __down_read
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $26, 17*8($30)
- lda $30, 18*8($30)
- ret $31, ($28), 0
- .end __down_read_failed
-
-/* __down_write_failed takes the semaphore in $24, count in $25;
- clobbers $24, $25 and $28. */
-
- .globl __down_write_failed
- .ent __down_write_failed
-__down_write_failed:
- ldgp $29,0($27)
- lda $30, -20*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $26, 17*8($30)
- .frame $30, 18*8, $28
- .prologue 1
-
- mov $24, $16
- mov $25, $17
- jsr __down_write
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $26, 17*8($30)
- lda $30, 18*8($30)
- ret $31, ($28), 0
- .end __down_write_failed
-
-/* __rwsem_wake takes the semaphore in $24, readers in $25;
- clobbers $24, $25, and $28. */
-
- .globl __rwsem_wake
- .ent __rwsem_wake
-__rwsem_wake:
- ldgp $29,0($27)
- lda $30, -18*8($30)
- stq $28, 0*8($30)
- stq $0, 1*8($30)
- stq $1, 2*8($30)
- stq $2, 3*8($30)
- stq $3, 4*8($30)
- stq $4, 5*8($30)
- stq $5, 6*8($30)
- stq $6, 7*8($30)
- stq $7, 8*8($30)
- stq $16, 9*8($30)
- stq $17, 10*8($30)
- stq $18, 11*8($30)
- stq $19, 12*8($30)
- stq $20, 13*8($30)
- stq $21, 14*8($30)
- stq $22, 15*8($30)
- stq $23, 16*8($30)
- stq $26, 17*8($30)
- .frame $30, 18*8, $28
- .prologue 1
-
- mov $24, $16
- mov $25, $17
- jsr __do_rwsem_wake
-
- ldq $28, 0*8($30)
- ldq $0, 1*8($30)
- ldq $1, 2*8($30)
- ldq $2, 3*8($30)
- ldq $3, 4*8($30)
- ldq $4, 5*8($30)
- ldq $5, 6*8($30)
- ldq $6, 7*8($30)
- ldq $7, 8*8($30)
- ldq $16, 9*8($30)
- ldq $17, 10*8($30)
- ldq $18, 11*8($30)
- ldq $19, 12*8($30)
- ldq $20, 13*8($30)
- ldq $21, 14*8($30)
- ldq $22, 15*8($30)
- ldq $23, 16*8($30)
- ldq $26, 17*8($30)
- lda $30, 18*8($30)
- ret $31, ($28), 0
- .end __rwsem_wake
diff --git a/arch/arm/config.in b/arch/arm/config.in
index fff056940..561cf3bf3 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -5,7 +5,9 @@
mainmenu_name "Linux Kernel Configuration"
define_bool CONFIG_ARM y
+define_bool CONFIG_EISA n
define_bool CONFIG_SBUS n
+define_bool CONFIG_MCA n
define_bool CONFIG_UID16 y
diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c
index f89852641..aac8be68b 100644
--- a/arch/arm/kernel/semaphore.c
+++ b/arch/arm/kernel/semaphore.c
@@ -58,7 +58,7 @@ void __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -78,7 +78,7 @@ void __down(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -92,7 +92,7 @@ int __down_interruptible(struct semaphore * sem)
int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -128,7 +128,7 @@ int __down_interruptible(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -197,7 +197,7 @@ struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
@@ -255,7 +255,7 @@ struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 96da8d33b..7ef695981 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -54,6 +54,10 @@ ifdef CONFIG_M686FXSR
CFLAGS += -march=i686
endif
+ifdef CONFIG_MPENTIUM4
+CFLAGS += -march=i686
+endif
+
ifdef CONFIG_MK6
CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; else echo "-march=i586"; fi)
endif
@@ -63,7 +67,7 @@ CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/nul
endif
ifdef CONFIG_MCRUSOE
-CFLAGS += -march=i586
+CFLAGS += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0
endif
ifdef CONFIG_MWINCHIPC6
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 327aa736d..d6c63a8b8 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -34,6 +34,7 @@ choice 'Processor family' \
Pentium-MMX CONFIG_M586MMX \
Pentium-Pro/Celeron/Pentium-II CONFIG_M686 \
Pentium-III CONFIG_M686FXSR \
+ Pentium-4 CONFIG_MPENTIUM4 \
K6/K6-II/K6-III CONFIG_MK6 \
Athlon/K7 CONFIG_MK7 \
Crusoe CONFIG_MCRUSOE \
@@ -92,6 +93,15 @@ if [ "$CONFIG_M686FXSR" = "y" ]; then
define_bool CONFIG_X86_FXSR y
define_bool CONFIG_X86_XMM y
fi
+if [ "$CONFIG_MPENTIUM4" = "y" ]; then
+ define_int CONFIG_X86_L1_CACHE_SHIFT 7
+ define_bool CONFIG_X86_TSC y
+ define_bool CONFIG_X86_GOOD_APIC y
+ define_bool CONFIG_X86_PGE y
+ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+ define_bool CONFIG_X86_FXSR y
+ define_bool CONFIG_X86_XMM y
+fi
if [ "$CONFIG_MK6" = "y" ]; then
define_int CONFIG_X86_L1_CACHE_SHIFT 5
define_bool CONFIG_X86_ALIGNMENT_16 y
@@ -158,6 +168,7 @@ if [ "$CONFIG_SMP" != "y" ]; then
define_bool CONFIG_X86_LOCAL_APIC y
fi
fi
+
if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
define_bool CONFIG_HAVE_DEC_LOCK y
fi
@@ -194,8 +205,12 @@ fi
source drivers/pci/Config.in
+bool 'EISA support' CONFIG_EISA
+
if [ "$CONFIG_VISWS" != "y" ]; then
bool 'MCA support' CONFIG_MCA
+else
+ define_bool CONFIG_MCA n
fi
bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index b22c770db..9f8625c6e 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -28,6 +28,7 @@ CONFIG_KMOD=y
# CONFIG_M586MMX is not set
# CONFIG_M686 is not set
CONFIG_M686FXSR=y
+# CONFIG_MPENTIUM4 is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MCRUSOE is not set
@@ -71,6 +72,7 @@ CONFIG_PCI_GOANY=y
CONFIG_PCI_BIOS=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_NAMES=y
+# CONFIG_EISA is not set
# CONFIG_MCA is not set
CONFIG_HOTPLUG=y
@@ -79,6 +81,8 @@ CONFIG_HOTPLUG=y
#
CONFIG_PCMCIA=y
CONFIG_CARDBUS=y
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
@@ -143,11 +147,12 @@ CONFIG_PACKET=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
@@ -359,21 +364,29 @@ CONFIG_NET_ETHERNET=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_TULIP is not set
+# CONFIG_DE4X5 is not set
# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PM is not set
+# CONFIG_LNE390 is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
# CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
# CONFIG_NET_POCKET is not set
#
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index f9424d105..98079f060 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -258,6 +258,8 @@ static struct ctl_table acpi_table[] =
{ACPI_FACP, "facp", &acpi_facp, 0, 0644, NULL, &acpi_do_table},
{ACPI_DSDT, "dsdt", &acpi_dsdt, 0, 0644, NULL, &acpi_do_table},
+
+ {ACPI_FACS, "facs", &acpi_facs, 0, 0644, NULL, &acpi_do_table},
{ACPI_PM1_ENABLE, "pm1_enable",
NULL, 0,
@@ -722,12 +724,21 @@ static int __init acpi_find_tables(void)
if (!acpi_init_table(&acpi_facp, dt, 1)) {
struct acpi_facp *facp
= (struct acpi_facp*) acpi_facp.table;
+ struct acpi_table *facs;
// map DSDT if it exists
- dt = acpi_map_table(facp->dsdt);
- if (acpi_init_table(&acpi_dsdt, dt, 1))
- acpi_unmap_table(dt);
-
+ if ((dt = acpi_map_table(facp->dsdt))) {
+ if (acpi_init_table(&acpi_dsdt, dt, 1))
+ acpi_unmap_table(dt);
+ }
+
+ /*
+ * map FACS if it exists
+ */
+ if ((facs = acpi_map_table(facp->facs))) {
+ if (acpi_init_table(&acpi_facs,facs,1))
+ acpi_unmap_table(facs);
+ }
break;
}
else {
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 4e5df4681..fc54896f8 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -219,39 +219,6 @@ void __init setup_local_APIC (void)
if (!test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map))
BUG();
- value = apic_read(APIC_SPIV);
- value &= ~APIC_VECTOR_MASK;
- /*
- * Enable APIC
- */
- value |= (1<<8);
-
- /*
- * Some unknown Intel IO/APIC (or APIC) errata is biting us with
- * certain networking cards. If high frequency interrupts are
- * happening on a particular IOAPIC pin, plus the IOAPIC routing
- * entry is masked/unmasked at a high rate as well then sooner or
- * later IOAPIC line gets 'stuck', no more interrupts are received
- * from the device. If focus CPU is disabled then the hang goes
- * away, oh well :-(
- *
- * [ This bug can be reproduced easily with a level-triggered
- * PCI Ne2000 networking cards and PII/PIII processors, dual
- * BX chipset. ]
- */
-#if 0
- /* Enable focus processor (bit==0) */
- value &= ~(1<<9);
-#else
- /* Disable focus processor (bit==1) */
- value |= (1<<9);
-#endif
- /*
- * Set spurious IRQ vector
- */
- value |= SPURIOUS_APIC_VECTOR;
- apic_write_around(APIC_SPIV, value);
-
/*
* Set up LVT0, LVT1:
*
@@ -323,6 +290,42 @@ void __init setup_local_APIC (void)
* Must be "all ones" explicitly for 82489DX.
*/
apic_write_around(APIC_DFR, 0xffffffff);
+
+ /*
+ * Now that we are all set up, enable the APIC
+ */
+ value = apic_read(APIC_SPIV);
+ value &= ~APIC_VECTOR_MASK;
+ /*
+ * Enable APIC
+ */
+ value |= (1<<8);
+
+ /*
+ * Some unknown Intel IO/APIC (or APIC) errata is biting us with
+ * certain networking cards. If high frequency interrupts are
+ * happening on a particular IOAPIC pin, plus the IOAPIC routing
+ * entry is masked/unmasked at a high rate as well then sooner or
+ * later IOAPIC line gets 'stuck', no more interrupts are received
+ * from the device. If focus CPU is disabled then the hang goes
+ * away, oh well :-(
+ *
+ * [ This bug can be reproduced easily with a level-triggered
+ * PCI Ne2000 networking cards and PII/PIII processors, dual
+ * BX chipset. ]
+ */
+#if 0
+ /* Enable focus processor (bit==0) */
+ value &= ~(1<<9);
+#else
+ /* Disable focus processor (bit==1) */
+ value |= (1<<9);
+#endif
+ /*
+ * Set spurious IRQ vector
+ */
+ value |= SPURIOUS_APIC_VECTOR;
+ apic_write_around(APIC_SPIV, value);
}
void __init init_apic_mappings(void)
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index b0aa2a7c3..dc47528cd 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -1126,6 +1126,7 @@ static void apm_mainloop(void)
}
#endif
}
+ remove_wait_queue(&apm_waitqueue, &wait);
}
static int check_apm_user(struct apm_user *as, const char *func)
@@ -1422,9 +1423,6 @@ static int apm(void *unused)
kapmd_running = 1;
- exit_files(current); /* daemonize doesn't do exit_files */
- current->files = init_task.files;
- atomic_inc(&current->files->count);
daemonize();
strcpy(current->comm, "kapm-idled");
@@ -1574,8 +1572,6 @@ static struct miscdevice apm_device = {
&apm_bios_fops
};
-#define APM_INIT_ERROR_RETURN return -1
-
/*
* Just start the APM thread. We do NOT want to do APM BIOS
* calls from anything but the APM thread, if for no other reason
@@ -1590,7 +1586,7 @@ static int __init apm_init(void)
{
if (apm_bios_info.version == 0) {
printk(KERN_INFO "apm: BIOS not found.\n");
- APM_INIT_ERROR_RETURN;
+ return -ENODEV;
}
printk(KERN_INFO
"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
@@ -1600,7 +1596,7 @@ static int __init apm_init(void)
driver_version);
if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
printk(KERN_INFO "apm: no 32 bit BIOS support\n");
- APM_INIT_ERROR_RETURN;
+ return -ENODEV;
}
/*
@@ -1629,15 +1625,15 @@ static int __init apm_init(void)
if (apm_disabled) {
printk(KERN_NOTICE "apm: disabled on user request.\n");
- APM_INIT_ERROR_RETURN;
+ return -ENODEV;
}
if ((smp_num_cpus > 1) && !power_off) {
printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
- APM_INIT_ERROR_RETURN;
+ return -ENODEV;
}
if (PM_IS_ACTIVE()) {
printk(KERN_NOTICE "apm: overridden by ACPI.\n");
- APM_INIT_ERROR_RETURN;
+ return -ENODEV;
}
pm_active = 1;
@@ -1686,7 +1682,7 @@ static int __init apm_init(void)
if (smp_num_cpus > 1) {
printk(KERN_NOTICE
"apm: disabled - APM is not SMP safe (power off active).\n");
- APM_INIT_ERROR_RETURN;
+ return 0;
}
misc_register(&apm_device);
diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
index ee6966d5f..59826db68 100644
--- a/arch/i386/kernel/bluesmoke.c
+++ b/arch/i386/kernel/bluesmoke.c
@@ -10,7 +10,7 @@
static int banks;
-void mcheck_fault(void)
+void do_machine_check(struct pt_regs * regs, long error_code)
{
int recover=1;
u32 alow, ahigh, high, low;
@@ -66,22 +66,19 @@ void mcheck_fault(void)
* This has to be run for each processor
*/
-void mcheck_init(void)
+void mcheck_init(struct cpuinfo_x86 *c)
{
u32 l, h;
int i;
- struct cpuinfo_x86 *c;
static int done;
- c=cpu_data+smp_processor_id();
-
- if(c->x86_vendor!=X86_VENDOR_INTEL)
+ if( c->x86_vendor != X86_VENDOR_INTEL )
return;
- if(!(c->x86_capability&X86_FEATURE_MCE))
+ if( !test_bit(X86_FEATURE_TSC, &c->x86_capability) )
return;
- if(!(c->x86_capability&X86_FEATURE_MCA))
+ if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
return;
/* Ok machine check is available */
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 4ae0ed2ee..5e3c91019 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -383,11 +383,6 @@ ENTRY(coprocessor_segment_overrun)
pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
-ENTRY(reserved)
- pushl $0
- pushl $ SYMBOL_NAME(do_reserved)
- jmp error_code
-
ENTRY(double_fault)
pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
@@ -418,7 +413,7 @@ ENTRY(page_fault)
ENTRY(machine_check)
pushl $0
- pushl $ SYMBOL_NAME(mcheck_fault)
+ pushl $ SYMBOL_NAME(do_machine_check)
jmp error_code
ENTRY(spurious_interrupt_bug)
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index ed3573426..3de4a76d1 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -49,7 +49,9 @@ extern unsigned long get_cmos_time(void);
/* platform dependent support */
EXPORT_SYMBOL(boot_cpu_data);
+#ifdef CONFIG_EISA
EXPORT_SYMBOL(EISA_bus);
+#endif
EXPORT_SYMBOL(MCA_bus);
EXPORT_SYMBOL(__verify_write);
EXPORT_SYMBOL(dump_thread);
diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
index c3d052e8a..3031432d0 100644
--- a/arch/i386/kernel/i387.c
+++ b/arch/i386/kernel/i387.c
@@ -442,6 +442,8 @@ int set_fpxregs( struct task_struct *tsk, struct user_fxsr_struct *buf )
if ( HAVE_FXSR ) {
__copy_from_user( &tsk->thread.i387.fxsave, (void *)buf,
sizeof(struct user_fxsr_struct) );
+ /* mxcsr bit 6 and 31-16 must be zero for security reasons */
+ tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
return 0;
} else {
return -EIO;
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index df377c5b4..570614282 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -374,7 +374,6 @@ void __init init_8259A(int auto_eoi)
spin_unlock_irqrestore(&i8259A_lock, flags);
}
-#ifndef CONFIG_VISWS
/*
* Note that on a 486, we don't want to do a SIGFPE on an irq13
* as the irq is unreliable, and exception 16 works correctly
@@ -400,12 +399,13 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
* New motherboards sometimes make IRQ 13 be a PCI interrupt,
* so allow interrupt sharing.
*/
-static struct irqaction irq13 = { math_error_irq, SA_SHIRQ, 0, "fpu", NULL, NULL };
+static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL };
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
+#ifndef CONFIG_VISWS
static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
#endif
@@ -494,6 +494,12 @@ void __init init_IRQ(void)
#ifndef CONFIG_VISWS
setup_irq(2, &irq2);
- setup_irq(13, &irq13);
#endif
+
+ /*
+ * External FPU? Set up irq13 if so, for
+ * original braindamaged IBM FERR coupling.
+ */
+ if (boot_cpu_data.hard_math && !cpu_has_fpu)
+ setup_irq(13, &irq13);
}
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index b17c30041..5dfbde523 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -97,6 +97,8 @@ static char __init *mpc_family(int family,int model)
return("Pentium(tm) Pro");
case 0x0F:
+ if (model == 0x00)
+ return("Pentium 4(tm)");
if (model == 0x0F)
return("Special controller");
}
@@ -125,6 +127,44 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
Dprintk(" 64 bit compare & exchange supported.\n");
if (m->mpc_featureflag&(1<<9))
Dprintk(" Internal APIC present.\n");
+ if (m->mpc_featureflag&(1<<11))
+ Dprintk(" SEP present.\n");
+ if (m->mpc_featureflag&(1<<12))
+ Dprintk(" MTRR present.\n");
+ if (m->mpc_featureflag&(1<<13))
+ Dprintk(" PGE present.\n");
+ if (m->mpc_featureflag&(1<<14))
+ Dprintk(" MCA present.\n");
+ if (m->mpc_featureflag&(1<<15))
+ Dprintk(" CMOV present.\n");
+ if (m->mpc_featureflag&(1<<16))
+ Dprintk(" PAT present.\n");
+ if (m->mpc_featureflag&(1<<17))
+ Dprintk(" PSE present.\n");
+ if (m->mpc_featureflag&(1<<18))
+ Dprintk(" PSN present.\n");
+ if (m->mpc_featureflag&(1<<19))
+ Dprintk(" Cache Line Flush Instruction present.\n");
+ /* 20 Reserved */
+ if (m->mpc_featureflag&(1<<21))
+ Dprintk(" Debug Trace and EMON Store present.\n");
+ if (m->mpc_featureflag&(1<<22))
+ Dprintk(" ACPI Thermal Throttle Registers present.\n");
+ if (m->mpc_featureflag&(1<<23))
+ Dprintk(" MMX present.\n");
+ if (m->mpc_featureflag&(1<<24))
+ Dprintk(" FXSR present.\n");
+ if (m->mpc_featureflag&(1<<25))
+ Dprintk(" XMM present.\n");
+ if (m->mpc_featureflag&(1<<26))
+ Dprintk(" Willamette New Instructions present.\n");
+ if (m->mpc_featureflag&(1<<27))
+ Dprintk(" Self Snoop present.\n");
+ /* 28 Reserved */
+ if (m->mpc_featureflag&(1<<29))
+ Dprintk(" Thermal Monitor present.\n");
+ /* 30, 31 Reserved */
+
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
Dprintk(" Bootup CPU\n");
@@ -378,7 +418,7 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) |
(boot_cpu_data.x86_model << 4) |
boot_cpu_data.x86_mask;
- processor.mpc_featureflag = boot_cpu_data.x86_capability;
+ processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
processor.mpc_reserved[0] = 0;
processor.mpc_reserved[1] = 0;
for (i = 0; i < 2; i++) {
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index fe52293da..badb6ed15 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -231,7 +231,7 @@ static int msr_open(struct inode *inode, struct file *file)
if ( !(cpu_online_map & (1UL << cpu)) )
return -ENXIO; /* No such CPU */
- if ( !(c->x86_capability & X86_FEATURE_MSR) )
+ if ( !test_bit(X86_FEATURE_MSR, &c->x86_capability) )
return -EIO; /* MSR not supported */
return 0;
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 045374d50..47c83f58e 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -228,6 +228,9 @@
20000221 Richard Gooch <rgooch@atnf.csiro.au>
Compile fix if procfs and devfs not enabled.
Formatting changes.
+ v1.37
+ 20001109 H. Peter Anvin <hpa@zytor.com>
+ Use the new centralized CPU feature detects.
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -266,11 +269,28 @@
#include <asm/hardirq.h>
#include <linux/irq.h>
-#define MTRR_VERSION "1.36 (20000221)"
+#define MTRR_VERSION "1.37 (20001109)"
#define TRUE 1
#define FALSE 0
+/*
+ * The code assumes all processors support the same MTRR
+ * interface. This is generally a good assumption, but could
+ * potentially be a problem.
+ */
+enum mtrr_if_type {
+ MTRR_IF_NONE, /* No MTRRs supported */
+ MTRR_IF_INTEL, /* Intel (P6) standard MTRRs */
+ MTRR_IF_AMD_K6, /* AMD pre-Athlon MTRRs */
+ MTRR_IF_CYRIX_ARR, /* Cyrix ARRs */
+ MTRR_IF_CENTAUR_MCR, /* Centaur MCRs */
+} mtrr_if = MTRR_IF_NONE;
+
+static __initdata char *mtrr_if_name[] = {
+ "none", "Intel", "AMD K6", "Cyrix ARR", "Centaur MCR"
+};
+
#define MTRRcap_MSR 0x0fe
#define MTRRdefType_MSR 0x2ff
@@ -350,18 +370,11 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
/* Disable interrupts locally */
__save_flags (ctxt->flags); __cli ();
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
- /* else fall through */
- case X86_VENDOR_CENTAUR:
- if(boot_cpu_data.x86 != 6)
- return;
- /*break;*/
- }
+ if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR )
+ return;
+
/* Save value of CR4 and clear Page Global Enable (bit 7) */
- if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+ if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
asm volatile ("movl %%cr4, %0\n\t"
"movl %0, %1\n\t"
"andb $0x7f, %b1\n\t"
@@ -377,20 +390,15 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
"wbinvd\n\t"
: "=r" (tmp) : : "memory");
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- case X86_VENDOR_INTEL:
- case X86_VENDOR_CENTAUR:
+ if ( mtrr_if == MTRR_IF_INTEL ) {
/* Disable MTRRs, and set the default type to uncached */
rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
- break;
- case X86_VENDOR_CYRIX:
+ } else {
+ /* Cyrix ARRs - everything else were excluded at the top */
tmp = getCx86 (CX86_CCR3);
setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
ctxt->ccr3 = tmp;
- break;
}
} /* End Function set_mtrr_prepare */
@@ -399,33 +407,21 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt)
{
unsigned long tmp;
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
- /* else fall through */
- case X86_VENDOR_CENTAUR:
- if(boot_cpu_data.x86 != 6)
- {
- __restore_flags (ctxt->flags);
- return;
- }
- /*break;*/
+ if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) {
+ __restore_flags (ctxt->flags);
+ return;
}
+
/* Flush caches and TLBs */
asm volatile ("wbinvd" : : : "memory" );
/* Restore MTRRdefType */
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- case X86_VENDOR_INTEL:
- case X86_VENDOR_CENTAUR:
+ if ( mtrr_if == MTRR_IF_INTEL ) {
+ /* Intel (P6) standard MTRRs */
wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
- break;
- case X86_VENDOR_CYRIX:
+ } else {
+ /* Cyrix ARRs - everything else was excluded at the top */
setCx86 (CX86_CCR3, ctxt->ccr3);
- break;
}
/* Enable caches */
@@ -435,7 +431,7 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt)
: "=r" (tmp) : : "memory");
/* Restore value of CR4 */
- if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+ if ( test_bit(X86_FEATURE_PGE, &boot_cpu_data.x86_capability) )
asm volatile ("movl %0, %%cr4"
: : "r" (ctxt->cr4val) : "memory");
@@ -448,31 +444,20 @@ static unsigned int get_num_var_ranges (void)
{
unsigned long config, dummy;
- switch (boot_cpu_data.x86_vendor)
+ switch ( mtrr_if )
{
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) return 2; /* pre-Athlon CPUs */
- /* else fall through */
- case X86_VENDOR_INTEL:
+ case MTRR_IF_INTEL:
rdmsr (MTRRcap_MSR, config, dummy);
return (config & 0xff);
- /*break;*/
- case X86_VENDOR_CYRIX:
- /* Cyrix have 8 ARRs */
+ case MTRR_IF_AMD_K6:
+ return 2;
+ case MTRR_IF_CYRIX_ARR:
return 8;
- case X86_VENDOR_CENTAUR:
- /* and Centaur has 8 MCR's */
- if(boot_cpu_data.x86==5)
- return 8;
- /* the cyrix III has intel compatible MTRR */
- if(boot_cpu_data.x86==6)
- {
- rdmsr (MTRRcap_MSR, config, dummy);
- return (config & 0xff);
- }
- /*break;*/
+ case MTRR_IF_CENTAUR_MCR:
+ return 8;
+ default:
+ return 0;
}
- return 0;
} /* End Function get_num_var_ranges */
/* Returns non-zero if we have the write-combining memory type */
@@ -480,24 +465,19 @@ static int have_wrcomb (void)
{
unsigned long config, dummy;
- switch (boot_cpu_data.x86_vendor)
+ switch ( mtrr_if )
{
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */
- /* else fall through */
- case X86_VENDOR_CENTAUR:
- if (boot_cpu_data.x86 == 5)
- return 1; /* C6 */
- /* CyrixIII is Intel like */
- case X86_VENDOR_INTEL:
+ case MTRR_IF_INTEL:
rdmsr (MTRRcap_MSR, config, dummy);
return (config & (1<<10));
- /*break;*/
- case X86_VENDOR_CYRIX:
return 1;
- /*break;*/
+ case MTRR_IF_AMD_K6:
+ case MTRR_IF_CENTAUR_MCR:
+ case MTRR_IF_CYRIX_ARR:
+ return 1;
+ default:
+ return 0;
}
- return 0;
} /* End Function have_wrcomb */
static void intel_get_mtrr (unsigned int reg, unsigned long *base,
@@ -1171,47 +1151,48 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
mtrr_type ltype;
unsigned long lbase, lsize, last;
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
- switch (boot_cpu_data.x86_vendor)
+ switch ( mtrr_if )
{
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6)
- { /* pre-Athlon CPUs */
- /* Apply the K6 block alignment and size rules
- In order
- o Uncached or gathering only
- o 128K or bigger block
- o Power of 2 block
- o base suitably aligned to the power
- */
- if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
- (size & ~(size-1))-size || ( base & (size-1) ) )
- return -EINVAL;
- break;
- }
- /* Else fall through */
- case X86_VENDOR_INTEL:
- /* Double check for Intel, we may run on Athlon */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+ case MTRR_IF_NONE:
+ return -ENXIO; /* No MTRRs whatsoever */
+
+ case MTRR_IF_AMD_K6:
+ /* Apply the K6 block alignment and size rules
+ In order
+ o Uncached or gathering only
+ o 128K or bigger block
+ o Power of 2 block
+ o base suitably aligned to the power
+ */
+ if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+ (size & ~(size-1))-size || ( base & (size-1) ) )
+ return -EINVAL;
+ break;
+
+ case MTRR_IF_INTEL:
+ /* For Intel PPro stepping <= 7, must be 4 MiB aligned */
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+ boot_cpu_data.x86 == 6 &&
+ boot_cpu_data.x86_model == 1 &&
+ boot_cpu_data.x86_mask <= 7 )
{
- /* For Intel PPro stepping <= 7, must be 4 MiB aligned */
- if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
- (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) )
+ if ( base & ((1 << 22)-1) )
{
printk (KERN_WARNING "mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
return -EINVAL;
}
}
- /* Fall through */
- case X86_VENDOR_CYRIX:
- case X86_VENDOR_CENTAUR:
+ /* Fall through */
+
+ case MTRR_IF_CYRIX_ARR:
+ case MTRR_IF_CENTAUR_MCR:
if ( (base & 0xfff) || (size & 0xfff) )
{
printk ("mtrr: size and base must be multiples of 4 kiB\n");
printk ("mtrr: size: %lx base: %lx\n", size, base);
return -EINVAL;
}
- if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5)
+ if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
{
if (type != MTRR_TYPE_WRCOMB)
{
@@ -1237,10 +1218,11 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char inc
return -EINVAL;
}
break;
- default:
+
+ default:
return -EINVAL;
- /*break;*/
}
+
if (type >= MTRR_NUM_TYPES)
{
printk ("mtrr: type: %u illegal\n", type);
@@ -1328,7 +1310,8 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
mtrr_type ltype;
unsigned long lbase, lsize;
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+ if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO;
+
max = get_num_var_ranges ();
down (&main_lock);
if (reg < 0)
@@ -1356,7 +1339,7 @@ int mtrr_del (int reg, unsigned long base, unsigned long size)
printk ("mtrr: register: %d too big\n", reg);
return -EINVAL;
}
- if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX)
+ if ( mtrr_if == MTRR_IF_CYRIX_ARR )
{
if ( (reg == 3) && arr3_protected )
{
@@ -1772,42 +1755,41 @@ static void __init centaur_mcr_init(void)
set_mtrr_done (&ctxt);
} /* End Function centaur_mcr_init */
-static void __init mtrr_setup(void)
+static int __init mtrr_setup(void)
{
- printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6)
- {
- /* pre-Athlon CPUs */
- get_mtrr = amd_get_mtrr;
- set_mtrr_up = amd_set_mtrr_up;
- break;
- }
- /* Else fall through */
- case X86_VENDOR_INTEL:
+ if ( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ) {
+ /* Intel (P6) standard MTRRs */
+ mtrr_if = MTRR_IF_INTEL;
get_mtrr = intel_get_mtrr;
set_mtrr_up = intel_set_mtrr_up;
- break;
- case X86_VENDOR_CYRIX:
+ } else if ( test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ) {
+ /* Pre-Athlon (K6) AMD CPU MTRRs */
+ mtrr_if = MTRR_IF_AMD_K6;
+ get_mtrr = amd_get_mtrr;
+ set_mtrr_up = amd_set_mtrr_up;
+ } else if ( test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ) {
+ /* Cyrix ARRs */
+ mtrr_if = MTRR_IF_CYRIX_ARR;
get_mtrr = cyrix_get_arr;
set_mtrr_up = cyrix_set_arr_up;
get_free_region = cyrix_get_free_region;
- break;
- case X86_VENDOR_CENTAUR:
- if(boot_cpu_data.x86 == 5)
- {
- get_mtrr = centaur_get_mcr;
- set_mtrr_up = centaur_set_mcr_up;
- }
- if(boot_cpu_data.x86 == 6)
- {
- get_mtrr = intel_get_mtrr;
- set_mtrr_up = intel_set_mtrr_up;
- }
- break;
+ cyrix_arr_init();
+ } else if ( test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) {
+ /* Centaur MCRs */
+ mtrr_if = MTRR_IF_CENTAUR_MCR;
+ get_mtrr = centaur_get_mcr;
+ set_mtrr_up = centaur_set_mcr_up;
+ centaur_mcr_init();
+ } else {
+ /* No supported MTRR interface */
+ mtrr_if = MTRR_IF_NONE;
}
+
+ printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n"
+ "mtrr: detected mtrr type: %s\n",
+ MTRR_VERSION, mtrr_if_name[mtrr_if]);
+
+ return (mtrr_if != MTRR_IF_NONE);
} /* End Function mtrr_setup */
#ifdef CONFIG_SMP
@@ -1817,24 +1799,12 @@ static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
void __init mtrr_init_boot_cpu(void)
{
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
- mtrr_setup ();
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */
- case X86_VENDOR_INTEL:
+ if ( !mtrr_setup () )
+ return;
+
+ if ( mtrr_if == MTRR_IF_INTEL ) {
+ /* Only for Intel MTRRs */
get_mtrr_state (&smp_mtrr_state);
- break;
- case X86_VENDOR_CYRIX:
- cyrix_arr_init ();
- break;
- case X86_VENDOR_CENTAUR: /* C6 and Cyrix III have different ones */
- if(boot_cpu_data.x86 == 5)
- centaur_mcr_init ();
- if(boot_cpu_data.x86 == 6)
- get_mtrr_state(&smp_mtrr_state);
- break;
}
} /* End Function mtrr_init_boot_cpu */
@@ -1859,16 +1829,12 @@ static void __init intel_mtrr_init_secondary_cpu(void)
void __init mtrr_init_secondary_cpu(void)
{
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- /* Just for robustness: pre-Athlon CPUs cannot do SMP */
- if (boot_cpu_data.x86 < 6) break;
- case X86_VENDOR_INTEL:
- intel_mtrr_init_secondary_cpu ();
+ switch ( mtrr_if ) {
+ case MTRR_IF_INTEL:
+ /* Intel (P6) standard MTRRs */
+ intel_mtrr_init_secondary_cpu();
break;
- case X86_VENDOR_CYRIX:
+ case MTRR_IF_CYRIX_ARR:
/* This is _completely theoretical_!
* I assume here that one day Cyrix will support Intel APIC.
* In reality on non-Intel CPUs we won't even get to this routine.
@@ -1877,39 +1843,26 @@ void __init mtrr_init_secondary_cpu(void)
*/
cyrix_arr_init_secondary ();
break;
- default:
+ default:
+ /* I see no MTRRs I can support in SMP mode... */
printk ("mtrr: SMP support incomplete for this vendor\n");
- break;
}
} /* End Function mtrr_init_secondary_cpu */
#endif /* CONFIG_SMP */
int __init mtrr_init(void)
{
- if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
#ifdef CONFIG_SMP
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */
- case X86_VENDOR_INTEL:
+ /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */
+
+ if ( mtrr_if == MTRR_IF_INTEL ) {
finalize_mtrr_state (&smp_mtrr_state);
mtrr_state_warn (smp_changes_mask);
- break;
}
-#else /* CONFIG_SMP */
- mtrr_setup ();
- switch (boot_cpu_data.x86_vendor)
- {
- case X86_VENDOR_CYRIX:
- cyrix_arr_init ();
- break;
- case X86_VENDOR_CENTAUR:
- if(boot_cpu_data.x86 == 5)
- centaur_mcr_init ();
- break;
- }
-#endif /* !CONFIG_SMP */
+#else
+ if ( !mtrr_setup() )
+ return 0; /* MTRRs not supported? */
+#endif
#ifdef CONFIG_PROC_FS
proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
@@ -1924,3 +1877,11 @@ int __init mtrr_init(void)
init_table ();
return 0;
} /* End Function mtrr_init */
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-file-style:"k&r"
+ * c-basic-offset:4
+ * End:
+ */
diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
index 9a5fe8958..17a929bb2 100644
--- a/arch/i386/kernel/pci-irq.c
+++ b/arch/i386/kernel/pci-irq.c
@@ -265,6 +265,20 @@ static int pirq_opti_set(struct pci_dev *router, struct pci_dev *dev, int pirq,
return 1;
}
+/*
+ * Cyrix: nibble offset 0x5C
+ */
+static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+ return read_config_nybble(router, 0x5C, pirq-1);
+}
+
+static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+ write_config_nybble(router, 0x5C, pirq-1, irq);
+ return 1;
+}
+
#ifdef CONFIG_PCI_BIOS
static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
@@ -283,12 +297,19 @@ static struct irq_router pirq_routers[] = {
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
+ { "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, pirq_piix_get, pirq_piix_set },
{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+
{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
+
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
+
{ "OPTI", PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C700, pirq_opti_get, pirq_opti_set },
+
+ { "NatSemi", PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, pirq_cyrix_get, pirq_cyrix_set },
+
{ "default", 0, 0, NULL, NULL }
};
@@ -298,7 +319,6 @@ static struct pci_dev *pirq_router_dev;
static void __init pirq_find_router(void)
{
struct irq_routing_table *rt = pirq_table;
- u16 rvendor, rdevice;
struct irq_router *r;
#ifdef CONFIG_PCI_BIOS
@@ -308,32 +328,31 @@ static void __init pirq_find_router(void)
return;
}
#endif
- if (!(pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn))) {
+ /* fall back to default router if nothing else found */
+ pirq_router = pirq_routers + sizeof(pirq_routers) / sizeof(pirq_routers[0]) - 1;
+
+ pirq_router_dev = pci_find_slot(rt->rtr_bus, rt->rtr_devfn);
+ if (!pirq_router_dev) {
DBG("PCI: Interrupt router not found at %02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
- /* fall back to default router */
- pirq_router = pirq_routers + sizeof(pirq_routers) / sizeof(pirq_routers[0]) - 1;
return;
}
- if (rt->rtr_vendor) {
- rvendor = rt->rtr_vendor;
- rdevice = rt->rtr_device;
- } else {
- /*
- * Several BIOSes forget to set the router type. In such cases, we
- * use chip vendor/device. This doesn't guarantee us semantics of
- * PIRQ values, but was found to work in practice and it's still
- * better than not trying.
- */
- DBG("PCI: Guessed interrupt router ID from %s\n", pirq_router_dev->slot_name);
- rvendor = pirq_router_dev->vendor;
- rdevice = pirq_router_dev->device;
- }
- for(r=pirq_routers; r->vendor; r++)
- if (r->vendor == rvendor && r->device == rdevice)
+
+ for(r=pirq_routers; r->vendor; r++) {
+ /* Exact match against router table entry? Use it! */
+ if (r->vendor == rt->rtr_vendor && r->device == rt->rtr_device) {
+ pirq_router = r;
break;
- pirq_router = r;
- printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n", r->name,
- rvendor, rdevice, pirq_router_dev->slot_name);
+ }
+ /* Match against router device entry? Use it as a fallback */
+ if (r->vendor == pirq_router_dev->vendor && r->device == pirq_router_dev->device) {
+ pirq_router = r;
+ }
+ }
+ printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n",
+ pirq_router->name,
+ pirq_router_dev->vendor,
+ pirq_router_dev->device,
+ pirq_router_dev->slot_name);
}
static struct irq_info *pirq_get_info(struct pci_dev *dev, int pin)
diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c
index d70e9e569..f97d3b1ad 100644
--- a/arch/i386/kernel/semaphore.c
+++ b/arch/i386/kernel/semaphore.c
@@ -59,7 +59,7 @@ void __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -79,7 +79,7 @@ void __down(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -93,7 +93,7 @@ int __down_interruptible(struct semaphore * sem)
int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -129,7 +129,7 @@ int __down_interruptible(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -315,7 +315,7 @@ struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
@@ -371,7 +371,7 @@ struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 7ac7fdb36..692965a06 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -55,6 +55,9 @@
* Cyrix III, Pentium IV support.
* Dave Jones <davej@suse.de>, October 2000
*
+ * Massive cleanup of CPU detection and bug handling;
+ * Transmeta CPU detection,
+ * H. Peter Anvin <hpa@zytor.com>, November 2000
*/
/*
@@ -107,7 +110,9 @@ unsigned long mmu_cr4_features;
/*
* Bus types ..
*/
+#ifdef CONFIG_EISA
int EISA_bus;
+#endif
int MCA_bus;
/* for MCA, but anyone else can use it if they want */
@@ -543,7 +548,7 @@ static inline void parse_mem_cmdline (char ** cmdline_p)
to--;
if (!memcmp(from+4, "nopentium", 9)) {
from += 9+4;
- boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
+ clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
} else if (!memcmp(from+4, "exactmap", 8)) {
from += 8+4;
e820.nr_map = 0;
@@ -846,70 +851,158 @@ void __init setup_arch(char **cmdline_p)
#endif
}
+#ifndef CONFIG_X86_TSC
+static int tsc_disable __initdata = 0;
+
+static int __init tsc_setup(char *str)
+{
+ tsc_disable = 1;
+ return 1;
+}
+
+__setup("notsc", tsc_setup);
+#endif
+
static int __init get_model_name(struct cpuinfo_x86 *c)
{
- unsigned int n, dummy, *v;
+ unsigned int *v;
+ char *p, *q;
- cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
- if (n < 0x80000004)
+ if (cpuid_eax(0x80000000) < 0x80000004)
return 0;
- cpuid(0x80000001, &dummy, &dummy, &dummy, &(c->x86_capability));
+
v = (unsigned int *) c->x86_model_id;
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
c->x86_model_id[48] = 0;
+
+ /* Intel chips right-justify this string for some dumb reason;
+ undo that brain damage */
+ p = q = &c->x86_model_id[0];
+ while ( *p == ' ' )
+ p++;
+ if ( p != q ) {
+ while ( *p )
+ *q++ = *p++;
+ while ( q <= &c->x86_model_id[48] )
+ *q++ = '\0'; /* Zero-pad the rest */
+ }
+
return 1;
}
static void __init display_cacheinfo(struct cpuinfo_x86 *c)
{
- unsigned int n, dummy, ecx, edx;
+ unsigned int n, dummy, ecx, edx, l2size;
- cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+ n = cpuid_eax(0x80000000);
if (n >= 0x80000005) {
cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
- printk("CPU: L1 I Cache: %dK L1 D Cache: %dK (%d bytes/line)\n",
- edx>>24, ecx>>24, edx&0xFF);
+ printk("CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
+ edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
c->x86_cache_size=(ecx>>24)+(edx>>24);
}
- if (n < 0x80000006) /* Cyrix just has large L1. */
+ if (n < 0x80000006) /* Some chips just has a large L1. */
return;
- cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
- c->x86_cache_size = ecx >>16;
+ ecx = cpuid_ecx(0x80000006);
+ l2size = ecx >> 16;
/* AMD errata T13 (order #21922) */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
- boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 3 &&
- boot_cpu_data.x86_mask == 0)
- {
- c->x86_cache_size = 64;
+ if (c->x86_vendor == X86_VENDOR_AMD &&
+ c->x86 == 6 &&
+ c->x86_model == 3 &&
+ c->x86_mask == 0) {
+ l2size = 64;
}
- printk("CPU: L2 Cache: %dK\n", ecx>>16);
+
+ if ( l2size == 0 )
+ return; /* Again, no L2 cache is possible */
+
+ c->x86_cache_size = l2size;
+
+ printk("CPU: L2 Cache: %dK (%d bytes/line)\n",
+ l2size, ecx & 0xFF);
}
+/*
+ * B step AMD K6 before B 9730xxxx have hardware bugs that can cause
+ * misexecution of code under Linux. Owners of such processors should
+ * contact AMD for precise details and a CPU swap.
+ *
+ * See http://www.mygale.com/~poulot/k6bug.html
+ * http://www.amd.com/K6/k6docs/revgd.html
+ *
+ * The following test is erm.. interesting. AMD neglected to up
+ * the chip setting when fixing the bug but they also tweaked some
+ * performance at the same time..
+ */
+
+extern void vide(void);
+__asm__(".align 4\nvide: ret");
-static int __init amd_model(struct cpuinfo_x86 *c)
+static int __init init_amd(struct cpuinfo_x86 *c)
{
u32 l, h;
unsigned long flags;
int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+ int r;
- int r=get_model_name(c);
+ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+ clear_bit(0*32+31, &c->x86_capability);
+
+ r = get_model_name(c);
switch(c->x86)
{
case 5:
if( c->x86_model < 6 )
{
- /* Anyone with a K5 want to fill this in */
+ /* Based on AMD doc 20734R - June 2000 */
+ if ( c->x86_model == 0 ) {
+ clear_bit(X86_FEATURE_APIC, &c->x86_capability);
+ set_bit(X86_FEATURE_PGE, &c->x86_capability);
+ }
break;
}
+ if ( c->x86_model == 6 && c->x86_mask == 1 ) {
+ const int K6_BUG_LOOP = 1000000;
+ int n;
+ void (*f_vide)(void);
+ unsigned long d, d2;
+
+ printk(KERN_INFO "AMD K6 stepping B detected - ");
+
+ /*
+ * It looks like AMD fixed the 2.6.2 bug and improved indirect
+ * calls at the same time.
+ */
+
+ n = K6_BUG_LOOP;
+ f_vide = vide;
+ rdtscl(d);
+ while (n--)
+ f_vide();
+ rdtscl(d2);
+ d = d2-d;
+
+ /* Knock these two lines out if it debugs out ok */
+ printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
+ printk(KERN_INFO "AMD K6 stepping B detected - ");
+ /* -- cut here -- */
+ if (d > 20*K6_BUG_LOOP)
+ printk("system stability may be impaired when more than 32 MB are used.\n");
+ else
+ printk("probably OK (after B9730xxxx).\n");
+ printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
+ }
+
/* K6 with old style WHCR */
if( c->x86_model < 8 ||
(c->x86_model== 8 && c->x86_mask < 8))
@@ -954,11 +1047,11 @@ static int __init amd_model(struct cpuinfo_x86 *c)
}
/* Set MTRR capability flag if appropriate */
- if((boot_cpu_data.x86_model == 13) ||
- (boot_cpu_data.x86_model == 9) ||
- ((boot_cpu_data.x86_model == 8) &&
- (boot_cpu_data.x86_mask >= 8)))
- c->x86_capability |= X86_FEATURE_MTRR;
+ if ( (c->x86_model == 13) ||
+ (c->x86_model == 9) ||
+ ((c->x86_model == 8) &&
+ (c->x86_mask >= 8)) )
+ set_bit(X86_FEATURE_K6_MTRR, &c->x86_capability);
break;
}
@@ -971,7 +1064,6 @@ static int __init amd_model(struct cpuinfo_x86 *c)
display_cacheinfo(c);
return r;
}
-
/*
* Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
@@ -1032,14 +1124,56 @@ static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
static char cyrix_model_mult1[] __initdata = "12??43";
static char cyrix_model_mult2[] __initdata = "12233445";
-static void __init cyrix_model(struct cpuinfo_x86 *c)
+/*
+ * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
+ * BIOSes for compatability with DOS games. This makes the udelay loop
+ * work correctly, and improves performance.
+ */
+
+extern void calibrate_delay(void) __init;
+
+static void __init check_cx686_slop(struct cpuinfo_x86 *c)
+{
+ if (Cx86_dir0_msb == 3) {
+ unsigned char ccr3, ccr5;
+
+ cli();
+ ccr3 = getCx86(CX86_CCR3);
+ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
+ ccr5 = getCx86(CX86_CCR5);
+ if (ccr5 & 2)
+ setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
+ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
+ sti();
+
+ if (ccr5 & 2) { /* possible wrong calibration done */
+ printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
+ calibrate_delay();
+ c->loops_per_sec = loops_per_sec;
+ }
+ }
+}
+
+static void __init init_cyrix(struct cpuinfo_x86 *c)
{
unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
char *buf = c->x86_model_id;
const char *p = NULL;
+ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+ clear_bit(0*32+31, &c->x86_capability);
+
+ /* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
+ if ( test_bit(1*32+24, &c->x86_capability) ) {
+ clear_bit(1*32+24, &c->x86_capability);
+ set_bit(X86_FEATURE_CXMMX, &c->x86_capability);
+ }
+
do_cyrix_devid(&dir0, &dir1);
+ check_cx686_slop(c);
+
Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family" */
dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
@@ -1080,7 +1214,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
} else /* 686 */
p = Cx86_cb+1;
/* Emulate MTRRs using Cyrix's ARRs. */
- c->x86_capability |= X86_FEATURE_MTRR;
+ set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
/* 6x86's contain this bug */
c->coma_bug = 1;
break;
@@ -1112,14 +1246,14 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
/* GXm supports extended cpuid levels 'ala' AMD */
if (c->cpuid_level == 2) {
get_model_name(c); /* get CPU marketing name */
- c->x86_capability&=~X86_FEATURE_TSC;
+ clear_bit(X86_FEATURE_TSC, c->x86_capability);
return;
}
else { /* MediaGX */
Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
p = Cx86_cb+2;
c->x86_model = (dir1 & 0x20) ? 1 : 2;
- c->x86_capability&=~X86_FEATURE_TSC;
+ clear_bit(X86_FEATURE_TSC, &c->x86_capability);
}
break;
@@ -1132,7 +1266,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
(c->x86_model)++;
/* Emulate MTRRs using Cyrix's ARRs. */
- c->x86_capability |= X86_FEATURE_MTRR;
+ set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
break;
case 0xf: /* Cyrix 486 without DEVID registers */
@@ -1158,7 +1292,7 @@ static void __init cyrix_model(struct cpuinfo_x86 *c)
return;
}
-static void __init centaur_model(struct cpuinfo_x86 *c)
+static void __init init_centaur(struct cpuinfo_x86 *c)
{
enum {
ECX8=1<<1,
@@ -1187,6 +1321,10 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
u32 lo,hi,newlo;
u32 aa,bb,cc,dd;
+ /* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+ 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+ clear_bit(0*32+31, &c->x86_capability);
+
switch (c->x86) {
case 5:
@@ -1196,7 +1334,7 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
fcr_clr=DPDC;
printk("Disabling bugged TSC.\n");
- c->x86_capability &= ~X86_FEATURE_TSC;
+ clear_bit(X86_FEATURE_TSC, &c->x86_capability);
break;
case 8:
switch(c->x86_mask) {
@@ -1238,15 +1376,15 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
printk("Centaur FCR is 0x%X\n",lo);
}
/* Emulate MTRRs using Centaur's MCR. */
- c->x86_capability |= X86_FEATURE_MTRR;
+ set_bit(X86_FEATURE_CENTAUR_MCR, &c->x86_capability);
/* Report CX8 */
- c->x86_capability |= X86_FEATURE_CX8;
+ set_bit(X86_FEATURE_CX8, &c->x86_capability);
/* Set 3DNow! on Winchip 2 and above. */
if (c->x86_model >=8)
- c->x86_capability |= X86_FEATURE_AMD3D;
+ set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
/* See if we can find out some more. */
- cpuid(0x80000000,&aa,&bb,&cc,&dd);
- if (aa>=0x80000005) { /* Yes, we can. */
+ if ( cpuid_eax(0x80000000) >= 0x80000005 ) {
+ /* Yes, we can. */
cpuid(0x80000005,&aa,&bb,&cc,&dd);
/* Add L1 data and code cache sizes. */
c->x86_cache_size = (cc>>24)+(dd>>24);
@@ -1261,10 +1399,10 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */
wrmsr (0x1107, lo, hi);
- c->x86_capability |= X86_FEATURE_CX8;
+ set_bit(X86_FEATURE_CX8, &c->x86_capability);
rdmsr (0x80000001, lo, hi);
if (hi & (1<<31))
- c->x86_capability |= X86_FEATURE_AMD3D;
+ set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
get_model_name(c);
display_cacheinfo(c);
@@ -1276,7 +1414,7 @@ static void __init centaur_model(struct cpuinfo_x86 *c)
}
-static void __init transmeta_model(struct cpuinfo_x86 *c)
+static void __init init_transmeta(struct cpuinfo_x86 *c)
{
unsigned int cap_mask, uk, max, dummy;
unsigned int cms_rev1, cms_rev2;
@@ -1287,17 +1425,15 @@ static void __init transmeta_model(struct cpuinfo_x86 *c)
display_cacheinfo(c);
/* Print CMS and CPU revision */
- cpuid(0x80860000, &max, &dummy, &dummy, &dummy);
+ max = cpuid_eax(0x80860000);
if ( max >= 0x80860001 ) {
cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags);
- printk("CPU: Processor revision %u.%u.%u.%u, %u MHz%s%s\n",
+ printk("CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
(cpu_rev >> 24) & 0xff,
(cpu_rev >> 16) & 0xff,
(cpu_rev >> 8) & 0xff,
cpu_rev & 0xff,
- cpu_freq,
- (cpu_flags & 1) ? " [recovery]" : "",
- (cpu_flags & 2) ? " [longrun]" : "");
+ cpu_freq);
}
if ( max >= 0x80860002 ) {
cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
@@ -1333,13 +1469,154 @@ static void __init transmeta_model(struct cpuinfo_x86 *c)
printk("CPU: %s\n", cpu_info);
}
- /* Unhide possibly hidden flags */
+ /* Unhide possibly hidden capability flags */
rdmsr(0x80860004, cap_mask, uk);
wrmsr(0x80860004, ~0, uk);
- cpuid(0x00000001, &dummy, &dummy, &dummy, &c->x86_capability);
+ c->x86_capability[0] = cpuid_edx(0x00000001);
wrmsr(0x80860004, cap_mask, uk);
}
+extern void trap_init_f00f_bug(void);
+
+static void __init init_intel(struct cpuinfo_x86 *c)
+{
+#ifndef CONFIG_M686
+ static int f00f_workaround_enabled = 0;
+#endif
+ extern void mcheck_init(struct cpuinfo_x86 *c);
+ char *p = NULL;
+ unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+
+#ifndef CONFIG_M686
+ /*
+ * All current models of Pentium and Pentium with MMX technology CPUs
+ * have the F0 0F bug, which lets nonpriviledged users lock up the system.
+ * Note that the workaround only should be initialized once...
+ */
+ c->f00f_bug = 0;
+ if ( c->x86 == 5 ) {
+ c->f00f_bug = 1;
+ if ( !f00f_workaround_enabled ) {
+ trap_init_f00f_bug();
+ printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
+ f00f_workaround_enabled = 1;
+ }
+ }
+#endif
+
+
+ if (c->cpuid_level > 1) {
+ /* supports eax=2 call */
+ int i, j, n;
+ int regs[4];
+ unsigned char *dp = (unsigned char *)regs;
+
+ /* Number of times to iterate */
+ n = cpuid_eax(2) & 0xFF;
+
+ for ( i = 0 ; i < n ; i++ ) {
+ cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
+
+ /* If bit 31 is set, this is an unknown format */
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( regs[j] < 0 ) regs[j] = 0;
+ }
+
+ /* Byte 0 is level count, not a descriptor */
+ for ( j = 1 ; j < 16 ; j++ ) {
+ unsigned char des = dp[j];
+ unsigned char dl, dh;
+ unsigned int cs;
+
+ dh = des >> 4;
+ dl = des & 0x0F;
+
+ switch ( dh )
+ {
+ case 2:
+ if ( dl ) {
+ /* L3 cache */
+ cs = (dl-1) << 9;
+ l3 += cs;
+ }
+ break;
+ case 4:
+ case 8:
+ if ( dl ) {
+ /* L2 cache */
+ cs = 128 << (dl-1);
+ l2 += cs;
+ }
+ break;
+ case 6:
+ if (dl > 5) {
+ /* L1 D cache */
+ cs = 8<<(dl-6);
+ l1d += cs;
+ }
+ break;
+ case 7:
+ /* L1 I cache */
+ cs = dl ? (16 << (dl-1)) : 12;
+ l1i += cs;
+ break;
+ default:
+ /* TLB, or something else we don't know about */
+ break;
+ }
+ }
+ }
+ if ( l1i || l1d )
+ printk("CPU: L1 I cache: %dK, L1 D cache: %dK\n",
+ l1i, l1d);
+ if ( l2 )
+ printk("CPU: L2 cache: %dK\n", l2);
+ if ( l3 )
+ printk("CPU: L3 cache: %dK\n", l3);
+
+ /*
+ * This assumes the L3 cache is shared; it typically lives in
+ * the northbridge. The L1 caches are included by the L2
+ * cache, and so should not be included for the purpose of
+ * SMP switching weights.
+ */
+ c->x86_cache_size = l2 ? l2 : (l1i+l1d);
+ }
+
+ /* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
+ if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
+ clear_bit(X86_FEATURE_SEP, &c->x86_capability);
+
+ /* Names for the Pentium II/Celeron processors
+ detectable only by also checking the cache size.
+ Dixon is NOT a Celeron. */
+ if (c->x86 == 6) {
+ switch (c->x86_model) {
+ case 5:
+ if (l2 == 0)
+ p = "Celeron (Covington)";
+ if (l2 == 256)
+ p = "Mobile Pentium II (Dixon)";
+ break;
+
+ case 6:
+ if (l2 == 128)
+ p = "Celeron (Mendocino)";
+ break;
+
+ case 8:
+ if (l2 == 128)
+ p = "Celeron (Coppermine)";
+ break;
+ }
+ }
+
+ if ( p )
+ strcpy(c->x86_model_id, p);
+
+ /* Enable MCA if available */
+ mcheck_init(c);
+}
void __init get_cpu_vendor(struct cpuinfo_x86 *c)
{
@@ -1359,7 +1636,8 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
c->x86_vendor = X86_VENDOR_NEXGEN;
else if (!strcmp(v, "RiseRiseRise"))
c->x86_vendor = X86_VENDOR_RISE;
- else if (!strcmp(v, "GenuineTMx86"))
+ else if (!strcmp(v, "GenuineTMx86") ||
+ !strcmp(v, "TransmetaCPU"))
c->x86_vendor = X86_VENDOR_TRANSMETA;
else
c->x86_vendor = X86_VENDOR_UNKNOWN;
@@ -1367,11 +1645,13 @@ void __init get_cpu_vendor(struct cpuinfo_x86 *c)
struct cpu_model_info {
int vendor;
- int x86;
+ int family;
char *model_names[16];
};
/* Naming convention should be: <Name> [(<Codename>)] */
+/* This table only is used unless init_<vendor>() below doesn't set it; */
+/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
static struct cpu_model_info cpu_models[] __initdata = {
{ X86_VENDOR_INTEL, 4,
{ "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL",
@@ -1391,12 +1671,12 @@ static struct cpu_model_info cpu_models[] __initdata = {
{ NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
"486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
"Am5x86-WB" }},
- { X86_VENDOR_AMD, 5,
+ { X86_VENDOR_AMD, 5, /* Is this this really necessary?? */
{ "K5/SSA5", "K5",
"K5", "K5", NULL, NULL,
"K6", "K6", "K6-2",
"K6-3", NULL, NULL, NULL, NULL, NULL, NULL }},
- { X86_VENDOR_AMD, 6,
+ { X86_VENDOR_AMD, 6, /* Is this this really necessary?? */
{ "Athlon", "Athlon",
"Athlon", NULL, "Athlon", NULL,
NULL, NULL, NULL,
@@ -1410,11 +1690,27 @@ static struct cpu_model_info cpu_models[] __initdata = {
{ X86_VENDOR_RISE, 5,
{ "mP6", "mP6", NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
- { X86_VENDOR_TRANSMETA, 5,
- { NULL, NULL, NULL, "Crusoe", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
};
+/* Look up CPU names by table lookup. */
+static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+{
+ struct cpu_model_info *info = cpu_models;
+ int i;
+
+ if ( c->x86_model >= 16 )
+ return NULL; /* Range check */
+
+ for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) {
+ if ( info->vendor == c->x86_vendor &&
+ info->family == c->x86 ) {
+ return info->model_names[c->x86_model];
+ }
+ info++;
+ }
+ return NULL; /* Not found */
+}
+
/*
* Detect a NexGen CPU running without BIOS hypercode new enough
* to have CPUID. (Thanks to Herbert Oppmann)
@@ -1439,13 +1735,15 @@ static int __init deep_magic_nexgen_probe(void)
static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{
- if(c->x86_capability&(X86_FEATURE_PN) && disable_x86_serial_nr) {
+ if( test_bit(X86_FEATURE_PN, &c->x86_capability) &&
+ disable_x86_serial_nr ) {
/* Disable processor serial number */
unsigned long lo,hi;
rdmsr(0x119,lo,hi);
lo |= 0x200000;
wrmsr(0x119,lo,hi);
printk(KERN_INFO "CPU serial number disabled.\n");
+ clear_bit(X86_FEATURE_PN, &c->x86_capability);
}
}
@@ -1458,157 +1756,255 @@ int __init x86_serial_nr_setup(char *s)
__setup("serialnumber", x86_serial_nr_setup);
-void __init identify_cpu(struct cpuinfo_x86 *c)
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
{
- int i=0;
- char *p = NULL;
- extern void mcheck_init(void);
-
- c->loops_per_sec = loops_per_sec;
- c->x86_cache_size = -1;
+ u32 f1, f2;
+
+ asm("pushfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "movl %0,%1\n\t"
+ "xorl %2,%0\n\t"
+ "pushl %0\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %0\n\t"
+ "popfl\n\t"
+ : "=&r" (f1), "=&r" (f2)
+ : "ir" (flag));
+
+ return ((f1^f2) & flag) != 0;
+}
- get_cpu_vendor(c);
+/* Probe for the CPUID instruction */
+static int __init have_cpuid_p(void)
+{
+ return flag_is_changeable_p(X86_EFLAGS_ID);
+}
- switch (c->x86_vendor) {
+/*
+ * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
+ * by the fact that they preserve the flags across the division of 5/2.
+ * PII and PPro exhibit this behavior too, but they have cpuid available.
+ */
+
+/*
+ * Perform the Cyrix 5/2 test. A Cyrix won't change
+ * the flags, while other 486 chips will.
+ */
+static inline int test_cyrix_52div(void)
+{
+ unsigned int test;
+
+ __asm__ __volatile__(
+ "sahf\n\t" /* clear flags (%eax = 0x0005) */
+ "div %b2\n\t" /* divide 5 by 2 */
+ "lahf" /* store flags into %ah */
+ : "=a" (test)
+ : "0" (5), "q" (2)
+ : "cc");
+
+ /* AH is 0x02 on Cyrix after the divide.. */
+ return (unsigned char) (test >> 8) == 0x02;
+}
- case X86_VENDOR_UNKNOWN:
- if (c->cpuid_level < 0)
- {
- /* It may be a nexgen with cpuid disabled.. */
- if(deep_magic_nexgen_probe())
- {
- strcpy(c->x86_model_id, "Nx586");
- c->x86_vendor = X86_VENDOR_NEXGEN;
- }
- return;
- }
- break;
+/* Try to detect a CPU with disabled CPUID, and if so, enable. This routine
+ may also be used to detect non-CPUID processors and fill in some of
+ the information manually. */
+static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c)
+{
+ /* First of all, decide if this is a 486 or higher */
+ /* It's a 486 if we can modify the AC flag */
+ if ( flag_is_changeable_p(X86_EFLAGS_AC) )
+ c->x86 = 4;
+ else
+ c->x86 = 3;
- case X86_VENDOR_CYRIX:
- cyrix_model(c);
- return;
+ /* Detect Cyrix with disabled CPUID */
+ if ( c->x86 == 4 && test_cyrix_52div() ) {
+ strcpy(c->x86_vendor_id, "CyrixInstead");
+ }
- case X86_VENDOR_AMD:
- if (amd_model(c))
- return;
- break;
+ /* Detect NexGen with old hypercode */
+ if ( deep_magic_nexgen_probe() ) {
+ strcpy(c->x86_vendor_id, "NexGenDriven");
+ }
- case X86_VENDOR_CENTAUR:
- centaur_model(c);
- return;
+ return have_cpuid_p(); /* Check to see if CPUID now enabled? */
+}
- case X86_VENDOR_INTEL:
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+ int junk, i;
+ u32 xlvl, tfms;
- squash_the_stupid_serial_number(c);
- mcheck_init();
+ c->loops_per_sec = loops_per_sec;
+ c->x86_cache_size = -1;
+ c->x86_vendor = X86_VENDOR_UNKNOWN;
+ c->cpuid_level = -1; /* CPUID not detected */
+ c->x86_model = c->x86_mask = 0; /* So far unknown... */
+ c->x86_vendor_id[0] = '\0'; /* Unset */
+ c->x86_model_id[0] = '\0'; /* Unset */
+ memset(&c->x86_capability, 0, sizeof c->x86_capability);
+
+ if ( !have_cpuid_p() && !id_and_try_enable_cpuid(c) ) {
+ /* CPU doesn't have CPUID */
+
+ /* If there are any capabilities, they're vendor-specific */
+ /* enable_cpuid() would have set c->x86 for us. */
+ } else {
+ /* CPU does have CPUID */
+
+ /* Get vendor name */
+ cpuid(0x00000000, &c->cpuid_level,
+ (int *)&c->x86_vendor_id[0],
+ (int *)&c->x86_vendor_id[8],
+ (int *)&c->x86_vendor_id[4]);
+
+ get_cpu_vendor(c);
+
+ /* Initialize the standard set of capabilities */
+ /* Note that the vendor-specific code below might override */
+
+ /* Intel-defined flags: level 0x00000001 */
+ if ( c->cpuid_level >= 0x00000001 ) {
+ cpuid(0x00000001, &tfms, &junk, &junk,
+ &c->x86_capability[0]);
+ c->x86 = (tfms >> 8) & 15;
+ c->x86_model = (tfms >> 4) & 15;
+ c->x86_mask = tfms & 15;
+ } else {
+ /* Have CPUID level 0 only - unheard of */
+ c->x86 = 4;
+ }
- if (c->cpuid_level > 1) {
- /* supports eax=2 call */
- int edx, dummy;
+ /* AMD-defined flags: level 0x80000001 */
+ xlvl = cpuid_eax(0x80000000);
+ if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+ if ( xlvl >= 0x80000001 )
+ c->x86_capability[1] = cpuid_edx(0x80000001);
+ if ( xlvl >= 0x80000004 )
+ get_model_name(c); /* Default name */
+ }
- cpuid(2, &dummy, &dummy, &dummy, &edx);
+ /* Transmeta-defined flags: level 0x80860001 */
+ xlvl = cpuid_eax(0x80860000);
+ if ( (xlvl & 0xffff0000) == 0x80860000 ) {
+ if ( xlvl >= 0x80860001 )
+ c->x86_capability[2] = cpuid_edx(0x80860001);
+ }
+ }
- /* We need only the LSB */
- edx &= 0xff;
+ printk("CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_vendor);
- switch (edx) {
- case 0x40:
- c->x86_cache_size = 0;
- break;
+ /*
+ * Vendor-specific initialization. In this section we
+ * canonicalize the feature flags, meaning if there are
+ * features a certain CPU supports which CPUID doesn't
+ * tell us, CPUID claiming incorrect flags, or other bugs,
+ * we handle them here.
+ *
+ * At the end of this section, c->x86_capability better
+ * indicate the features this CPU genuinely supports!
+ */
+ switch ( c->x86_vendor ) {
+ case X86_VENDOR_UNKNOWN:
+ default:
+ /* Not much we can do here... */
+ break;
- case 0x41: /* 4-way 128 */
- c->x86_cache_size = 128;
- break;
+ case X86_VENDOR_CYRIX:
+ init_cyrix(c);
+ break;
- case 0x42: /* 4-way 256 */
- case 0x82: /* 8-way 256 */
- c->x86_cache_size = 256;
- break;
+ case X86_VENDOR_AMD:
+ init_amd(c);
+ break;
- case 0x43: /* 4-way 512 */
- c->x86_cache_size = 512;
- break;
+ case X86_VENDOR_CENTAUR:
+ init_centaur(c);
+ break;
- case 0x44: /* 4-way 1024 */
- case 0x84: /* 8-way 1024 */
- c->x86_cache_size = 1024;
- break;
+ case X86_VENDOR_INTEL:
+ init_intel(c);
+ break;
- case 0x45: /* 4-way 2048 */
- case 0x85: /* 8-way 2048 */
- c->x86_cache_size = 2048;
- break;
+ case X86_VENDOR_NEXGEN:
+ c->x86_cache_size = 256; /* A few had 1 MB... */
+ break;
- default:
- c->x86_cache_size = 0;
- break;
- }
- }
+ case X86_VENDOR_TRANSMETA:
+ init_transmeta(c);
+ break;
+ }
+
+ printk("CPU: After vendor init, caps: %08x %08x %08x %08x\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_capability[3]);
- /* Pentium IV. */
- if (c->x86 == 15) {
- get_model_name(c);
- return;
- }
+ /*
+ * The vendor-specific functions might have changed features. Now
+ * we do "generic changes."
+ */
- /* Names for the Pentium II/Celeron processors
- detectable only by also checking the cache size.
- Dixon is NOT a Celeron. */
- if (c->x86 == 6) {
- switch (c->x86_model) {
- case 5:
- if (c->x86_cache_size == 0)
- p = "Celeron (Covington)";
- if (c->x86_cache_size == 256)
- p = "Mobile Pentium II (Dixon)";
- break;
-
- case 6:
- if (c->x86_cache_size == 128)
- p = "Celeron (Mendocino)";
- break;
-
- case 8:
- if (c->x86_cache_size == 128)
- p = "Celeron (Coppermine)";
- break;
- }
- }
- if (p!=NULL)
- goto name_decoded;
+ /* TSC disabled? */
+#ifdef CONFIG_TSC
+ if ( tsc_disable )
+ clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+#endif
- break;
+ /* Disable the PN if appropriate */
+ squash_the_stupid_serial_number(c);
- case X86_VENDOR_TRANSMETA:
- transmeta_model(c);
- squash_the_stupid_serial_number(c);
- return;
+ /* If the model name is still unset, do table lookup. */
+ if ( !c->x86_model_id[0] ) {
+ char *p;
+ p = table_lookup_model(c);
+ if ( p )
+ strcpy(c->x86_model_id, p);
+ else
+ /* Last resort... */
+ sprintf(c->x86_model_id, "%02x/%02x",
+ c->x86_vendor, c->x86_model);
}
- /* may be changed in the switch so needs to be after */
-
- if(c->x86_vendor == X86_VENDOR_NEXGEN)
- c->x86_cache_size = 256; /* A few had 1Mb.. */
-
- for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
- if (cpu_models[i].vendor == c->x86_vendor &&
- cpu_models[i].x86 == c->x86) {
- if (c->x86_model <= 16)
- p = cpu_models[i].model_names[c->x86_model];
- }
- }
+ /* Now the feature flags better reflect actual CPU features! */
-name_decoded:
+ printk("CPU: After generic, caps: %08x %08x %08x %08x\n",
+ c->x86_capability[0],
+ c->x86_capability[1],
+ c->x86_capability[2],
+ c->x86_capability[3]);
- if (p) {
- strcpy(c->x86_model_id, p);
- return;
+ /*
+ * On SMP, boot_cpu_data holds the common feature set between
+ * all CPUs; so make sure that we indicate which features are
+ * common between the CPUs. The first time this routine gets
+ * executed, c == &boot_cpu_data.
+ */
+ if ( c != &boot_cpu_data ) {
+ /* AND the already accumulated flags with these */
+ for ( i = 0 ; i < NCAPINTS ; i++ )
+ boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
}
- sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model);
+ printk("CPU: Common caps: %08x %08x %08x %08x\n",
+ boot_cpu_data.x86_capability[0],
+ boot_cpu_data.x86_capability[1],
+ boot_cpu_data.x86_capability[2],
+ boot_cpu_data.x86_capability[3]);
}
-
/*
* Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
*/
@@ -1617,14 +2013,12 @@ void __init dodgy_tsc(void)
{
get_cpu_vendor(&boot_cpu_data);
- if(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)
- return;
-
- cyrix_model(&boot_cpu_data);
+ if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX )
+ init_cyrix(&boot_cpu_data);
}
-
+/* These need to match <asm/processor.h> */
static char *cpu_vendor_names[] __initdata = {
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
@@ -1646,7 +2040,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
else
printk("%s", c->x86_model_id);
- if (c->x86_mask || c->cpuid_level>=0)
+ if (c->x86_mask || c->cpuid_level >= 0)
printk(" stepping %02x\n", c->x86_mask);
else
printk("\n");
@@ -1659,23 +2053,39 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
int get_cpuinfo(char * buffer)
{
char *p = buffer;
- int sep_bug;
/*
- * Flags should be entered into the array ONLY if there is no overlap.
- * Else a number should be used and then overridden in the case
- * statement below. --Jauder <jauderho@carumba.com>
- *
- * NOTE: bits 10, 19-22, 26-31 are reserved.
- *
- * Data courtesy of http://www.sandpile.org/arch/cpuid.htm
- * Thanks to the Greasel!
+ * These flag bits must match the definitions in <asm/cpufeature.h>.
+ * NULL means this bit is undefined or reserved; either way it doesn't
+ * have meaning as far as Linux is concerned. Note that it's important
+ * to realize there is a difference between this table and CPUID -- if
+ * applications want to get the raw CPUID data, they should access
+ * /dev/cpu/<cpu_nr>/cpuid instead.
*/
static char *x86_cap_flags[] = {
+ /* Intel-defined */
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
- "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
- "16", "pse36", "psn", "19", "20", "21", "22", "mmx",
- "24", "xmm", "26", "27", "28", "29", "30", "31"
+ "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+ "pat", "pse36", "pn", "clflsh", NULL, "dtes", "acpi", "mmx",
+ "fxsr", "sse", "sse2", "selfsnoop", NULL, "acc", "ia64", NULL,
+
+ /* AMD-defined */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "mmxext", NULL,
+ NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
+
+ /* Transmeta-defined */
+ "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Other (Linux-defined) */
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
struct cpuinfo_x86 *c = cpu_data;
int i, n;
@@ -1702,7 +2112,7 @@ int get_cpuinfo(char * buffer)
else
p += sprintf(p, "stepping\t: unknown\n");
- if (c->x86_capability & X86_FEATURE_TSC) {
+ if ( test_bit(X86_FEATURE_TSC, &c->x86_capability) ) {
p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n",
cpu_khz / 1000, (cpu_khz % 1000));
}
@@ -1711,65 +2121,19 @@ int get_cpuinfo(char * buffer)
if (c->x86_cache_size >= 0)
p += sprintf(p, "cache size\t: %d KB\n", c->x86_cache_size);
- /* Modify the capabilities according to chip type */
- switch (c->x86_vendor) {
-
- case X86_VENDOR_CYRIX:
- x86_cap_flags[24] = "cxmmx";
- break;
-
- case X86_VENDOR_AMD:
- if (c->x86 == 5 && c->x86_model == 6)
- x86_cap_flags[10] = "sep";
- if (c->x86 < 6)
- x86_cap_flags[16] = "fcmov";
- else
- x86_cap_flags[16] = "pat";
- x86_cap_flags[22] = "mmxext";
- x86_cap_flags[24] = "fxsr";
- x86_cap_flags[30] = "3dnowext";
- x86_cap_flags[31] = "3dnow";
- break;
-
- case X86_VENDOR_INTEL:
- x86_cap_flags[16] = "pat";
- x86_cap_flags[18] = "pn";
- x86_cap_flags[24] = "fxsr";
- x86_cap_flags[25] = "xmm";
- break;
-
- case X86_VENDOR_CENTAUR:
- if (c->x86_model >=8) /* Only Winchip2 and above */
- x86_cap_flags[31] = "3dnow";
- break;
-
- default:
- /* Unknown CPU manufacturer or no special handling needed */
- break;
- }
-
- sep_bug = c->x86_vendor == X86_VENDOR_INTEL &&
- c->x86 == 0x06 &&
- c->cpuid_level >= 0 &&
- (c->x86_capability & X86_FEATURE_SEP) &&
- c->x86_model < 3 &&
- c->x86_mask < 3;
-
/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
- fpu_exception = c->hard_math && (ignore_irq13 | (c->x86_capability & X86_FEATURE_FPU));
+ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
p += sprintf(p, "fdiv_bug\t: %s\n"
"hlt_bug\t\t: %s\n"
- "sep_bug\t\t: %s\n"
"f00f_bug\t: %s\n"
"coma_bug\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
"wp\t\t: %s\n"
- "flags\t\t:",
+ "features\t:",
c->fdiv_bug ? "yes" : "no",
c->hlt_works_ok ? "no" : "yes",
- sep_bug ? "yes" : "no",
c->f00f_bug ? "yes" : "no",
c->coma_bug ? "yes" : "no",
c->hard_math ? "yes" : "no",
@@ -1777,8 +2141,9 @@ int get_cpuinfo(char * buffer)
c->cpuid_level,
c->wp_works_ok ? "yes" : "no");
- for ( i = 0 ; i < 32 ; i++ )
- if ( c->x86_capability & (1 << i) )
+ for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+ if ( test_bit(i, &c->x86_capability) &&
+ x86_cap_flags[i] != NULL )
p += sprintf(p, " %s", x86_cap_flags[i]);
p += sprintf(p, "\nbogomips\t: %lu.%02lu\n\n",
@@ -1788,18 +2153,6 @@ int get_cpuinfo(char * buffer)
return p - buffer;
}
-#ifndef CONFIG_X86_TSC
-static int tsc_disable __initdata = 0;
-
-static int __init tsc_setup(char *str)
-{
- tsc_disable = 1;
- return 1;
-}
-
-__setup("notsc", tsc_setup);
-#endif
-
static unsigned long cpu_initialized __initdata = 0;
/*
@@ -1824,7 +2177,8 @@ void __init cpu_init (void)
#ifndef CONFIG_X86_TSC
if (tsc_disable && cpu_has_tsc) {
printk("Disabling TSC...\n");
- boot_cpu_data.x86_capability &= ~X86_FEATURE_TSC;
+ /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
+ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
set_in_cr4(X86_CR4_TSD);
}
#endif
@@ -1869,3 +2223,11 @@ void __init cpu_init (void)
current->used_math = 0;
stts();
}
+
+/*
+ * Local Variables:
+ * mode:c
+ * c-file-style:"k&r"
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 6092aec3b..57a07765e 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -455,7 +455,7 @@ int __init start_secondary(void *unused)
cpu_init();
smp_callin();
while (!atomic_read(&smp_commenced))
- /* nothing */ ;
+ rep_nop();
/*
* low-memory mappings have been cleared, flush them from
* the local TLBs too.
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index ae87ded92..b84421374 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -63,6 +63,7 @@ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
extern int console_loglevel;
+extern void bust_spinlocks(void);
static inline void console_silent(void)
{
@@ -92,7 +93,6 @@ asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void simd_coprocessor_error(void);
-asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);
@@ -312,7 +312,6 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
-DO_ERROR(18, SIGSEGV, "reserved", reserved)
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
@@ -396,7 +395,6 @@ static int __init setup_nmi_watchdog(char *str)
__setup("nmi_watchdog=", setup_nmi_watchdog);
-extern spinlock_t console_lock;
static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
inline void nmi_watchdog_tick(struct pt_regs * regs)
@@ -439,8 +437,7 @@ inline void nmi_watchdog_tick(struct pt_regs * regs)
* We are in trouble anyway, lets at least try
* to get a message out.
*/
- spin_trylock(&console_lock);
- spin_unlock(&console_lock);
+ bust_spinlocks();
printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu);
show_registers(regs);
printk("console shuts up ...\n");
@@ -954,8 +951,10 @@ cobalt_init(void)
#endif
void __init trap_init(void)
{
+#ifdef CONFIG_EISA
if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
EISA_bus = 1;
+#endif
set_trap_gate(0,&divide_error);
set_trap_gate(1,&debug);
diff --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c
index 0314041f9..4aca07e72 100644
--- a/arch/i386/lib/mmx.c
+++ b/arch/i386/lib/mmx.c
@@ -16,6 +16,9 @@
* Add *user handling. Checksums are not a win with MMX on any CPU
* tested so far for any MMX solution figured.
*
+ * 22/09/2000 - Arjan van de Ven
+ * Improved for non-egineering-sample Athlons
+ *
*/
void *_mmx_memcpy(void *to, const void *from, size_t len)
@@ -104,28 +107,26 @@ static void fast_clear_page(void *page)
" pxor %%mm0, %%mm0\n" : :
);
- for(i=0;i<4096/128;i++)
+ for(i=0;i<4096/64;i++)
{
__asm__ __volatile__ (
- " movq %%mm0, (%0)\n"
- " movq %%mm0, 8(%0)\n"
- " movq %%mm0, 16(%0)\n"
- " movq %%mm0, 24(%0)\n"
- " movq %%mm0, 32(%0)\n"
- " movq %%mm0, 40(%0)\n"
- " movq %%mm0, 48(%0)\n"
- " movq %%mm0, 56(%0)\n"
- " movq %%mm0, 64(%0)\n"
- " movq %%mm0, 72(%0)\n"
- " movq %%mm0, 80(%0)\n"
- " movq %%mm0, 88(%0)\n"
- " movq %%mm0, 96(%0)\n"
- " movq %%mm0, 104(%0)\n"
- " movq %%mm0, 112(%0)\n"
- " movq %%mm0, 120(%0)\n"
+ " movntq %%mm0, (%0)\n"
+ " movntq %%mm0, 8(%0)\n"
+ " movntq %%mm0, 16(%0)\n"
+ " movntq %%mm0, 24(%0)\n"
+ " movntq %%mm0, 32(%0)\n"
+ " movntq %%mm0, 40(%0)\n"
+ " movntq %%mm0, 48(%0)\n"
+ " movntq %%mm0, 56(%0)\n"
: : "r" (page) : "memory");
- page+=128;
+ page+=64;
}
+ /* since movntq is weakly-ordered, a "sfence" is needed to become
+ * ordered again.
+ */
+ __asm__ __volatile__ (
+ " sfence \n" : :
+ );
stts();
}
@@ -140,6 +141,9 @@ static void fast_copy_page(void *to, void *from)
current->flags &= ~PF_USEDFPU;
}
+ /* maybe the prefetch stuff can go before the expensive fnsave...
+ * but that is for later. -AV
+ */
__asm__ __volatile__ (
"1: prefetch (%0)\n"
" prefetch 64(%0)\n"
@@ -162,21 +166,21 @@ static void fast_copy_page(void *to, void *from)
__asm__ __volatile__ (
"1: prefetch 320(%0)\n"
"2: movq (%0), %%mm0\n"
+ " movntq %%mm0, (%1)\n"
" movq 8(%0), %%mm1\n"
+ " movntq %%mm1, 8(%1)\n"
" movq 16(%0), %%mm2\n"
+ " movntq %%mm2, 16(%1)\n"
" movq 24(%0), %%mm3\n"
- " movq %%mm0, (%1)\n"
- " movq %%mm1, 8(%1)\n"
- " movq %%mm2, 16(%1)\n"
- " movq %%mm3, 24(%1)\n"
- " movq 32(%0), %%mm0\n"
- " movq 40(%0), %%mm1\n"
- " movq 48(%0), %%mm2\n"
- " movq 56(%0), %%mm3\n"
- " movq %%mm0, 32(%1)\n"
- " movq %%mm1, 40(%1)\n"
- " movq %%mm2, 48(%1)\n"
- " movq %%mm3, 56(%1)\n"
+ " movntq %%mm3, 24(%1)\n"
+ " movq 32(%0), %%mm4\n"
+ " movntq %%mm4, 32(%1)\n"
+ " movq 40(%0), %%mm5\n"
+ " movntq %%mm5, 40(%1)\n"
+ " movq 48(%0), %%mm6\n"
+ " movntq %%mm6, 48(%1)\n"
+ " movq 56(%0), %%mm7\n"
+ " movntq %%mm7, 56(%1)\n"
".section .fixup, \"ax\"\n"
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
@@ -189,6 +193,12 @@ static void fast_copy_page(void *to, void *from)
from+=64;
to+=64;
}
+ /* since movntq is weakly-ordered, a "sfence" is needed to become
+ * ordered again.
+ */
+ __asm__ __volatile__ (
+ " sfence \n" : :
+ );
stts();
}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 946d1f40a..e2a9ee9fe 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -77,6 +77,19 @@ bad_area:
return 0;
}
+extern spinlock_t console_lock, timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out (timerlist_lock is aquired through the
+ * console unblank code)
+ */
+void bust_spinlocks(void)
+{
+ spin_lock_init(&console_lock);
+ spin_lock_init(&timerlist_lock);
+}
+
asmlinkage void do_invalid_op(struct pt_regs *, unsigned long);
extern unsigned long idt;
@@ -251,6 +264,8 @@ no_context:
* terminate things with extreme prejudice.
*/
+ bust_spinlocks();
+
if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
else
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index 33bf47a44..8defec849 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -21,6 +21,8 @@ define_bool CONFIG_IA64 y
define_bool CONFIG_SWIOTLB y # for now...
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_SBUS n
choice 'IA-64 system type' \
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 0383741a0..416b23faa 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -3392,7 +3392,7 @@ sockfd_lookup(int fd, int *err)
}
inode = file->f_dentry->d_inode;
- if (!inode || !inode->i_sock || !socki_lookup(inode))
+ if (!inode->i_sock || !socki_lookup(inode))
{
*err = -ENOTSOCK;
fput(file);
diff --git a/arch/ia64/kernel/semaphore.c b/arch/ia64/kernel/semaphore.c
index 84ff34cf6..f26099912 100644
--- a/arch/ia64/kernel/semaphore.c
+++ b/arch/ia64/kernel/semaphore.c
@@ -50,7 +50,7 @@ __down (struct semaphore *sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -70,7 +70,7 @@ __down (struct semaphore *sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -85,7 +85,7 @@ __down_interruptible (struct semaphore * sem)
int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -121,7 +121,7 @@ __down_interruptible (struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -248,7 +248,7 @@ down_write_failed_biased (struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
@@ -277,7 +277,7 @@ down_write_failed (struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (sem->count >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index b06fdb516..b287daca8 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -25,6 +25,8 @@ mainmenu_option next_comment
comment 'Platform dependent setup'
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_PCMCIA n
bool 'Amiga support' CONFIG_AMIGA
diff --git a/arch/m68k/kernel/semaphore.c b/arch/m68k/kernel/semaphore.c
index 139a75b64..a3a3e17f1 100644
--- a/arch/m68k/kernel/semaphore.c
+++ b/arch/m68k/kernel/semaphore.c
@@ -180,7 +180,7 @@ void down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
@@ -199,7 +199,7 @@ void down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(current, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(current, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 65cb90b3d..a5486d93a 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -40,6 +40,7 @@ unset CONFIG_VIDEO_G364
unset CONFIG_PC_KEYB
unset CONFIG_I8259
+define_bool CONFIG_MCA n
define_bool CONFIG_SBUS n
if [ "$CONFIG_MIPS_EV96100" = "y" ]; then
@@ -103,6 +104,9 @@ fi
if [ "$CONFIG_ISA" != "y" ]; then
define_bool CONFIG_ISA n
+ define_bool CONFIG_EISA n
+else
+ define_bool CONFIG_EISA y
fi
if [ "$CONFIG_PCI" != "y" ]; then
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 534d17b1d..6b9ae3b5b 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -24,12 +24,14 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_BOARD_SCACHE=y
CONFIG_PC_KEYB=y
CONFIG_SGI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
# CONFIG_I8259 is not set
diff --git a/arch/mips/defconfig-atlas b/arch/mips/defconfig-atlas
index b7c45f78c..af230e0c5 100644
--- a/arch/mips/defconfig-atlas
+++ b/arch/mips/defconfig-atlas
@@ -24,10 +24,12 @@ CONFIG_MIPS_ATLAS=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_PCI=y
# CONFIG_ISA is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_I8259 is not set
#
diff --git a/arch/mips/defconfig-ddb5476 b/arch/mips/defconfig-ddb5476
index 77130d7da..b4aa2ccde 100644
--- a/arch/mips/defconfig-ddb5476
+++ b/arch/mips/defconfig-ddb5476
@@ -24,12 +24,14 @@ CONFIG_DDB5476=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_I8259=y
CONFIG_ISA=y
CONFIG_PCI=y
CONFIG_PC_KEYB=y
CONFIG_ROTTEN_IRQ=y
+CONFIG_EISA=y
#
# Loadable module support
@@ -283,8 +285,8 @@ CONFIG_NET_PCI=y
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
# CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
CONFIG_TULIP=y
+# CONFIG_DE4X5 is not set
# CONFIG_DGRS is not set
# CONFIG_DM9102 is not set
CONFIG_EEPRO100=y
@@ -294,14 +296,15 @@ CONFIG_EEPRO100=y
CONFIG_NE2K_PCI=y
# CONFIG_NE3210 is not set
# CONFIG_ES3210 is not set
-# CONFIG_RTL8129 is not set
# CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
# CONFIG_LAN_SAA9730 is not set
# CONFIG_NET_POCKET is not set
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index d264f047a..751bd10e3 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -24,8 +24,10 @@ CONFIG_DECSTATION=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
# CONFIG_I8259 is not set
diff --git a/arch/mips/defconfig-ev96100 b/arch/mips/defconfig-ev96100
index 44eeaa0e1..acce83979 100644
--- a/arch/mips/defconfig-ev96100
+++ b/arch/mips/defconfig-ev96100
@@ -24,10 +24,12 @@ CONFIG_MIPS_EV96100=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_PCI=y
CONFIG_MIPS_GT96100=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_I8259 is not set
#
@@ -211,27 +213,28 @@ CONFIG_MIPS_GT96100ETH=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_TULIP=y
+# CONFIG_DE4X5 is not set
# CONFIG_DGRS is not set
# CONFIG_DM9102 is not set
# CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PM is not set
# CONFIG_LNE390 is not set
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_NE3210 is not set
# CONFIG_ES3210 is not set
-# CONFIG_RTL8129 is not set
# CONFIG_8139TOO is not set
+# CONFIG_RTL8129 is not set
# CONFIG_SIS900 is not set
# CONFIG_EPIC100 is not set
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_WINBOND_840 is not set
+# CONFIG_HAPPYMEAL is not set
# CONFIG_LAN_SAA9730 is not set
# CONFIG_NET_POCKET is not set
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 534d17b1d..6b9ae3b5b 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -24,12 +24,14 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_OLIVETTI_M700 is not set
CONFIG_SGI_IP22=y
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_BOARD_SCACHE=y
CONFIG_PC_KEYB=y
CONFIG_SGI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
# CONFIG_I8259 is not set
diff --git a/arch/mips/defconfig-malta b/arch/mips/defconfig-malta
index 1e9f8e70b..08ae459c5 100644
--- a/arch/mips/defconfig-malta
+++ b/arch/mips/defconfig-malta
@@ -24,11 +24,13 @@ CONFIG_MIPS_MALTA=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_I8259=y
CONFIG_PCI=y
# CONFIG_ISA is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
#
# Loadable module support
diff --git a/arch/mips/defconfig-orion b/arch/mips/defconfig-orion
index 967043363..11f9353cf 100644
--- a/arch/mips/defconfig-orion
+++ b/arch/mips/defconfig-orion
@@ -24,8 +24,10 @@ CONFIG_ORION=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
# CONFIG_I8259 is not set
diff --git a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200
index 5eb83f270..4881669c0 100644
--- a/arch/mips/defconfig-rm200
+++ b/arch/mips/defconfig-rm200
@@ -24,6 +24,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
CONFIG_SNI_RM200_PCI=y
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_ARC32=y
CONFIG_I8259=y
@@ -31,6 +32,7 @@ CONFIG_ISA=y
CONFIG_PC_KEYB=y
CONFIG_PCI=y
CONFIG_ROTTEN_IRQ=y
+CONFIG_EISA=y
#
# Loadable module support
diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c
index 1f47bd929..5a9478f03 100644
--- a/arch/mips/kernel/semaphore.c
+++ b/arch/mips/kernel/semaphore.c
@@ -187,8 +187,7 @@ __down_write(struct rw_semaphore *sem, int count)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
break;
schedule();
@@ -208,8 +207,7 @@ __down_write(struct rw_semaphore *sem, int count)
while (1) {
if (test_and_clear_bit(1, &sem->granted))
break;
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if ((sem->granted & 2) == 0)
schedule();
}
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 129c24913..97730d9be 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -57,12 +57,16 @@ fi
if [ "$CONFIG_ISA" != "y" ]; then
define_bool CONFIG_ISA n
+ define_bool CONFIG_EISA n
+else
+ define_bool CONFIG_EISA y
fi
if [ "$CONFIG_PCI" != "y" ]; then
define_bool CONFIG_PCI n
fi
+define_bool CONFIG_MCA n
define_bool CONFIG_SBUS n
mainmenu_option next_comment
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 8c86e86f3..72f0b52bc 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -25,6 +25,8 @@ CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
#
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index 1e1e020eb..3848c0c96 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -18,7 +18,9 @@ CONFIG_BOARD_SCACHE=y
CONFIG_ARC_MEMORY=y
CONFIG_SGI=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
# CONFIG_PCI is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
#
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 8c86e86f3..72f0b52bc 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -25,6 +25,8 @@ CONFIG_COHERENT_IO=y
CONFIG_PCI=y
CONFIG_QL_ISP_A64=y
# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
# CONFIG_SBUS is not set
#
diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c
index b29514758..2e64aa465 100644
--- a/arch/mips64/kernel/linux32.c
+++ b/arch/mips64/kernel/linux32.c
@@ -277,7 +277,7 @@ int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
diff --git a/arch/mips64/kernel/semaphore.c b/arch/mips64/kernel/semaphore.c
index 1f47bd929..5a9478f03 100644
--- a/arch/mips64/kernel/semaphore.c
+++ b/arch/mips64/kernel/semaphore.c
@@ -187,8 +187,7 @@ __down_write(struct rw_semaphore *sem, int count)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
break;
schedule();
@@ -208,8 +207,7 @@ __down_write(struct rw_semaphore *sem, int count)
while (1) {
if (test_and_clear_bit(1, &sem->granted))
break;
- set_task_state(tsk, (TASK_UNINTERRUPTIBLE
- | TASK_EXCLUSIVE));
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if ((sem->granted & 2) == 0)
schedule();
}
diff --git a/arch/mips64/ld.script.elf32 b/arch/mips64/ld.script.elf32
new file mode 100644
index 000000000..e83f23508
--- /dev/null
+++ b/arch/mips64/ld.script.elf32
@@ -0,0 +1,123 @@
+/* 2^^40 *//* 2^^40 *//* 2^^40 *//* 2^^40 *//* max syssegsz *//* 2^^40 - 1 *//* KUSIZE for a 32 bit proc *//* exclusive on write *//* noncoherent *//* exclusive *//* Uncached attr 3, uncac *//* 32-bit compat k1 *//* _ASM_ADDRSPACE_H *//* CONFIG_MAPPED_KERNEL *//* CONFIG_MAPPED_KERNEL */OUTPUT_ARCH(mips)
+ENTRY(kernel_entry)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ .init : { *(.init) } =0
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___dbe_table = .; /* Exception table for data bus errors */
+ __dbe_table : { *(__dbe_table) }
+ __stop___dbe_table = .;
+
+ _etext = .;
+
+ . = ALIGN(16384);
+ . = . + 0 ; /* for CONFIG_MAPPED_KERNEL */
+ .data.init_task : { *(.data.init_task) }
+
+ /* Startup code */
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096); /* Align double page for init_task_union */
+ __init_end = .;
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ .fini : { *(.fini) } =0
+ .reginfo : { *(.reginfo) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. It would
+ be more correct to do this:
+ . = .;
+ The current expression does not correctly handle the case of a
+ text segment ending precisely at the end of a page; it causes the
+ data segment to skip a page. The above expression does not have
+ this problem, but it will currently (2/95) cause BFD to allocate
+ a single segment, combining both text and data, for this case.
+ This will prevent the text segment from being shared among
+ multiple executions of the program; I think that is more
+ important than losing a page of the virtual address space (note
+ that no actual memory is lost; the page which is skipped can not
+ be referenced). */
+ . = .;
+ .data :
+ {
+ _fdata = . ;
+ *(.data)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ _edata = .;
+
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ _end = . ;
+ }
+
+ /* Sections to be discarded */
+ /DISCARD/ :
+ {
+ *(.text.exit)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+}
diff --git a/arch/mips64/mm/fault.c b/arch/mips64/mm/fault.c
index 204419e98..c8f4534d4 100644
--- a/arch/mips64/mm/fault.c
+++ b/arch/mips64/mm/fault.c
@@ -57,6 +57,19 @@ dodebug2(abi64_no_regargs, struct pt_regs regs)
printk("Got exception 0x%lx at 0x%lx\n", retaddr, regs.cp0_epc);
}
+extern spinlock_t console_lock, timerlist_lock;
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out (timerlist_lock is aquired through the
+ * console unblank code)
+ */
+void bust_spinlocks(void)
+{
+ spin_lock_init(&console_lock);
+ spin_lock_init(&timerlist_lock);
+}
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -181,6 +194,9 @@ no_context:
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
+
+ bust_spinlocks();
+
printk(KERN_ALERT "Cpu %d Unable to handle kernel paging request at "
"address %08lx, epc == %08x, ra == %08x\n",
smp_processor_id(), address, (unsigned int) regs->cp0_epc,
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 4b871c230..0790a81c5 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -149,7 +149,7 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
/* After servicing the interrupt, we have to remove the status
* indicator.
*/
- ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec);
+ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec);
}
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index ef17e6334..34606f99a 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -98,8 +98,12 @@ bool 'High memory support (experimental)' CONFIG_HIGHMEM
bool 'Mac-on-Linux support' CONFIG_MOL
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
define_bool CONFIG_SBUS n
+# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
+define_bool CONFIG_MCA n
+
if [ "$CONFIG_APUS" = "y" -o "$CONFIG_4xx" = "y" -o \
"$CONFIG_8260" = "y" ]; then
define_bool CONFIG_PCI n
diff --git a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig
index 328d5c660..ed930fff2 100644
--- a/arch/ppc/configs/apus_defconfig
+++ b/arch/ppc/configs/apus_defconfig
@@ -1,139 +1,161 @@
#
# Automatically generated make config: don't edit
#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
#
# Platform support
#
CONFIG_PPC=y
CONFIG_6xx=y
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
# CONFIG_8xx is not set
-CONFIG_PMAC=y
-# CONFIG_PREP is not set
-# CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
+CONFIG_ALL_PPC=y
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
# CONFIG_APUS is not set
-# CONFIG_MBX is not set
# CONFIG_SMP is not set
-CONFIG_MACH_SPECIFIC=y
+# CONFIG_ALTIVEC is not set
#
# General setup
#
-CONFIG_EXPERIMENTAL=y
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
CONFIG_BINFMT_MISC=m
-# CONFIG_BINFMT_JAVA is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
# CONFIG_VGA_CONSOLE is not set
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
-CONFIG_PMAC_PBOOK=y
-CONFIG_MAC_KEYBOARD=y
-CONFIG_MAC_FLOPPY=y
-CONFIG_MAC_SERIAL=y
-CONFIG_ADBMOUSE=y
+# CONFIG_PPC_RTC is not set
CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
#
-# Plug and Play support
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD 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=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_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_BLK_DEV_SL82C105 is not set
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_PMAC_AUTO=y
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
# 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_RAM_SIZE=4096
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
#
CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
CONFIG_NETLINK=y
# CONFIG_RTNETLINK is not set
# CONFIG_NETLINK_DEV is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_INET_RARP=y
-CONFIG_IP_NOSR=y
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
#
#
#
# CONFIG_IPX is not set
CONFIG_ATALK=m
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT 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
-# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED 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
@@ -142,14 +164,17 @@ CONFIG_SCSI=y
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_SR_EXTRA_DEVS=2
# CONFIG_CHR_DEV_SG is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
@@ -157,96 +182,136 @@ CONFIG_SCSI_CONSTANTS=y
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
CONFIG_SCSI_AIC7XXX=y
-# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
CONFIG_AIC7XXX_PROC_STATS=y
CONFIG_AIC7XXX_RESET_DELAY=15
# 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_CPQFCTS 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
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# 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_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX 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_QLOGIC_ISP is not set
-# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 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
# CONFIG_SCSI_DEBUG is not set
CONFIG_SCSI_MESH=y
CONFIG_SCSI_MESH_SYNC_RATE=5
CONFIG_SCSI_MAC53C94=y
#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
# Network device support
#
CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_APPLETALK is not set
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
CONFIG_NET_ETHERNET=y
CONFIG_MACE=y
CONFIG_BMAC=y
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
# CONFIG_NET_VENDOR_3COM is not set
# 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_YELLOWFIN is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-CONFIG_DE4X5=y
-CONFIG_DEC_ELCP=m
-# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
-# CONFIG_LNE390 is not set
-# CONFIG_NE3210 is not set
-# CONFIG_NE2K_PCI 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_PCI is not set
# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-# CONFIG_DLCI is not set
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
#
-# CCP compressors for PPP are only built as modules.
+# Wireless LAN (non-hamradio)
#
-# CONFIG_SLIP is not set
# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
-# CONFIG_HOSTESS_SV11 is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
#
# Amateur Radio support
@@ -254,27 +319,46 @@ CONFIG_PPP=y
# CONFIG_HAMRADIO is not set
#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
#
# Console drivers
#
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
CONFIG_FB_OF=y
CONFIG_FB_CONTROL=y
CONFIG_FB_PLATINUM=y
CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
-CONFIG_FB_IMSTT=y
CONFIG_FB_CT65550=y
+CONFIG_FB_IMSTT=y
# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_ATY=y
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_SIS is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
CONFIG_FBCON_CFB8=y
@@ -292,6 +376,21 @@ CONFIG_FONT_SUN12x22=y
# CONFIG_FONT_ACORN_8x8 is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_ADB_CUDA is not set
+# CONFIG_ADB_PMU is not set
+CONFIG_MAC_FLOPPY=y
+CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_ADB is not set
+
+#
# Character devices
#
CONFIG_VT=y
@@ -301,58 +400,127 @@ CONFIG_SERIAL=m
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_INTEL_RNG is not set
CONFIG_NVRAM=y
-# CONFIG_JOYSTICK is not set
+# CONFIG_RTC 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_AGP is not set
+# CONFIG_DRM is not set
#
-# Filesystems
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=y
+# 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=y
+# CONFIG_BFS_FS is not set
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
# CONFIG_UMSDOS_FS is not set
CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_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_MOUNT 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
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=y
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_ADFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-CONFIG_MAC_PARTITION=y
+# 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
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
CONFIG_NLS=y
#
# Native Language Support
#
+CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
@@ -369,6 +537,10 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
@@ -378,16 +550,40 @@ CONFIG_NLS_CODEPAGE_437=y
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_UTF8 is not set
#
# Sound
#
CONFIG_SOUND=y
-CONFIG_DMASOUND=y
+# CONFIG_DMASOUND_AWACS is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff --git a/arch/ppc/configs/bseip_defconfig b/arch/ppc/configs/bseip_defconfig
index 7233997fd..f0ff611f4 100644
--- a/arch/ppc/configs/bseip_defconfig
+++ b/arch/ppc/configs/bseip_defconfig
@@ -9,18 +9,27 @@
CONFIG_EXPERIMENTAL=y
#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
# Platform support
#
CONFIG_PPC=y
# CONFIG_6xx is not set
# CONFIG_4xx is not set
-# CONFIG_PPC64BRIDGE is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
# CONFIG_8260 is not set
CONFIG_8xx=y
CONFIG_SERIAL_CONSOLE=y
# CONFIG_RPXLITE is not set
# CONFIG_RPXCLASSIC is not set
CONFIG_BSEIP=y
+# CONFIG_TQM8xxL is not set
+# CONFIG_TQM860L is not set
+# CONFIG_TQM860 is not set
# CONFIG_MBX is not set
# CONFIG_WINCEPT is not set
# CONFIG_ALL_PPC is not set
@@ -29,15 +38,13 @@ CONFIG_MACH_SPECIFIC=y
CONFIG_MATH_EMULATION=y
#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
# General setup
#
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
+# CONFIG_PCI_QSPAN is not set
# CONFIG_PCI is not set
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -56,6 +63,11 @@ CONFIG_KERNEL_ELF=y
# CONFIG_PARPORT is not set
#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
# Plug and Play configuration
#
# CONFIG_PNP is not set
@@ -68,16 +80,25 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -96,17 +117,11 @@ CONFIG_IP_MULTICAST=y
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_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -117,10 +132,11 @@ CONFIG_SKB_LARGE=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -155,6 +171,7 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
# CONFIG_NET_SB1000 is not set
@@ -173,6 +190,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
@@ -180,8 +198,9 @@ CONFIG_NET_ETHERNET=y
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -236,6 +255,15 @@ CONFIG_NET_ETHERNET=y
# CONFIG_FB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -260,19 +288,19 @@ CONFIG_UNIX98_PTY_COUNT=256
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_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
@@ -281,9 +309,13 @@ CONFIG_UNIX98_PTY_COUNT=256
# 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
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
@@ -301,6 +333,7 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
@@ -360,6 +393,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
@@ -375,7 +409,9 @@ CONFIG_SCC_ENET=y
# CONFIG_SCC1_ENET is not set
CONFIG_SCC2_ENET=y
# CONFIG_FEC_ENET is not set
+# CONFIG_ENET_BIG_BUFFERS is not set
CONFIG_8xxSMC2=y
+# CONFIG_8xx_ALTSMC2 is not set
# CONFIG_8xxSCC is not set
#
diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
index a9ae80db0..5574ecbdb 100644
--- a/arch/ppc/configs/common_defconfig
+++ b/arch/ppc/configs/common_defconfig
@@ -36,6 +36,7 @@ CONFIG_ALTIVEC=y
# General setup
#
# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
CONFIG_PCI=y
@@ -58,7 +59,6 @@ CONFIG_PCI_NAMES=y
CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
-CONFIG_PMAC_PBOOK=y
CONFIG_PPC_RTC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BOOTX_TEXT=y
@@ -83,18 +83,25 @@ CONFIG_BOOTX_TEXT=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -130,6 +137,7 @@ CONFIG_ATALK=m
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -203,10 +211,11 @@ CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC202XX is not set
# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_VIA82CXXX_TUNING is not set
CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -262,6 +271,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
@@ -273,8 +283,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# 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_NCR53C8XX is not set
CONFIG_SCSI_SYM53C8XX=y
@@ -293,6 +301,8 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
@@ -342,6 +352,7 @@ CONFIG_GMAC=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_PCI=y
CONFIG_PCNET32=y
@@ -358,26 +369,28 @@ CONFIG_DE4X5=y
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
# CONFIG_RTL8129 is not set
# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE 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_WINBOND_840 is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP=y
CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
CONFIG_PPP_ASYNC=y
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=y
@@ -483,13 +496,15 @@ CONFIG_INPUT_EVDEV=y
#
# Macintosh device drivers
#
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_PBOOK=y
+CONFIG_PMAC_BACKLIGHT=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
CONFIG_ADB_MACIO=y
-CONFIG_ADB_PMU=y
CONFIG_INPUT_ADBHID=y
CONFIG_MAC_HID=y
CONFIG_MAC_ADBKEYCODES=y
@@ -686,6 +701,7 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_EMU10K1 is not set
# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
# CONFIG_SOUND_ESSSOLO1 is not set
@@ -715,7 +731,6 @@ CONFIG_SOUND_CS4232=m
# 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 is not set
# CONFIG_SOUND_AWE32_SYNTH is not set
# CONFIG_SOUND_WAVEFRONT is not set
@@ -768,6 +783,7 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_DSBR is not set
# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_NET1080 is not set
#
# USB Human Interface Devices (HID)
diff --git a/arch/ppc/configs/est8260_defconfig b/arch/ppc/configs/est8260_defconfig
index d317c8517..afb972c03 100644
--- a/arch/ppc/configs/est8260_defconfig
+++ b/arch/ppc/configs/est8260_defconfig
@@ -38,6 +38,7 @@ CONFIG_MACH_SPECIFIC=y
# General setup
#
# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
# CONFIG_PCI is not set
@@ -81,18 +82,25 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -130,6 +138,7 @@ CONFIG_SYN_COOKIES=y
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -183,6 +192,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
@@ -190,8 +200,9 @@ CONFIG_NET_ETHERNET=y
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
diff --git a/arch/ppc/configs/gemini_defconfig b/arch/ppc/configs/gemini_defconfig
index 522bd5d5d..44147f58c 100644
--- a/arch/ppc/configs/gemini_defconfig
+++ b/arch/ppc/configs/gemini_defconfig
@@ -9,12 +9,20 @@
CONFIG_EXPERIMENTAL=y
#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
# Platform support
#
CONFIG_PPC=y
CONFIG_6xx=y
# CONFIG_4xx is not set
-# CONFIG_PPC64 is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
# CONFIG_8260 is not set
# CONFIG_8xx is not set
# CONFIG_ALL_PPC is not set
@@ -26,15 +34,10 @@ CONFIG_ALTIVEC=y
CONFIG_MACH_SPECIFIC=y
#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
-
-#
# General setup
#
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
CONFIG_PCI=y
@@ -46,6 +49,7 @@ CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
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
@@ -55,33 +59,47 @@ CONFIG_KERNEL_ELF=y
# CONFIG_PARPORT is not set
# CONFIG_VGA_CONSOLE is not set
# CONFIG_FB is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADB is not set
+# CONFIG_PPC_RTC is not set
# CONFIG_PROC_DEVICETREE is not set
# CONFIG_BOOTX_TEXT is not set
# CONFIG_MOTOROLA_HOTSWAP is not set
#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD 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_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
#
-# Additional Block Devices
+# Multi-device support (RAID and LVM)
#
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
-# CONFIG_RAID15_DANGEROUS is not set
-# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -98,17 +116,11 @@ CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -119,10 +131,11 @@ CONFIG_SKB_LARGE=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -167,6 +180,7 @@ CONFIG_SCSI_CONSTANTS=y
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -178,6 +192,8 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS 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,17 +201,29 @@ CONFIG_SCSI_CONSTANTS=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_sync is not set
-# CONFIG_SCSI_NCR53C7xx_FAST is not set
-# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_DEBUG is not set
@@ -203,6 +231,11 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_MAC53C94 is not set
#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
# Network device support
#
CONFIG_NETDEVICES=y
@@ -214,6 +247,7 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
# CONFIG_NET_SB1000 is not set
@@ -232,6 +266,7 @@ CONFIG_NCR885E=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
@@ -239,8 +274,9 @@ CONFIG_NCR885E=y
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -295,6 +331,15 @@ CONFIG_NCR885E=y
# CONFIG_FB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -320,19 +365,19 @@ CONFIG_UNIX98_PTY_COUNT=256
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_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
@@ -341,8 +386,13 @@ CONFIG_UNIX98_PTY_COUNT=256
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
-# CONFIG_DRM is not set
# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
@@ -351,27 +401,39 @@ CONFIG_UNIX98_PTY_COUNT=256
# 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
# 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_JFFS_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_MOUNT 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
@@ -379,11 +441,23 @@ CONFIG_EXT2_FS=y
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
# 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=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
diff --git a/arch/ppc/configs/mbx_defconfig b/arch/ppc/configs/mbx_defconfig
index 7080efb3e..6230f5877 100644
--- a/arch/ppc/configs/mbx_defconfig
+++ b/arch/ppc/configs/mbx_defconfig
@@ -1,98 +1,110 @@
#
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
#
# Platform support
#
CONFIG_PPC=y
# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
CONFIG_8xx=y
-# CONFIG_PMAC is not set
-# CONFIG_PREP is not set
-# CONFIG_CHRP is not set
-# CONFIG_ALL_PPC is not set
-# CONFIG_APUS is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM8xxL is not set
+# CONFIG_TQM860L is not set
+# CONFIG_TQM860 is not set
CONFIG_MBX=y
-CONFIG_MACH_SPECIFIC=y
+# CONFIG_WINCEPT is not set
+# CONFIG_ALL_PPC is not set
# CONFIG_SMP is not set
-CONFIG_SERIAL_CONSOLE=y
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
#
# General setup
#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_MODULES is not set
-CONFIG_PCI=y
-# CONFIG_PCI_QUIRKS is not set
-CONFIG_PCI_OLD_PROC=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI_QSPAN is not set
+# CONFIG_PCI is not set
CONFIG_NET=y
# CONFIG_SYSCTL is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_FB is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_KEYBOARD is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADBMOUSE is not set
-# CONFIG_BLK_DEV_IDE_PMAC is not set
-# CONFIG_PROC_DEVICETREE is not set
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-# CONFIG_TOTALMP is not set
-# CONFIG_BOOTX_TEXT is not set
#
-# Plug and Play support
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD 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=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-CONFIG_BLK_DEV_IDEDISK=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
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_PCI_AUTO=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_BLK_DEV_CMD646 is not set
-CONFIG_BLK_DEV_SL82C105=y
-# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
#
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
+# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
@@ -101,26 +113,29 @@ CONFIG_INET=y
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_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
-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_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT 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
-CONFIG_CPU_IS_SLOW=y
#
# QoS and/or fair queueing
@@ -128,6 +143,13 @@ CONFIG_CPU_IS_SLOW=y
# CONFIG_NET_SCHED 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 is not set
@@ -136,33 +158,66 @@ CONFIG_CPU_IS_SLOW=y
# 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_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
CONFIG_NET_ETHERNET=y
# CONFIG_MACE is not set
# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
# CONFIG_NET_VENDOR_3COM is not set
# 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_YELLOWFIN is not set
-# CONFIG_ACENIC is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA is not set
+# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-# CONFIG_DLCI 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 devices
+#
# CONFIG_TR is not set
-# CONFIG_SHAPER is not set
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA 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
#
# Amateur Radio support
@@ -170,12 +225,17 @@ CONFIG_NET_ETHERNET=y
# CONFIG_HAMRADIO is not set
#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
@@ -184,83 +244,182 @@ CONFIG_NET_ETHERNET=y
#
#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
-CONFIG_VT=y
-# CONFIG_VT_CONSOLE is not set
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
-# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
#
-# Video For Linux
+# I2C support
#
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
#
-# Joystick support
+# Joysticks
#
# CONFIG_JOYSTICK is not set
#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC 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_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV 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_ADFS_FS_RW 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_JFFS_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_MOUNT 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
#
-# CONFIG_BSD_DISKLABEL is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
# Sound
#
# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+CONFIG_SCC1_ENET=y
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+# CONFIG_8xx_ALTSMC2 is not set
+CONFIG_8xxSCC=y
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff --git a/arch/ppc/configs/oak_defconfig b/arch/ppc/configs/oak_defconfig
index 362c83689..f33966d35 100644
--- a/arch/ppc/configs/oak_defconfig
+++ b/arch/ppc/configs/oak_defconfig
@@ -1,6 +1,7 @@
#
-# Default configuration for the IBM PowerPC 403 "Oak" evaluation boards.
+# Automatically generated make config: don't edit
#
+# CONFIG_UID16 is not set
#
# Code maturity level options
@@ -8,13 +9,21 @@
CONFIG_EXPERIMENTAL=y
#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
# Platform support
#
CONFIG_PPC=y
# CONFIG_6xx is not set
CONFIG_4xx=y
-# CONFIG_PPC64BRIDGE is not set
-# CONFIG_82xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
# CONFIG_8xx is not set
CONFIG_OAK=y
# CONFIG_WALNUT is not set
@@ -23,35 +32,33 @@ CONFIG_MACH_SPECIFIC=y
# CONFIG_MATH_EMULATION is not set
#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
# General setup
#
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
# CONFIG_PCI is not set
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_FB is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADB is not set
-# CONFIG_PROC_DEVICETREE is not set
-# CONFIG_TOTALMP is not set
-# CONFIG_BOOTX_TEXT is not set
-# CONFIG_MOTOROLA_HOTSWAP is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
#
# Plug and Play configuration
@@ -63,22 +70,28 @@ CONFIG_KERNEL_ELF=y
# 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
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
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
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -94,17 +107,11 @@ CONFIG_IP_MULTICAST=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -115,10 +122,11 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -130,6 +138,13 @@ CONFIG_SYN_COOKIES=y
# CONFIG_NET_SCHED 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 is not set
@@ -144,7 +159,9 @@ CONFIG_NETDEVICES=y
#
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
#
@@ -153,25 +170,26 @@ CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
# CONFIG_MACE is not set
# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
# CONFIG_NCR885E is not set
CONFIG_OAKNET=y
# CONFIG_NET_VENDOR_3COM is not set
# 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_HP100 is not set
# CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA 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_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -184,7 +202,7 @@ CONFIG_OAKNET=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
@@ -202,6 +220,11 @@ CONFIG_OAKNET=y
# CONFIG_HAMRADIO is not set
#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
@@ -221,6 +244,15 @@ CONFIG_OAKNET=y
# CONFIG_FB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -240,24 +272,24 @@ CONFIG_SERIAL_CONSOLE=y
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
#
-# Watchdog Cards
+# Joysticks
#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
#
-# Video For Linux
+# Input core support is needed for joysticks
#
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_QIC02_TAPE is not set
#
-# Joystick support
+# Watchdog Cards
#
-# CONFIG_JOYSTICK is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -266,19 +298,22 @@ CONFIG_SERIAL_CONSOLE=y
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
# CONFIG_DRM is not set
#
-# Support for USB
+# Multimedia devices
#
-# CONFIG_USB is not set
+# CONFIG_VIDEO_DEV 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -287,39 +322,60 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_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_UDF_FS 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_MOUNT 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
#
# CONFIG_PARTITION_ADVANCED is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
@@ -328,6 +384,11 @@ CONFIG_LOCKD=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/ppc/configs/rpxcllf_defconfig b/arch/ppc/configs/rpxcllf_defconfig
index 4dda3d93f..78ee82230 100644
--- a/arch/ppc/configs/rpxcllf_defconfig
+++ b/arch/ppc/configs/rpxcllf_defconfig
@@ -41,8 +41,10 @@ CONFIG_MATH_EMULATION=y
# General setup
#
# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
+# CONFIG_PCI_QSPAN is not set
# CONFIG_PCI is not set
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -78,18 +80,25 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -127,6 +136,7 @@ CONFIG_SYN_COOKIES=y
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -180,6 +190,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
@@ -187,8 +198,9 @@ CONFIG_NET_ETHERNET=y
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
diff --git a/arch/ppc/configs/rpxlite_defconfig b/arch/ppc/configs/rpxlite_defconfig
index bacefe6f7..741d9265f 100644
--- a/arch/ppc/configs/rpxlite_defconfig
+++ b/arch/ppc/configs/rpxlite_defconfig
@@ -9,18 +9,27 @@
CONFIG_EXPERIMENTAL=y
#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
# Platform support
#
CONFIG_PPC=y
# CONFIG_6xx is not set
# CONFIG_4xx is not set
-# CONFIG_PPC64BRIDGE is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
# CONFIG_8260 is not set
CONFIG_8xx=y
CONFIG_SERIAL_CONSOLE=y
CONFIG_RPXLITE=y
# CONFIG_RPXCLASSIC is not set
# CONFIG_BSEIP is not set
+# CONFIG_TQM8xxL is not set
+# CONFIG_TQM860L is not set
+# CONFIG_TQM860 is not set
# CONFIG_MBX is not set
# CONFIG_WINCEPT is not set
# CONFIG_ALL_PPC is not set
@@ -29,15 +38,13 @@ CONFIG_MACH_SPECIFIC=y
CONFIG_MATH_EMULATION=y
#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
# General setup
#
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
+# CONFIG_PCI_QSPAN is not set
# CONFIG_PCI is not set
CONFIG_NET=y
CONFIG_SYSCTL=y
@@ -56,6 +63,11 @@ CONFIG_KERNEL_ELF=y
# CONFIG_PARPORT is not set
#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
# Plug and Play configuration
#
# CONFIG_PNP is not set
@@ -68,16 +80,25 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
-# CONFIG_RAID15_DANGEROUS is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -96,17 +117,11 @@ CONFIG_IP_MULTICAST=y
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_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -117,10 +132,11 @@ CONFIG_SKB_LARGE=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -155,6 +171,7 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
# CONFIG_NET_SB1000 is not set
@@ -173,6 +190,7 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
@@ -180,8 +198,9 @@ CONFIG_NET_ETHERNET=y
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -236,6 +255,15 @@ CONFIG_NET_ETHERNET=y
# CONFIG_FB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -260,19 +288,19 @@ CONFIG_UNIX98_PTY_COUNT=256
# Joysticks
#
# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
# CONFIG_QIC02_TAPE is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_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
@@ -281,9 +309,13 @@ CONFIG_UNIX98_PTY_COUNT=256
# 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
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
#
# File systems
@@ -301,6 +333,7 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
@@ -360,6 +393,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
@@ -375,6 +409,7 @@ CONFIG_SCC_ENET=y
# CONFIG_SCC1_ENET is not set
CONFIG_SCC2_ENET=y
# CONFIG_FEC_ENET is not set
+# CONFIG_ENET_BIG_BUFFERS is not set
# CONFIG_8xxSMC2 is not set
# CONFIG_8xxSCC is not set
diff --git a/arch/ppc/configs/walnut_defconfig b/arch/ppc/configs/walnut_defconfig
index 73bc24eea..c3e95c6ac 100644
--- a/arch/ppc/configs/walnut_defconfig
+++ b/arch/ppc/configs/walnut_defconfig
@@ -1,6 +1,7 @@
#
-# Default configuration for the IBM PowerPC 405GP "Walnut" evaluation board.
+# Automatically generated make config: don't edit
#
+# CONFIG_UID16 is not set
#
# Code maturity level options
@@ -8,13 +9,21 @@
CONFIG_EXPERIMENTAL=y
#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
# Platform support
#
CONFIG_PPC=y
# CONFIG_6xx is not set
CONFIG_4xx=y
-# CONFIG_PPC64BRIDGE is not set
-# CONFIG_82xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
# CONFIG_8xx is not set
# CONFIG_OAK is not set
CONFIG_WALNUT=y
@@ -23,35 +32,33 @@ CONFIG_MACH_SPECIFIC=y
# CONFIG_MATH_EMULATION is not set
#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
# General setup
#
-CONFIG_PCI=y
+# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
CONFIG_NET=y
CONFIG_SYSCTL=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_FB is not set
-# CONFIG_PMAC_PBOOK is not set
-# CONFIG_MAC_FLOPPY is not set
-# CONFIG_MAC_SERIAL is not set
-# CONFIG_ADB is not set
-# CONFIG_PROC_DEVICETREE is not set
-# CONFIG_TOTALMP is not set
-# CONFIG_BOOTX_TEXT is not set
-# CONFIG_MOTOROLA_HOTSWAP is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
#
# Plug and Play configuration
@@ -63,22 +70,28 @@ CONFIG_KERNEL_ELF=y
# 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
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
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
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -94,17 +107,11 @@ CONFIG_IP_MULTICAST=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
+# CONFIG_INET_ECN is not set
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
-# CONFIG_SKB_LARGE is not set
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
@@ -115,10 +122,11 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -130,6 +138,13 @@ CONFIG_SYN_COOKIES=y
# CONFIG_NET_SCHED 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 is not set
@@ -144,7 +159,9 @@ CONFIG_NETDEVICES=y
#
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
#
@@ -153,25 +170,26 @@ CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
# CONFIG_MACE is not set
# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
# CONFIG_NCR885E is not set
# CONFIG_OAKNET is not set
# CONFIG_NET_VENDOR_3COM is not set
# 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_HP100 is not set
# CONFIG_NET_ISA is not set
-# CONFIG_NET_EISA 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_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -184,7 +202,7 @@ CONFIG_NET_ETHERNET=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
@@ -202,6 +220,11 @@ CONFIG_NET_ETHERNET=y
# CONFIG_HAMRADIO is not set
#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
# ISDN subsystem
#
# CONFIG_ISDN is not set
@@ -221,6 +244,15 @@ CONFIG_NET_ETHERNET=y
# CONFIG_FB is not set
#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Macintosh device drivers
+#
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -234,30 +266,33 @@ CONFIG_SERIAL_CONSOLE=y
# I2C support
#
CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_CHARDEV is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
-# CONFIG_QIC02_TAPE is not set
#
-# Watchdog Cards
+# Joysticks
#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
#
-# Video For Linux
+# Input core support is needed for joysticks
#
-# CONFIG_VIDEO_DEV is not set
+# CONFIG_QIC02_TAPE is not set
#
-# Joystick support
+# Watchdog Cards
#
-# CONFIG_JOYSTICK is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -266,19 +301,22 @@ CONFIG_I2C=y
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
# CONFIG_DRM is not set
#
-# Support for USB
+# Multimedia devices
#
-# CONFIG_USB is not set
+# CONFIG_VIDEO_DEV 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_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -287,39 +325,60 @@ CONFIG_I2C=y
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_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_UDF_FS 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_MOUNT 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
#
# CONFIG_PARTITION_ADVANCED is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
@@ -328,6 +387,11 @@ CONFIG_LOCKD=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/ppc/defconfig b/arch/ppc/defconfig
index 9b3d88212..5574ecbdb 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -36,6 +36,7 @@ CONFIG_ALTIVEC=y
# General setup
#
# CONFIG_HIGHMEM is not set
+# CONFIG_MOL is not set
# CONFIG_ISA is not set
# CONFIG_SBUS is not set
CONFIG_PCI=y
@@ -58,7 +59,6 @@ CONFIG_PCI_NAMES=y
CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
CONFIG_FB_COMPAT_XPMAC=y
-CONFIG_PMAC_PBOOK=y
CONFIG_PPC_RTC=y
CONFIG_PROC_DEVICETREE=y
CONFIG_BOOTX_TEXT=y
@@ -83,18 +83,25 @@ CONFIG_BOOTX_TEXT=y
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_LVM_PROC_FS is not set
#
# Networking options
@@ -130,6 +137,7 @@ CONFIG_ATALK=m
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -203,10 +211,11 @@ CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_OPTI621 is not set
# CONFIG_BLK_DEV_PDC202XX is not set
# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_OSB4 is not set
# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_VIA82CXXX_TUNING is not set
CONFIG_BLK_DEV_SL82C105=y
CONFIG_BLK_DEV_IDE_PMAC=y
CONFIG_BLK_DEV_IDEDMA_PMAC=y
@@ -262,6 +271,7 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
@@ -273,8 +283,6 @@ CONFIG_AIC7XXX_RESET_DELAY=15
# 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_NCR53C8XX is not set
CONFIG_SCSI_SYM53C8XX=y
@@ -293,6 +301,8 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
@@ -342,6 +352,7 @@ CONFIG_GMAC=y
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_PCI=y
CONFIG_PCNET32=y
@@ -358,26 +369,28 @@ CONFIG_DE4X5=y
# CONFIG_NATSEMI is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
# CONFIG_RTL8129 is not set
# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE 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_WINBOND_840 is not set
# CONFIG_NET_POCKET is not set
#
# Ethernet (1000 Mbit)
#
-# CONFIG_YELLOWFIN is not set
# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP=y
CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
CONFIG_PPP_ASYNC=y
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=y
@@ -483,13 +496,15 @@ CONFIG_INPUT_EVDEV=y
#
# Macintosh device drivers
#
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_PBOOK=y
+CONFIG_PMAC_BACKLIGHT=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADB=y
-CONFIG_ADB_CUDA=y
CONFIG_ADB_MACIO=y
-CONFIG_ADB_PMU=y
CONFIG_INPUT_ADBHID=y
CONFIG_MAC_HID=y
CONFIG_MAC_ADBKEYCODES=y
@@ -686,6 +701,7 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_CMPCI is not set
# CONFIG_SOUND_EMU10K1 is not set
# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
# CONFIG_SOUND_ESSSOLO1 is not set
@@ -715,7 +731,6 @@ CONFIG_SOUND_CS4232=m
# 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 is not set
# CONFIG_SOUND_AWE32_SYNTH is not set
# CONFIG_SOUND_WAVEFRONT is not set
@@ -768,6 +783,7 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_DSBR is not set
# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_NET1080 is not set
#
# USB Human Interface Devices (HID)
@@ -776,11 +792,6 @@ CONFIG_USB_HID=y
# CONFIG_USB_WACOM is not set
#
-# Mac-on-Linux (MOL) support
-#
-# CONFIG_MOL is not set
-
-#
# Kernel hacking
#
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 627cd7a2a..89922aaab 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -298,12 +298,10 @@ _GLOBAL(_switch)
SYNC
RFI
-#ifdef CONFIG_SMP
- .globl ret_from_smpfork
-ret_from_smpfork:
+ .globl ret_from_fork
+ret_from_fork:
bl schedule_tail
b ret_from_except
-#endif
.globl ret_from_intercept
ret_from_intercept:
diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S
index 1129dd40e..06b7c6f1d 100644
--- a/arch/ppc/kernel/hashtable.S
+++ b/arch/ppc/kernel/hashtable.S
@@ -90,9 +90,14 @@ hash_page:
REST_2GPRS(7, r21)
#endif
/* Get PTE (linux-style) and check access */
+ lis r0,KERNELBASE@h /* check if kernel address */
+ cmplw 0,r3,r0
mfspr r2,SPRG3 /* current task's THREAD (phys) */
lwz r5,PGDIR(r2) /* virt page-table root */
- tophys(r5,r5) /* convert to phys addr */
+ blt+ 112f /* assume user more likely */
+ lis r5,swapper_pg_dir@ha /* if kernel address, use */
+ addi r5,r5,swapper_pg_dir@l /* kernel page table */
+112: tophys(r5,r5) /* convert to phys addr */
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
@@ -152,11 +157,7 @@ hash_page:
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,0,5,31
sldi r5,r5,12
-
-#ifndef CONFIG_SMP /* do this later for SMP */
ori r5,r5,1 /* set V (valid) bit */
-#endif
-
rlwimi r5,r3,16,20,24 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
.globl hash_page_patch_A
@@ -284,7 +285,9 @@ found_slot:
*/
found_empty:
found_slot:
- std r5,0(r3) /* clear V (valid) bit in PTE */
+ li r0,1
+ andc r5,r5,r0 /* clear V (valid) bit in PTE */
+ std r5,0(r3)
sync
tlbsync
sync
@@ -299,11 +302,7 @@ found_slot:
/* Construct the high word of the PPC-style PTE */
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
-
-#ifndef CONFIG_SMP /* do this later for SMP */
oris r5,r5,0x8000 /* set V (valid) bit */
-#endif
-
rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
.globl hash_page_patch_A
@@ -417,7 +416,8 @@ found_slot:
*/
found_empty:
found_slot:
- stw r5,0(r3) /* clear V (valid) bit in PTE */
+ rlwinm r5,r5,0,1,31 /* clear V (valid) bit in PTE */
+ stw r5,0(r3)
sync
tlbsync
sync
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 5d26e2917..71b5a96c5 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -521,10 +521,15 @@ InstructionTLBMiss:
*/
mfctr r0
/* Get PTE (linux-style) and check access */
+ mfspr r3,IMISS
+ lis r1,KERNELBASE@h /* check if kernel address */
+ cmplw 0,r3,r1
mfspr r2,SPRG3
lwz r2,PGDIR(r2)
- tophys(r2,r2)
- mfspr r3,IMISS
+ blt+ 112f
+ lis r2,swapper_pg_dir@ha /* if kernel address, use */
+ addi r2,r2,swapper_pg_dir@l /* kernel page table */
+112: tophys(r2,r2)
rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
lwz r2,0(r2) /* get pmd entry */
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
@@ -588,10 +593,15 @@ DataLoadTLBMiss:
*/
mfctr r0
/* Get PTE (linux-style) and check access */
+ mfspr r3,DMISS
+ lis r1,KERNELBASE@h /* check if kernel address */
+ cmplw 0,r3,r1
mfspr r2,SPRG3
lwz r2,PGDIR(r2)
- tophys(r2,r2)
- mfspr r3,DMISS
+ blt+ 112f
+ lis r2,swapper_pg_dir@ha /* if kernel address, use */
+ addi r2,r2,swapper_pg_dir@l /* kernel page table */
+112: tophys(r2,r2)
rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
lwz r2,0(r2) /* get pmd entry */
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
@@ -654,10 +664,15 @@ DataStoreTLBMiss:
*/
mfctr r0
/* Get PTE (linux-style) and check access */
+ mfspr r3,DMISS
+ lis r1,KERNELBASE@h /* check if kernel address */
+ cmplw 0,r3,r1
mfspr r2,SPRG3
lwz r2,PGDIR(r2)
- tophys(r2,r2)
- mfspr r3,DMISS
+ blt+ 112f
+ lis r2,swapper_pg_dir@ha /* if kernel address, use */
+ addi r2,r2,swapper_pg_dir@l /* kernel page table */
+112: tophys(r2,r2)
rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */
lwz r2,0(r2) /* get pmd entry */
rlwinm. r2,r2,0,0,19 /* extract address of pte page */
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index eef89f352..a0caa4a4c 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -343,6 +343,11 @@ int probe_irq_off (unsigned long irqs)
return 0;
}
+unsigned int probe_irq_mask(unsigned long irqs)
+{
+ return 0;
+}
+
void __init init_IRQ(void)
{
static int once = 0;
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index e3826293b..94e1cd277 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1219,11 +1219,7 @@ _GLOBAL(sys_call_table)
.long sys_getresuid /* 165 */
.long sys_query_module
.long sys_poll
-#ifdef CONFIG_NFSD
.long sys_nfsservctl
-#else
- .long sys_ni_syscall
-#endif
.long sys_setresgid
.long sys_getresgid /* 170 */
.long sys_prctl
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 84faa0e1d..6d6f775f2 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -344,11 +344,6 @@ pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ra
ranges->mem_end -= bus->resource[1]->start;
}
-unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
- unsigned long start, unsigned long size)
-{
- return start;
-}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
diff --git a/arch/ppc/kernel/ppc8260_pic.c b/arch/ppc/kernel/ppc8260_pic.c
index 21cfde0f7..5bd42a11f 100644
--- a/arch/ppc/kernel/ppc8260_pic.c
+++ b/arch/ppc/kernel/ppc8260_pic.c
@@ -79,7 +79,7 @@ static void m8260_mask_and_ack(unsigned int irq_nr)
sipnr = &(immr->im_intctl.ic_sipnrh);
ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
simr[word] = ppc_cached_irq_mask[word];
- sipnr[word] = 1 << bit;
+ sipnr[word] = 1 << (31 - bit);
}
struct hw_interrupt_type ppc8260_pic = {
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 9240431e6..827e37540 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -79,6 +79,7 @@ EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(probe_irq_mask);
#ifdef CONFIG_SMP
EXPORT_SYMBOL(kernel_flag);
#endif /* CONFIG_SMP */
@@ -222,6 +223,8 @@ EXPORT_SYMBOL(cuda_poll);
#ifdef CONFIG_ADB_PMU
EXPORT_SYMBOL(pmu_request);
EXPORT_SYMBOL(pmu_poll);
+EXPORT_SYMBOL(pmu_suspend);
+EXPORT_SYMBOL(pmu_resume);
#endif /* CONFIG_ADB_PMU */
#ifdef CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(pmu_register_sleep_notifier);
@@ -298,6 +301,7 @@ EXPORT_SYMBOL(console_lock);
EXPORT_SYMBOL(xmon);
#endif
EXPORT_SYMBOL(down_read_failed);
+EXPORT_SYMBOL(down_write_failed);
#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
extern void (*debugger)(struct pt_regs *regs);
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 27adc9958..a200b1c78 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -319,11 +319,8 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
{
unsigned long msr;
struct pt_regs * childregs, *kregs;
-#ifdef CONFIG_SMP
- extern void ret_from_smpfork(void);
-#else
- extern void ret_from_except(void);
-#endif
+ extern void ret_from_fork(void);
+
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -336,11 +333,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
p->thread.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
p->thread.ksp -= sizeof(struct pt_regs ) + STACK_FRAME_OVERHEAD;
kregs = (struct pt_regs *)(p->thread.ksp + STACK_FRAME_OVERHEAD);
-#ifdef CONFIG_SMP
- kregs->nip = (unsigned long)ret_from_smpfork;
-#else
- kregs->nip = (unsigned long)ret_from_except;
-#endif
+ kregs->nip = (unsigned long)ret_from_fork;
asm volatile("mfmsr %0" : "=r" (msr):);
kregs->msr = msr;
kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
diff --git a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c
index f17bc16ce..0ed7eaa4d 100644
--- a/arch/ppc/kernel/semaphore.c
+++ b/arch/ppc/kernel/semaphore.c
@@ -152,7 +152,7 @@ void down_read_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
do {
- __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&sem->lock);
schedule();
spin_lock_irq(&sem->lock);
@@ -169,7 +169,7 @@ void down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
do {
- __set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&sem->lock);
schedule();
spin_lock_irq(&sem->lock);
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index cc8d2290a..2c17e7bcb 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -630,7 +630,7 @@ mmu_context_overflow(void)
void flush_page_to_ram(struct page *page)
{
- unsigned long vaddr = kmap(page);
+ unsigned long vaddr = (unsigned long) kmap(page);
__flush_page_to_ram(vaddr);
kunmap(page);
}
diff --git a/arch/s390/config.in b/arch/s390/config.in
index 894e40d5b..4415799ff 100644
--- a/arch/s390/config.in
+++ b/arch/s390/config.in
@@ -3,6 +3,9 @@
# see Documentation/kbuild/config-language.txt.
#
+define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_UID16 y
mainmenu_name "Linux Kernel Configuration"
diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
index 86aef0185..a0a434581 100644
--- a/arch/s390/kernel/semaphore.c
+++ b/arch/s390/kernel/semaphore.c
@@ -55,7 +55,7 @@ void __down(struct semaphore * sem)
{
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -75,7 +75,7 @@ void __down(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_UNINTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -89,7 +89,7 @@ int __down_interruptible(struct semaphore * sem)
int retval = 0;
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
add_wait_queue_exclusive(&sem->wait, &wait);
spin_lock_irq(&semaphore_lock);
@@ -125,7 +125,7 @@ int __down_interruptible(struct semaphore * sem)
spin_unlock_irq(&semaphore_lock);
schedule();
- tsk->state = TASK_INTERRUPTIBLE|TASK_EXCLUSIVE;
+ tsk->state = TASK_INTERRUPTIBLE;
spin_lock_irq(&semaphore_lock);
}
spin_unlock_irq(&semaphore_lock);
@@ -188,7 +188,7 @@ void down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
@@ -240,7 +240,7 @@ void down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/sh/config.in b/arch/sh/config.in
index f0a51f8d6..0bd1cf4bb 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -66,6 +66,8 @@ mainmenu_option next_comment
comment 'General setup'
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_SBUS n
bool 'Networking support' CONFIG_NET
diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c
index 990960aa8..7cdda223c 100644
--- a/arch/sh/kernel/semaphore.c
+++ b/arch/sh/kernel/semaphore.c
@@ -195,7 +195,7 @@ struct rw_semaphore *down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!sem->write_bias_granted)
schedule();
}
@@ -251,7 +251,7 @@ struct rw_semaphore *down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (atomic_read(&sem->count) < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (atomic_read(&sem->count) >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index cb615fa0b..1a75cdf17 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.104 2000/10/04 09:01:38 anton Exp $
+# $Id: config.in,v 1.105 2000/11/12 10:01:41 davem Exp $
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/config-language.txt.
#
@@ -31,6 +31,8 @@ bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_S
# Global things across all Sun machines.
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_PCMCIA n
define_bool CONFIG_SBUS y
define_bool CONFIG_SBUSCHAR y
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index f61be9932..00c465b10 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.11 2000/10/10 01:07:38 davem Exp $
+/* $Id: ebus.c,v 1.15 2000/11/08 05:06:21 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -24,18 +24,9 @@
struct linux_ebus *ebus_chain = 0;
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_ENVCTRL
-extern int envctrl_init(void);
-#endif
/* We are together with pcic.c under CONFIG_PCI. */
extern unsigned int pcic_pin_to_irq(unsigned int, char *name);
@@ -367,20 +358,7 @@ void __init ebus_init(void)
++num_ebus;
}
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
-#ifdef CONFIG_ENVCTRL
- envctrl_init();
-#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
}
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 028612687..e7b4e96de 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.18 2000/09/25 06:09:12 anton Exp $
+/* $Id: pcic.c,v 1.19 2000/11/08 04:49:17 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -866,23 +866,6 @@ void pcibios_update_resource(struct pci_dev *pdev, struct resource *res1,
{
}
-#if 0
-void pcibios_update_irq(struct pci_dev *pdev, int irq)
-{
-}
-
-unsigned long resource_fixup(struct pci_dev *pdev, struct resource *res,
- unsigned long start, unsigned long size)
-{
- return start;
-}
-
-void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
- struct pbus_set_ranges_data *pranges)
-{
-}
-#endif
-
void pcibios_align_resource(void *data, struct resource *res, unsigned long size)
{
}
diff --git a/arch/sparc/kernel/semaphore.c b/arch/sparc/kernel/semaphore.c
index 4359ec232..d6638be10 100644
--- a/arch/sparc/kernel/semaphore.c
+++ b/arch/sparc/kernel/semaphore.c
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.3 2000/10/14 10:09:00 davem Exp $
+/* $Id: semaphore.c,v 1.4 2000/11/10 04:02:03 davem Exp $
* Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
@@ -166,7 +166,7 @@ void down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (!ldstub(&sem->write_not_granted))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (sem->write_not_granted)
schedule();
}
@@ -216,7 +216,7 @@ void down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (sem->count >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 9cbbb1c9c..85161a3a6 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.94 2000/10/19 00:49:51 davem Exp $
+/* $Id: init.c,v 1.95 2000/11/10 04:49:56 davem Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -579,8 +579,7 @@ void si_meminfo(struct sysinfo *val)
void flush_page_to_ram(struct page *page)
{
- unsigned long vaddr;
- vaddr = kmap(page);
- __flush_page_to_ram((unsigned long)page_address(page));
+ unsigned long vaddr = (unsigned long) kmap(page);
+ __flush_page_to_ram(vaddr);
kunmap(page);
}
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index a91809d03..b32199c13 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.223 2000/10/16 14:32:49 anton Exp $
+/* $Id: srmmu.c,v 1.224 2000/11/09 22:40:05 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1163,7 +1163,7 @@ extern int linux_num_cpus;
void (*poke_srmmu)(void) __initdata = NULL;
-extern unsigned long bootmem_init(void);
+extern void bootmem_init(void);
extern void sun_serial_setup(void);
void __init srmmu_paging_init(void)
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index a416ecf19..edba89672 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.200 2000/10/16 14:32:49 anton Exp $
+/* $Id: sun4c.c,v 1.201 2000/11/09 22:39:36 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2509,7 +2509,7 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
extern void sparc_context_init(int);
extern unsigned long end;
-extern unsigned long bootmem_init(void);
+extern void bootmem_init(void);
extern unsigned long last_valid_pfn;
extern void sun_serial_setup(void);
@@ -2524,7 +2524,8 @@ void __init sun4c_paging_init(void)
kernel_end += (SUN4C_REAL_PGDIR_SIZE * 4);
kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
- last_valid_pfn = end_pfn = bootmem_init();
+ bootmem_init();
+ end_pfn = last_valid_pfn;
/* This does not logically belong here, but we need to
* call it at the moment we are able to use the bootmem
diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds
index bba19d4c5..e449e26fa 100644
--- a/arch/sparc/vmlinux.lds
+++ b/arch/sparc/vmlinux.lds
@@ -31,6 +31,9 @@ SECTIONS
__start___ksymtab = .;
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
. = ALIGN(4096);
__init_begin = .;
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index a754b796b..19b05e28f 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -29,6 +29,8 @@ bool 'Symmetric multi-processing support' CONFIG_SMP
# Global things across all Sun machines.
define_bool CONFIG_HAVE_DEC_LOCK y
define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
define_bool CONFIG_PCMCIA n
define_bool CONFIG_SBUS y
define_bool CONFIG_SBUSCHAR y
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S
index 72120b563..80c74aa18 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.7 2000/03/26 09:13:48 davem Exp $
+/* $Id: dtlb_base.S,v 1.8 2000/11/10 08:28:45 davem Exp $
* dtlb_base.S: Front end to DTLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -57,7 +57,7 @@
srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
1: brlz,pt %g5, 9f ! Valid, load into TLB
- and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits
+ nop ! Delay-slot
ba,a,pt %xcc, 4f ! Invalid, branch out
/* DTLB ** ICACHE line 2: Quick kernel TLB misses */
@@ -68,27 +68,27 @@
nop
9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
retry ! Trap return
- nop
+4: rdpr %pstate, %g5 ! Move into alternate globals
/* DTLB ** ICACHE line 3: winfixups+real_faults */
-4: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
- be,pn %xcc, 5f ! Yep, refbit update
- sllx %g1, 60, %g4 ! Get valid bit
- rdpr %pstate, %g5 ! Move into alternate globals
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tl, %g4 ! See where we came from.
cmp %g4, 1 ! Is etrap/rtrap window fault?
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
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)
- ba,a,pt %xcc, 9b ! Complete tlb miss
+
+/* DTLB ** ICACHE line 4: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
#undef TAG_CONTEXT_BITS
#undef VPTE_SHIFT
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S
index 5e99d5d47..1da370c7c 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.20 2000/03/26 09:13:48 davem Exp $
+/* $Id: dtlb_prot.S,v 1.21 2000/11/10 08:28:45 davem Exp $
* dtlb_prot.S: DTLB protection trap strategy.
* This is included directly into the trap table.
*
@@ -6,10 +6,6 @@
* Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#define TAG_CONTEXT_BITS 0x3ff
-#define VPTE_SHIFT (PAGE_SHIFT - 3)
-#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED)
-
/* Ways we can get here:
*
* [TL == 0] 1) User stores to readonly pages.
@@ -18,45 +14,41 @@
*/
/* PROT ** ICACHE line 1: User DTLB protection trap */
- ldxa [%g1] ASI_DMMU, %g6 ! Primary or Secondary ctx?
- and %g6, 0x10, %g6 ! Get pri/sec ctx bit
stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit
membar #Sync ! Synchronize ASI stores
- ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Load TAG_ACCESS
- andn %g4, TAG_CONTEXT_BITS, %g4 ! Clear CTX bits
- stxa %g0, [%g4 + %g6] ASI_DMMU_DEMAP ! Perform TLB flush of page
- membar #Sync ! Synchronize ASI stores
-
-/* PROT ** ICACHE line 2: Further normal processing */
- srax %g4, VPTE_SHIFT, %g6 ! Compute VPTE offset
- ldxa [%g3 + %g6] ASI_S, %g5 ! Load PTE entry
- andcc %g5, _PAGE_WRITE, %g0 ! Writable page?
- be,pt %xcc, 1f ! Nope, real fault
- or %g5, (MODIFIED_BITS), %g5 ! Mark as writable/modified
- stxa %g5, [%g3 + %g6] ASI_S ! Update PTE entry
- stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load PTE into TLB
- retry ! Trap return
-
-/* PROT ** ICACHE line 3: Real user faults */
-1: rdpr %pstate, %g5 ! Move into alternate globals
+ rdpr %pstate, %g5 ! Move into alternate globals
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
rdpr %tl, %g1 ! Need to do a winfixup?
cmp %g1, 1 ! Trap level >1?
mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr
+ nop
+
+/* PROT ** ICACHE line 2: More real fault processing */
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 FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
nop
nop
nop
nop
+
+/* PROT ** ICACHE line 3: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
nop
nop
nop
-#undef TAG_CONTEXT_BITS
-#undef VPTE_SHIFT
-#undef MODIFIED_BITS
+/* PROT ** ICACHE line 3: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 5872046b1..e175fac27 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.48 2000/08/02 06:22:35 davem Exp $
+/* $Id: ebus.c,v 1.53 2000/11/08 05:08:23 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -22,21 +22,9 @@
struct linux_ebus *ebus_chain = 0;
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_ENVCTRL
-extern int envctrl_init(void);
-#endif
-#ifdef CONFIG_DISPLAY7SEG
-extern int d7s_init(void);
-#endif
static inline void *ebus_alloc(size_t size)
{
@@ -372,24 +360,9 @@ void __init ebus_init(void)
++num_ebus;
}
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
-#ifdef CONFIG_ENVCTRL
- envctrl_init();
-#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
-#ifdef CONFIG_DISPLAY7SEG
- d7s_init();
-#endif
clock_probe();
power_init();
}
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 9f7cd59e9..a510c2aff 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.99 2000/10/17 16:20:33 davem Exp $
+/* $Id: ioctl32.c,v 1.103 2000/11/10 05:44:33 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -71,8 +71,9 @@
#include <asm/openpromio.h>
#include <asm/envctrl.h>
#include <asm/audioio.h>
-#include <asm/ethtool.h>
+#include <linux/ethtool.h>
#include <asm/display7seg.h>
+#include <asm/module.h>
#include <linux/soundcard.h>
#include <linux/atm.h>
@@ -3230,6 +3231,7 @@ COMPATIBLE_IOCTL(ENVCTRL_RD_SCSI_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_ETHERNET_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_MTHRBD_TEMPERATURE)
COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_VOLTAGE)
+COMPATIBLE_IOCTL(ENVCTRL_RD_GLOBALADDRESS)
/* COMPATIBLE_IOCTL(D7SIOCRD) same value as ENVCTRL_RD_VOLTAGE_STATUS */
COMPATIBLE_IOCTL(D7SIOCWR)
COMPATIBLE_IOCTL(D7SIOCTM)
@@ -3467,6 +3469,14 @@ COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */
/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */
@@ -3492,6 +3502,14 @@ COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */
/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S
index 7f0da3d14..bd6a3603d 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.9 2000/03/26 09:13:48 davem Exp $
+/* $Id: itlb_base.S,v 1.10 2000/11/10 08:28:45 davem Exp $
* itlb_base.S: Front end to ITLB miss replacement strategy.
* This is included directly into the trap table.
*
@@ -23,22 +23,13 @@
srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset
ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE
1: brgez,pn %g5, 3f ! Not valid, branch out
- and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits
+ nop ! Delay-slot
2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB
retry ! Trap return
-3: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page?
+3: rdpr %pstate, %g4 ! Move into alternate globals
-/* ITLB ** ICACHE line 2: Quick user ref updates */
- bne,pn %xcc, 4f ! Nope, real missing page
- sllx %g1, 60, %g4 ! Sliiickkk...
- or %g5, _PAGE_ACCESSED, %g5 ! Mark as touched
- or %g5, %g4, %g5 ! Allow user to see it
- ba,pt %xcc, 2b ! Branch to load TLB
- stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table
-4: rdpr %pstate, %g4 ! Move into alternate globals
+/* ITLB ** ICACHE line 2: Real faults */
wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate
-
-/* ITLB ** ICACHE line 3: Real faults */
rdpr %tpc, %g5 ! And load faulting VA
mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB
sparc64_realfault_common: ! Called by TL0 dtlb_miss too
@@ -46,10 +37,11 @@ sparc64_realfault_common: ! Called by TL0 dtlb_miss too
stx %g5, [%g6 + AOFF_task_thread + AOFF_thread_fault_address]
ba,pt %xcc, etrap ! Save state
1: rd %pc, %g7 ! ...
+ nop
+
+/* ITLB ** ICACHE line 3: Finish faults + window fixups */
call do_sparc64_fault ! Call fault handler
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:
@@ -57,6 +49,14 @@ winfix_trampoline:
or %g3, 0x7c, %g3 ! Compute offset to branch
wrpr %g3, %tnpc ! Write it into TNPC
done ! Do it to it
+
+/* ITLB ** ICACHE line 4: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
nop
nop
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index dd153a24e..1abef824f 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.18 2000/10/03 11:31:42 anton Exp $
+/* $Id: pci.c,v 1.19 2000/11/08 04:49:17 davem Exp $
* pci.c: UltraSparc PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -202,12 +202,6 @@ void pcibios_update_irq(struct pci_dev *pdev, int irq)
{
}
-unsigned long resource_fixup(struct pci_dev *pdev, struct resource *res,
- unsigned long start, unsigned long size)
-{
- return start;
-}
-
void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
struct pbus_set_ranges_data *pranges)
{
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 1f3386d53..4534ad59b 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.112 2000/09/06 00:45:01 davem Exp $
+/* $Id: process.c,v 1.113 2000/11/08 08:14:58 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -647,14 +647,21 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
long retval;
- __asm__ __volatile("mov %1, %%g1\n\t"
+ /* If the parent runs before fn(arg) is called by the child,
+ * the input registers of this function can be clobbered.
+ * So we stash 'fn' and 'arg' into global registers which
+ * will not be modified by the parent.
+ */
+ __asm__ __volatile("mov %4, %%g2\n\t" /* Save FN into global */
+ "mov %5, %%g3\n\t" /* Save ARG into global */
+ "mov %1, %%g1\n\t" /* Clone syscall nr. */
"mov %2, %%o0\n\t" /* Clone flags. */
"mov 0, %%o1\n\t" /* usp arg == 0 */
"t 0x6d\n\t" /* Linux/Sparc clone(). */
"brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */
" mov %%o0, %0\n\t"
- "jmpl %4, %%o7\n\t" /* Call the function. */
- " mov %5, %%o0\n\t" /* Set arg in delay. */
+ "jmpl %%g2, %%o7\n\t" /* Call the function. */
+ " mov %%g3, %%o0\n\t" /* Set arg in delay. */
"mov %3, %%g1\n\t"
"t 0x6d\n\t" /* Linux/Sparc exit(). */
/* Notreached by child. */
@@ -662,7 +669,7 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
"=r" (retval) :
"i" (__NR_clone), "r" (flags | CLONE_VM),
"i" (__NR_exit), "r" (fn), "r" (arg) :
- "g1", "o0", "o1", "memory", "cc");
+ "g1", "g2", "g3", "o0", "o1", "memory", "cc");
return retval;
}
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
index 8cb6e7211..1928d5a0d 100644
--- a/arch/sparc64/kernel/semaphore.c
+++ b/arch/sparc64/kernel/semaphore.c
@@ -1,4 +1,4 @@
-/* $Id: semaphore.c,v 1.4 2000/10/14 10:09:00 davem Exp $
+/* $Id: semaphore.c,v 1.5 2000/11/10 04:02:03 davem Exp $
* Generic semaphore code. Buyer beware. Do your own
* specific changes in <asm/semaphore-helper.h>
*/
@@ -223,7 +223,7 @@ void down_write_failed_biased(struct rw_semaphore *sem)
for (;;) {
if (test_and_clear_le_bit(1, &sem->granted))
break;
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (!test_le_bit(1, &sem->granted))
schedule();
}
@@ -273,7 +273,7 @@ void down_write_failed(struct rw_semaphore *sem)
add_wait_queue_exclusive(&sem->wait, &wait);
while (sem->count < 0) {
- set_task_state(tsk, TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (sem->count >= 0)
break; /* we must attempt to acquire or bias the lock */
schedule();
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 6e7f59309..e1ae982bf 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.95 2000/10/30 21:01:40 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.98 2000/11/13 10:03:32 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -87,7 +87,6 @@ extern long sparc32_open(const char * filename, int flags, int mode);
extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
extern int unregister_ioctl32_conversion(unsigned int cmd);
extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
-extern void __flush_dcache_page(void *addr);
extern int __ashrdi3(int, int);
@@ -110,25 +109,14 @@ extern void _do_write_unlock(rwlock_t *rw);
extern unsigned long phys_base;
-/* One thing to note is that the way the symbols of the mul/div
- * support routines are named is a mess, they all start with
- * a '.' which makes it a bitch to export, here is the trick:
- */
-
-#define EXPORT_SYMBOL_PRIVATE(sym) \
-extern int __sparc_priv_ ## sym (int) __asm__("__" #sym); \
-const struct module_symbol __export_priv_##sym \
-__attribute__((section("__ksymtab"))) = \
-{ (unsigned long) &__sparc_priv_ ## sym, "__" #sym }
-
/* used by various drivers */
#ifdef CONFIG_SMP
#ifndef SPIN_LOCK_DEBUG
/* Out of line rw-locking implementation. */
-EXPORT_SYMBOL_PRIVATE(read_lock);
-EXPORT_SYMBOL_PRIVATE(read_unlock);
-EXPORT_SYMBOL_PRIVATE(write_lock);
-EXPORT_SYMBOL_PRIVATE(write_unlock);
+EXPORT_SYMBOL(__read_lock);
+EXPORT_SYMBOL(__read_unlock);
+EXPORT_SYMBOL(__write_lock);
+EXPORT_SYMBOL(__write_unlock);
#endif
/* Kernel wide locking */
@@ -137,10 +125,10 @@ EXPORT_SYMBOL(kernel_flag);
/* Hard IRQ locking */
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL_PRIVATE(global_cli);
-EXPORT_SYMBOL_PRIVATE(global_sti);
-EXPORT_SYMBOL_PRIVATE(global_save_flags);
-EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
/* Per-CPU information table */
EXPORT_SYMBOL(cpu_data);
@@ -163,27 +151,33 @@ EXPORT_SYMBOL(_do_write_unlock);
#endif
+/* semaphores */
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__up);
+
/* rw semaphores */
EXPORT_SYMBOL_NOVERS(__down_read_failed);
EXPORT_SYMBOL_NOVERS(__down_write_failed);
EXPORT_SYMBOL_NOVERS(__rwsem_wake);
/* Atomic counter implementation. */
-EXPORT_SYMBOL_PRIVATE(atomic_add);
-EXPORT_SYMBOL_PRIVATE(atomic_sub);
+EXPORT_SYMBOL(__atomic_add);
+EXPORT_SYMBOL(__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(__test_and_set_bit);
+EXPORT_SYMBOL(__test_and_clear_bit);
+EXPORT_SYMBOL(__test_and_change_bit);
+EXPORT_SYMBOL(__test_and_set_le_bit);
+EXPORT_SYMBOL(__test_and_clear_le_bit);
EXPORT_SYMBOL(ivector_table);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL_PRIVATE(flushw_user);
+EXPORT_SYMBOL(__flushw_user);
EXPORT_SYMBOL(__flush_dcache_page);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 24c8cd593..9b211d86d 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.165 2000/10/10 04:47:31 davem Exp $
+/* $Id: sys_sparc32.c,v 1.166 2000/11/10 04:49:56 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -2952,7 +2952,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
@@ -2967,7 +2967,7 @@ static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
err = copy_from_user(kaddr + offset, (char *)A(str),
bytes_to_copy);
flush_page_to_ram(page);
- kunmap((unsigned long)kaddr);
+ kunmap(page);
if (err)
return -EFAULT;
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 75d5c096e..a5f5411f5 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -601,7 +601,6 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
int try_port;
int ret;
struct socket *socket;
- struct dentry *dentry;
struct inode *inode;
struct file *file;
@@ -609,8 +608,7 @@ sunos_nfs_get_server_fd (int fd, struct sockaddr_in *addr)
if(!file)
return 0;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
+ inode = file->f_dentry->d_inode;
socket = &inode->u.socket_i;
local.sin_family = AF_INET;
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index fa057936a..77531321d 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.23 2000/07/10 20:57:34 davem Exp $
+# $Id: Makefile,v 1.24 2000/11/01 07:33:47 davem Exp $
# Makefile for Sparc64 library files..
#
@@ -8,7 +8,8 @@ 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 bitops.o \
- dec_and_lock.o
+ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \
+ U3copy_in_user.o
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
diff --git a/arch/sparc64/lib/U3copy_from_user.S b/arch/sparc64/lib/U3copy_from_user.S
new file mode 100644
index 000000000..b1003e607
--- /dev/null
+++ b/arch/sparc64/lib/U3copy_from_user.S
@@ -0,0 +1,500 @@
+/* $Id: U3copy_from_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy from userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ ba,pt %xcc, U3cfu_fixup; \
+ a, b, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ ba,pt %xcc, U3cfu_fixup; \
+ a, b, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ add %o1, %o4, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, 0x1c0, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ sll %g3, 6, %g3; \
+ add %o1, 0x80, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, %g3, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o1; \
+ add %o1, 0x40, %o1; \
+ ba,pt %xcc, U3cfu_fixup; \
+ add %o1, %g3, %o1; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_BLK_P 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EX2(x,y) x,y;
+#define EX3(x,y) x,y;
+#define EX4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_from_user
+U3copy_from_user: /* %o0=dst, %o1=src, %o2=len */
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_from_user_short_ret! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_from_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_from_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_from_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_from_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_from_user_short ! BR
+ stb %o3, [%o0 + -1] ! MS Group (1-cycle stall)
+
+U3copy_from_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_from_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_from_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_from_user_begin:
+ prefetcha [%o1 + 0x000] %asi, #one_read ! MS Group1
+ prefetcha [%o1 + 0x040] %asi, #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetcha [%o1 + 0x080] %asi, #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetcha [%o1 + 0x0c0] %asi, #one_read ! MS Group4
+ EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetcha [%o1 + 0x100] %asi, #one_read ! MS Group6
+1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetcha [%o1 + 0x140] %asi, #one_read ! MS Group7
+1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetcha [%o1 + 0x180] %asi, #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_from_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_from_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_from_user_loop1:
+ EX2(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ EX2(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ EX2(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ EX2(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ EX2(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ EX2(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ EX2(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ EX2(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19)
+ prefetcha [%o1 + 0x180] %asi, #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_from_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_from_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_from_user_loop2:
+ EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ EX3(ldda [%o1 + 0x040] %asi, %f0) ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_from_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_from_user_loopfini:
+ EX3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ EX3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ stda %f16, [%o0] ASI_BLK_P ! MS Group20
+ EX3(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ EX3(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ EX3(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ EX3(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ EX3(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ EX4(ldda [%o1 + 0x040] %asi, %f0) ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_from_user_toosmall processing.
+ */
+U3copy_from_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_from_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_from_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS
+
+1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_from_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_from_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_from_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_from_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_from_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_from_user_short_ret! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_from_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_from_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ stb %o3, [%o0 + -1]
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: EXNV(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ stx %o3, [%o0 + -8]
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_from_user_short
+ nop
+ ba,a,pt %xcc, U3copy_from_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
+
+#ifdef __KERNEL__
+ .globl U3cfu_fixup
+U3cfu_fixup:
+ /* Since this is copy_from_user(), zero out the rest of the
+ * kernel buffer.
+ */
+ cmp %o1, 0
+ ble,pn %icc, 2f
+ mov %o1, %g2
+
+1: subcc %g2, 1, %g2
+ stb %g0, [%o0]
+ bne,pt %icc, 1b
+ add %o0, 1, %o0
+
+2: retl
+ mov %o1, %o0
+#endif
diff --git a/arch/sparc64/lib/U3copy_in_user.S b/arch/sparc64/lib/U3copy_in_user.S
new file mode 100644
index 000000000..0fc169b9d
--- /dev/null
+++ b/arch/sparc64/lib/U3copy_in_user.S
@@ -0,0 +1,531 @@
+/* $Id: U3copy_in_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy within userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV2(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV3(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 8, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK1(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ add %o4, 0x1c0, %o1; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ sll %o3, 6, %o3; \
+ and %o2, (0x40 - 1), %o2; \
+ add %o3, 0x80, %o1; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x80, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x40, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_AIUS 0x80
+#define ASI_BLK_AIUS 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EXNV2(x,y,a,b) x,y;
+#define EXNV3(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EXBLK1(x,y) x,y;
+#define EXBLK2(x,y) x,y;
+#define EXBLK3(x,y) x,y;
+#define EXBLK4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ *
+ * XXX Actually, Cheetah can buffer up to 8 concurrent
+ * XXX prefetches, revisit this...
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_in_user
+U3copy_in_user: /* %o0=dst, %o1=src, %o2=len */
+ /* Writing to %asi is _expensive_ so we hardcode it.
+ * Reading %asi to check for KERNEL_DS is comparatively
+ * cheap.
+ */
+ rd %asi, %g1 ! MS Group (4 cycles)
+ cmp %g1, ASI_AIUS ! A0 Group
+ bne U3memcpy ! BR
+ nop ! A1
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_in_user_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_in_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_in_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_in_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_in_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g0)! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_in_user_short ! BR
+ EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall)
+
+U3copy_in_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_in_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_in_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_in_user_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ EX(ldda [%o1 + 0x000] %asi, %f0, add %o2, %g0) ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: EX(ldda [%o1 + 0x008] %asi, %f2, add %o2, %g0) ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: EX(ldda [%o1 + 0x010] %asi, %f4, add %o2, %g0) ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ EX(ldda [%o1 + 0x018] %asi, %f6, add %o2, %g0) ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ EX(ldda [%o1 + 0x020] %asi, %f8, add %o2, %g0) ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ EX(ldda [%o1 + 0x028] %asi, %f10, add %o2, %g0) ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ EX(ldda [%o1 + 0x030] %asi, %f12, add %o2, %g0) ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ EX(ldda [%o1 + 0x038] %asi, %f14, add %o2, %g0) ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ EX(ldda [%o1 + 0x040] %asi, %f0, add %o2, %g0) ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_in_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_in_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_in_user_loop1:
+ EXBLK1(ldda [%o1 + 0x008] %asi, %f2) ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ EXBLK1(ldda [%o1 + 0x010] %asi, %f4) ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ EXBLK1(ldda [%o1 + 0x018] %asi, %f6) ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ EXBLK1(ldda [%o1 + 0x020] %asi, %f8) ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ EXBLK1(ldda [%o1 + 0x028] %asi, %f10) ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ EXBLK1(ldda [%o1 + 0x030] %asi, %f12) ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ EXBLK1(ldda [%o1 + 0x038] %asi, %f14) ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ EXBLK1(ldda [%o1 + 0x040] %asi, %f0) ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_in_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_in_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_in_user_loop2:
+ EXBLK2(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ EXBLK2(ldda [%o1 + 0x010] %asi, %f4) ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ EXBLK2(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ EXBLK2(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ EXBLK2(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ EXBLK2(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ EXBLK2(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ EXBLK2(ldda [%o1 + 0x040] %asi, %f0) ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_in_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_in_user_loopfini:
+ EXBLK3(ldda [%o1 + 0x008] %asi, %f2) ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ EXBLK3(ldda [%o1 + 0x010] %asi, %f4) ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20
+ EXBLK4(ldda [%o1 + 0x018] %asi, %f6) ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ EXBLK4(ldda [%o1 + 0x020] %asi, %f8) ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ EXBLK4(ldda [%o1 + 0x028] %asi, %f10) ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ EXBLK4(ldda [%o1 + 0x030] %asi, %f12) ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ EXBLK4(ldda [%o1 + 0x038] %asi, %f14) ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ EXBLK4(ldda [%o1 + 0x040] %asi, %f0) ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_in_user_toosmall processing.
+ */
+U3copy_in_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_in_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_in_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ EX(ldda [%o1 + 0x00] %asi, %f0, add %o2, %g0) ! MS
+
+1: EX(ldda [%o1 + 0x08] %asi, %f2, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_in_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ EX(ldda [%o1 + 0x08] %asi, %f0, add %o2, %g0) ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_in_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_in_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_in_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_in_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: EX(ldda [%g1 + 0x00] %asi, %f2, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ EX(ldda [%g1 + 0x00] %asi, %f0, add %o2, %g0) ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_in_user_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_in_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_in_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: EXNV2(lduba [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: EXNV3(ldxa [%o1 + 0x00] %asi, %o3, add %o2, %g2)
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_in_user_short
+ nop
+ ba,a,pt %xcc, U3copy_in_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
diff --git a/arch/sparc64/lib/U3copy_to_user.S b/arch/sparc64/lib/U3copy_to_user.S
new file mode 100644
index 000000000..e08b1290b
--- /dev/null
+++ b/arch/sparc64/lib/U3copy_to_user.S
@@ -0,0 +1,528 @@
+/* $Id: U3copy_to_user.S,v 1.3 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized copy to userspace.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV2(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 1, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXNV3(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: a, b, %o0; \
+ retl; \
+ add %o0, 8, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EX(x,y,a,b) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ retl; \
+ a, b, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK1(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ add %o4, 0x1c0, %o1; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK2(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ sll %o3, 6, %o3; \
+ and %o2, (0x40 - 1), %o2; \
+ add %o3, 0x80, %o1; \
+ retl; \
+ add %o1, %o2, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK3(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x80, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#define EXBLK4(x,y) \
+98: x,y; \
+ .section .fixup; \
+ .align 4; \
+99: VISExitHalf; \
+ and %o2, (0x40 - 1), %o2; \
+ retl; \
+ add %o2, 0x40, %o0; \
+ .section __ex_table; \
+ .align 4; \
+ .word 98b, 99b; \
+ .text; \
+ .align 4;
+#else
+#define ASI_AIUS 0x80
+#define ASI_BLK_AIUS 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#define EXNV(x,y,a,b) x,y;
+#define EXNV2(x,y,a,b) x,y;
+#define EXNV3(x,y,a,b) x,y;
+#define EX(x,y,a,b) x,y;
+#define EXBLK1(x,y) x,y;
+#define EXBLK2(x,y) x,y;
+#define EXBLK3(x,y) x,y;
+#define EXBLK4(x,y) x,y;
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3copy_to_user
+U3copy_to_user: /* %o0=dst, %o1=src, %o2=len */
+ /* Writing to %asi is _expensive_ so we hardcode it.
+ * Reading %asi to check for KERNEL_DS is comparatively
+ * cheap.
+ */
+ rd %asi, %g1 ! MS Group (4 cycles)
+ cmp %g1, ASI_AIUS ! A0 Group
+ bne U3memcpy ! BR
+ nop ! A1
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3copy_to_user_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3copy_to_user_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3copy_to_user_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3copy_to_user_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3copy_to_user_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ ldub [%o1 + 0x00], %o3 ! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3copy_to_user_short ! BR
+ EXNV(stba %o3, [%o0 + -1] %asi, add %o2, 1) ! MS Group (1-cycle stall)
+
+U3copy_to_user_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3copy_to_user_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3copy_to_user_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3copy_to_user_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3copy_to_user_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3copy_to_user_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3copy_to_user_loop1:
+ ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ EXBLK1(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_to_user_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3copy_to_user_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3copy_to_user_loop2:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ ldd [%o1 + 0x010], %f4 ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ EXBLK2(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ ldd [%o1 + 0x040], %f0 ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3copy_to_user_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3copy_to_user_loopfini:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ ldd [%o1 + 0x010], %f4 ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ EXBLK3(stda %f16, [%o0] ASI_BLK_AIUS) ! MS Group20
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ ldd [%o1 + 0x040], %f0 ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ EXBLK4(stda %f16, [%o0] ASI_BLK_AIUS) ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3copy_to_user_toosmall processing.
+ */
+U3copy_to_user_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3copy_to_user_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3copy_to_user_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ ldd [%o1 + 0x00], %f0 ! MS
+
+1: ldd [%o1 + 0x08], %f2 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3copy_to_user_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ ldd [%o1 + 0x08], %f0 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3copy_to_user_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3copy_to_user_short_ret
+ nop
+ ba,a,pt %xcc, U3copy_to_user_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3copy_to_user_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2) ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: ldd [%g1 + 0x00], %f2 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ ldd [%g1 + 0x00], %f0 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ EX(stda %f8, [%o0 + 0x00] %asi, add %o2, 0x8) ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3copy_to_user_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3copy_to_user_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3copy_to_user_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: ldub [%o1 + 0x00], %o3
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ EXNV2(stba %o3, [%o0 + -1] %asi, add %o2, %g2)
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: ldx [%o1 + 0x00], %o3
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ EXNV3(stxa %o3, [%o0 + -8] %asi, add %o2, %g2)
+
+ cmp %o2, 0
+ bne,pn %icc, U3copy_to_user_short
+ nop
+ ba,a,pt %xcc, U3copy_to_user_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
diff --git a/arch/sparc64/lib/U3memcpy.S b/arch/sparc64/lib/U3memcpy.S
new file mode 100644
index 000000000..d38289145
--- /dev/null
+++ b/arch/sparc64/lib/U3memcpy.S
@@ -0,0 +1,409 @@
+/* $Id: U3memcpy.S,v 1.2 2000/11/01 09:29:19 davem Exp $
+ * U3memcpy.S: UltraSparc-III optimized memcpy.
+ *
+ * Copyright (C) 1999, 2000 David S. Miller (davem@redhat.com)
+ */
+
+#ifdef __KERNEL__
+#include <asm/visasm.h>
+#include <asm/asi.h>
+#undef SMALL_COPY_USES_FPU
+#else
+#define ASI_BLK_P 0xf0
+#define FPRS_FEF 0x04
+#define VISEntryHalf rd %fprs, %o5; wr %g0, FPRS_FEF, %fprs
+#define VISExitHalf and %o5, FPRS_FEF, %o5; wr %o5, 0x0, %fprs
+#define SMALL_COPY_USES_FPU
+#endif
+
+ /* Special/non-trivial issues of this code:
+ *
+ * 1) %o5 is preserved from VISEntryHalf to VISExitHalf
+ * 2) Only low 32 FPU registers are used so that only the
+ * lower half of the FPU register set is dirtied by this
+ * code. This is especially important in the kernel.
+ * 3) This code never prefetches cachelines past the end
+ * of the source buffer.
+ */
+
+ .text
+ .align 32
+
+ /* The cheetah's flexible spine, oversized liver, enlarged heart,
+ * slender muscular body, and claws make it the swiftest hunter
+ * in Africa and the fastest animal on land. Can reach speeds
+ * of up to 2.4GB per second.
+ */
+
+ .globl U3memcpy
+U3memcpy: /* %o0=dst, %o1=src, %o2=len */
+#ifndef __KERNEL__
+ /* Save away original 'dst' for memcpy return value. */
+ mov %o0, %g3 ! A0 Group
+#endif
+ /* Anything to copy at all? */
+ cmp %o2, 0 ! A1
+ ble,pn %icc, U3memcpy_short_ret ! BR
+
+ /* Extremely small copy? */
+ cmp %o2, 31 ! A0 Group
+ ble,pn %icc, U3memcpy_short ! BR
+
+ /* Large enough to use unrolled prefetch loops? */
+ cmp %o2, 0x100 ! A1
+ bge,a,pt %icc, U3memcpy_enter ! BR Group
+ andcc %o0, 0x3f, %g2 ! A0
+
+ ba,pt %xcc, U3memcpy_toosmall ! BR Group
+ andcc %o0, 0x7, %g2 ! A0
+
+ .align 32
+U3memcpy_short:
+ /* Copy %o2 bytes from src to dst, one byte at a time. */
+ ldub [%o1 + 0x00], %o3 ! MS Group
+ add %o1, 0x1, %o1 ! A0
+ add %o0, 0x1, %o0 ! A1
+ subcc %o2, 1, %o2 ! A0 Group
+
+ bg,pt %icc, U3memcpy_short ! BR
+ stb %o3, [%o0 + -1] ! MS Group (1-cycle stall)
+
+U3memcpy_short_ret:
+#ifdef __KERNEL__
+ retl ! BR Group (0-4 cycle stall)
+ clr %o0 ! A0
+#else
+ retl ! BR Group (0-4 cycle stall)
+ mov %g3, %o0 ! A0
+#endif
+
+ /* Here len >= (6 * 64) and condition codes reflect execution
+ * of "andcc %o0, 0x7, %g2", done by caller.
+ */
+ .align 64
+U3memcpy_enter:
+ /* Is 'dst' already aligned on an 64-byte boundary? */
+ be,pt %xcc, 2f ! BR
+
+ /* Compute abs((dst & 0x3f) - 0x40) into %g2. This is the number
+ * of bytes to copy to make 'dst' 64-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x40, %g2 ! A0 Group
+ sub %g0, %g2, %g2 ! A0 Group
+ sub %o2, %g2, %o2 ! A0 Group
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+ and %o1, 0x7, %g1 ! A1
+ ba,pt %xcc, U3memcpy_begin ! BR
+ alignaddr %o1, %g0, %o1 ! MS (Break-after)
+
+ .align 64
+U3memcpy_begin:
+ prefetch [%o1 + 0x000], #one_read ! MS Group1
+ prefetch [%o1 + 0x040], #one_read ! MS Group2
+ andn %o2, (0x40 - 1), %o4 ! A0
+ prefetch [%o1 + 0x080], #one_read ! MS Group3
+ cmp %o4, 0x140 ! A0
+ prefetch [%o1 + 0x0c0], #one_read ! MS Group4
+ ldd [%o1 + 0x000], %f0 ! MS Group5 (%f0 results at G8)
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x100], #one_read ! MS Group6
+1: ldd [%o1 + 0x008], %f2 ! AX (%f2 results at G9)
+ cmp %o4, 0x180 ! A1
+ bge,a,pt %icc, 1f ! BR
+ prefetch [%o1 + 0x140], #one_read ! MS Group7
+1: ldd [%o1 + 0x010], %f4 ! AX (%f4 results at G10)
+ cmp %o4, 0x1c0 ! A1
+ bge,a,pt %icc, 1f ! BR
+
+ prefetch [%o1 + 0x180], #one_read ! MS Group8
+1: faligndata %f0, %f2, %f16 ! FGA Group9 (%f16 at G12)
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G12)
+ faligndata %f2, %f4, %f18 ! FGA Group10 (%f18 results at G13)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G13)
+ faligndata %f4, %f6, %f20 ! FGA Group12 (1-cycle stall,%f20 at G15)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G15)
+ faligndata %f6, %f8, %f22 ! FGA Group13 (%f22 results at G16)
+
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G16)
+ faligndata %f8, %f10, %f24 ! FGA Group15 (1-cycle stall,%f24 at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+ faligndata %f10, %f12, %f26 ! FGA Group16 (%f26 results at G19)
+ ldd [%o1 + 0x040], %f0 ! MS (%f0 results at G19)
+
+ /* We only use the first loop if len > (7 * 64). */
+ subcc %o4, 0x1c0, %o4 ! A0 Group17
+ bg,pt %icc, U3memcpy_loop1 ! BR
+ add %o1, 0x40, %o1 ! A1
+
+ add %o4, 0x140, %o4 ! A0 Group18
+ ba,pt %xcc, U3memcpy_loop2 ! BR
+ srl %o4, 6, %o3 ! A0 Group19
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ nop
+ nop
+
+ /* This loop performs the copy and queues new prefetches.
+ * We drop into the second loop when len <= (5 * 64). Note
+ * that this (5 * 64) factor has been subtracted from len
+ * already.
+ */
+U3memcpy_loop1:
+ ldd [%o1 + 0x008], %f2 ! MS Group2 (%f2 results at G5)
+ faligndata %f12, %f14, %f28 ! FGA (%f28 results at G5)
+ ldd [%o1 + 0x010], %f4 ! MS Group3 (%f4 results at G6)
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall, %f30 at G7)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ ldd [%o1 + 0x018], %f6 ! AX (%f6 results at G7)
+
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS (%f8 results at G15)
+ faligndata %f2, %f4, %f18 ! FGA Group13 (%f18 results at G16)
+ ldd [%o1 + 0x028], %f10 ! MS (%f10 results at G16)
+ faligndata %f4, %f6, %f20 ! FGA Group14 (%f20 results at G17)
+ ldd [%o1 + 0x030], %f12 ! MS (%f12 results at G17)
+ faligndata %f6, %f8, %f22 ! FGA Group15 (%f22 results at G18)
+ ldd [%o1 + 0x038], %f14 ! MS (%f14 results at G18)
+
+ faligndata %f8, %f10, %f24 ! FGA Group16 (%f24 results at G19)
+ ldd [%o1 + 0x040], %f0 ! AX (%f0 results at G19)
+ prefetch [%o1 + 0x180], #one_read ! MS
+ faligndata %f10, %f12, %f26 ! FGA Group17 (%f26 results at G20)
+ subcc %o4, 0x40, %o4 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3memcpy_loop1 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+U3memcpy_loop2_enter:
+ mov 5, %o3 ! A1
+
+ /* This loop performs on the copy, no new prefetches are
+ * queued. We do things this way so that we do not perform
+ * any spurious prefetches past the end of the src buffer.
+ */
+U3memcpy_loop2:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA Group2
+ ldd [%o1 + 0x010], %f4 ! MS
+ faligndata %f14, %f0, %f30 ! FGA Group4 (1-cycle stall)
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group12 (7-cycle stall)
+
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group13
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group14
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group15
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group16
+
+ ldd [%o1 + 0x040], %f0 ! AX
+ faligndata %f10, %f12, %f26 ! FGA Group17
+ subcc %o3, 0x01, %o3 ! A0
+ add %o1, 0x40, %o1 ! A1
+ bg,pt %xcc, U3memcpy_loop2 ! BR
+ add %o0, 0x40, %o0 ! A0 Group18
+
+ /* Finally we copy the last full 64-byte block. */
+U3memcpy_loopfini:
+ ldd [%o1 + 0x008], %f2 ! MS
+ faligndata %f12, %f14, %f28 ! FGA
+ ldd [%o1 + 0x010], %f4 ! MS Group19
+ faligndata %f14, %f0, %f30 ! FGA
+ stda %f16, [%o0] ASI_BLK_P ! MS Group20
+ ldd [%o1 + 0x018], %f6 ! AX
+ faligndata %f0, %f2, %f16 ! FGA Group11 (7-cycle stall)
+ ldd [%o1 + 0x020], %f8 ! MS
+ faligndata %f2, %f4, %f18 ! FGA Group12
+ ldd [%o1 + 0x028], %f10 ! MS
+ faligndata %f4, %f6, %f20 ! FGA Group13
+ ldd [%o1 + 0x030], %f12 ! MS
+ faligndata %f6, %f8, %f22 ! FGA Group14
+ ldd [%o1 + 0x038], %f14 ! MS
+ faligndata %f8, %f10, %f24 ! FGA Group15
+ cmp %g1, 0 ! A0
+ be,pt %icc, 1f ! BR
+ add %o0, 0x40, %o0 ! A1
+ ldd [%o1 + 0x040], %f0 ! MS
+1: faligndata %f10, %f12, %f26 ! FGA Group16
+ faligndata %f12, %f14, %f28 ! FGA Group17
+ faligndata %f14, %f0, %f30 ! FGA Group18
+ stda %f16, [%o0] ASI_BLK_P ! MS
+ add %o0, 0x40, %o0 ! A0
+ add %o1, 0x40, %o1 ! A1
+ membar #Sync ! MS Group26 (7-cycle stall)
+
+ /* Now we copy the (len modulo 64) bytes at the end.
+ * Note how we borrow the %f0 loaded above.
+ *
+ * Also notice how this code is careful not to perform a
+ * load past the end of the src buffer just like similar
+ * code found in U3memcpy_toosmall processing.
+ */
+U3memcpy_loopend:
+ and %o2, 0x3f, %o2 ! A0 Group
+ andcc %o2, 0x38, %g2 ! A0 Group
+ be,pn %icc, U3memcpy_endcruft ! BR
+ subcc %g2, 0x8, %g2 ! A1
+ be,pn %icc, U3memcpy_endcruft ! BR Group
+ cmp %g1, 0 ! A0
+
+ be,a,pt %icc, 1f ! BR Group
+ ldd [%o1 + 0x00], %f0 ! MS
+
+1: ldd [%o1 + 0x08], %f2 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f0, %f2, %f8 ! FGA Group
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ be,pn %icc, U3memcpy_endcruft ! BR
+ add %o0, 0x8, %o0 ! A0
+ ldd [%o1 + 0x08], %f0 ! MS Group
+ add %o1, 0x8, %o1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA
+ std %f8, [%o0 + 0x00] ! MS (XXX does it stall here? XXX)
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A0 Group
+
+ /* If anything is left, we copy it one byte at a time.
+ * Note that %g1 is (src & 0x3) saved above before the
+ * alignaddr was performed.
+ */
+U3memcpy_endcruft:
+ cmp %o2, 0
+ add %o1, %g1, %o1
+ VISExitHalf
+ be,pn %icc, U3memcpy_short_ret
+ nop
+ ba,a,pt %xcc, U3memcpy_short
+
+ /* If we get here, then 32 <= len < (6 * 64) */
+U3memcpy_toosmall:
+
+#ifdef SMALL_COPY_USES_FPU
+
+ /* Is 'dst' already aligned on an 8-byte boundary? */
+ be,pt %xcc, 2f ! BR Group
+
+ /* Compute abs((dst & 7) - 8) into %g2. This is the number
+ * of bytes to copy to make 'dst' 8-byte aligned. We pre-
+ * subtract this from 'len'.
+ */
+ sub %g2, 0x8, %g2 ! A0
+ sub %g0, %g2, %g2 ! A0 Group (reg-dep)
+ sub %o2, %g2, %o2 ! A0 Group (reg-dep)
+
+ /* Copy %g2 bytes from src to dst, one byte at a time. */
+1: ldub [%o1 + 0x00], %o3 ! MS (Group) (%o3 in 3 cycles)
+ add %o1, 0x1, %o1 ! A1
+ add %o0, 0x1, %o0 ! A0 Group
+ subcc %g2, 0x1, %g2 ! A1
+
+ bg,pt %icc, 1b ! BR Group
+ stb %o3, [%o0 + -1] ! MS Group
+
+2: VISEntryHalf ! MS+MS
+
+ /* Compute (len - (len % 8)) into %g2. This is guarenteed
+ * to be nonzero.
+ */
+ andn %o2, 0x7, %g2 ! A0 Group
+
+ /* You may read this and believe that it allows reading
+ * one 8-byte longword past the end of src. It actually
+ * does not, as %g2 is subtracted as loads are done from
+ * src, so we always stop before running off the end.
+ * Also, we are guarenteed to have at least 0x10 bytes
+ * to move here.
+ */
+ sub %g2, 0x8, %g2 ! A0 Group (reg-dep)
+ alignaddr %o1, %g0, %g1 ! MS (Break-after)
+ ldd [%g1 + 0x00], %f0 ! MS Group (1-cycle stall)
+ add %g1, 0x8, %g1 ! A0
+
+1: ldd [%g1 + 0x00], %f2 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+ subcc %g2, 0x8, %g2 ! A0 Group
+
+ faligndata %f0, %f2, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+ be,pn %icc, 2f ! BR
+
+ add %o0, 0x8, %o0 ! A1
+ ldd [%g1 + 0x00], %f0 ! MS Group
+ add %g1, 0x8, %g1 ! A0
+ sub %o2, 0x8, %o2 ! A1
+
+ subcc %g2, 0x8, %g2 ! A0 Group
+ faligndata %f2, %f0, %f8 ! FGA Group (1-cycle stall)
+ std %f8, [%o0 + 0x00] ! MS Group (2-cycle stall)
+ add %o1, 0x8, %o1 ! A0
+
+ bne,pn %icc, 1b ! BR
+ add %o0, 0x8, %o0 ! A1
+
+ /* Nothing left to copy? */
+2: cmp %o2, 0 ! A0 Group
+ VISExitHalf ! A0+MS
+ be,pn %icc, U3memcpy_short_ret ! BR Group
+ nop ! A0
+ ba,a,pt %xcc, U3memcpy_short ! BR Group
+
+#else /* !(SMALL_COPY_USES_FPU) */
+
+ xor %o1, %o0, %g2
+ andcc %g2, 0x7, %g0
+ bne,pn %icc, U3memcpy_short
+ andcc %o1, 0x7, %g2
+
+ be,pt %xcc, 2f
+ sub %g2, 0x8, %g2
+ sub %g0, %g2, %g2
+ sub %o2, %g2, %o2
+
+1: ldub [%o1 + 0x00], %o3
+ add %o1, 0x1, %o1
+ add %o0, 0x1, %o0
+ subcc %g2, 0x1, %g2
+ bg,pt %icc, 1b
+ stb %o3, [%o0 + -1]
+
+2: andn %o2, 0x7, %g2
+ sub %o2, %g2, %o2
+
+3: ldx [%o1 + 0x00], %o3
+ add %o1, 0x8, %o1
+ add %o0, 0x8, %o0
+ subcc %g2, 0x8, %g2
+ bg,pt %icc, 3b
+ stx %o3, [%o0 + -8]
+
+ cmp %o2, 0
+ bne,pn %icc, U3memcpy_short
+ nop
+ ba,a,pt %xcc, U3memcpy_short_ret
+
+#endif /* !(SMALL_COPY_USES_FPU) */
diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
index 56634f83f..b944a0ae7 100644
--- a/arch/sparc64/lib/VIScopy.S
+++ b/arch/sparc64/lib/VIScopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.23 2000/03/26 09:13:49 davem Exp $
+/* $Id: VIScopy.S,v 1.25 2000/11/01 09:29:19 davem Exp $
* VIScopy.S: High speed copy operations utilizing the UltraSparc
* Visual Instruction Set.
*
@@ -361,6 +361,38 @@ bcopy: or %o0, 0, %g3 ! IEU0 Group
clr %o0 ! IEU0
+#ifdef __KERNEL__
+#define BRANCH_ALWAYS 0x10680000
+#define NOP 0x01000000
+#define ULTRA3_DO_PATCH(OLD, NEW) \
+ sethi %hi(NEW), %g1; \
+ or %g1, %lo(NEW), %g1; \
+ sethi %hi(OLD), %g2; \
+ or %g2, %lo(OLD), %g2; \
+ sub %g1, %g2, %g1; \
+ sethi %hi(BRANCH_ALWAYS), %g3; \
+ srl %g1, 2, %g1; \
+ or %g3, %lo(BRANCH_ALWAYS), %g3; \
+ or %g3, %g1, %g3; \
+ stw %g3, [%g2]; \
+ sethi %hi(NOP), %g3; \
+ or %g3, %lo(NOP), %g3; \
+ stw %g3, [%g2 + 0x4]; \
+ flush %g2;
+
+ .globl cheetah_patch_copyops
+cheetah_patch_copyops:
+ ULTRA3_DO_PATCH(memcpy, U3memcpy)
+ ULTRA3_DO_PATCH(__copy_from_user, U3copy_from_user)
+ ULTRA3_DO_PATCH(__copy_to_user, U3copy_to_user)
+ ULTRA3_DO_PATCH(__copy_in_user, U3copy_in_user)
+ retl
+ nop
+#undef BRANCH_ALWAYS
+#undef NOP
+#undef ULTRA3_DO_PATCH
+#endif /* __KERNEL__ */
+
.align 32
#ifdef __KERNEL__
__memcpy_384plus:
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 65fbd6e37..6da2d0b85 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.157 2000/10/19 00:49:52 davem Exp $
+/* $Id: init.c,v 1.159 2000/11/06 06:59:04 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -99,6 +99,20 @@ int do_check_pgt_cache(int low, int high)
return freed;
}
+extern void __update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+ struct page *page = pte_page(pte);
+
+ if (VALID_PAGE(page) && page->mapping &&
+ test_bit(PG_dcache_dirty, &page->flags)) {
+ __flush_dcache_page(page->virtual, 1);
+ clear_bit(PG_dcache_dirty, &page->flags);
+ }
+ __update_mmu_cache(vma, address, pte);
+}
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 7940218d2..daaf580a0 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.46 2000/08/05 13:30:33 davem Exp $
+/* $Id: ultra.S,v 1.48 2000/11/06 06:59:04 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -208,27 +208,58 @@ iflush2:sub %o1, 0x20, %g3
.align 64
.globl __flush_dcache_page
-__flush_dcache_page:
+__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
sub %o0, %g4, %o0
- clr %o1
+ clr %o4
srlx %o0, 11, %o0
sethi %hi(1 << 14), %o2
-1: ldxa [%o1] ASI_DCACHE_TAG, %o3
- andn %o3, 0x3, %o3
- cmp %o0, %o3
- bne,pt %xcc, 2f
- nop
- stxa %g0, [%o1] ASI_DCACHE_TAG
- membar #Sync
-2: add %o1, (1 << 5), %o1
- cmp %o1, %o2
- bne,pt %xcc, 1b
- nop
+1: ldxa [%o4] ASI_DCACHE_TAG, %o3 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ ldxa [%o4] ASI_DCACHE_TAG, %g1 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ ldxa [%o4] ASI_DCACHE_TAG, %g2 ! LSU Group o3 available
+ add %o4, (1 << 5), %o4 ! IEU0
+ andn %o3, 0x3, %o3 ! IEU1
+ ldxa [%o4] ASI_DCACHE_TAG, %g3 ! LSU Group
+ add %o4, (1 << 5), %o4 ! IEU0
+ andn %g1, 0x3, %g1 ! IEU1
+ cmp %o0, %o3 ! IEU1 Group
+ be,a,pn %xcc, dflush1 ! CTI
+ sub %o4, (4 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g1 ! IEU1 Group
+ andn %g2, 0x3, %g2 ! IEU0
+ be,a,pn %xcc, dflush2 ! CTI
+ sub %o4, (3 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g2 ! IEU1 Group
+ andn %g3, 0x3, %g3 ! IEU0
+ be,a,pn %xcc, dflush3 ! CTI
+ sub %o4, (2 << 5), %o4 ! IEU0 (Group)
+ cmp %o0, %g3 ! IEU1 Group
+ be,a,pn %xcc, dflush4 ! CTI
+ sub %o4, (1 << 5), %o4 ! IEU0
+2: cmp %o4, %o2 ! IEU1 Group
+ bne,pt %xcc, 1b ! CTI
+ nop ! IEU0
+
/* The I-cache does not snoop local stores so we
- * better flush that too.
+ * better flush that too when necessary.
*/
- ba,pt %xcc, __flush_icache_page
+ brnz,pt %o1, __flush_icache_page
sllx %o0, 11, %o0
+ retl
+ nop
+
+dflush1:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush2:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush3:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG
+ add %o4, (1 << 5), %o4
+ membar #Sync
+ ba,pt %xcc, 2b
+ nop
.align 32
__prefill_dtlb:
@@ -250,8 +281,8 @@ __prefill_itlb:
retl
wrpr %g7, %pstate
- .globl update_mmu_cache
-update_mmu_cache: /* %o0=vma, %o1=address, %o2=pte */
+ .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 */
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
index 0e899da18..4a10c1b4c 100644
--- a/arch/sparc64/solaris/ioctl.c
+++ b/arch/sparc64/solaris/ioctl.c
@@ -464,8 +464,8 @@ static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd
struct sol_socket_struct *sock;
struct module_info *mi;
- if (! (ino = filp->f_dentry->d_inode) ||
- ! ino->i_sock)
+ ino = filp->f_dentry->d_inode;
+ if (! ino->i_sock)
return -EBADF;
sock = filp->private_data;
if (! sock) {
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
index 3013d43cf..9b910a633 100644
--- a/arch/sparc64/solaris/socket.c
+++ b/arch/sparc64/solaris/socket.c
@@ -265,7 +265,7 @@ extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
}
inode = file->f_dentry->d_inode;
- if (!inode || !inode->i_sock || !socki_lookup(inode)) {
+ if (!inode->i_sock || !socki_lookup(inode)) {
*err = -ENOTSOCK;
fput(file);
return NULL;
diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds
index f686decfb..91d4575d0 100644
--- a/arch/sparc64/vmlinux.lds
+++ b/arch/sparc64/vmlinux.lds
@@ -35,6 +35,9 @@ SECTIONS
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
__kstrtab : { *(.kstrtab) }
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
. = ALIGN(8192);
__init_begin = .;
.text.init : { *(.text.init) }
diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
index bf84fca56..9c4505494 100644
--- a/drivers/acorn/net/etherh.c
+++ b/drivers/acorn/net/etherh.c
@@ -622,9 +622,6 @@ static int __init etherh_init(void)
{
int i, ret = -ENODEV;
- if (load_8390_module("etherh.c"))
- return -ENOSYS;
-
ecard_startfind();
for (i = 0; i < MAX_ECARDS; i++) {
@@ -644,9 +641,6 @@ static int __init etherh_init(void)
ret = 0;
}
- if (ret)
- unload_8390_module();
-
return ret;
}
@@ -667,7 +661,6 @@ static void __exit etherh_exit(void)
e_card[i] = NULL;
}
}
- unload_8390_module();
}
module_init(etherh_init);
diff --git a/drivers/acpi/driver.c b/drivers/acpi/driver.c
index 58da76eb0..411e07fcb 100644
--- a/drivers/acpi/driver.c
+++ b/drivers/acpi/driver.c
@@ -284,7 +284,7 @@ acpi_thread(void *context)
/*
* initialize
*/
- exit_files(current);
+
daemonize();
strcpy(current->comm, "acpi");
diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
index 5e96bf9c9..9c4f2e7f3 100644
--- a/drivers/atm/atmtcp.c
+++ b/drivers/atm/atmtcp.c
@@ -77,6 +77,7 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
}
+ current->state = TASK_RUNNING;
remove_wait_queue(&vcc->sleep,&wait);
return error;
}
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index e4d709cb0..8b6d71237 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -271,24 +271,8 @@ static struct atmdev_ops atm_ops =
proc_read: ns_proc_read
};
static struct timer_list ns_timer;
-static char *mac[NS_MAX_CARDS] = { NULL
-#if NS_MAX_CARDS > 1
- , NULL
-#endif /* NS_MAX_CARDS > 1 */
-#if NS_MAX_CARDS > 2
- , NULL
-#endif /* NS_MAX_CARDS > 2 */
-#if NS_MAX_CARDS > 3
- , NULL
-#endif /* NS_MAX_CARDS > 3 */
-#if NS_MAX_CARDS > 4
- , NULL
-#endif /* NS_MAX_CARDS > 4 */
- };
-
-#ifdef MODULE
+static char *mac[NS_MAX_CARDS];
MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s");
-#endif /* MODULE */
/* Functions*******************************************************************/
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 0bfa895b7..afbf60ddc 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -44,8 +44,8 @@
#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.0)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,0)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.1)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,1)
/* Embedded module documentation macros - see modules.h */
/* Original author Chris Frantz - Compaq Computer Corporation */
@@ -1664,6 +1664,7 @@ static void getgeometry(int ctlr)
int ret_code, size;
drv_info_t *drv;
ctlr_info_t *info_p = hba[ctlr];
+ int i;
info_p->log_drv_map = 0;
@@ -1729,7 +1730,8 @@ static void getgeometry(int ctlr)
}
info_p->log_drives = id_ctlr_buf->nr_drvs;;
- *(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
+ for(i=0;i<4;i++)
+ info_p->firm_rev[i] = id_ctlr_buf->firm_rev[i];
info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
printk(" (%s)\n", info_p->product_name);
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index d9d3f8622..ad370bcb7 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -347,10 +347,9 @@ static void generic_plug_device(request_queue_t *q, kdev_t dev)
*/
static inline void __generic_unplug_device(request_queue_t *q)
{
- if (q->plugged) {
+ if (!list_empty(&q->queue_head)) {
q->plugged = 0;
- if (!list_empty(&q->queue_head))
- q->request_fn(q);
+ q->request_fn(q);
}
}
@@ -496,7 +495,7 @@ static struct request *__get_request_wait(request_queue_t *q, int rw)
add_wait_queue_exclusive(&q->wait_for_request, &wait);
for (;;) {
- __set_current_state(TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE);
+ __set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irq(&io_request_lock);
rq = get_request(q, rw);
spin_unlock_irq(&io_request_lock);
@@ -683,7 +682,7 @@ static int __make_request(request_queue_t * q, int rw,
{
unsigned int sector, count;
int max_segments = MAX_SEGMENTS;
- struct request * req = NULL;
+ struct request * req = NULL, *freereq = NULL;
int rw_ahead, max_sectors, el_ret;
struct list_head *head = &q->queue_head;
int latency;
@@ -733,6 +732,7 @@ static int __make_request(request_queue_t * q, int rw,
* Now we acquire the request spinlock, we have to be mega careful
* not to schedule or do something nonatomic
*/
+again:
spin_lock_irq(&io_request_lock);
/*
@@ -791,19 +791,16 @@ static int __make_request(request_queue_t * q, int rw,
* are not crucial.
*/
get_rq:
- if ((req = get_request(q, rw)) == NULL) {
+ if (freereq) {
+ req = freereq;
+ freereq = NULL;
+ } else if ((req = get_request(q, rw)) == NULL) {
spin_unlock_irq(&io_request_lock);
if (rw_ahead)
goto end_io;
- req = __get_request_wait(q, rw);
- spin_lock_irq(&io_request_lock);
-
- if (q->head_active) {
- head = &q->queue_head;
- if (!q->plugged)
- head = head->next;
- }
+ freereq = __get_request_wait(q, rw);
+ goto again;
}
/* fill up the request-info, and add it to the queue */
@@ -824,6 +821,8 @@ get_rq:
out:
if (!q->plugged)
(q->request_fn)(q);
+ if (freereq)
+ blkdev_release_request(freereq);
spin_unlock_irq(&io_request_lock);
return 0;
end_io:
@@ -1059,7 +1058,7 @@ int __init blk_dev_init(void)
#endif
#ifdef CONFIG_ISP16_CDI
isp16_init();
-#endif CONFIG_ISP16_CDI
+#endif
#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
ide_init(); /* this MUST precede hd_init */
#endif
@@ -1099,37 +1098,37 @@ int __init blk_dev_init(void)
#endif
#ifdef CONFIG_CDU31A
cdu31a_init();
-#endif CONFIG_CDU31A
+#endif
#ifdef CONFIG_ATARI_ACSI
acsi_init();
-#endif CONFIG_ATARI_ACSI
+#endif
#ifdef CONFIG_MCD
mcd_init();
-#endif CONFIG_MCD
+#endif
#ifdef CONFIG_MCDX
mcdx_init();
-#endif CONFIG_MCDX
+#endif
#ifdef CONFIG_SBPCD
sbpcd_init();
-#endif CONFIG_SBPCD
+#endif
#ifdef CONFIG_AZTCD
aztcd_init();
-#endif CONFIG_AZTCD
+#endif
#ifdef CONFIG_CDU535
sony535_init();
-#endif CONFIG_CDU535
+#endif
#ifdef CONFIG_GSCD
gscd_init();
-#endif CONFIG_GSCD
+#endif
#ifdef CONFIG_CM206
cm206_init();
#endif
#ifdef CONFIG_OPTCD
optcd_init();
-#endif CONFIG_OPTCD
+#endif
#ifdef CONFIG_SJCD
sjcd_init();
-#endif CONFIG_SJCD
+#endif
#ifdef CONFIG_APBLOCK
ap_init();
#endif
@@ -1150,7 +1149,7 @@ int __init blk_dev_init(void)
#endif
#ifdef CONFIG_BLK_DEV_LVM
lvm_init();
-#endif
+#endif
return 0;
};
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 329d10c9c..dc5ecd151 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -235,7 +235,7 @@ static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned l
if (size > count)
size = count;
- kaddr = (char*)kmap(page);
+ kaddr = kmap(page);
if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
size = 0;
printk(KERN_ERR "loop: transfer error block %ld\n",
@@ -411,10 +411,6 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
error = -EINVAL;
inode = file->f_dentry->d_inode;
- if (!inode) {
- printk(KERN_ERR "loop_set_fd: NULL inode?!?\n");
- goto out_putf;
- }
if (S_ISBLK(inode->i_mode)) {
/* dentry will be wired, so... */
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 6f583c3de..1799ccef5 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -100,7 +100,7 @@ static int rd_hardsec[NUM_RAMDISKS]; /* Size of real blocks in bytes */
static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */
static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */
static devfs_handle_t devfs_handle;
-static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
+static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
/*
* Parameters for the boot-loading of the RAM disk. These are set by
@@ -108,7 +108,7 @@ static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
* architecture-specific setup routine (from the stored boot sector
* information).
*/
-int rd_size = 4096; /* Size of the RAM disks */
+int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */
/*
* It would be very desiderable to have a soft-blocksize (that in the case
* of the ramdisk driver is also the hardblocksize ;) of PAGE_SIZE because
@@ -120,7 +120,7 @@ int rd_size = 4096; /* Size of the RAM disks */
* behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that
* supposes the filesystem in the image uses a BLOCK_SIZE blocksize).
*/
-int rd_blocksize = BLOCK_SIZE; /* Size of the RAM disks */
+int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */
#ifndef MODULE
@@ -194,50 +194,53 @@ __setup("ramdisk_blocksize=", ramdisk_blocksize);
* 19-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Added devfs support
*
*/
-static void rd_request(request_queue_t * q)
+static int rd_make_request(request_queue_t * q, int rw, struct buffer_head *sbh)
{
unsigned int minor;
unsigned long offset, len;
struct buffer_head *rbh;
- struct buffer_head *sbh;
+ char *bdata;
-repeat:
- INIT_REQUEST;
- minor = MINOR(CURRENT->rq_dev);
+ minor = MINOR(sbh->b_rdev);
+
+ if (minor >= NUM_RAMDISKS)
+ goto fail;
- if (minor >= NUM_RAMDISKS) {
- end_request(0);
- goto repeat;
- }
- offset = CURRENT->sector << 9;
- len = CURRENT->current_nr_sectors << 9;
+ offset = sbh->b_rsector << 9;
+ len = sbh->b_size;
- if ((offset + len) > rd_length[minor]) {
- end_request(0);
- goto repeat;
- }
+ if ((offset + len) > rd_length[minor])
+ goto fail;
- if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
- printk(KERN_INFO "RAMDISK: bad command: %d\n", CURRENT->cmd);
- end_request(0);
- goto repeat;
+ if (rw==READA)
+ rw=READ;
+ if ((rw != READ) && (rw != WRITE)) {
+ printk(KERN_INFO "RAMDISK: bad command: %d\n", rw);
+ goto fail;
}
- sbh = CURRENT->bh;
- rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
- if (CURRENT->cmd == READ) {
+ rbh = getblk(sbh->b_rdev, sbh->b_rsector/(sbh->b_size>>9), sbh->b_size);
+ /* I think that it is safe to assume that rbh is not in HighMem, though
+ * sbh might be - NeilBrown
+ */
+ bdata = bh_kmap(sbh);
+ if (rw == READ) {
if (sbh != rbh)
- memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
+ memcpy(bdata, rbh->b_data, rbh->b_size);
} else
if (sbh != rbh)
- memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
+ memcpy(rbh->b_data, bdata, rbh->b_size);
+ bh_kunmap(sbh);
mark_buffer_protected(rbh);
brelse(rbh);
- end_request(1);
- goto repeat;
+ sbh->b_end_io(sbh,1);
+ return 0;
+ fail:
+ sbh->b_end_io(sbh,0);
+ return 0;
}
static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -378,7 +381,6 @@ static void __exit rd_cleanup (void)
devfs_unregister (devfs_handle);
unregister_blkdev( MAJOR_NR, "ramdisk" );
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
hardsect_size[MAJOR_NR] = NULL;
blksize_size[MAJOR_NR] = NULL;
blk_size[MAJOR_NR] = NULL;
@@ -403,7 +405,7 @@ int __init rd_init (void)
return -EIO;
}
- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_request);
+ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), &rd_make_request);
for (i = 0; i < NUM_RAMDISKS; i++) {
/* rd_size is given in kB */
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 1ec7792a6..e2e57cc90 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -16,7 +16,7 @@ if [ "$CONFIG_SERIAL" = "y" ]; then
tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
fi
fi
-dep_bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
+dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
@@ -178,8 +178,8 @@ endmenu
tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
if [ "$CONFIG_AGP" != "n" ]; then
- bool ' Intel 440LX/BX/GX 840 support' CONFIG_AGP_INTEL
- bool ' Intel I810/I815 support' CONFIG_AGP_I810
+ bool ' Intel 440LX/BX/GX and I815/I840 support' CONFIG_AGP_INTEL
+ bool ' Intel I810/I815 (on-board) support' CONFIG_AGP_I810
bool ' VIA chipset support' CONFIG_AGP_VIA
bool ' AMD Irongate support' CONFIG_AGP_AMD
bool ' Generic SiS support' CONFIG_AGP_SIS
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index acad5947a..a054af745 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -144,8 +144,6 @@ struct agp_bridge_data {
#define min(a,b) (((a)<(b))?(a):(b))
#endif
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#define AGPGART_MODULE_NAME "agpgart"
#define PFX AGPGART_MODULE_NAME ": "
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index 44bd3bfb4..5d2b3de61 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -2057,6 +2057,13 @@ static struct {
"Intel",
"440GX",
intel_generic_setup },
+ /* could we add support for PCI_DEVICE_ID_INTEL_815_1 too ? */
+ { PCI_DEVICE_ID_INTEL_815_0,
+ PCI_VENDOR_ID_INTEL,
+ INTEL_I815,
+ "Intel",
+ "i815",
+ intel_generic_setup },
{ PCI_DEVICE_ID_INTEL_840_0,
PCI_VENDOR_ID_INTEL,
INTEL_I840,
@@ -2182,16 +2189,16 @@ static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int i;
- for (i = 0; i < arraysize (agp_bridge_info); i++)
+ for (i = 0; i < ARRAY_SIZE (agp_bridge_info); i++)
if (pdev->vendor == agp_bridge_info[i].vendor_id)
break;
- if (i >= arraysize (agp_bridge_info)) {
+ if (i >= ARRAY_SIZE (agp_bridge_info)) {
printk (KERN_DEBUG PFX "unsupported bridge\n");
return -ENODEV;
}
- while ((i < arraysize (agp_bridge_info)) &&
+ while ((i < ARRAY_SIZE (agp_bridge_info)) &&
(agp_bridge_info[i].vendor_id == pdev->vendor)) {
if (pdev->device == agp_bridge_info[i].device_id) {
printk (KERN_INFO PFX "Detected %s %s chipset\n",
@@ -2490,6 +2497,17 @@ static void agp_backend_cleanup(void)
extern int agp_frontend_initialize(void);
extern void agp_frontend_cleanup(void);
+static const drm_agp_t drm_agp = {
+ &agp_free_memory,
+ &agp_allocate_memory,
+ &agp_bind_memory,
+ &agp_unbind_memory,
+ &agp_enable,
+ &agp_backend_acquire,
+ &agp_backend_release,
+ &agp_copy_info
+};
+
static int __init agp_init(void)
{
int ret_val;
@@ -2509,6 +2527,7 @@ static int __init agp_init(void)
return ret_val;
}
+ inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
return 0;
}
@@ -2516,6 +2535,7 @@ static void __exit agp_cleanup(void)
{
agp_frontend_cleanup();
agp_backend_cleanup();
+ inter_module_unregister("drm_agp");
}
module_init(agp_init);
diff --git a/drivers/char/console.c b/drivers/char/console.c
index ea44cace4..0285eab79 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -2135,7 +2135,6 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
}
}
set_cursor(currcons);
- poke_blanked_console();
quit:
clear_bit(0, &printing);
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e5bdb6ccf..35b23d944 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -2517,6 +2517,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
firm_id = (struct FIRM_ID *)
(base_addr + ID_ADDRESS);
if (!ISZLOADED(*cinfo)){
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
return -EINVAL;
}
diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c
index 24fd59cdf..c996df8f4 100644
--- a/drivers/char/drm/agpsupport.c
+++ b/drivers/char/drm/agpsupport.c
@@ -31,48 +31,14 @@
#define __NO_VERSION__
#include "drmP.h"
#include <linux/module.h>
+#if LINUX_VERSION_CODE < 0x020400
+#include "agpsupport-pre24.h"
+#else
+#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
+#define DRM_AGP_PUT inter_module_put("drm_agp")
+#endif
-drm_agp_func_t drm_agp = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
-/* The C standard says that 'void *' is not guaranteed to hold a function
- pointer, so we use this union to define a generic pointer that is
- guaranteed to hold any of the function pointers we care about. */
-typedef union {
- void (*free_memory)(agp_memory *);
- agp_memory *(*allocate_memory)(size_t, u32);
- int (*bind_memory)(agp_memory *, off_t);
- int (*unbind_memory)(agp_memory *);
- void (*enable)(u32);
- int (*acquire)(void);
- void (*release)(void);
- void (*copy_info)(agp_kern_info *);
- unsigned long address;
-} drm_agp_func_u;
-
-typedef struct drm_agp_fill {
- const char *name;
- drm_agp_func_u *f;
-} drm_agp_fill_t;
-
-static drm_agp_fill_t drm_agp_fill[] = {
- { __MODULE_STRING(agp_free_memory),
- (drm_agp_func_u *)&drm_agp.free_memory },
- { __MODULE_STRING(agp_allocate_memory),
- (drm_agp_func_u *)&drm_agp.allocate_memory },
- { __MODULE_STRING(agp_bind_memory),
- (drm_agp_func_u *)&drm_agp.bind_memory },
- { __MODULE_STRING(agp_unbind_memory),
- (drm_agp_func_u *)&drm_agp.unbind_memory },
- { __MODULE_STRING(agp_enable),
- (drm_agp_func_u *)&drm_agp.enable },
- { __MODULE_STRING(agp_backend_acquire),
- (drm_agp_func_u *)&drm_agp.acquire },
- { __MODULE_STRING(agp_backend_release),
- (drm_agp_func_u *)&drm_agp.release },
- { __MODULE_STRING(agp_copy_info),
- (drm_agp_func_u *)&drm_agp.copy_info },
- { NULL, NULL }
-};
+static const drm_agp_t *drm_agp = NULL;
int drm_agp_info(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
@@ -82,7 +48,7 @@ int drm_agp_info(struct inode *inode, struct file *filp, unsigned int cmd,
agp_kern_info *kern;
drm_agp_info_t info;
- if (!dev->agp->acquired || !drm_agp.copy_info) return -EINVAL;
+ if (!dev->agp->acquired || !drm_agp->copy_info) return -EINVAL;
kern = &dev->agp->agp_info;
info.agp_version_major = kern->version.major;
@@ -107,8 +73,8 @@ int drm_agp_acquire(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
int retcode;
- if (dev->agp->acquired || !drm_agp.acquire) return -EINVAL;
- if ((retcode = (*drm_agp.acquire)())) return retcode;
+ if (dev->agp->acquired || !drm_agp->acquire) return -EINVAL;
+ if ((retcode = drm_agp->acquire())) return retcode;
dev->agp->acquired = 1;
return 0;
}
@@ -119,13 +85,18 @@ int drm_agp_release(struct inode *inode, struct file *filp, unsigned int cmd,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
- if (!dev->agp->acquired || !drm_agp.release) return -EINVAL;
- (*drm_agp.release)();
+ if (!dev->agp->acquired || !drm_agp->release) return -EINVAL;
+ drm_agp->release();
dev->agp->acquired = 0;
return 0;
}
+void _drm_agp_release(void)
+{
+ if (drm_agp->release) drm_agp->release();
+}
+
int drm_agp_enable(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -133,13 +104,13 @@ int drm_agp_enable(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_agp_mode_t mode;
- if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL;
+ if (!dev->agp->acquired || !drm_agp->enable) return -EINVAL;
if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
return -EFAULT;
dev->agp->mode = mode.mode;
- (*drm_agp.enable)(mode.mode);
+ drm_agp->enable(mode.mode);
dev->agp->base = dev->agp->agp_info.aper_base;
dev->agp->enabled = 1;
return 0;
@@ -231,7 +202,7 @@ int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd,
int retcode;
int page;
- if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL;
+ if (!dev->agp->acquired || !drm_agp->bind_memory) return -EINVAL;
if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
return -EFAULT;
if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
@@ -270,24 +241,14 @@ int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
drm_agp_head_t *drm_agp_init(void)
{
- drm_agp_fill_t *fill;
drm_agp_head_t *head = NULL;
- int agp_available = 1;
-
- for (fill = &drm_agp_fill[0]; fill->name; fill++) {
- char *n = (char *)fill->name;
- *fill->f = (drm_agp_func_u)get_module_symbol(NULL, n);
- DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address);
- if (!(*fill->f).address) agp_available = 0;
- }
-
- DRM_DEBUG("agp_available = %d\n", agp_available);
- if (agp_available) {
+ drm_agp = DRM_AGP_GET;
+ if (drm_agp) {
if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
return NULL;
memset((void *)head, 0, sizeof(*head));
- (*drm_agp.copy_info)(&head->agp_info);
+ drm_agp->copy_info(&head->agp_info);
if (head->agp_info.chipset == NOT_SUPPORTED) {
drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
return NULL;
@@ -337,12 +298,31 @@ drm_agp_head_t *drm_agp_init(void)
void drm_agp_uninit(void)
{
- drm_agp_fill_t *fill;
-
- for (fill = &drm_agp_fill[0]; fill->name; fill++) {
-#if LINUX_VERSION_CODE >= 0x020400
- if ((*fill->f).address) put_module_symbol((*fill->f).address);
-#endif
- (*fill->f).address = 0;
- }
+ DRM_AGP_PUT;
+ drm_agp = NULL;
+}
+
+agp_memory *drm_agp_allocate_memory(size_t pages, u32 type)
+{
+ if (!drm_agp->allocate_memory) return NULL;
+ return drm_agp->allocate_memory(pages, type);
+}
+
+int drm_agp_free_memory(agp_memory *handle)
+{
+ if (!handle || !drm_agp->free_memory) return 0;
+ drm_agp->free_memory(handle);
+ return 1;
+}
+
+int drm_agp_bind_memory(agp_memory *handle, off_t start)
+{
+ if (!handle || !drm_agp->bind_memory) return -EINVAL;
+ return drm_agp->bind_memory(handle, start);
+}
+
+int drm_agp_unbind_memory(agp_memory *handle)
+{
+ if (!handle || !drm_agp->unbind_memory) return -EINVAL;
+ return drm_agp->unbind_memory(handle);
}
diff --git a/drivers/char/drm/dma.c b/drivers/char/drm/dma.c
index 5cc3ec369..56dd2441e 100644
--- a/drivers/char/drm/dma.c
+++ b/drivers/char/drm/dma.c
@@ -405,6 +405,7 @@ int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
schedule();
if (signal_pending(current)) {
atomic_dec(&q->use_count);
+ remove_wait_queue(&q->write_queue, &entry);
return -EINTR;
}
}
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 6be90c516..affeae705 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -510,19 +510,6 @@ typedef struct drm_agp_head {
unsigned long base;
int agp_mtrr;
} drm_agp_head_t;
-
-typedef struct {
- void (*free_memory)(agp_memory *);
- agp_memory *(*allocate_memory)(size_t, u32);
- int (*bind_memory)(agp_memory *, off_t);
- int (*unbind_memory)(agp_memory *);
- void (*enable)(u32);
- int (*acquire)(void);
- void (*release)(void);
- void (*copy_info)(agp_kern_info *);
-} drm_agp_func_t;
-
-extern drm_agp_func_t drm_agp;
#endif
typedef struct drm_sigdata {
@@ -824,6 +811,7 @@ extern drm_agp_head_t *drm_agp_init(void);
extern void drm_agp_uninit(void);
extern int drm_agp_acquire(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern void _drm_agp_release(void);
extern int drm_agp_release(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_agp_enable(struct inode *inode, struct file *filp,
@@ -838,6 +826,10 @@ extern int drm_agp_unbind(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_agp_bind(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern agp_memory *drm_agp_allocate_memory(size_t pages, u32 type);
+extern int drm_agp_free_memory(agp_memory *handle);
+extern int drm_agp_bind_memory(agp_memory *handle, off_t start);
+extern int drm_agp_unbind_memory(agp_memory *handle);
#endif
#endif
#endif
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
index 84c7f0644..cf9a9f5d9 100644
--- a/drivers/char/drm/ffb_drv.c
+++ b/drivers/char/drm/ffb_drv.c
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.6 2000/08/10 05:26:23 davem Exp $
+/* $Id: ffb_drv.c,v 1.7 2000/11/12 10:01:41 davem Exp $
* ffb_drv.c: Creator/Creator3D direct rendering driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -244,7 +244,7 @@ static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
};
}
-static int ffb_init_one(int prom_node, int instance)
+static int __init ffb_init_one(int prom_node, int instance)
{
struct linux_prom64_registers regs[2*PROMREG_MAX];
drm_device_t *dev;
@@ -305,7 +305,7 @@ static int ffb_init_one(int prom_node, int instance)
return 0;
}
-static int ffb_init_dev_table(void)
+static int __init ffb_init_dev_table(void)
{
int root, node;
int total = 0;
@@ -324,7 +324,7 @@ static int ffb_init_dev_table(void)
return 0;
}
-int ffb_init(void)
+int __init ffb_init(void)
{
int root, node, instance, ret;
@@ -345,7 +345,7 @@ int ffb_init(void)
return 0;
}
-void ffb_cleanup(void)
+void __exit ffb_cleanup(void)
{
int instance;
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
index dba974c2b..a17bc1a9f 100644
--- a/drivers/char/drm/gamma_drv.c
+++ b/drivers/char/drm/gamma_drv.c
@@ -339,7 +339,7 @@ int gamma_find_devices(void)
/* gamma_init is called via init_module at module load time, or via
* linux/init/main.c (this is not currently supported). */
-static int gamma_init(void)
+static int __init gamma_init(void)
{
int retcode;
drm_device_t *dev = &gamma_device;
@@ -380,7 +380,7 @@ static int gamma_init(void)
/* gamma_cleanup is called via cleanup_module at module unload time. */
-static void gamma_cleanup(void)
+static void __exit gamma_cleanup(void)
{
drm_device_t *dev = &gamma_device;
diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
index ed880c41a..7152eac3a 100644
--- a/drivers/char/drm/i810_drv.c
+++ b/drivers/char/drm/i810_drv.c
@@ -255,8 +255,7 @@ static int i810_takedown(drm_device_t *dev)
}
dev->agp->memory = NULL;
- if (dev->agp->acquired && drm_agp.release)
- (*drm_agp.release)();
+ if (dev->agp->acquired) _drm_agp_release();
dev->agp->acquired = 0;
dev->agp->enabled = 0;
@@ -338,7 +337,7 @@ static int i810_takedown(drm_device_t *dev)
/* i810_init is called via init_module at module load time, or via
* linux/init/main.c (this is not currently supported). */
-static int i810_init(void)
+static int __init i810_init(void)
{
int retcode;
drm_device_t *dev = &i810_device;
@@ -397,7 +396,7 @@ static int i810_init(void)
/* i810_cleanup is called via cleanup_module at module unload time. */
-static void i810_cleanup(void)
+static void __exit i810_cleanup(void)
{
drm_device_t *dev = &i810_device;
diff --git a/drivers/char/drm/memory.c b/drivers/char/drm/memory.c
index 34d19b203..261fb34a3 100644
--- a/drivers/char/drm/memory.c
+++ b/drivers/char/drm/memory.c
@@ -352,16 +352,13 @@ agp_memory *drm_alloc_agp(int pages, u32 type)
return NULL;
}
- if (drm_agp.allocate_memory) {
- if ((handle = (*drm_agp.allocate_memory)(pages,
- type))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
- drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
- += pages << PAGE_SHIFT;
- spin_unlock(&drm_mem_lock);
- return handle;
- }
+ if ((handle = drm_agp_allocate_memory(pages, type))) {
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+ drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
+ += pages << PAGE_SHIFT;
+ spin_unlock(&drm_mem_lock);
+ return handle;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
@@ -381,8 +378,7 @@ int drm_free_agp(agp_memory *handle, int pages)
return retval;;
}
- if (drm_agp.free_memory) {
- (*drm_agp.free_memory)(handle);
+ if (drm_agp_free_memory(handle)) {
spin_lock(&drm_mem_lock);
free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count;
alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
@@ -403,24 +399,19 @@ int drm_bind_agp(agp_memory *handle, unsigned int start)
{
int retcode = -EINVAL;
- DRM_DEBUG("drm_bind_agp called\n");
if (!handle) {
DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
"Attempt to bind NULL AGP handle\n");
return retcode;
}
- DRM_DEBUG("drm_agp.bind_memory : %p\n", drm_agp.bind_memory);
- if (drm_agp.bind_memory) {
- if (!(retcode = (*drm_agp.bind_memory)(handle, start))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
- drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
- += handle->page_count << PAGE_SHIFT;
- spin_unlock(&drm_mem_lock);
- DRM_DEBUG("drm_agp.bind_memory: retcode %d\n", retcode);
- return retcode;
- }
+ if (!(retcode = drm_agp_bind_memory(handle, start))) {
+ spin_lock(&drm_mem_lock);
+ ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+ drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
+ += handle->page_count << PAGE_SHIFT;
+ spin_unlock(&drm_mem_lock);
+ return retcode;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
@@ -440,20 +431,17 @@ int drm_unbind_agp(agp_memory *handle)
return retcode;
}
- if (drm_agp.unbind_memory) {
- int c = handle->page_count;
- if ((retcode = (*drm_agp.unbind_memory)(handle)))
- return retcode;
- spin_lock(&drm_mem_lock);
- free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
- alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
- drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed += c << PAGE_SHIFT;
- spin_unlock(&drm_mem_lock);
- if (free_count > alloc_count) {
- DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
- "Excess frees: %d frees, %d allocs\n",
- free_count, alloc_count);
- }
+ if ((retcode = drm_agp_unbind_memory(handle))) return retcode;
+ spin_lock(&drm_mem_lock);
+ free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
+ alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+ drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed
+ += handle->page_count << PAGE_SHIFT;
+ spin_unlock(&drm_mem_lock);
+ if (free_count > alloc_count) {
+ DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+ "Excess frees: %d frees, %d allocs\n",
+ free_count, alloc_count);
}
return retcode;
}
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 4aaac6254..883eb75ca 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -255,8 +255,7 @@ static int mga_takedown(drm_device_t *dev)
}
dev->agp->memory = NULL;
- if (dev->agp->acquired && drm_agp.release)
- (*drm_agp.release)();
+ if (dev->agp->acquired) _drm_agp_release();
dev->agp->acquired = 0;
dev->agp->enabled = 0;
@@ -338,7 +337,7 @@ static int mga_takedown(drm_device_t *dev)
/* mga_init is called via init_module at module load time, or via
* linux/init/main.c (this is not currently supported). */
-static int mga_init(void)
+static int __init mga_init(void)
{
int retcode;
drm_device_t *dev = &mga_device;
@@ -398,7 +397,7 @@ static int mga_init(void)
/* mga_cleanup is called via cleanup_module at module unload time. */
-static void mga_cleanup(void)
+static void __exit mga_cleanup(void)
{
drm_device_t *dev = &mga_device;
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
index 9bbd254c1..6ac3d6059 100644
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -287,7 +287,7 @@ static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000);
PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000);
PRIMOUTREG(MGAREG_DMAPAD, 0);
}
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index ac6f73bcd..8a4842cf3 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -57,9 +57,9 @@ typedef struct drm_r128_init {
} drm_r128_init_t;
typedef struct drm_r128_packet {
- unsigned long *buffer;
- int count;
- int flags;
+ unsigned int *buffer;
+ int count;
+ int flags;
} drm_r128_packet_t;
typedef enum drm_r128_prim {
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index 7ae498014..969ada93f 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -252,8 +252,7 @@ static int r128_takedown(drm_device_t *dev)
}
dev->agp->memory = NULL;
- if (dev->agp->acquired && drm_agp.release)
- (*drm_agp.release)();
+ if (dev->agp->acquired) _drm_agp_release();
dev->agp->acquired = 0;
dev->agp->enabled = 0;
@@ -323,7 +322,7 @@ static int r128_takedown(drm_device_t *dev)
/* r128_init is called via init_module at module load time, or via
* linux/init/main.c (this is not currently supported). */
-static int r128_init(void)
+static int __init r128_init(void)
{
int retcode;
drm_device_t *dev = &r128_device;
@@ -387,7 +386,7 @@ static int r128_init(void)
/* r128_cleanup is called via cleanup_module at module unload time. */
-static void r128_cleanup(void)
+static void __exit r128_cleanup(void)
{
drm_device_t *dev = &r128_device;
diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c
index 5f2c804af..7d79a013b 100644
--- a/drivers/char/drm/tdfx_drv.c
+++ b/drivers/char/drm/tdfx_drv.c
@@ -235,7 +235,7 @@ static int tdfx_takedown(drm_device_t *dev)
drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS);
temp = temp_next;
}
- if (dev->agp->acquired) (*drm_agp.release)();
+ if (dev->agp->acquired) _drm_agp_release();
}
#endif
/* Clear vma list (only built for debugging) */
@@ -298,7 +298,7 @@ static int tdfx_takedown(drm_device_t *dev)
/* tdfx_init is called via init_module at module load time, or via
* linux/init/main.c (this is not currently supported). */
-static int tdfx_init(void)
+static int __init tdfx_init(void)
{
int retcode;
drm_device_t *dev = &tdfx_device;
@@ -346,7 +346,7 @@ static int tdfx_init(void)
/* tdfx_cleanup is called via cleanup_module at module unload time. */
-static void tdfx_cleanup(void)
+static void __exit tdfx_cleanup(void)
{
drm_device_t *dev = &tdfx_device;
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c
index 4196458d0..6c1ef5235 100644
--- a/drivers/char/ftape/lowlevel/ftape-ctl.c
+++ b/drivers/char/ftape/lowlevel/ftape-ctl.c
@@ -40,6 +40,9 @@
#endif
#include <asm/io.h>
+/* ease porting between pre-2.4.x and later kernels */
+#define vma_get_pgoff(v) ((v)->vm_pgoff)
+
#include "../lowlevel/ftape-tracing.h"
#include "../lowlevel/ftape-io.h"
#include "../lowlevel/ftape-ctl.h"
@@ -701,23 +704,23 @@ int ftape_mmap(struct vm_area_struct *vma)
if (ft_failure) {
TRACE_EXIT -ENODEV;
}
- if ((vma_get_flags(vma) & (VM_READ|VM_WRITE)) == 0) {
+ if (!(vma->vm_flags & (VM_READ|VM_WRITE))) {
TRACE_ABORT(-EINVAL, ft_t_err, "Undefined mmap() access");
}
if (vma_get_pgoff(vma) != 0) {
TRACE_ABORT(-EINVAL, ft_t_err, "page offset must be 0");
}
- if ((vma_get_end (vma) - vma_get_start (vma)) % FT_BUFF_SIZE != 0) {
+ if ((vma->vm_end - vma->vm_start) % FT_BUFF_SIZE != 0) {
TRACE_ABORT(-EINVAL, ft_t_err,
"size = %ld, should be a multiple of %d",
- vma_get_end (vma) - vma_get_start (vma),
+ vma->vm_end - vma->vm_start,
FT_BUFF_SIZE);
}
- num_buffers = (vma_get_end (vma) - vma_get_start (vma)) / FT_BUFF_SIZE;
+ num_buffers = (vma->vm_end - vma->vm_start) / FT_BUFF_SIZE;
if (num_buffers > ft_nr_buffers) {
TRACE_ABORT(-EINVAL,
ft_t_err, "size = %ld, should be less than %d",
- vma_get_end (vma) - vma_get_start (vma),
+ vma->vm_end - vma->vm_start,
ft_nr_buffers * FT_BUFF_SIZE);
}
if (ft_driver_state != idle) {
@@ -728,15 +731,15 @@ int ftape_mmap(struct vm_area_struct *vma)
ftape_reset_buffer();
}
for (i = 0; i < num_buffers; i++) {
- TRACE_CATCH(remap_page_range(vma_get_start (vma) +
+ TRACE_CATCH(remap_page_range(vma->vm_start +
i * FT_BUFF_SIZE,
- virt_to_phys(ft_buffer[i]->address),
+ virt_to_phys(ft_buffer[i]->address),
FT_BUFF_SIZE,
- vma_get_page_prot (vma)),
+ vma->vm_page_prot),
_res = -EAGAIN);
TRACE(ft_t_noise, "remapped dma buffer @ %p to location @ %p",
ft_buffer[i]->address,
- (void *)(vma_get_start(vma) + i * FT_BUFF_SIZE));
+ (void *)(vma->vm_start + i * FT_BUFF_SIZE));
}
for (i = 0; i < num_buffers; i++) {
memset(ft_buffer[i]->address, 0xAA, FT_BUFF_SIZE);
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 78617055e..3e8c404df 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -19,21 +19,21 @@
* best to be responsive. -- REW
* */
+#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/mm.h>
+#include <linux/generic_serial.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/generic_serial.h>
#define DEBUG
static char * tmp_buf;
static DECLARE_MUTEX(tmp_buf_sem);
-int gs_debug;
+static int gs_debug;
#ifdef DEBUG
@@ -57,30 +57,7 @@ int gs_debug;
#define RS_EVENT_WRITE_WAKEUP 1
-#ifdef MODULE
MODULE_PARM(gs_debug, "i");
-#endif
-
-#ifdef DEBUG
-static void my_hd (unsigned char *addr, int len)
-{
- int i, j, ch;
-
- for (i=0;i<len;i+=16) {
- printk ("%08x ", (int) addr+i);
- for (j=0;j<16;j++) {
- printk ("%02x %s", addr[j+i], (j==7)?" ":"");
- }
- for (j=0;j<16;j++) {
- ch = addr[j+i];
- printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
- }
- printk ("\n");
- }
-}
-#else
-#define my_hd(addr,len)
-#endif
void gs_put_char(struct tty_struct * tty, unsigned char ch)
@@ -1083,15 +1060,20 @@ void gs_getserial(struct gs_port *port, struct serial_struct *sp)
copy_to_user(sp, &sio, sizeof(struct serial_struct));
}
+EXPORT_SYMBOL(gs_put_char);
+EXPORT_SYMBOL(gs_write);
+EXPORT_SYMBOL(gs_write_room);
+EXPORT_SYMBOL(gs_chars_in_buffer);
+EXPORT_SYMBOL(gs_flush_buffer);
+EXPORT_SYMBOL(gs_flush_chars);
+EXPORT_SYMBOL(gs_stop);
+EXPORT_SYMBOL(gs_start);
+EXPORT_SYMBOL(gs_hangup);
+EXPORT_SYMBOL(gs_do_softint);
+EXPORT_SYMBOL(block_til_ready);
+EXPORT_SYMBOL(gs_close);
+EXPORT_SYMBOL(gs_set_termios);
+EXPORT_SYMBOL(gs_init_port);
+EXPORT_SYMBOL(gs_setserial);
+EXPORT_SYMBOL(gs_getserial);
-#ifdef MODULE
-int init_module (void)
-{
- return 0;
-}
-
-int cleanup_module (void)
-{
- return 0;
-}
-#endif
diff --git a/drivers/char/joystick/adi.c b/drivers/char/joystick/adi.c
index 3195fce03..a2f68d74e 100644
--- a/drivers/char/joystick/adi.c
+++ b/drivers/char/joystick/adi.c
@@ -418,7 +418,7 @@ static void adi_init_input(struct adi *adi, struct adi_port *port)
adi->dev.private = port;
adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++)
+ for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
set_bit(adi->abs[i], &adi->dev.absbit);
for (i = 0; i < adi->buttons; i++)
@@ -431,7 +431,7 @@ static void adi_init_center(struct adi *adi)
if (!adi->length) return;
- for (i = 0; i < adi->axes10 + adi->axes8 + adi->hats * 2; i++) {
+ for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
t = adi->abs[i];
x = adi->dev.abs[t];
diff --git a/drivers/char/joystick/analog.c b/drivers/char/joystick/analog.c
index 6514bef9b..dbd46fb7e 100644
--- a/drivers/char/joystick/analog.c
+++ b/drivers/char/joystick/analog.c
@@ -41,17 +41,18 @@
#include <linux/gameport.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
/*
* Option parsing.
*/
-MODULE_PARM(js,"1-16s");
-
#define ANALOG_PORTS 16
static char *js[ANALOG_PORTS];
static int analog_options[ANALOG_PORTS];
+MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
+MODULE_PARM_DESC(js, "Analog joystick options");
/*
* Times, feature definitions.
diff --git a/drivers/char/joystick/iforce.c b/drivers/char/joystick/iforce.c
index acb0bfe5b..444d4e91c 100644
--- a/drivers/char/joystick/iforce.c
+++ b/drivers/char/joystick/iforce.c
@@ -54,6 +54,7 @@ MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
struct iforce {
signed char data[IFORCE_MAX_LENGTH];
+ struct usb_device *usbdev;
struct input_dev dev;
struct urb irq;
int open;
@@ -113,9 +114,11 @@ static int iforce_open(struct input_dev *dev)
{
struct iforce *iforce = dev->private;
- if (dev->idbus == BUS_USB && !iforce->open++)
+ if (dev->idbus == BUS_USB && !iforce->open++) {
+ iforce->irq.dev = iforce->usbdev;
if (usb_submit_urb(&iforce->irq))
return -EIO;
+ }
return 0;
}
@@ -177,15 +180,12 @@ static void iforce_usb_irq(struct urb *urb)
iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1);
}
-static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum)
+static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_endpoint_descriptor *endpoint;
struct iforce *iforce;
- if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
- dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
- return NULL;
-
endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL;
@@ -216,10 +216,21 @@ static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
kfree(iforce);
}
+static struct usb_device_id iforce_usb_ids [] = {
+ {
+ idVendor: USB_VENDOR_ID_LOGITECH,
+ idProduct: USB_DEVICE_ID_LOGITECH_WMFORCE
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
+
static struct usb_driver iforce_usb_driver = {
name: "iforce",
probe: iforce_usb_probe,
disconnect: iforce_usb_disconnect,
+ id_table: iforce_usb_ids,
};
#endif
diff --git a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c
index 573eac51b..36c5d9f9e 100644
--- a/drivers/char/joystick/ns558.c
+++ b/drivers/char/joystick/ns558.c
@@ -58,7 +58,7 @@ struct ns558 {
};
static struct ns558 *ns558;
-static int have_pci_devices;
+static int ns558_pci;
/*
* ns558_isa_probe() tries to find an isa gameport at the
@@ -188,12 +188,10 @@ static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_devi
}
memset(port, 0, sizeof(struct ns558));
- port->next = ns558;
port->type = NS558_PCI;
port->gameport.io = ioport;
port->gameport.size = iolen;
port->dev = pdev;
- ns558 = port;
pdev->driver_data = port;
@@ -316,9 +314,7 @@ int __init ns558_init(void)
* it is the least-invasive probe.
*/
- i = pci_module_init(&ns558_pci_driver);
- if (i == 0)
- have_pci_devices = 1;
+ ns558_pci = !pci_module_init(&ns558_pci_driver);
/*
* Probe for ISA ports.
@@ -339,12 +335,12 @@ int __init ns558_init(void)
}
#endif
- return ns558 ? 0 : -ENODEV;
+ return (ns558 || ns558_pci) ? 0 : -ENODEV;
}
void __exit ns558_exit(void)
{
- struct ns558 *port = ns558;
+ struct ns558 *next, *port = ns558;
while (port) {
gameport_unregister_port(&port->gameport);
@@ -365,10 +361,12 @@ void __exit ns558_exit(void)
break;
}
- port = port->next;
+ next = port->next;
+ kfree(port);
+ port = next;
}
- if (have_pci_devices)
+ if (ns558_pci)
pci_unregister_driver(&ns558_pci_driver);
}
diff --git a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c
index 85be9f8b1..ae31265cb 100644
--- a/drivers/char/joystick/sidewinder.c
+++ b/drivers/char/joystick/sidewinder.c
@@ -102,7 +102,7 @@ static short sw_btn[][12] = {
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
- { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3 }};
+ { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
static struct {
int x;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 1b49e6e1b..828675d47 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -179,8 +179,11 @@ static inline int noncached_address(unsigned long addr)
* caching for the high addresses through the KEN pin, but
* we maintain the tradition of paranoia in this code.
*/
- return !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR)
- && addr >= __pa(high_memory);
+ return !( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) ||
+ test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) )
+ && addr >= __pa(high_memory);
#else
return addr >= __pa(high_memory);
#endif
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 1681ac603..2ab0563c2 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -120,7 +120,7 @@
#define CI104J_ASIC_ID 5
enum {
- MXSER_BOARD_C168_ISA = 1,
+ MXSER_BOARD_C168_ISA = 0,
MXSER_BOARD_C104_ISA,
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index e9585bcaa..3427c1421 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -9,7 +9,7 @@
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
- * ==FILEDATE 20000706==
+ * $Id: n_hdlc.c,v 3.2 2000/11/06 22:34:38 paul Exp $
*
* This code is released under the GNU General Public License (GPL)
*
@@ -78,11 +78,12 @@
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.16"
+#define HDLC_VERSION "3.2"
#include <linux/version.h>
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
@@ -93,14 +94,7 @@
#undef VERSION
#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-#if LINUX_VERSION_CODE < VERSION(2,1,14)
-#include <linux/ioport.h>
-#endif
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,23)
#include <linux/poll.h>
-#endif
-
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/tty.h>
@@ -118,86 +112,16 @@
#include <linux/kerneld.h>
#endif
-#if LINUX_VERSION_CODE < VERSION(2,3,0)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
-#define init_waitqueue_head(head) *(head) = NULL
-#define set_current_state(a) current->state = (a)
-#endif
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
#include <asm/segment.h>
#define GET_USER(error,value,addr) error = get_user(value,addr)
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
#define PUT_USER(error,value,addr) error = put_user(value,addr)
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
#include <asm/uaccess.h>
-#endif
-
-#else /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
- if (error == 0) \
- value = get_user(addr); \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_READ, (void *) src, size); \
- if (error == 0) \
- memcpy_fromfs (dest, src, size); \
-} while (0)
-
-#define PUT_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
- if (error == 0) \
- put_user (value, addr); \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) dest, size); \
- if (error == 0) \
- memcpy_tofs (dest, src, size); \
-} while (0)
-
-#endif
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-#define __init
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,37)
-#define test_and_set_bit(nr, addr) set_bit(nr, addr)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,57)
-#define signal_pending(p) ((p)->signal & ~(p)->blocked)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,25)
-#define net_device_stats enet_statistics
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,60)
-typedef int rw_ret_t;
-typedef unsigned int rw_count_t;
-#else
typedef ssize_t rw_ret_t;
typedef size_t rw_count_t;
-#endif
/*
* Buffers for individual HDLC frames
@@ -261,10 +185,9 @@ N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list);
static struct n_hdlc *n_hdlc_alloc (void);
-#if LINUX_VERSION_CODE >= VERSION(2,1,19)
MODULE_PARM(debuglevel, "i");
MODULE_PARM(maxframe, "i");
-#endif
+
/* debug level can be set by insmod for debugging purposes */
#define DEBUG_LEVEL_INFO 1
@@ -281,13 +204,8 @@ static rw_ret_t n_hdlc_tty_write(struct tty_struct *,
struct file *, const __u8 *, rw_count_t);
static int n_hdlc_tty_ioctl(struct tty_struct *,
struct file *, unsigned int, unsigned long);
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
- struct file *filp, int sel_type, select_table * wait);
-#else
static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp,
poll_table * wait);
-#endif
static int n_hdlc_tty_open (struct tty_struct *);
static void n_hdlc_tty_close (struct tty_struct *);
static int n_hdlc_tty_room (struct tty_struct *tty);
@@ -660,11 +578,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
wake_up_interruptible (&n_hdlc->read_wait);
wake_up_interruptible (&n_hdlc->poll_wait);
if (n_hdlc->tty->fasync != NULL)
-#if LINUX_VERSION_CODE < VERSION(2,3,0)
- kill_fasync (n_hdlc->tty->fasync, SIGIO);
-#else
kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
-#endif
+
} /* end of n_hdlc_tty_receive() */
/* n_hdlc_tty_read()
@@ -893,73 +808,6 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
} /* end of n_hdlc_tty_ioctl() */
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-/* n_hdlc_tty_select()
- *
- * Device select method. Determine if operation requires
- * blocking and if so put appropriate wait queue in select
- * table and return 0, otherwise return 1.
- *
- * Arguments:
- *
- * tty pointer to tty device instance data
- * inode pointer to inode for device
- * filp pointer to file object
- * sel_type identified the select type (read/write/exception)
- * wait select table for adding wait queue if appropriate
- *
- * Return Value:
- *
- * 1 if no need to block on operation
- * 0 if must block and wait queue added to select table
- */
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
- struct file *filp, int sel_type, select_table * wait)
-{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
- int result = 1;
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__);
-
- /* Verify the status of the device */
- if (!n_hdlc)
- return -EBADF;
-
- if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty)
- return -EBADF;
-
- switch (sel_type) {
- case SEL_IN:
- if (n_hdlc->rx_buf_list.head)
- break;
-
- case SEL_EX: /* Exceptions or read errors */
- /* Is this a pty link and the remote disconnected? */
- if (tty->flags & (1 << TTY_OTHER_CLOSED))
- break;
-
- /* Is this a local link and the modem disconnected? */
- if (tty_hung_up_p (filp))
- break;
-
- select_wait (&n_hdlc->read_wait, wait);
- result = 0;
- break;
-
- /* Write mode. A write is allowed if there is no current transmission */
- case SEL_OUT:
- if (!n_hdlc->tx_free_buf_list.head) {
- select_wait (&n_hdlc->write_wait, wait);
- result = 0;
- }
- break;
- }
- return result;
-} /* end of n_hdlc_tty_select() */
-
-#else /* 2.1.23 or later */
-
/* n_hdlc_tty_poll()
*
* TTY callback for poll system call. Determine which
@@ -988,11 +836,8 @@ static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
/* queue current process into any wait queue that */
/* may awaken in the future (read and write) */
-#if LINUX_VERSION_CODE < VERSION(2,1,89)
- poll_wait(&n_hdlc->poll_wait, wait);
-#else
poll_wait(filp, &n_hdlc->poll_wait, wait);
-#endif
+
/* set bits for operations that wont block */
if(n_hdlc->rx_buf_list.head)
mask |= POLLIN | POLLRDNORM; /* readable */
@@ -1006,8 +851,6 @@ static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
return mask;
} /* end of n_hdlc_tty_poll() */
-#endif
-
/* n_hdlc_alloc()
*
* Allocate an n_hdlc instance data structure
@@ -1135,14 +978,7 @@ N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list)
} /* end of n_hdlc_buf_get() */
-/* init_module()
- *
- * called when module is loading to register line discipline
- *
- * Arguments: None
- * Return Value: 0 if success, otherwise error code
- */
-int init_module(void)
+static int __init n_hdlc_init(void)
{
static struct tty_ldisc n_hdlc_ldisc;
int status;
@@ -1160,19 +996,13 @@ int init_module(void)
memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc));
n_hdlc_ldisc.magic = TTY_LDISC_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,28)
n_hdlc_ldisc.name = "hdlc";
-#endif
n_hdlc_ldisc.open = n_hdlc_tty_open;
n_hdlc_ldisc.close = n_hdlc_tty_close;
n_hdlc_ldisc.read = n_hdlc_tty_read;
n_hdlc_ldisc.write = n_hdlc_tty_write;
n_hdlc_ldisc.ioctl = n_hdlc_tty_ioctl;
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
- n_hdlc_ldisc.select = n_hdlc_tty_select;
-#else
n_hdlc_ldisc.poll = n_hdlc_tty_poll;
-#endif
n_hdlc_ldisc.receive_room = n_hdlc_tty_room;
n_hdlc_ldisc.receive_buf = n_hdlc_tty_receive;
n_hdlc_ldisc.write_wakeup = n_hdlc_tty_wakeup;
@@ -1189,14 +1019,7 @@ int init_module(void)
} /* end of init_module() */
-/* cleanup_module()
- *
- * called when module is unloading to unregister line discipline
- *
- * Arguments: None
- * Return Value: None
- */
-void cleanup_module(void)
+static void __exit n_hdlc_exit(void)
{
int status;
/* Release tty registration of line discipline */
@@ -1205,3 +1028,6 @@ void cleanup_module(void)
else
printk("N_HDLC: line discipline unregistered\n");
}
+
+module_init(n_hdlc_init);
+module_exit(n_hdlc_exit);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index bf1242e35..bbd5aff21 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -710,7 +710,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
int entropy = 0;
#if defined (__i386__)
- if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+ if ( test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability) ) {
__u32 high;
__asm__(".byte 0x0f,0x31"
:"=a" (time), "=d" (high));
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 7ff56f84f..6b0e3d298 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -1103,8 +1103,6 @@ void fix_rio_pci (PDEV)
#define rio_init init_module
#endif
-extern int gs_debug;
-
int rio_init(void)
{
int found = 0;
@@ -1129,7 +1127,6 @@ int rio_init(void)
func_enter();
rio_dprintk (RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n",
rio_debug);
- gs_debug = rio_debug >> 24;
if (abs ((long) (&rio_debug) - rio_debug) < 0x10000) {
printk (KERN_WARNING "rio: rio_debug is an address, instead of a value. "
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index d916a6aba..c249cb559 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -654,7 +654,7 @@ static int __init rtc_init(void)
}
}
}
- printk("rtc_init: no PC rtc found\n");
+ printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
found:
@@ -670,7 +670,7 @@ found:
* Standard way for sparc to print irq's is to use
* __irq_itoa(). I think for EBus it's ok to use %d.
*/
- printk("rtc: cannot register IRQ %d\n", rtc_irq);
+ printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
return -EIO;
}
#else
@@ -725,7 +725,7 @@ found:
guess = "Digital DECstation";
}
if (guess)
- printk("rtc: %s epoch (%lu) detected\n", guess, epoch);
+ printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
#endif
#if RTC_IRQ
init_timer(&rtc_irq_timer);
@@ -792,7 +792,7 @@ static void rtc_dropped_irq(unsigned long data)
spin_unlock_irq(&rtc_lock);
- printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", freq);
+ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);
/* Now we have new data */
wake_up_interruptible(&rtc_wait);
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 3dd5811d9..902642151 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -1756,16 +1756,12 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
sx_initialized++;
break;
case SXIO_SETDEBUG:
+ case SXIO_SETGSDEBUG:
sx_debug = arg;
break;
case SXIO_GETDEBUG:
- rc = sx_debug;
- break;
- case SXIO_SETGSDEBUG:
- gs_debug = arg;
- break;
case SXIO_GETGSDEBUG:
- rc = gs_debug;
+ rc = sx_debug;
break;
case SXIO_GETNPORTS:
rc = sx_nports;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 6da32381e..156c683e4 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * ==FILEDATE 20000707==
+ * $Id: synclink.c,v 3.2 2000/11/06 22:34:38 paul Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -82,13 +82,9 @@
#include <linux/netdevice.h>
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <asm/serial.h>
-#else
-#include <linux/bios32.h>
-#endif
#include <linux/delay.h>
#include <linux/ioctl.h>
@@ -102,98 +98,21 @@
#include <linux/termios.h>
#include <linux/tqueue.h>
-#if LINUX_VERSION_CODE < VERSION(2,3,0)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
-#define init_waitqueue_head(head) *(head) = NULL
-#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX
-#define set_current_state(a) current->state = (a)
-#endif
-
#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
#define CONFIG_SYNCLINK_SYNCPPP 1
#endif
#ifdef CONFIG_SYNCLINK_SYNCPPP
-#if LINUX_VERSION_CODE < VERSION(2,3,43)
-#include "../net/syncppp.h"
-#define net_device device
-#define netif_stop_queue(a) (a)->tbusy = 1
-#define netif_start_queue(a) (a)->tbusy = 0
-#define netif_wake_queue(a) (a)->tbusy = 0; mark_bh(NET_BH)
-#define netif_queue_stopped(a) ((a)->tbusy)
-#else
#include "../net/wan/syncppp.h"
#endif
-#endif
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
#include <asm/segment.h>
#define GET_USER(error,value,addr) error = get_user(value,addr)
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
#define PUT_USER(error,value,addr) error = put_user(value,addr)
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
#include <asm/uaccess.h>
-#endif
-
-#else /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
- if (error == 0) \
- value = get_user(addr); \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_READ, (void *) src, size); \
- if (error == 0) \
- memcpy_fromfs (dest, src, size); \
-} while (0)
-
-#define PUT_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
- if (error == 0) \
- put_user (value, addr); \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) dest, size); \
- if (error == 0) \
- memcpy_tofs (dest, src, size); \
-} while (0)
-
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-#define __init
-#define ioremap(a,b) vremap((a),(b))
-#define iounmap(a) vfree((a))
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#define signal_pending(a) ((a)->signal & ~(a)->blocked)
-#endif
-
-
#include "linux/synclink.h"
@@ -365,10 +284,12 @@ struct mgsl_struct {
u32 last_mem_alloc;
unsigned char* memory_base; /* shared memory address (PCI only) */
u32 phys_memory_base;
+ int shared_mem_requested;
unsigned char* lcr_base; /* local config registers (PCI only) */
u32 phys_lcr_base;
u32 lcr_offset;
+ int lcr_mem_requested;
u32 misc_ctrl_value;
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
@@ -389,10 +310,8 @@ struct mgsl_struct {
char netname[10];
struct net_device *netdev;
struct net_device_stats netstats;
-#if LINUX_VERSION_CODE >= VERSION(2,2,16)
struct net_device netdevice;
#endif
-#endif
};
#define MGSL_MAGIC 0x5401
@@ -845,7 +764,7 @@ int mgsl_claim_resources(struct mgsl_struct *info);
void mgsl_release_resources(struct mgsl_struct *info);
void mgsl_add_device(struct mgsl_struct *info);
struct mgsl_struct* mgsl_allocate_device(void);
-int mgsl_enumerate_devices(void);
+int mgsl_enum_isa_devices(void);
/*
* DMA buffer manupulation functions.
@@ -952,7 +871,6 @@ static int debug_level = 0;
static int maxframe[MAX_TOTAL_DEVICES] = {0,};
static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
MODULE_PARM(break_on_load,"i");
MODULE_PARM(ttymajor,"i");
MODULE_PARM(cuamajor,"i");
@@ -962,10 +880,26 @@ MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
MODULE_PARM(debug_level,"i");
MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
-#endif
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.21";
+static char *driver_version = "3.2";
+
+static int __init synclink_init_one (struct pci_dev *dev,
+ const struct pci_device_id *ent);
+static void __exit synclink_remove_one (struct pci_dev *dev);
+
+static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);
+
+static struct pci_driver synclink_pci_driver = {
+ name: "synclink",
+ id_table: synclink_pci_tbl,
+ probe: synclink_init_one,
+ remove: synclink_remove_one,
+};
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
@@ -977,9 +911,9 @@ static int serial_refcount;
static void mgsl_change_params(struct mgsl_struct *info);
static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);
-static struct tty_struct **serial_table = NULL;
-static struct termios **serial_termios = NULL;
-static struct termios **serial_termios_locked = NULL;
+static struct tty_struct *serial_table[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES];
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -1591,16 +1525,9 @@ void mgsl_isr_receive_data( struct mgsl_struct *info )
icount->parity,icount->frame,icount->overrun);
}
- if ( tty->flip.count ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+ if ( tty->flip.count )
tty_flip_buffer_push(tty);
-#else
- queue_task(&tty->flip.tqueue, &tq_timer);
-#endif
- }
-
-
-} /* end of mgsl_isr_receive_data() */
+}
/* mgsl_isr_misc()
*
@@ -1795,11 +1722,7 @@ static int startup(struct mgsl_struct * info)
retval = mgsl_adapter_test(info);
if ( retval ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
if (capable(CAP_SYS_ADMIN) && info->tty)
-#else
- if (suser() && info->tty)
-#endif
set_bit(TTY_IO_ERROR, &info->tty->flags);
mgsl_release_resources(info);
return retval;
@@ -1974,21 +1897,8 @@ static void mgsl_change_params(struct mgsl_struct *info)
* allow tty settings to override, otherwise keep the
* current data rate.
*/
- if (info->params.data_rate <= 460800) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+ if (info->params.data_rate <= 460800)
info->params.data_rate = tty_get_baud_rate(info->tty);
-#else
- int i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- info->params.data_rate = baud_table[i];
-#endif
- }
if ( info->params.data_rate ) {
info->timeout = (32*HZ*bits_per_char) /
@@ -2950,7 +2860,6 @@ static int set_modem_info(struct mgsl_struct * info, unsigned int cmd,
} /* end of set_modem_info() */
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
/* mgsl_break() Set or clear transmit break condition
*
* Arguments: tty pointer to tty instance data
@@ -2977,7 +2886,6 @@ static void mgsl_break(struct tty_struct *tty, int break_state)
spin_unlock_irqrestore(&info->irq_spinlock,flags);
} /* end of mgsl_break() */
-#endif
/* mgsl_ioctl() Service an IOCTL request
*
@@ -3100,7 +3008,6 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long
if (error) return error;
PUT_USER(error,cnow.dcd, &p_cuser->dcd);
if (error) return error;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
PUT_USER(error,cnow.rx, &p_cuser->rx);
if (error) return error;
PUT_USER(error,cnow.tx, &p_cuser->tx);
@@ -3115,7 +3022,6 @@ int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long
if (error) return error;
PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
if (error) return error;
-#endif
return 0;
default:
return -ENOIOCTLCMD;
@@ -3596,9 +3502,7 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
tmp_buf = (unsigned char *) page;
}
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-#endif
spin_lock_irqsave(&info->netlock, flags);
if (info->netcount) {
@@ -3985,22 +3889,14 @@ int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
} /* end of mgsl_alloc_buffer_list_memory() */
-/*
- * mgsl_free_buffer_list_memory()
- *
- * Free the common DMA buffer allocated for use as the
- * receive and transmit buffer lists. The associated Memory
- * Descriptor List (MDL) is also freed.
- *
+/* Free DMA buffers allocated for use as the
+ * receive and transmit buffer lists.
* Warning:
*
* The data transfer buffers associated with the buffer list
* MUST be freed before freeing the buffer list itself because
* the buffer list contains the information necessary to free
* the individual buffers!
- *
- * Arguments: info pointer to device extension
- * Return Value: None
*/
void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
{
@@ -4138,67 +4034,61 @@ int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info)
void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info)
{
if ( info->intermediate_rxbuffer )
- kfree( info->intermediate_rxbuffer );
+ kfree(info->intermediate_rxbuffer);
info->intermediate_rxbuffer = NULL;
} /* end of mgsl_free_intermediate_rxbuffer_memory() */
-/* mgsl_claim_resources()
- *
- * Claim all resources used by a device
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise -ENODEV
- */
int mgsl_claim_resources(struct mgsl_struct *info)
{
- /* claim 16C32 I/O base address */
-
- if ( check_region(info->io_base,info->io_addr_size) < 0 ) {
+ if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) {
printk( "%s(%d):I/O address conflict on device %s Addr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->io_base );
+ __FILE__,__LINE__,info->device_name, info->io_base);
return -ENODEV;
}
- request_region(info->io_base,info->io_addr_size,"synclink.o");
info->io_addr_requested = 1;
- /* claim interrupt level */
-
if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags,
info->device_name, info ) < 0 ) {
printk( "%s(%d):Cant request interrupt on device %s IRQ=%d\n",
__FILE__,__LINE__,info->device_name, info->irq_level );
- mgsl_release_resources( info );
- return -ENODEV;
+ goto errout;
}
info->irq_requested = 1;
if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* claim shared memory range */
+ if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) {
+ printk( "%s(%d):mem addr conflict device %s Addr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_memory_base);
+ goto errout;
+ }
+ info->shared_mem_requested = 1;
+ if (request_mem_region(info->phys_lcr_base,128,"synclink") == NULL) {
+ printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
+ __FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+ goto errout;
+ }
+ info->lcr_mem_requested = 1;
+
info->memory_base = ioremap(info->phys_memory_base,0x40000);
if (!info->memory_base) {
printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
- mgsl_release_resources( info );
- return -ENODEV;
+ goto errout;
}
- /* test the shared memory range */
if ( !mgsl_memory_test(info) ) {
printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
- mgsl_release_resources( info );
- return -ENODEV;
+ goto errout;
}
- /* claim LCR memory range */
info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
if (!info->lcr_base) {
printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
- mgsl_release_resources( info );
- return -ENODEV;
+ goto errout;
}
} else {
@@ -4220,21 +4110,16 @@ int mgsl_claim_resources(struct mgsl_struct *info)
if ( mgsl_allocate_dma_buffers(info) < 0 ) {
printk( "%s(%d):Cant allocate DMA buffers on device %s DMA=%d\n",
__FILE__,__LINE__,info->device_name, info->dma_level );
- mgsl_release_resources( info );
- return -ENODEV;
+ goto errout;
}
return 0;
-
+errout:
+ mgsl_release_resources(info);
+ return ENODEV;
+
} /* end of mgsl_claim_resources() */
-/* mgsl_release_resources()
- *
- * Release all resources used by a device
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
void mgsl_release_resources(struct mgsl_struct *info)
{
if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -4245,7 +4130,6 @@ void mgsl_release_resources(struct mgsl_struct *info)
free_irq(info->irq_level, info);
info->irq_requested = 0;
}
-
if ( info->dma_requested ) {
disable_dma(info->dma_level);
free_dma(info->dma_level);
@@ -4258,12 +4142,18 @@ void mgsl_release_resources(struct mgsl_struct *info)
release_region(info->io_base,info->io_addr_size);
info->io_addr_requested = 0;
}
-
+ if ( info->shared_mem_requested ) {
+ release_mem_region(info->phys_memory_base,0x40000);
+ info->shared_mem_requested = 0;
+ }
+ if ( info->lcr_mem_requested ) {
+ release_mem_region(info->phys_lcr_base,128);
+ info->lcr_mem_requested = 0;
+ }
if (info->memory_base){
iounmap(info->memory_base);
info->memory_base = 0;
}
-
if (info->lcr_base){
iounmap(info->lcr_base - info->lcr_offset);
info->lcr_base = 0;
@@ -4367,210 +4257,23 @@ struct mgsl_struct* mgsl_allocate_device()
} /* end of mgsl_allocate_device()*/
-/* mgsl_enumerate_devices()
- *
- * Enumerate SyncLink serial devices based on user specified
- * options for ISA adapters and autodetected PCI adapters.
- *
- * Arguments: None
- * Return Value: 0 if success, otherwise error code
- */
-int mgsl_enumerate_devices()
-{
- struct mgsl_struct *info;
- int i;
-
- /* Check for user specified ISA devices */
-
- for (i=0 ;(i < MAX_ISA_DEVICES) && io[i] && irq[i]; i++){
- if ( debug_level >= DEBUG_LEVEL_INFO )
- printk("ISA device specified io=%04X,irq=%d,dma=%d\n",
- io[i], irq[i], dma[i] );
-
- info = mgsl_allocate_device();
- if ( !info ) {
- /* error allocating device instance data */
- if ( debug_level >= DEBUG_LEVEL_ERROR )
- printk( "can't allocate device instance data.\n");
- continue;
- }
-
- /* Copy user configuration info to device instance data */
- info->io_base = (unsigned int)io[i];
- info->irq_level = (unsigned int)irq[i];
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
- info->irq_level = irq_cannonicalize(info->irq_level);
-#else
- if (info->irq_level == 2)
- info->irq_level = 9;
-#endif
- info->dma_level = (unsigned int)dma[i];
- info->bus_type = MGSL_BUS_TYPE_ISA;
- info->io_addr_size = 16;
- info->irq_flags = 0;
-
- mgsl_add_device( info );
- }
-
-
-#ifdef CONFIG_PCI
- /* Auto detect PCI adapters */
-
- if ( pcibios_present() ) {
- unsigned char bus;
- unsigned char func;
- unsigned int shared_mem_base;
- unsigned int lcr_mem_base;
- unsigned int io_base;
- unsigned char irq_line;
-
- for(i=0;;i++){
- if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
- MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
- struct pci_dev *pdev = pci_find_slot(bus,func);
- irq_line = pdev->irq;
-#else
- if (pcibios_read_config_byte(bus,func,
- PCI_INTERRUPT_LINE,&irq_line) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-#endif
-
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
- printk( "%s(%d):Shared mem addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_0,&lcr_mem_base) ) {
- printk( "%s(%d):LCR mem addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_2,&io_base) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
- info = mgsl_allocate_device();
- if ( !info ) {
- /* error allocating device instance data */
- if ( debug_level >= DEBUG_LEVEL_ERROR )
- printk( "can't allocate device instance data.\n");
- continue;
- }
-
- /* Copy user configuration info to device instance data */
-
- info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK;
- info->irq_level = (unsigned int)irq_line;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
- info->irq_level = irq_cannonicalize(info->irq_level);
-#else
- if (info->irq_level == 2)
- info->irq_level = 9;
-#endif
- info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
-
- /* Because veremap only works on page boundaries we must map
- * a larger area than is actually implemented for the LCR
- * memory range. We map a full page starting at the page boundary.
- */
- info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
- info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1);
- info->phys_lcr_base &= ~(PAGE_SIZE-1);
-
- info->bus_type = MGSL_BUS_TYPE_PCI;
- info->io_addr_size = 8;
- info->irq_flags = SA_SHIRQ;
- info->bus = bus;
- info->function = func;
-
- /* Store the PCI9050 misc control register value because a flaw
- * in the PCI9050 prevents LCR registers from being read if
- * BIOS assigns an LCR base address with bit 7 set.
- *
- * Only the misc control register is accessed for which only
- * write access is needed, so set an initial value and change
- * bits to the device instance data as we write the value
- * to the actual misc control register.
- */
- info->misc_ctrl_value = 0x087e4546;
-
- /* add new device to device list */
- mgsl_add_device( info );
- } else {
- break;
- }
- }
- }
-#endif
-
- /*
- * Allocate memory to hold the following tty/termios arrays
- * with an element for each enumerated device.
- */
-
- serial_table = (struct tty_struct**)kmalloc(sizeof(struct tty_struct*)*mgsl_device_count, GFP_KERNEL);
- serial_termios = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
- serial_termios_locked = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
-
- if (!serial_table || !serial_termios || !serial_termios_locked){
- printk("%s(%d):Can't allocate tty/termios arrays.\n",
- __FILE__,__LINE__);
- return -ENOMEM;
- }
-
- memset(serial_table,0,sizeof(struct tty_struct*)*mgsl_device_count);
- memset(serial_termios,0,sizeof(struct termios*)*mgsl_device_count);
- memset(serial_termios_locked,0,sizeof(struct termios*)*mgsl_device_count);
-
- return 0;
-
-} /* end of mgsl_enumerate_devices() */
-
-/* mgsl_init()
- *
- * Driver initialization entry point.
- *
- * Arguments: None
- * Return Value: 0 if success, otherwise error code
+/*
+ * perform tty device initialization
*/
-int __init mgsl_init(void)
+int mgsl_init_tty(void);
+int mgsl_init_tty()
{
struct mgsl_struct *info;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
- EXPORT_NO_SYMBOLS;
-#else
- register_symtab(NULL);
-#endif
-
- printk("%s version %s\n", driver_name, driver_version);
-
- /* determine how many SyncLink devices are installed */
- mgsl_enumerate_devices();
- if ( !mgsl_device_list ) {
- printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
- return -ENODEV;
- }
+ memset(serial_table,0,sizeof(struct tty_struct*)*MAX_TOTAL_DEVICES);
+ memset(serial_termios,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
+ memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
/* Initialize the tty_driver structure */
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
serial_driver.driver_name = "synclink";
-#endif
serial_driver.name = "ttySL";
serial_driver.major = ttymajor;
serial_driver.minor_start = 64;
@@ -4597,12 +4300,10 @@ int __init mgsl_init(void)
serial_driver.ioctl = mgsl_ioctl;
serial_driver.throttle = mgsl_throttle;
serial_driver.unthrottle = mgsl_unthrottle;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
serial_driver.send_xchar = mgsl_send_xchar;
serial_driver.break_ctl = mgsl_break;
serial_driver.wait_until_sent = mgsl_wait_until_sent;
serial_driver.read_proc = mgsl_read_proc;
-#endif
serial_driver.set_termios = mgsl_set_termios;
serial_driver.stop = mgsl_stop;
serial_driver.start = mgsl_start;
@@ -4616,10 +4317,8 @@ int __init mgsl_init(void)
callout_driver.name = "cuaSL";
callout_driver.major = cuamajor;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
callout_driver.read_proc = 0;
callout_driver.proc_entry = 0;
-#endif
if (tty_register_driver(&serial_driver) < 0)
printk("%s(%d):Couldn't register serial driver\n",
@@ -4641,13 +4340,76 @@ int __init mgsl_init(void)
info->normal_termios = serial_driver.init_termios;
info = info->next_device;
}
+
+ return 0;
+}
+
+/* enumerate user specified ISA adapters
+ */
+int mgsl_enum_isa_devices()
+{
+ struct mgsl_struct *info;
+ int i;
+
+ /* Check for user specified ISA devices */
+
+ for (i=0 ;(i < MAX_ISA_DEVICES) && io[i] && irq[i]; i++){
+ if ( debug_level >= DEBUG_LEVEL_INFO )
+ printk("ISA device specified io=%04X,irq=%d,dma=%d\n",
+ io[i], irq[i], dma[i] );
+
+ info = mgsl_allocate_device();
+ if ( !info ) {
+ /* error allocating device instance data */
+ if ( debug_level >= DEBUG_LEVEL_ERROR )
+ printk( "can't allocate device instance data.\n");
+ continue;
+ }
+
+ /* Copy user configuration info to device instance data */
+ info->io_base = (unsigned int)io[i];
+ info->irq_level = (unsigned int)irq[i];
+ info->irq_level = irq_cannonicalize(info->irq_level);
+ info->dma_level = (unsigned int)dma[i];
+ info->bus_type = MGSL_BUS_TYPE_ISA;
+ info->io_addr_size = 16;
+ info->irq_flags = 0;
+
+ mgsl_add_device( info );
+ }
return 0;
+}
+
+/* mgsl_init()
+ *
+ * Driver initialization entry point.
+ *
+ * Arguments: None
+ * Return Value: 0 if success, otherwise error code
+ */
+int __init mgsl_init(void)
+{
+ int rc;
+
+ EXPORT_NO_SYMBOLS;
+
+ printk("%s version %s\n", driver_name, driver_version);
-} /* end of mgsl_init() */
+ mgsl_enum_isa_devices();
+ pci_register_driver(&synclink_pci_driver);
-#ifdef MODULE
-int init_module(void)
+ if ( !mgsl_device_list ) {
+ printk("%s(%d):No SyncLink devices found.\n",__FILE__,__LINE__);
+ return -ENODEV;
+ }
+ if ((rc = mgsl_init_tty()))
+ return rc;
+
+ return 0;
+}
+
+static int __init synclink_init(void)
{
/* Uncomment this to kernel debug module.
* mgsl_get_text_ptr() leaves the .text address in eax
@@ -4661,7 +4423,7 @@ int init_module(void)
return mgsl_init();
}
-void cleanup_module(void)
+static void __exit synclink_exit(void)
{
unsigned long flags;
int rc;
@@ -4693,19 +4455,11 @@ void cleanup_module(void)
tmp_buf = NULL;
}
- if (serial_table)
- kfree(serial_table);
-
- if (serial_termios)
- kfree(serial_termios);
-
- if (serial_termios_locked)
- kfree(serial_termios_locked);
-
-} /* end of cleanup_module() */
-
-#endif /* MODULE */
+ pci_unregister_driver(&synclink_pci_driver);
+}
+module_init(synclink_init);
+module_exit(synclink_exit);
/*
* usc_RTCmd()
@@ -6953,7 +6707,6 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
while( EndTime-- && !info->irq_occurred ) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(jiffies_from_ms(10));
- set_current_state(TASK_RUNNING);
}
spin_lock_irqsave(&info->irq_spinlock,flags);
@@ -7567,16 +7320,13 @@ void mgsl_sppp_init(struct mgsl_struct *info)
sprintf(info->netname,"mgsl%d",info->line);
-#if LINUX_VERSION_CODE < VERSION(2,2,16)
- info->netdev = &info->pppdev.dev;
-#else
info->if_ptr = &info->pppdev;
info->netdev = info->pppdev.dev = &info->netdevice;
-#endif
+
sppp_attach(&info->pppdev);
d = info->netdev;
- strcpy(d->name, info->netname);
+ strcpy(d->name,info->netname);
d->base_addr = info->io_base;
d->irq = info->irq_level;
d->dma = info->dma_level;
@@ -7587,10 +7337,9 @@ void mgsl_sppp_init(struct mgsl_struct *info)
d->hard_start_xmit = mgsl_sppp_tx;
d->do_ioctl = mgsl_sppp_ioctl;
d->get_stats = mgsl_net_stats;
-#if LINUX_VERSION_CODE >= VERSION(2,3,43)
d->tx_timeout = mgsl_sppp_tx_timeout;
d->watchdog_timeo = 10*HZ;
-#endif
+
dev_init_buffers(d);
if (register_netdev(d) == -1) {
@@ -7680,17 +7429,7 @@ int mgsl_sppp_tx(struct sk_buff *skb, struct net_device *dev)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgsl_sppp_tx(%s)\n",info->netname);
-#if LINUX_VERSION_CODE < VERSION(2,3,43)
- if (dev->tbusy) {
- if (time_before(jiffies, dev->trans_start+10*HZ))
- return -EBUSY; /* 10 seconds timeout */
- mgsl_sppp_tx_timeout(dev);
- }
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- return -EBUSY;
-#else
netif_stop_queue(dev);
-#endif
info->xmit_cnt = skb->len;
mgsl_load_tx_dma_buffer(info, skb->data, skb->len);
@@ -7777,3 +7516,57 @@ int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */
+
+static int __init synclink_init_one (struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct mgsl_struct *info;
+
+ if (pci_enable_device(dev)) {
+ printk("error enabling pci device %p\n", dev);
+ return -EIO;
+ }
+
+ if (!(info = mgsl_allocate_device())) {
+ printk("can't allocate device instance data.\n");
+ return -EIO;
+ }
+
+ /* Copy user configuration info to device instance data */
+
+ info->io_base = pci_resource_start(dev, 2);
+ info->irq_level = dev->irq;
+ info->phys_memory_base = pci_resource_start(dev, 3);
+
+ /* Because veremap only works on page boundaries we must map
+ * a larger area than is actually implemented for the LCR
+ * memory range. We map a full page starting at the page boundary.
+ */
+ info->phys_lcr_base = pci_resource_start(dev, 0);
+ info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1);
+ info->phys_lcr_base &= ~(PAGE_SIZE-1);
+
+ info->bus_type = MGSL_BUS_TYPE_PCI;
+ info->io_addr_size = 8;
+ info->irq_flags = SA_SHIRQ;
+
+ /* Store the PCI9050 misc control register value because a flaw
+ * in the PCI9050 prevents LCR registers from being read if
+ * BIOS assigns an LCR base address with bit 7 set.
+ *
+ * Only the misc control register is accessed for which only
+ * write access is needed, so set an initial value and change
+ * bits to the device instance data as we write the value
+ * to the actual misc control register.
+ */
+ info->misc_ctrl_value = 0x087e4546;
+
+ mgsl_add_device(info);
+
+ return 0;
+}
+
+static void __exit synclink_remove_one (struct pci_dev *dev)
+{
+}
+
diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c
index 76ddf7c38..8389039d6 100644
--- a/drivers/i2o/i2o_block.c
+++ b/drivers/i2o/i2o_block.c
@@ -584,7 +584,6 @@ static int i2ob_evt(void *dummy)
int i;
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
@@ -593,6 +592,7 @@ static int i2ob_evt(void *dummy)
while(1)
{
+#warning "RACE"
interruptible_sleep_on(&i2ob_evt_wait);
if(signal_pending(current)) {
evt_running = 0;
diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c
index 87871fa15..e9942c614 100644
--- a/drivers/i2o/i2o_core.c
+++ b/drivers/i2o/i2o_core.c
@@ -842,7 +842,6 @@ static int i2o_core_evt(void *reply_data)
int flags;
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
@@ -1005,7 +1004,6 @@ static int i2o_dyn_lct(void *foo)
char name[16];
lock_kernel();
- exit_files(current);
daemonize();
unlock_kernel();
diff --git a/drivers/i2o/i2o_proc.c b/drivers/i2o/i2o_proc.c
index 4c92ff09d..dc70e7322 100644
--- a/drivers/i2o/i2o_proc.c
+++ b/drivers/i2o/i2o_proc.c
@@ -3237,7 +3237,7 @@ static void i2o_proc_remove_controller(struct i2o_controller *pctrl,
for(dev=pctrl->devices; dev; dev=dev->next)
i2o_proc_remove_device(dev);
- if(!pctrl->proc_entry->count)
+ if(!atomic_read(&pctrl->proc_entry->count))
{
sprintf(buff, "iop%d", pctrl->unit);
@@ -3257,7 +3257,7 @@ void i2o_proc_remove_device(struct i2o_device *dev)
i2o_device_notify_off(dev, &i2o_proc_handler);
/* Would it be safe to remove _files_ even if they are in use? */
- if((de) && (!de->count))
+ if((de) && (!atomic_read(&de->count)))
{
i2o_proc_remove_entries(generic_dev_entries, de);
switch(dev->lct_data.class_id)
@@ -3334,7 +3334,7 @@ static int __exit destroy_i2o_procfs(void)
}
}
- if(!i2o_proc_dir_root->count)
+ if(!atomic_read(&i2o_proc_dir_root->count))
remove_proc_entry("i2o", 0);
else
return -1;
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index d5b4b637e..f85ab2aa4 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -31,7 +31,7 @@ ide-obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
ide-obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
ide-obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HD) += hd.o
+obj-$(CONFIG_BLK_DEV_HD) += hd.o
ide-obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
ide-obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
ide-obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
index 813aecd3b..abf08c5a0 100644
--- a/drivers/ide/alim15x3.c
+++ b/drivers/ide/alim15x3.c
@@ -691,7 +691,7 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
}
}
-void ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
{
if ((dmabase) && (m5229_revision < 0x20)) {
return;
diff --git a/drivers/ide/amd7409.c b/drivers/ide/amd7409.c
index ca23d3af4..d03f63b9f 100644
--- a/drivers/ide/amd7409.c
+++ b/drivers/ide/amd7409.c
@@ -464,7 +464,7 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase)
{
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index 698112b35..ca3a5c72b 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -723,7 +723,7 @@ static struct block_device_operations hd_fops = {
* We enable interrupts in some of the routines after making sure it's
* safe.
*/
-static void hd_geninit(void)
+static void __init hd_geninit(void)
{
int drive;
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
index 270cacc61..abd6d8ac7 100644
--- a/drivers/ide/hpt366.c
+++ b/drivers/ide/hpt366.c
@@ -698,7 +698,7 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif)
#endif /* CONFIG_BLK_DEV_IDEDMA */
}
-void ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
{
byte masterdma = 0, slavedma = 0;
byte dma_new = 0, dma_old = inb(dmabase+2);
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
index fb15adc4d..c727cb889 100644
--- a/drivers/ide/icside.c
+++ b/drivers/ide/icside.c
@@ -163,7 +163,7 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = {
* Purpose : identify IDE interface type
* Notes : checks the description string
*/
-static iftype_t icside_identifyif (struct expansion_card *ec)
+static iftype_t __init icside_identifyif (struct expansion_card *ec)
{
unsigned int addr;
iftype_t iftype;
@@ -505,7 +505,7 @@ icside_setup(unsigned long base, struct cardinfo *info, int irq)
return hwif;
}
-static int icside_register_v5(struct expansion_card *ec, int autodma)
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
{
unsigned long slot_port;
ide_hwif_t *hwif;
@@ -527,7 +527,7 @@ static int icside_register_v5(struct expansion_card *ec, int autodma)
return hwif ? 0 : -1;
}
-static int icside_register_v6(struct expansion_card *ec, int autodma)
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
{
unsigned long slot_port, port;
ide_hwif_t *hwif, *mate;
@@ -585,7 +585,7 @@ no_dma:
return hwif || mate ? 0 : -1;
}
-int icside_init(void)
+int __init icside_init(void)
{
int autodma = 0;
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index f1304a4a0..6e99442fa 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -528,10 +528,7 @@ static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *
autodma = 1;
#endif
-#if 1 /* what do do with this useful tool ??? */
- if (pci_enable_device(dev))
- return;
-#endif
+ pci_enable_device(dev);
check_if_enabled:
if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
index f11c41d99..1e1b57f26 100644
--- a/drivers/ide/opti621.c
+++ b/drivers/ide/opti621.c
@@ -308,7 +308,7 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
/*
* ide_init_opti621() is called once for each hwif found at boot.
*/
-void ide_init_opti621 (ide_hwif_t *hwif)
+void __init ide_init_opti621 (ide_hwif_t *hwif)
{
hwif->drives[0].drive_data = PIO_DONT_KNOW;
hwif->drives[1].drive_data = PIO_DONT_KNOW;
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index c00f3305a..571cae563 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -33,8 +33,6 @@
static struct pci_dev *host_dev = NULL;
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#define SIS5513_FLAG_ATA_00 0x00000000
#define SIS5513_FLAG_ATA_16 0x00000001
#define SIS5513_FLAG_ATA_33 0x00000002
@@ -545,7 +543,7 @@ unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
- for (i = 0; i < arraysize (SiSHostChipInfo) && !host_dev; i++) {
+ for (i = 0; i < ARRAY_SIZE (SiSHostChipInfo) && !host_dev; i++) {
host = pci_find_device (PCI_VENDOR_ID_SI,
SiSHostChipInfo[i].host_id,
NULL);
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index c58c612ed..2451e801d 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -91,7 +91,7 @@ static void tune_sl82c105(ide_drive_t *drive, byte pio)
}
#endif
-void ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
{
unsigned char rev;
@@ -107,7 +107,7 @@ void ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
ide_setup_dma(hwif, dmabase, 8);
}
-void ide_init_sl82c105(ide_hwif_t *hwif)
+void __init ide_init_sl82c105(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index 566dcc4d5..3ea1e261e 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -611,7 +611,7 @@ void __init ide_init_via82cxxx(ide_hwif_t *hwif)
* We allow the BM-DMA driver only work on enabled interfaces.
*/
-void ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
{
if ((via_enabled >> hwif->channel) & 1)
ide_setup_dma(hwif, dmabase, 8);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 65109e9ca..8e676b8da 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -123,7 +123,7 @@ 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 > EVDEV_MINORS || !evdev_table[i])
+ if (i >= EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
@@ -288,7 +288,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
int minor;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
- if (evdev_table[minor]) {
+ if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return NULL;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index e121192a6..c78e49086 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -29,6 +29,8 @@
*/
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/random.h>
@@ -378,7 +380,11 @@ static int input_open_file(struct inode *inode, struct file *file)
}
old_fops = file->f_op;
file->f_op = new_fops;
+
+ lock_kernel();
err = new_fops->open(inode, file);
+ unlock_kernel();
+
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 90c4dbcef..4e12f55b7 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -193,7 +193,7 @@ static int joydev_open(struct inode *inode, struct file *file)
struct joydev_list *list;
int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
- if (i > JOYDEV_MINORS || !joydev_table[i])
+ if (i >= JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
@@ -395,7 +395,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
|| test_bit(BTN_1, dev->keybit)))) return NULL;
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
- if (joydev_table[minor]) {
+ if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
return NULL;
}
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 1aa85e227..e6a9e02a1 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -39,6 +39,7 @@
#include <linux/input.h>
#include <linux/config.h>
#include <linux/smp_lock.h>
+#include <linux/random.h>
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
@@ -86,6 +87,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
struct mousedev_list *list;
int index, size;
+ add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
+
while (*mousedev) {
list = (*mousedev)->list;
while (list) {
@@ -213,7 +216,7 @@ static int mousedev_open(struct inode * inode, struct file * file)
struct mousedev_list *list;
int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
- if (i > MOUSEDEV_MINORS || !mousedev_table[i])
+ if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
@@ -407,7 +410,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
return NULL;
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
- if (mousedev_table[minor]) {
+ if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return NULL;
}
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 2062f753c..f42516b12 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -10,7 +10,7 @@ if [ "$CONFIG_INET" != "n" ]; then
fi
bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
- bool ' Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+ bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
fi
if [ "$CONFIG_X25" != "n" ]; then
bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25
diff --git a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile
index 0e3c4a7e1..31312e8f6 100644
--- a/drivers/isdn/act2000/Makefile
+++ b/drivers/isdn/act2000/Makefile
@@ -7,7 +7,7 @@ ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
O_TARGET += act2000.o
else
ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
- O_TARGET += act2000.o
+ O_TARGET += act2000.o
M_OBJS = act2000.o
endif
endif
diff --git a/drivers/isdn/act2000/act2000.h b/drivers/isdn/act2000/act2000.h
index 5d35a12ec..432f433cb 100644
--- a/drivers/isdn/act2000/act2000.h
+++ b/drivers/isdn/act2000/act2000.h
@@ -1,4 +1,4 @@
-/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $
+/* $Id: act2000.h,v 1.8 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
@@ -19,31 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: act2000.h,v $
- * Revision 1.7 1999/04/12 13:13:54 fritz
- * Made cards pointer static to avoid name-clash.
- *
- * Revision 1.6 1998/11/05 22:12:38 fritz
- * Changed mail-address.
- *
- * Revision 1.5 1997/10/09 22:22:59 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.4 1997/09/25 17:25:37 fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3 1997/09/24 23:11:43 fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.2 1997/09/24 19:44:12 fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1 1997/09/23 18:00:05 fritz
- * New driver for IBM Active 2000.
- *
*/
#ifndef act2000_h
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
index 99c93dbed..216269dca 100644
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.c,v 1.10 1999/10/24 18:46:05 fritz Exp $
+/* $Id: act2000_isa.c,v 1.11 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
*
@@ -19,43 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: act2000_isa.c,v $
- * Revision 1.10 1999/10/24 18:46:05 fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.9 1999/09/04 06:20:04 keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.8 1999/01/05 18:29:25 he
- * merged remaining schedule_timeout() changes from 2.1.127
- *
- * Revision 1.7 1998/11/05 22:12:41 fritz
- * Changed mail-address.
- *
- * Revision 1.6 1998/06/17 19:51:09 he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
- *
- * Revision 1.5 1998/02/12 23:06:47 keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.4 1997/10/09 22:23:00 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.3 1997/09/25 17:25:38 fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.2 1997/09/24 23:11:44 fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.1 1997/09/23 18:00:05 fritz
- * New driver for IBM Active 2000.
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/act2000/act2000_isa.h b/drivers/isdn/act2000/act2000_isa.h
index ff3e5419a..0b705d33f 100644
--- a/drivers/isdn/act2000/act2000_isa.h
+++ b/drivers/isdn/act2000/act2000_isa.h
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.h,v 1.3 1999/10/24 18:46:05 fritz Exp $
+/* $Id: act2000_isa.h,v 1.4 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
*
@@ -19,17 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: act2000_isa.h,v $
- * Revision 1.3 1999/10/24 18:46:05 fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.2 1998/11/05 22:12:43 fritz
- * Changed mail-address.
- *
- * Revision 1.1 1997/09/23 18:00:07 fritz
- * New driver for IBM Active 2000.
- *
*/
#ifndef act2000_isa_h
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
index 9502b314e..ad2471a17 100644
--- a/drivers/isdn/act2000/capi.c
+++ b/drivers/isdn/act2000/capi.c
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $
+/* $Id: capi.c,v 1.9 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
* CAPI encoder/decoder
@@ -20,34 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: capi.c,v $
- * Revision 1.8 1998/11/05 22:12:46 fritz
- * Changed mail-address.
- *
- * Revision 1.7 1998/02/23 23:35:41 fritz
- * Eliminated some compiler warnings.
- *
- * Revision 1.6 1998/02/12 23:06:50 keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.5 1997/10/09 22:23:02 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.4 1997/09/25 17:25:39 fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3 1997/09/24 19:44:14 fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.2 1997/09/23 19:41:24 fritz
- * Disabled Logging of DATA_B3_IND/RESP/REQ/CONF Messages.
- *
- * Revision 1.1 1997/09/23 18:00:08 fritz
- * New driver for IBM Active 2000.
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
index 0500550db..88e9b1aab 100644
--- a/drivers/isdn/act2000/capi.h
+++ b/drivers/isdn/act2000/capi.h
@@ -1,4 +1,4 @@
-/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $
+/* $Id: capi.h,v 1.6 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
@@ -19,25 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: capi.h,v $
- * Revision 1.5 1998/11/05 22:12:48 fritz
- * Changed mail-address.
- *
- * Revision 1.4 1997/10/01 09:21:04 fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.3 1997/09/25 17:25:41 fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.2 1997/09/24 19:44:15 fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1 1997/09/23 18:00:10 fritz
- * New driver for IBM Active 2000.
- *
*/
#ifndef CAPI_H
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index 158d9463e..c602d945f 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.11 1999/10/30 09:48:04 keil Exp $
+/* $Id: module.c,v 1.14 2000/11/12 16:32:06 kai Exp $
*
* ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
*
@@ -19,44 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: module.c,v $
- * Revision 1.11 1999/10/30 09:48:04 keil
- * miss one prefix act2000
- *
- * Revision 1.10 1999/10/24 18:46:05 fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.9 1999/04/12 13:13:56 fritz
- * Made cards pointer static to avoid name-clash.
- *
- * Revision 1.8 1998/11/05 22:12:51 fritz
- * Changed mail-address.
- *
- * Revision 1.7 1998/02/12 23:06:52 keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.6 1998/01/31 22:10:42 keil
- * changes for 2.1.82
- *
- * Revision 1.5 1997/10/09 22:23:04 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.4 1997/09/25 17:25:43 fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3 1997/09/24 23:11:45 fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.2 1997/09/24 19:44:17 fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1 1997/09/23 18:00:13 fritz
- * New driver for IBM Active 2000.
- *
*/
#include "act2000.h"
@@ -563,37 +525,6 @@ act2000_readstatus(u_char * buf, int len, int user, act2000_card * card)
return count;
}
-static void
-act2000_putmsg(act2000_card *card, char c)
-{
- ulong flags;
-
- save_flags(flags);
- cli();
- *card->status_buf_write++ = c;
- if (card->status_buf_write == card->status_buf_read) {
- if (++card->status_buf_read > card->status_buf_end)
- card->status_buf_read = card->status_buf;
- }
- if (card->status_buf_write > card->status_buf_end)
- card->status_buf_write = card->status_buf;
- restore_flags(flags);
-}
-
-static void
-act2000_logstat(struct act2000_card *card, char *str)
-{
- char *p = str;
- isdn_ctrl c;
-
- while (*p)
- act2000_putmsg(card, *p++);
- c.command = ISDN_STAT_STAVAIL;
- c.driver = card->myid;
- c.arg = strlen(str);
- card->interface.statcallb(&c);
-}
-
/*
* Find card with given driverId
*/
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index cd2223911..56f7ac4be 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.18 2000/04/03 16:39:25 calle Exp $
+# $Id: Makefile,v 1.21 2000/11/01 14:05:02 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -11,6 +11,23 @@
# parent makes..
#
# $Log: Makefile,v $
+# Revision 1.21 2000/11/01 14:05:02 calle
+# - use module_init/module_exit from linux/init.h.
+# - all static struct variables are initialized with "membername:" now.
+# - avm_cs.c, let it work with newer pcmcia-cs.
+#
+# Revision 1.20 2000/10/18 06:13:34 ostoyke
+# Removing CAPI4Linux from I4L CVS.
+#
+# Revision 1.19 2000/08/10 14:46:25 ostoyke
+# CAPI4Linux.
+#
+# Revision 1.18 2000/04/03 16:39:25 calle
+# Makefile checked in with future things :-(
+#
+# Revision 1.17 2000/04/03 16:38:05 calle
+# made suppress_pollack static.
+#
# Revision 1.16 2000/03/17 12:15:44 calle
# ALL_SUB_DIRS were wrong.
#
@@ -109,7 +126,7 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
-ALL_SUB_DIRS := # fcpci fcclassic
+ALL_SUB_DIRS :=
#
# Objects that don't export a symtab
#
@@ -158,14 +175,6 @@ ifeq ($(CONFIG_ISDN_CAPI),y)
ifdef CONFIG_ISDN_DRV_AVMB1_C4
O_OBJS += c4.o
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
- SUB_DIRS += fcpci
- MOD_SUB_DIRS += fcpci
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
- SUB_DIRS += fcclassic
- MOD_SUB_DIRS += fcclassic
- endif
OX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
else
ifeq ($(CONFIG_ISDN_CAPI),m)
@@ -198,12 +207,6 @@ else
ifdef CONFIG_ISDN_DRV_AVMB1_C4
M_OBJS += c4.o
endif
- ifdef CONFIG_ISDN_DRV_AVMB1_FCPCI
- MOD_SUB_DIRS += fcpci
- endif
- ifdef CONFIG_ISDN_DRV_AVMB1_FCCLASSIC
- MOD_SUB_DIRS += fcclassic
- endif
MX_OBJS += capiutil.o capidrv.o b1.o b1dma.o
endif
endif
diff --git a/drivers/isdn/avmb1/avmcard.h b/drivers/isdn/avmb1/avmcard.h
index 56fa0fba6..cf8287aa3 100644
--- a/drivers/isdn/avmb1/avmcard.h
+++ b/drivers/isdn/avmb1/avmcard.h
@@ -1,9 +1,12 @@
/*
- * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $
+ * $Id: avmcard.h,v 1.8 2000/10/10 17:44:19 kai Exp $
*
* Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: avmcard.h,v $
+ * Revision 1.8 2000/10/10 17:44:19 kai
+ * changes from/for 2.2.18
+ *
* Revision 1.7 2000/01/25 14:33:38 calle
* - Added Support AVM B1 PCI V4.0 (tested with prototype)
* - splitted up t1pci.c into b1dma.c for common function with b1pciv4
@@ -347,13 +350,13 @@ static inline unsigned int b1_rd_reg(unsigned int base,
static inline void b1_reset(unsigned int base)
{
b1outp(base, B1_RESET, 0);
- udelay(55 * 2 * 1000); /* 2 TIC's */
+ mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 1);
- udelay(55 * 2 * 1000); /* 2 TIC's */
+ mdelay(55 * 2); /* 2 TIC's */
b1outp(base, B1_RESET, 0);
- udelay(55 * 2 * 1000); /* 2 TIC's */
+ mdelay(55 * 2); /* 2 TIC's */
}
static inline unsigned char b1_disable_irq(unsigned int base)
diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c
index 8ccf5fc7e..747b5ea7f 100644
--- a/drivers/isdn/avmb1/b1.c
+++ b/drivers/isdn/avmb1/b1.c
@@ -517,7 +517,7 @@ void b1_handle_interrupt(avmcard * card)
struct sk_buff *skb;
unsigned ApplId;
- signed MsgLen;
+ unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index 94f493620..6cdc6c5a4 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -1,11 +1,19 @@
/*
- * $Id: b1dma.c,v 1.7 2000/08/04 12:20:08 calle Exp $
+ * $Id: b1dma.c,v 1.9 2000/11/01 14:05:02 calle Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1dma.c,v $
+ * Revision 1.9 2000/11/01 14:05:02 calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.8 2000/10/10 17:44:19 kai
+ * changes from/for 2.2.18
+ *
* Revision 1.7 2000/08/04 12:20:08 calle
* - Fix unsigned/signed warning in the right way ...
*
@@ -47,7 +55,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.9 $";
/* ------------------------------------------------------------- */
@@ -243,14 +251,14 @@ void b1dma_reset(avmcard *card)
restore_flags(flags);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
+ mdelay(10);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
+ mdelay(10);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
if (card->cardtype == avm_t1pci)
- udelay(42 * 1000);
+ mdelay(42);
else
- udelay(10 * 1000);
+ mdelay(10);
}
/* ------------------------------------------------------------- */
@@ -258,11 +266,11 @@ void b1dma_reset(avmcard *card)
int b1dma_detect(avmcard *card)
{
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
- udelay(10 * 1000);
+ mdelay(10);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0x0f000000); /* reset all */
- udelay(10 * 1000);
+ mdelay(10);
b1dmaoutmeml(card->mbase+AMCC_MCSR, 0);
- udelay(42 * 1000);
+ mdelay(42);
b1dmaoutmeml(card->mbase+AMCC_RXLEN, 0);
b1dmaoutmeml(card->mbase+AMCC_TXLEN, 0);
@@ -475,8 +483,7 @@ static void b1dma_handle_rx(avmcard *card)
struct capi_ctr *ctrl = cinfo->capi_ctrl;
struct sk_buff *skb;
void *p = dma->recvbuf+4;
- __u32 ApplId, DataB3Len, NCCI, WindowSize;
- __s32 MsgLen;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
__u8 b1cmd = _get_byte(&p);
#ifdef CONFIG_B1DMA_DEBUG
diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c
index 9c67a0a42..486a0f28d 100644
--- a/drivers/isdn/avmb1/b1isa.c
+++ b/drivers/isdn/avmb1/b1isa.c
@@ -244,20 +244,20 @@ static char *b1isa_procinfo(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
static struct capi_driver b1isa_driver = {
- "b1isa",
- "0.0",
- b1_load_firmware,
- b1_reset_ctr,
- b1isa_remove_ctr,
- b1_register_appl,
- b1_release_appl,
- b1_send_message,
-
- b1isa_procinfo,
- b1ctl_read_proc,
- 0, /* use standard driver_read_proc */
-
- b1isa_add_card,
+ name: "b1isa",
+ revision: "0.0",
+ load_firmware: b1_load_firmware,
+ reset_ctr: b1_reset_ctr,
+ remove_ctr: b1isa_remove_ctr,
+ register_appl: b1_register_appl,
+ release_appl: b1_release_appl,
+ send_message: b1_send_message,
+
+ procinfo: b1isa_procinfo,
+ ctr_read_proc: b1ctl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: b1isa_add_card,
};
#ifdef MODULE
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index 69bab9557..27af2e27b 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -276,20 +276,20 @@ static int b1pci_add_card(struct capi_driver *driver, struct capicardparams *p)
/* ------------------------------------------------------------- */
static struct capi_driver b1pci_driver = {
- "b1pci",
- "0.0",
- b1_load_firmware,
- b1_reset_ctr,
- b1pci_remove_ctr,
- b1_register_appl,
- b1_release_appl,
- b1_send_message,
-
- b1pci_procinfo,
- b1ctl_read_proc,
- 0, /* use standard driver_read_proc */
-
- 0, /* no add_card function */
+ name: "b1pci",
+ revision: "0.0",
+ load_firmware: b1_load_firmware,
+ reset_ctr: b1_reset_ctr,
+ remove_ctr: b1pci_remove_ctr,
+ register_appl: b1_register_appl,
+ release_appl: b1_release_appl,
+ send_message: b1_send_message,
+
+ procinfo: b1pci_procinfo,
+ ctr_read_proc: b1ctl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: 0, /* no add_card function */
};
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
@@ -463,20 +463,20 @@ static int b1pciv4_add_card(struct capi_driver *driver, struct capicardparams *p
static struct capi_driver b1pciv4_driver = {
- "b1pciv4",
- "0.0",
- b1dma_load_firmware,
- b1dma_reset_ctr,
- b1pciv4_remove_ctr,
- b1dma_register_appl,
- b1dma_release_appl,
- b1dma_send_message,
-
- b1pciv4_procinfo,
- b1dmactl_read_proc,
- 0, /* use standard driver_read_proc */
-
- 0, /* no add_card function */
+ name: "b1pciv4",
+ revision: "0.0",
+ load_firmware: b1dma_load_firmware,
+ reset_ctr: b1dma_reset_ctr,
+ remove_ctr: b1pciv4_remove_ctr,
+ register_appl: b1dma_register_appl,
+ release_appl: b1dma_release_appl,
+ send_message: b1dma_send_message,
+
+ procinfo: b1pciv4_procinfo,
+ ctr_read_proc: b1dmactl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: 0, /* no add_card function */
};
#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c
index c3537c363..20b851548 100644
--- a/drivers/isdn/avmb1/b1pcmcia.c
+++ b/drivers/isdn/avmb1/b1pcmcia.c
@@ -245,20 +245,20 @@ static char *b1pcmcia_procinfo(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
static struct capi_driver b1pcmcia_driver = {
- "b1pcmcia",
- "0.0",
- b1_load_firmware,
- b1_reset_ctr,
- b1pcmcia_remove_ctr,
- b1_register_appl,
- b1_release_appl,
- b1_send_message,
-
- b1pcmcia_procinfo,
- b1ctl_read_proc,
- 0, /* use standard driver_read_proc */
-
- 0,
+ name: "b1pcmcia",
+ revision: "0.0",
+ load_firmware: b1_load_firmware,
+ reset_ctr: b1_reset_ctr,
+ remove_ctr: b1pcmcia_remove_ctr,
+ register_appl: b1_register_appl,
+ release_appl: b1_release_appl,
+ send_message: b1_send_message,
+
+ procinfo: b1pcmcia_procinfo,
+ ctr_read_proc: b1ctl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: 0,
};
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index bbb5d5793..7f1340001 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1,11 +1,19 @@
/*
- * $Id: c4.c,v 1.16 2000/08/20 07:30:13 keil Exp $
+ * $Id: c4.c,v 1.18 2000/11/01 14:05:02 calle Exp $
*
* Module for AVM C4 card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: c4.c,v $
+ * Revision 1.18 2000/11/01 14:05:02 calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.17 2000/10/10 17:44:19 kai
+ * changes from/for 2.2.18
+ *
* Revision 1.16 2000/08/20 07:30:13 keil
* changes for 2.4
*
@@ -80,7 +88,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.16 $";
+static char *revision = "$Revision: 1.18 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
@@ -410,7 +418,7 @@ static int c4_detect(avmcard *card)
return 8;
if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9;
- udelay(1000);
+ mdelay(1);
if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10;
if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11;
@@ -422,7 +430,7 @@ static int c4_detect(avmcard *card)
if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16;
if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17;
- udelay(1000);
+ mdelay(1);
if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF))
return 18;
@@ -572,8 +580,7 @@ static void c4_handle_rx(avmcard *card)
avmctrl_info *cinfo;
struct sk_buff *skb;
void *p = dma->recvbuf;
- __u32 ApplId, DataB3Len, NCCI, WindowSize;
- __s32 MsgLen;
+ __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
__u8 b1cmd = _get_byte(&p);
__u32 cidx;
@@ -927,7 +934,7 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
c4outmeml(card->mbase+MBOX_UP_LEN, 0);
c4outmeml(card->mbase+MBOX_DOWN_LEN, 0);
c4outmeml(card->mbase+DOORBELL, DBELL_INIT);
- udelay(1000);
+ mdelay(1);
c4outmeml(card->mbase+DOORBELL,
DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST);
@@ -1303,22 +1310,23 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
/* ------------------------------------------------------------- */
static struct capi_driver c4_driver = {
- "c4",
- "0.0",
- c4_load_firmware,
- c4_reset_ctr,
- c4_remove_ctr,
- c4_register_appl,
- c4_release_appl,
- c4_send_message,
-
- c4_procinfo,
- c4_read_proc,
- 0, /* use standard driver_read_proc */
-
- 0, /* no add_card function */
+ name: "c4",
+ revision: "0.0",
+ load_firmware: c4_load_firmware,
+ reset_ctr: c4_reset_ctr,
+ remove_ctr: c4_remove_ctr,
+ register_appl: c4_register_appl,
+ release_appl: c4_release_appl,
+ send_message: c4_send_message,
+
+ procinfo: c4_procinfo,
+ ctr_read_proc: c4_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: 0, /* no add_card function */
};
+
#ifdef MODULE
#define c4_init init_module
void cleanup_module(void);
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index ff91a89f8..69385b4df 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -2054,8 +2054,8 @@ static void lower_callback(unsigned int cmd, __u32 contr, void *data)
}
static struct capi_interface_user cuser = {
- "capi20",
- lower_callback,
+ name: "capi20",
+ callback: lower_callback,
};
static char rev[10];
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index a66057e1c..e512c8672 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -386,16 +386,16 @@ static inline __u32 b3prot(int l2, int l3)
}
}
-static _cstruct b1config_sync_v110(__u16 rate)
+static _cstruct b1config_async_v110(__u16 rate)
{
/* CAPI-Spec "B1 Configuration" */
static unsigned char buf[9];
buf[0] = 8; /* len */
/* maximum bitrate */
buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
- buf[3] = buf[4] = 0; /* reserved, bits per character */
- buf[5] = buf[6] = 0; /* reserved, parity */
- buf[7] = buf[9] = 0; /* reserved, stop bits */
+ buf[3] = 8; buf[4] = 0; /* 8 bits per character */
+ buf[5] = 0; buf[6] = 0; /* parity none */
+ buf[7] = 0; buf[8] = 0; /* 1 stop bit */
return buf;
}
@@ -410,11 +410,11 @@ static _cstruct b1config(int l2, int l3)
default:
return 0;
case ISDN_PROTO_L2_V11096:
- return b1config_sync_v110(9600);
+ return b1config_async_v110(9600);
case ISDN_PROTO_L2_V11019:
- return b1config_sync_v110(19200);
+ return b1config_async_v110(19200);
case ISDN_PROTO_L2_V11038:
- return b1config_sync_v110(38400);
+ return b1config_async_v110(38400);
}
}
@@ -2464,8 +2464,8 @@ static void __exit proc_exit(void)
}
static struct capi_interface_user cuser = {
- "capidrv",
- lower_callback
+ name: "capidrv",
+ callback: lower_callback
};
int __init capidrv_init(void)
diff --git a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
index d4956c45b..b932c17e0 100644
--- a/drivers/isdn/avmb1/capifs.c
+++ b/drivers/isdn/avmb1/capifs.c
@@ -119,8 +119,6 @@ struct inode_operations capifs_root_inode_operations = {
lookup: capifs_root_lookup,
};
-struct inode_operations capifs_inode_operations;
-
static struct dentry_operations capifs_dentry_operations = {
d_revalidate: capifs_revalidate,
};
@@ -468,10 +466,8 @@ static void capifs_read_inode(struct inode *inode)
ino_t ino = inode->i_ino;
struct capifs_sb_info *sbi = SBI(inode->i_sb);
- inode->i_op = NULL;
inode->i_mode = 0;
inode->i_nlink = 0;
- inode->i_size = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
inode->i_blksize = 1024;
@@ -485,9 +481,6 @@ static void capifs_read_inode(struct inode *inode)
return;
}
- /* need dummy inode operations .... */
- inode->i_op = &capifs_inode_operations;
-
ino -= 2;
if ( ino >= sbi->max_ncci )
return; /* Bogus */
diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c
index 2abd7ed4c..ff77c5f20 100644
--- a/drivers/isdn/avmb1/t1isa.c
+++ b/drivers/isdn/avmb1/t1isa.c
@@ -1,11 +1,19 @@
/*
- * $Id: t1isa.c,v 1.13 2000/08/04 15:36:31 calle Exp $
+ * $Id: t1isa.c,v 1.15 2000/11/01 14:05:02 calle Exp $
*
* Module for AVM T1 HEMA-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1isa.c,v $
+ * Revision 1.15 2000/11/01 14:05:02 calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.14 2000/10/10 17:44:19 kai
+ * changes from/for 2.2.18
+ *
* Revision 1.13 2000/08/04 15:36:31 calle
* copied wrong from file to file :-(
*
@@ -85,13 +93,14 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/capi.h>
+#include <linux/init.h>
#include <asm/io.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.15 $";
/* ------------------------------------------------------------- */
@@ -145,7 +154,7 @@ static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
cli();
/* board reset */
t1outp(base, T1_RESETBOARD, 0xf);
- udelay(100 * 1000);
+ mdelay(100);
dummy = t1inp(base, T1_FASTLINK+T1_OUTSTAT); /* first read */
/* write config */
@@ -157,18 +166,18 @@ static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
t1outp(base, ((base >> 4)) & 0x3, cregs[7]);
restore_flags(flags);
- udelay(100 * 1000);
+ mdelay(100);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
- udelay(10 * 1000);
+ mdelay(10);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 1);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 1);
- udelay(100 * 1000);
+ mdelay(100);
t1outp(base, T1_FASTLINK+T1_RESETLINK, 0);
t1outp(base, T1_SLOWLINK+T1_RESETLINK, 0);
- udelay(10 * 1000);
+ mdelay(10);
t1outp(base, T1_FASTLINK+T1_ANALYSE, 0);
- udelay(5 * 1000);
+ mdelay(5);
t1outp(base, T1_SLOWLINK+T1_ANALYSE, 0);
if (t1inp(base, T1_FASTLINK+T1_OUTSTAT) != 0x1) /* tx empty */
@@ -200,7 +209,7 @@ static void t1_handle_interrupt(avmcard * card)
struct sk_buff *skb;
unsigned ApplId;
- signed MsgLen;
+ unsigned MsgLen;
unsigned DataB3Len;
unsigned NCCI;
unsigned WindowSize;
@@ -588,20 +597,20 @@ static char *t1isa_procinfo(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
static struct capi_driver t1isa_driver = {
- "t1isa",
- "0.0",
- t1isa_load_firmware,
- t1isa_reset_ctr,
- t1isa_remove_ctr,
- b1_register_appl,
- b1_release_appl,
- t1isa_send_message,
-
- t1isa_procinfo,
- b1ctl_read_proc,
- 0, /* use standard driver_read_proc */
-
- t1isa_add_card,
+ name: "t1isa",
+ revision: "0.0",
+ load_firmware: t1isa_load_firmware,
+ reset_ctr: t1isa_reset_ctr,
+ remove_ctr: t1isa_remove_ctr,
+ register_appl: b1_register_appl,
+ release_appl: b1_release_appl,
+ send_message: t1isa_send_message,
+
+ procinfo: t1isa_procinfo,
+ ctr_read_proc: b1ctl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: t1isa_add_card,
};
#ifdef MODULE
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index d2303feab..50ecc729d 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -259,20 +259,20 @@ static char *t1pci_procinfo(struct capi_ctr *ctrl)
/* ------------------------------------------------------------- */
static struct capi_driver t1pci_driver = {
- "t1pci",
- "0.0",
- b1dma_load_firmware,
- b1dma_reset_ctr,
- t1pci_remove_ctr,
- b1dma_register_appl,
- b1dma_release_appl,
- b1dma_send_message,
-
- t1pci_procinfo,
- b1dmactl_read_proc,
- 0, /* use standard driver_read_proc */
-
- 0, /* no add_card function */
+ name: "t1pci",
+ revision: "0.0",
+ load_firmware: b1dma_load_firmware,
+ reset_ctr: b1dma_reset_ctr,
+ remove_ctr: t1pci_remove_ctr,
+ register_appl: b1dma_register_appl,
+ release_appl: b1dma_release_appl,
+ send_message: b1dma_send_message,
+
+ procinfo: t1pci_procinfo,
+ ctr_read_proc: b1dmactl_read_proc,
+ driver_read_proc: 0, /* use standard driver_read_proc */
+
+ add_card: 0, /* no add_card function */
};
#ifdef MODULE
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
index ce44cfa19..0e0c43964 100644
--- a/drivers/isdn/divert/divert_init.c
+++ b/drivers/isdn/divert/divert_init.c
@@ -1,5 +1,5 @@
/*
- * $Id: divert_init.c,v 1.4 1999/08/22 20:26:32 calle Exp $
+ * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $
*
* Module init for DSS1 diversion services for i4l.
*
@@ -19,22 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: divert_init.c,v $
- * Revision 1.4 1999/08/22 20:26:32 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3 1999/07/05 20:21:39 werner
- * changes to use diversion sources for all kernel versions.
- * removed static device, only proc filesystem used
- *
- * Revision 1.2 1999/07/04 21:37:30 werner
- * Ported from kernel version 2.0
- *
- *
- *
*/
#include <linux/module.h>
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 5b08e8025..8cff1683a 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -1,5 +1,5 @@
/*
- * $Id: divert_procfs.c,v 1.9 2000/08/20 07:40:14 keil Exp $
+ * $Id: divert_procfs.c,v 1.10 2000/11/13 22:51:47 kai Exp $
*
* Filesystem handling for the diversion supplementary services.
*
@@ -19,38 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: divert_procfs.c,v $
- * Revision 1.9 2000/08/20 07:40:14 keil
- * changes from 2.4
- *
- * Revision 1.8 2000/03/03 16:37:11 kai
- * incorporated some cosmetic changes from the official kernel tree back
- * into CVS
- *
- * Revision 1.7 2000/03/02 00:11:06 werner
- *
- * Changes related to procfs for 2.3.48
- *
- * Revision 1.6 2000/02/14 19:23:03 werner
- *
- * Changed handling of proc filesystem tables to a more portable version
- *
- * Revision 1.5 1999/09/14 20:31:01 werner
- *
- * Removed obsoleted functions for proc fs and synced with new ones.
- *
- * Revision 1.4 1999/08/06 07:42:48 calle
- * Added COMPAT_HAS_NEW_WAITQ for rd_queue for newer kernels.
- *
- * Revision 1.3 1999/07/05 20:21:41 werner
- * changes to use diversion sources for all kernel versions.
- * removed static device, only proc filesystem used
- *
- * Revision 1.2 1999/07/04 21:37:31 werner
- * Ported from kernel version 2.0
- *
- *
- *
*/
#include <linux/config.h>
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index 7079232e7..f5b6b8773 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -1,5 +1,5 @@
/*
- * $Id: isdn_divert.c,v 1.5 1999/08/31 11:20:04 paul Exp $
+ * $Id: isdn_divert.c,v 1.6 2000/11/13 22:51:47 kai Exp $
*
* DSS1 main diversion supplementary handling for i4l.
*
@@ -19,25 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: isdn_divert.c,v $
- * Revision 1.5 1999/08/31 11:20:04 paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.4 1999/08/25 20:02:21 werner
- * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
- * with existing software definitions. (PtP incomplete called party number)
- *
- * Revision 1.3 1999/08/22 20:26:35 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.2 1999/07/04 21:37:32 werner
- * Ported from kernel version 2.0
- *
- *
- *
*/
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
index 6ab119ed9..84390c997 100644
--- a/drivers/isdn/divert/isdn_divert.h
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -1,5 +1,5 @@
/*
- * $Id: isdn_divert.h,v 1.4 1999/09/02 13:24:12 paul Exp $
+ * $Id: isdn_divert.h,v 1.5 2000/11/13 22:51:47 kai Exp $
*
* Header for the diversion supplementary ioctl interface.
*
@@ -19,19 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: isdn_divert.h,v $
- * Revision 1.4 1999/09/02 13:24:12 paul
- * cosmetics; text following #endif is not ANSI C
- *
- * Revision 1.3 1999/08/22 20:26:37 calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- * define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.2 1999/07/04 21:37:33 werner
- * Ported from kernel version 2.0
- *
*/
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 4ed7e4129..614f145cb 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -484,7 +484,7 @@ HiSax_setup(char *line)
}
i++;
}
- if (strlen(str)) {
+ if (str && *str) {
strcpy(HiSaxID, str);
HiSax_id = HiSaxID;
} else {
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index b61f397d2..ac0392251 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -31,6 +31,7 @@
#include "isdnl1.h"
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
extern const char *CardType[];
@@ -1631,11 +1632,9 @@ static struct pci_dev *dev_hfcpci __initdata = NULL;
#endif /* CONFIG_PCI */
-__initfunc(int
- setup_hfcpci(struct IsdnCard *card))
+int __init setup_hfcpci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
- unsigned short cmd;
char tmp[64];
int i;
struct pci_dev *tmp_hfcpci = NULL;
@@ -1645,15 +1644,11 @@ __initfunc(int
#endif
strcpy(tmp, hfcpci_revision);
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
cs->hw.hfcpci.int_s1 = 0;
cs->dc.hfcpci.ph_state = 0;
cs->hw.hfcpci.fifo = 255;
if (cs->typ == ISDN_CTYPE_HFC_PCI) {
- if (!pci_present()) {
- printk(KERN_ERR "HFC-PCI: no PCI bus present\n");
- return (0);
- }
i = 0;
while (id_list[i].vendor_id) {
tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
@@ -1686,41 +1681,6 @@ __initfunc(int
printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
return (0);
}
-#ifdef notdef
- if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
- printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- 0x0103); /* set SERR */
- pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- &cmd);
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- cmd & ~2);
- (int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
- pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_BASE_ADDRESS_1,
- (int) cs->hw.hfcpci.pci_io);
- pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_COMMAND,
- cmd);
- pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
- cs->hw.hfcpci.pci_device_fn,
- PCI_BASE_ADDRESS_1,
- (void *) &cs->hw.hfcpci.pci_io);
- if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
- printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
- return (0);
- }
- dev_hfcpci->resource[1].start = (int) cs->hw.hfcpci.pci_io;
- }
-#endif
if (!cs->hw.hfcpci.pci_io) {
printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
return (0);
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index 2acb1a6de..1ff42d3b7 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -148,11 +148,10 @@ setup_netjet_s(struct IsdnCard *card))
return(0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- for ( ;; )
- {
-
#if CONFIG_PCI
+ for ( ;; )
+ {
if (!pci_present()) {
printk(KERN_ERR "Netjet: no PCI bus present\n");
return(0);
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 5ad977128..57de4b44b 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -150,11 +150,10 @@ setup_netjet_u(struct IsdnCard *card))
return(0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
- for ( ;; )
- {
-
#if CONFIG_PCI
+ for ( ;; )
+ {
if (!pci_present()) {
printk(KERN_ERR "NETspider-U: no PCI bus present\n");
return(0);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index eca66942e..0a2e1d4ec 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.7 2000/06/26 08:59:15 keil Exp $
+/* $Id: w6692.c,v 1.8 2000/09/07 20:33:30 werner Exp $
*
* w6692.c Winbond W6692 specific routines
*
@@ -46,7 +46,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.7 $";
+const char *w6692_revision = "$Revision: 1.8 $";
#define DBUSY_TIMER_VALUE 80
@@ -1056,6 +1056,7 @@ __initfunc(int setup_w6692(struct IsdnCard *card))
cs->BC_Send_Data = &W6692B_fill_fifo;
cs->cardmsg = &w6692_card_msg;
cs->irq_func = &W6692_interrupt;
+ cs->irq_flags |= SA_SHIRQ;
W6692Version(cs, "W6692:");
printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 471ec549e..17fc82ffc 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -1,4 +1,4 @@
-/* $Id: boardergo.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
+/* $Id: boardergo.c,v 1.4 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, specific routines for ergo type boards.
*
@@ -24,18 +24,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: boardergo.c,v $
- * Revision 1.3 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.2 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h
index 0e2c3f678..224d1823a 100644
--- a/drivers/isdn/hysdn/boardergo.h
+++ b/drivers/isdn/hysdn/boardergo.h
@@ -1,4 +1,4 @@
-/* $Id: boardergo.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+/* $Id: boardergo.h,v 1.2 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,12 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: boardergo.h,v $
- * Revision 1.1 2000/02/10 19:44:30 werner
- *
- * Initial release
- *
- *
*/
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index aabb28b8d..f90d902e2 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -1,4 +1,4 @@
-/* $Id: hycapi.c,v 1.6 2000/07/25 08:07:42 ualbrecht Exp $
+/* $Id: hycapi.c,v 1.7 2000/11/13 22:51:47 kai Exp $
*
* Linux driver for HYSDN cards, CAPI2.0-Interface.
* written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
@@ -19,26 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hycapi.c,v $
- * Revision 1.6 2000/07/25 08:07:42 ualbrecht
- * Fixed stupid re-registering bug resulting in system-freeze
- *
- * Revision 1.5 2000/06/18 16:08:18 keil
- * 2.4 PCI changes and some cosmetics
- *
- * Revision 1.4 2000/06/13 09:13:06 ualbrecht
- * Changed internal application handling: Registration is now deferred
- * until a CAPI-message is actually sent to the controller (no good
- * wasting memory on the card if it's never used anyways).
- * Module will now unload more gracefully.
- *
- * Revision 1.2 2000/05/22 10:31:22 ualbrecht
- * Parameter-checking for app-registration fixed
- *
- * Revision 1.1 2000/05/17 11:34:30 ualbrecht
- * Initial release
- *
- *
*/
#define __NO_VERSION__
@@ -61,7 +41,7 @@
#include "hysdn_defs.h"
#include <linux/kernelcapi.h>
-static char hycapi_revision[]="$Revision: 1.6 $";
+static char hycapi_revision[]="$Revision: 1.7 $";
typedef struct _hycapi_appl {
unsigned int ctrl_mask;
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
index 31eaa14cb..2af44170e 100644
--- a/drivers/isdn/hysdn/hysdn_boot.c
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_boot.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
+/* $Id: hysdn_boot.c,v 1.4 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, specific routines for booting and pof handling.
*
@@ -20,18 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_boot.c,v $
- * Revision 1.3 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.2 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
index e5ad863d4..0e4794c39 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -1,4 +1,4 @@
-/* $Id: hysdn_defs.h,v 1.3 2000/06/13 09:14:26 ualbrecht Exp $
+/* $Id: hysdn_defs.h,v 1.4 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, global definitions and exported vars and functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,18 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_defs.h,v $
- * Revision 1.3 2000/06/13 09:14:26 ualbrecht
- * Removed obsolete struct for CAPI-application tracking.
- *
- * Revision 1.2 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.1 2000/02/10 19:44:30 werner
- *
- * Initial release
- *
- *
*/
#ifndef HYSDN_DEFS_H
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 6ae0c3a7f..2b3916753 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_init.c,v 1.5 2000/08/20 16:46:09 keil Exp $
+/* $Id: hysdn_init.c,v 1.6 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, init functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,24 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_init.c,v $
- * Revision 1.5 2000/08/20 16:46:09 keil
- * Changes for 2.4
- *
- * Revision 1.4 2000/06/18 16:08:18 keil
- * 2.4 PCI changes and some cosmetics
- *
- * Revision 1.3 2000/06/13 09:15:07 ualbrecht
- * Module will now unload more gracefully.
- *
- * Revision 1.2 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#include <linux/config.h>
@@ -49,7 +31,7 @@
#include "hysdn_defs.h"
-static char *hysdn_init_revision = "$Revision: 1.5 $";
+static char *hysdn_init_revision = "$Revision: 1.6 $";
int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 61441da10..cf250e48d 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.7 2000/05/23 06:48:54 ualbrecht Exp $
+/* $Id: hysdn_net.c,v 1.8 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, net (ethernet type) handling routines.
*
@@ -23,33 +23,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_net.c,v $
- * Revision 1.7 2000/05/23 06:48:54 ualbrecht
- * Reverted last change in dev->name assignment (broken netdevice.h in 2.3.99pre6?)
- *
- * Revision 1.6 2000/05/17 11:43:03 ualbrecht
- * Fixed a NULL-pointer kernel-oops assigning the device-name
- *
- * Revision 1.5 2000/05/06 00:52:38 kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.4 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.3 2000/02/14 19:24:12 werner
- *
- * Removed superflous file
- *
- * Revision 1.2 2000/02/13 17:32:19 werner
- *
- * Added support for new network layer of 2.3.43 and 44 kernels and tested driver.
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
@@ -65,7 +38,7 @@
#include "hysdn_defs.h"
/* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.7 $";
+char *hysdn_net_revision = "$Revision: 1.8 $";
#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h
index 619c07897..524b7a0ae 100644
--- a/drivers/isdn/hysdn/hysdn_pof.h
+++ b/drivers/isdn/hysdn/hysdn_pof.h
@@ -1,4 +1,4 @@
-/* $Id: hysdn_pof.h,v 1.1 2000/02/10 19:44:30 werner Exp $
+/* $Id: hysdn_pof.h,v 1.2 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, definitions used for handling pof-files.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,12 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_pof.h,v $
- * Revision 1.1 2000/02/10 19:44:30 werner
- *
- * Initial release
- *
- *
*/
/************************/
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index aa17c1014..2200f9906 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_procconf.c,v 1.7 2000/08/20 16:46:09 keil Exp $
+/* $Id: hysdn_procconf.c,v 1.8 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,33 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_procconf.c,v $
- * Revision 1.7 2000/08/20 16:46:09 keil
- * Changes for 2.4
- *
- * Revision 1.6 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.5 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.4 2000/03/03 16:37:12 kai
- * incorporated some cosmetic changes from the official kernel tree back
- * into CVS
- *
- * Revision 1.3 2000/03/02 00:11:07 werner
- *
- * Changes related to procfs for 2.3.48
- *
- * Revision 1.2 2000/02/14 19:23:03 werner
- *
- * Changed handling of proc filesystem tables to a more portable version
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
@@ -58,7 +31,7 @@
#include "hysdn_defs.h"
-static char *hysdn_procconf_revision = "$Revision: 1.7 $";
+static char *hysdn_procconf_revision = "$Revision: 1.8 $";
#define INFO_OUT_LEN 80 /* length of info line including lf */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index a0ac125fe..09c595236 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_proclog.c,v 1.7 2000/08/20 16:46:09 keil Exp $
+/* $Id: hysdn_proclog.c,v 1.8 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, /proc/net filesystem log functions.
* written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -19,33 +19,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_proclog.c,v $
- * Revision 1.7 2000/08/20 16:46:09 keil
- * Changes for 2.4
- *
- * Revision 1.6 2000/06/18 16:08:18 keil
- * 2.4 PCI changes and some cosmetics
- *
- * Revision 1.5 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.4 2000/03/03 16:37:12 kai
- * incorporated some cosmetic changes from the official kernel tree back
- * into CVS
- *
- * Revision 1.3 2000/03/02 00:11:07 werner
- *
- * Changes related to procfs for 2.3.48
- *
- * Revision 1.2 2000/02/14 19:23:03 werner
- *
- * Changed handling of proc filesystem tables to a more portable version
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
index 64b8782f0..3091c2bc1 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -1,4 +1,4 @@
-/* $Id: hysdn_sched.c,v 1.3 2000/05/17 11:41:30 ualbrecht Exp $
+/* $Id: hysdn_sched.c,v 1.4 2000/11/13 22:51:47 kai Exp $
* Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
*
@@ -20,18 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: hysdn_sched.c,v $
- * Revision 1.3 2000/05/17 11:41:30 ualbrecht
- * CAPI 2.0 support added
- *
- * Revision 1.2 2000/04/23 14:18:36 kai
- * merge changes from main tree
- *
- * Revision 1.1 2000/02/10 19:45:18 werner
- *
- * Initial release
- *
- *
*/
#define __NO_VERSION__
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 74905bba0..180b3711a 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.63 2000/05/06 00:52:39 kai Exp $
+/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $
* ISDN low-level module for the ICN active ISDN-Card.
*
@@ -18,224 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: icn.c,v $
- * Revision 1.63 2000/05/06 00:52:39 kai
- * merged changes from kernel tree
- * fixed timer and net_device->name breakage
- *
- * Revision 1.62 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.61 1999/09/03 14:06:58 fritz
- * Fixed a memory leak.
- *
- * Revision 1.60 1999/08/31 11:20:32 paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.59 1999/08/28 22:10:55 keil
- * __setup function should be static
- *
- * Revision 1.58 1999/08/25 16:44:17 keil
- * Support for new __setup function
- *
- * Revision 1.57 1999/07/06 16:15:30 detabc
- * remove unused messages
- *
- * Revision 1.56 1999/04/12 13:15:07 fritz
- * Fixed a cast.
- *
- * Revision 1.55 1999/04/12 12:34:02 fritz
- * Changes from 2.0 tree.
- *
- * Revision 1.54 1999/01/05 18:29:39 he
- * merged remaining schedule_timeout() changes from 2.1.127
- *
- * Revision 1.53 1998/06/17 19:51:28 he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
- *
- * Revision 1.52 1998/05/20 19:29:58 tsbogend
- * fixed bug introduced by changes for new BSENT callback
- *
- * Revision 1.51 1998/03/07 22:29:55 fritz
- * Adapted Detlef's chenges for 2.1.
- *
- * Revision 1.49 1998/02/13 11:14:15 keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.48 1997/10/10 15:56:14 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.47 1997/10/01 09:21:51 fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.46 1997/08/21 22:38:33 fritz
- * Fixed a typo.
- *
- * Revision 1.45 1997/06/21 10:42:06 fritz
- * Added availability to select leased mode on only one channel.
- *
- * Revision 1.44 1997/03/30 16:51:26 calle
- * changed calls to copy_from_user/copy_to_user and removed verify_area
- * were possible.
- *
- * Revision 1.43 1997/03/21 18:27:04 fritz
- * Corrected parsing of incoming setup.
- *
- * Revision 1.42 1997/03/05 21:13:18 fritz
- * Bugfix: sndcount was not reset on hangup.
- *
- * Revision 1.41 1997/02/24 23:34:29 fritz
- * Bugfix in Layer1 error-recovery.
- *
- * Revision 1.40 1997/02/23 23:34:45 fritz
- * Minor bugfixes in debugging code.
- *
- * Revision 1.39 1997/02/23 16:21:56 fritz
- * Bugfix: Check for NULL pointer in icn_parse_status().
- *
- * Revision 1.38 1997/02/11 18:29:31 fritz
- * Bugfix in D64S initialization.
- *
- * Revision 1.37 1997/02/10 22:43:20 fritz
- * Added plan and screen elements on ISDN_STAT_ICALL
- *
- * Revision 1.36 1997/02/10 21:31:20 fritz
- * Changed setup-interface (incoming and outgoing).
- *
- * Revision 1.35 1997/02/10 10:10:28 fritz
- * Changes for Kernel 2.1.X compatibility.
- * Enhanced initialization, can recover from
- * misconfiguration by other autoprobing drivers.
- *
- * Revision 1.34 1997/01/29 22:34:44 fritz
- * Cleanup, Corrected D64S setup of 2nd channel.
- *
- * Revision 1.33 1996/12/05 20:31:48 tsbogend
- * added handling of L2: DATA LINK LOST messages
- *
- * Revision 1.32 1996/11/14 23:49:18 fritz
- * Bugfix: copy_to_user/copy_from_user mismatch in debugging-ioctl.
- *
- * Revision 1.31 1996/11/13 02:36:25 fritz
- * Fixed a race condition in writecmd.
- * Some optimizations and cleanup.
- *
- * Revision 1.30 1996/10/22 23:14:09 fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.29 1996/08/29 20:34:54 fritz
- * Bugfix in send queue management:
- * sndcount was not updated correctly.
- * Minor Bugfixes.
- *
- * Revision 1.28 1996/06/28 17:02:53 fritz
- * replaced memcpy_fromfs_toio.
- *
- * Revision 1.27 1996/06/25 18:38:59 fritz
- * Fixed function name in error message.
- *
- * Revision 1.26 1996/06/24 17:20:35 fritz
- * Bugfixes in pollbchan_send():
- * - Using lock field of skbuff breaks networking.
- * - Added channel locking
- * - changed dequeuing scheme.
- * Eliminated misc. compiler warnings.
- *
- * Revision 1.25 1996/06/11 22:53:35 tsbogend
- * fixed problem with large array on stack
- * made the driver working on Linux/alpha
- *
- * Revision 1.24 1996/06/06 13:58:33 fritz
- * Changed code to be architecture independent
- *
- * Revision 1.23 1996/06/03 19:59:00 fritz
- * Fixed typos.
- *
- * Revision 1.22 1996/05/17 15:46:41 fritz
- * Removed own queue management.
- * Changed queue management to use sk_buffs.
- *
- * Revision 1.21 1996/05/02 04:01:20 fritz
- * Bugfix:
- * - icn_addcard() evaluated wrong driverId.
- *
- * Revision 1.20 1996/05/02 00:40:27 fritz
- * Major rewrite to support more than one card
- * with a single module.
- * Support for new firmware.
- *
- * Revision 1.19 1996/04/21 17:43:32 fritz
- * Changes for Support of new Firmware BRV3.02
- *
- * Revision 1.18 1996/04/20 16:50:26 fritz
- * Fixed status-buffer overrun.
- * Misc. typos
- *
- * Revision 1.17 1996/02/11 02:39:04 fritz
- * Increased Buffer for status-messages.
- * Removed conditionals for HDLC-firmware.
- *
- * Revision 1.16 1996/01/22 05:01:55 fritz
- * Revert to GPL.
- *
- * Revision 1.15 1996/01/10 20:57:39 fritz
- * Bugfix: Loading firmware twice caused the device stop working.
- *
- * Revision 1.14 1995/12/18 18:23:37 fritz
- * Support for ICN-2B Cards.
- * Change for supporting user-settable service-octet.
- *
- * Revision 1.13 1995/10/29 21:41:07 fritz
- * Added support for DriverId's, added Jan's patches for Kernel versions.
- *
- * Revision 1.12 1995/04/29 13:07:35 fritz
- * Added support for new Euro-ISDN-firmware
- *
- * Revision 1.11 1995/04/23 13:40:45 fritz
- * Added support for SPV's.
- * Changed Dial-Command to support MSN's on DSS1-Lines.
- *
- * Revision 1.10 1995/03/25 23:23:24 fritz
- * Changed configurable Ports, to allow settings for DIP-Switch Cardversions.
- *
- * Revision 1.9 1995/03/25 23:17:30 fritz
- * Fixed race-condition in pollbchan_send
- *
- * Revision 1.8 1995/03/15 12:49:44 fritz
- * Added support for SPV's
- * Split pollbchan_work for calling send-routine directly
- *
- * Revision 1.7 1995/02/20 03:48:03 fritz
- * Added support of new request_region-function.
- * Minor bugfixes.
- *
- * Revision 1.6 1995/01/31 15:48:45 fritz
- * Added Cause-Messages to be signaled to upper layers.
- * Added Revision-Info on load.
- *
- * Revision 1.5 1995/01/29 23:34:59 fritz
- * Added stopdriver() and appropriate calls.
- * Changed printk-statements to support loglevels.
- *
- * Revision 1.4 1995/01/09 07:40:46 fritz
- * Added GPL-Notice
- *
- * Revision 1.3 1995/01/04 05:15:18 fritz
- * Added undocumented "bootload-finished"-command in download-code
- * to satisfy some brain-damaged icn card-versions.
- *
- * Revision 1.2 1995/01/02 02:14:45 fritz
- * Misc Bugfixes
- *
- * Revision 1.1 1994/12/14 17:56:06 fritz
- * Initial revision
- *
*/
#include "icn.h"
@@ -251,7 +33,7 @@
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.63 $";
+*revision = "$Revision: 1.65 $";
static int icn_addcard(int, char *, char *);
@@ -1873,7 +1655,7 @@ icn_setup(char *line)
portbase = ints[1];
if (ints[0] > 1)
membase = ints[2];
- if (strlen(str)) {
+ if (str && *str) {
strcpy(sid, str);
icn_id = sid;
if ((p = strchr(sid, ','))) {
diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h
index 6d40a695c..b49887c2a 100644
--- a/drivers/isdn/icn/icn.h
+++ b/drivers/isdn/icn/icn.h
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.29 1999/09/06 07:29:35 fritz Exp $
+/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $
* ISDN lowlevel-module for the ICN active ISDN-Card.
*
@@ -18,110 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: icn.h,v $
- * Revision 1.29 1999/09/06 07:29:35 fritz
- * Changed my mail-address.
- *
- * Revision 1.28 1997/10/10 15:56:18 fritz
- * New HL<->LL interface:
- * New BSENT callback with nr. of bytes included.
- * Sending without ACK.
- *
- * Revision 1.27 1997/10/01 09:21:56 fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.26 1997/02/14 12:23:16 fritz
- * Added support for new insmod parameter handling.
- *
- * Revision 1.25 1997/02/10 10:10:31 fritz
- * Changes for Kernel 2.1.X compatibility.
- * Enhanced initialization, can recover from
- * misconfiguration by other autoprobing drivers.
- *
- * Revision 1.24 1997/01/29 22:34:46 fritz
- * Cleanup, Corrected D64S setup of 2nd channel.
- *
- * Revision 1.23 1996/12/17 18:47:55 tsbogend
- * changed timeouts from absolute numbers to HZ based values
- *
- * Revision 1.22 1996/11/13 02:37:33 fritz
- * Added delay include.
- *
- * Revision 1.21 1996/08/29 20:35:57 fritz
- * Speed up B-Channel polling interval.
- *
- * Revision 1.20 1996/06/24 17:20:37 fritz
- * Bugfixes in pollbchan_send():
- * - Using lock field of skbuff breaks networking.
- * - Added channel locking
- * - changed dequeuing scheme.
- * Eliminated misc. compiler warnings.
- *
- * Revision 1.19 1996/06/06 13:58:35 fritz
- * Changed code to be architecture independent
- *
- * Revision 1.18 1996/06/03 19:59:30 fritz
- * Removed include of config.h
- *
- * Revision 1.17 1996/05/18 00:47:04 fritz
- * Removed callback debug code.
- *
- * Revision 1.16 1996/05/17 15:46:43 fritz
- * Removed own queue management.
- * Changed queue management to use sk_buffs.
- *
- * Revision 1.15 1996/05/02 04:01:57 fritz
- * Removed ICN_MAXCARDS
- *
- * Revision 1.14 1996/05/02 00:40:29 fritz
- * Major rewrite to support more than one card
- * with a single module.
- * Support for new firmware.
- *
- * Revision 1.13 1996/04/20 16:51:41 fritz
- * Increased status buffer.
- * Misc. typos
- *
- * Revision 1.12 1996/01/22 05:01:22 fritz
- * Revert to GPL.
- *
- * Revision 1.11 1995/12/18 18:25:00 fritz
- * Support for ICN-2B Cards.
- * Change for supporting user-settable service-octet.
- *
- * Revision 1.10 1995/10/29 21:43:10 fritz
- * Added support for leased lines.
- *
- * Revision 1.9 1995/04/23 13:42:10 fritz
- * Added some constants for distinguishing 1TR6 and DSS1
- *
- * Revision 1.8 1995/03/25 23:18:55 fritz
- * Changed ICN_PORTLEN to reflect correct number of ports.
- *
- * Revision 1.7 1995/03/15 12:52:06 fritz
- * Some cleanup
- *
- * Revision 1.6 1995/02/20 03:49:22 fritz
- * Fixed ICN_MAX_SQUEUE to correctly reflect outstanding bytes, not number
- * of buffers.
- *
- * Revision 1.5 1995/01/29 23:36:50 fritz
- * Minor cleanup.
- *
- * Revision 1.4 1995/01/09 07:41:20 fritz
- * Added GPL-Notice
- *
- * Revision 1.3 1995/01/04 05:14:20 fritz
- * removed include of linux/asm/string.h for compiling with Linux 1.1.76
- *
- * Revision 1.2 1995/01/02 02:15:57 fritz
- * Misc. Bugfixes
- *
- * Revision 1.1 1994/12/14 18:02:38 fritz
- * Initial revision
- *
*/
#ifndef icn_h
diff --git a/drivers/isdn/isdn_cards.c b/drivers/isdn/isdn_cards.c
index 63da26096..14413285f 100644
--- a/drivers/isdn/isdn_cards.c
+++ b/drivers/isdn/isdn_cards.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_cards.c,v 1.11 2000/05/11 22:29:20 kai Exp $
+/* $Id: isdn_cards.c,v 1.13 2000/10/28 23:03:38 kai Exp $
* Linux ISDN subsystem, initialization for non-modularized drivers.
*
@@ -43,6 +43,9 @@ extern void kcapi_init(void);
extern void capi_init(void);
extern void capidrv_init(void);
#endif
+#if CONFIG_ISDN_DRV_ACT2000
+extern void act2000_init(void);
+#endif
void
isdn_cards_init(void)
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index ba2c41eb5..dc117e886 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.111 2000/08/20 07:40:14 keil Exp $
+/* $Id: isdn_common.c,v 1.113 2000/11/01 17:54:00 detabc Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -48,7 +48,7 @@
isdn_dev *dev;
-static char *isdn_revision = "$Revision: 1.111 $";
+static char *isdn_revision = "$Revision: 1.113 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index d33fb5135..b3b431443 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.135 2000/08/10 22:52:46 kai Exp $
+/* $Id: isdn_net.c,v 1.140 2000/11/01 17:54:01 detabc Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -181,7 +181,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
-char *isdn_net_revision = "$Revision: 1.135 $";
+char *isdn_net_revision = "$Revision: 1.140 $";
/*
* Code for raw-networking over ISDN
@@ -190,7 +190,6 @@ char *isdn_net_revision = "$Revision: 1.135 $";
static void
isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
{
-
if(skb) {
u_short proto = ntohs(skb->protocol);
@@ -704,6 +703,7 @@ isdn_net_dial(void)
i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
if (i >= 0) {
strcpy(dev->num[i], cmd.parm.setup.phone);
+ dev->usage[i] |= ISDN_USAGE_OUTGOING;
isdn_info_update();
}
printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
@@ -1001,8 +1001,7 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
/*
* called from tq_immediate
*/
-static void
-isdn_net_softint(void *private)
+static void isdn_net_softint(void *private)
{
isdn_net_local *lp = private;
struct sk_buff *skb;
@@ -1086,9 +1085,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
return isdn_ppp_xmit(skb, ndev);
}
#endif
-
nd = ((isdn_net_local *) ndev->priv)->netdev;
-
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
@@ -1218,6 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
buf = skb->data;
isdn_dumppkt("S:", buf, skb->len, 40);
#endif
+
if (!(lp->flags & ISDN_NET_CONNECTED)) {
int chi;
/* only do autodial if allowed by config */
@@ -1532,7 +1530,6 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
}
-
skb->dev = ndev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
@@ -1615,6 +1612,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
isdn_ppp_receive(lp->netdev, olp, skb);
return;
#endif
+
default:
#ifdef CONFIG_ISDN_X25
/* try if there are generic sync_device receiver routines */
diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c
index 204995061..5ad0edc6a 100644
--- a/drivers/isdn/isdn_ppp.c
+++ b/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.77 2000/06/12 16:46:34 keil Exp $
+/* $Id: isdn_ppp.c,v 1.84 2000/11/13 22:51:46 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -36,8 +36,6 @@
#define PPP_IPX 0x002b
#endif
-/* set this if you use dynamic addressing */
-
/* Prototypes */
static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot);
@@ -46,7 +44,7 @@ static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
- struct ippp_struct *,struct ippp_struct *,int proto);
+ struct ippp_struct *,struct ippp_struct *,int *proto);
static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb,int proto);
static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
@@ -85,7 +83,7 @@ static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
#endif /* CONFIG_ISDN_MPP */
-char *isdn_ppp_revision = "$Revision: 1.77 $";
+char *isdn_ppp_revision = "$Revision: 1.84 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -849,15 +847,49 @@ isdn_ppp_cleanup(void)
}
/*
+ * check for address/control field and skip if allowed
+ * retval != 0 -> discard packet silently
+ */
+static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
+{
+ if (skb->len < 1)
+ return -1;
+
+ if (skb->data[0] == 0xff) {
+ if (skb->len < 2)
+ return -1;
+
+ if (skb->data[1] != 0x03)
+ return -1;
+
+ // skip address/control (AC) field
+ skb_pull(skb, 2);
+ } else {
+ if (is->pppcfg & SC_REJ_COMP_AC)
+ // if AC compression was not negotiated, but used, discard packet
+ return -1;
+ }
+ return 0;
+}
+
+/*
* get the PPP protocol header and pull skb
+ * retval < 0 -> discard packet silently
*/
static int isdn_ppp_strip_proto(struct sk_buff *skb)
{
int proto;
+
+ if (skb->len < 1)
+ return -1;
+
if (skb->data[0] & 0x1) {
+ // protocol field is compressed
proto = skb->data[0];
- skb_pull(skb, 1); /* protocol ID is only 8 bit */
+ skb_pull(skb, 1);
} else {
+ if (skb->len < 2)
+ return -1;
proto = ((int) skb->data[0] << 8) + skb->data[1];
skb_pull(skb, 2);
}
@@ -874,6 +906,9 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
int slot;
int proto;
+ if (net_dev->local->master)
+ BUG(); // we're called with the master device always
+
slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
@@ -887,122 +922,95 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
(long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
}
- if (net_dev->local->master) {
- printk(KERN_WARNING "isdn_ppp_receive: net_dev != master\n");
- net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev;
- }
- if (skb->data[0] == 0xff && skb->data[1] == 0x03)
- skb_pull(skb, 2);
- else if (is->pppcfg & SC_REJ_COMP_AC) {
- dev_kfree_skb(skb);
- return; /* discard it silently */
- }
-
- proto = isdn_ppp_strip_proto(skb);
+ if (isdn_ppp_skip_ac(is, skb) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ proto = isdn_ppp_strip_proto(skb);
+ if (proto < 0) {
+ kfree_skb(skb);
+ return;
+ }
+
#ifdef CONFIG_ISDN_MPP
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
-
- if(is->compflags & SC_LINK_DECOMP_ON) {
- if(proto == PPP_COMPFRAG) {
- if(is->debug & 0x10)
- printk(KERN_DEBUG "received single link compressed frame\n");
- skb = isdn_ppp_decompress(skb,is,NULL,proto);
- if(!skb)
- return;
- proto = isdn_ppp_strip_proto(skb);
- }
- else
- isdn_ppp_decompress(skb,is,NULL,proto);
- }
-
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
- }
- else
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
- } else
-#endif /* CONFIG_ISDN_MPP */
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
+ if (is->compflags & SC_LINK_DECOMP_ON) {
+ skb = isdn_ppp_decompress(skb, is, NULL, &proto);
+ if (!skb) // decompression error
+ return;
+ }
+
+ if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
+ if (proto == PPP_MP) {
+ isdn_ppp_mp_receive(net_dev, lp, skb);
+ return;
+ }
+ }
+#endif
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
/*
- * push frame to higher layers
+ * we receive a reassembled frame, MPPP has been taken care of before.
+ * address/control and protocol have been stripped from the skb
* note: net_dev has to be master net_dev
*/
static void
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
struct net_device *dev = &net_dev->dev;
- struct ippp_struct *is;
+ struct ippp_struct *is, *mis;
int slot;
slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
- kfree_skb(skb);
- return;
+ goto drop_packet;
}
is = ippp_table[slot];
+
+ if (lp->master) { // FIXME?
+ slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ goto drop_packet;
+ }
+ }
+ mis = ippp_table[slot];
+
if (is->debug & 0x10) {
printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
}
-
- if(proto == PPP_COMP) {
- if(!lp->master)
- skb = isdn_ppp_decompress(skb,is,is,proto);
- else
- skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
-
- if(!skb) {
- printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
- return;
- }
-
- proto = isdn_ppp_strip_proto(skb);
- if (is->debug & 0x10) {
- printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
- }
- }
- else if(is->compflags & SC_DECOMP_ON) { /* If decomp is ON */
- if(!lp->master)
- isdn_ppp_decompress(skb,is,is,proto);
- else
- isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
- }
-
+ if (is->compflags & SC_DECOMP_ON) {
+ skb = isdn_ppp_decompress(skb, is, mis, &proto);
+ if (!skb) // decompression error
+ return;
+ }
switch (proto) {
case PPP_IPX: /* untested */
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_IPX);
break;
+ case PPP_IP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IP\n");
+ skb->protocol = htons(ETH_P_IP);
+ break;
#ifdef CONFIG_ISDN_PPP_VJ
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- net_dev->local->stats.rx_dropped++;
- dev_kfree_skb(skb);
- return;
+ goto drop_packet;
}
-#endif
- case PPP_IP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_IP);
break;
case PPP_VJC_COMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
-#ifdef CONFIG_ISDN_PPP_VJ
{
struct sk_buff *skb_old = skb;
int pkt_len;
@@ -1010,32 +1018,22 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
if (!skb) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- net_dev->local->stats.rx_dropped++;
- dev_kfree_skb(skb_old);
- return;
+ skb = skb_old;
+ goto drop_packet;
}
- skb->dev = dev;
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
- skb->mac.raw = skb->data;
pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
skb->data, skb_old->len);
- dev_kfree_skb(skb_old);
- if (pkt_len < 0) {
- dev_kfree_skb(skb);
- lp->stats.rx_dropped++;
- return;
- }
+ kfree_skb(skb_old);
+ if (pkt_len < 0)
+ goto drop_packet;
+
skb_trim(skb, pkt_len);
skb->protocol = htons(ETH_P_IP);
}
-#else
- printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
- lp->stats.rx_dropped++;
- dev_kfree_skb(skb);
- return;
-#endif
break;
+#endif
case PPP_CCP:
case PPP_CCPFRAG:
isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
@@ -1047,21 +1045,27 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
/* fall through */
default:
isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return;
}
/* Reset hangup-timer */
lp->huptimer = 0;
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
return;
+
+ drop_packet:
+ net_dev->local->stats.rx_dropped++;
+ kfree_skb(skb);
}
/*
* isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the SKB
+ * checks whether we have enough space at the beginning of the skb
* and allocs a new SKB if necessary
*/
static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
@@ -1363,9 +1367,9 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
static u32 isdn_ppp_mp_get_seq( int short_seq,
struct sk_buff * skb, u32 last_seq );
-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
struct sk_buff * from, struct sk_buff * to );
-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff * from, struct sk_buff * to );
static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
@@ -2256,8 +2260,20 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
is->reset->lastid++;
}
+/*
+ * decompress packet
+ *
+ * if master = 0, we're trying to uncompress an per-link compressed packet,
+ * as opposed to an compressed reconstructed-from-MPPP packet.
+ * proto is updated to protocol field of uncompressed packet.
+ *
+ * retval: decompressed packet,
+ * same packet if uncompressed,
+ * NULL if decompression error
+ */
+
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
- int proto)
+ int *proto)
{
void *stat = NULL;
struct isdn_ppp_compressor *ipc = NULL;
@@ -2268,84 +2284,69 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc
unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
if(!master) {
- /*
- * single link decompression
- */
- if(!is->link_decompressor) {
- printk(KERN_ERR "ippp: no link decompressor defined!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- if(!is->link_decomp_stat) {
- printk(KERN_DEBUG "ippp: no link decompressor data allocated\n");
- dev_kfree_skb(skb);
- return NULL;
- }
+ // per-link decompression
stat = is->link_decomp_stat;
ipc = is->link_decompressor;
ri = is;
- }
- else {
- /*
- * 'normal' or bundle-compression
- */
- if(!master->decompressor) {
- printk(KERN_ERR "ippp: no decompressor defined!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- if(!master->decomp_stat) {
- printk(KERN_DEBUG "ippp: no decompressor data allocated\n");
- dev_kfree_skb(skb);
- return NULL;
- }
+ } else {
stat = master->decomp_stat;
ipc = master->decompressor;
ri = master;
}
- /*
- printk(KERN_DEBUG "ippp: Decompress valid!\n");
- */
+ if (!ipc) {
+ // no decompressor -> we can't decompress.
+ printk(KERN_DEBUG "ippp: no decompressor defined!\n");
+ return skb;
+ }
+ if (!stat) // if we have a compressor, stat has been set as well
+ BUG();
- if((master && proto == PPP_COMP) || (!master && proto == PPP_COMPFRAG) ) {
- /* Set up reset params for the decompressor */
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+ if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
+ // compressed packets are compressed by their protocol type
-/* !!!HACK,HACK,HACK!!! 2048 is only assumed */
- skb_out = dev_alloc_skb(2048);
- len = ipc->decompress(stat,skb,skb_out, &rsparm);
- dev_kfree_skb(skb);
- if(len <= 0) {
- /* Ok, some error */
- switch(len) {
- case DECOMP_ERROR:
- ri->pppcfg |= SC_DC_ERROR;
- printk(KERN_INFO "ippp: decomp wants reset %s params\n",
- rsparm.valid ? "with" : "without");
-
- isdn_ppp_ccp_reset_trans(ri, &rsparm);
-
- break;
- case DECOMP_FATALERROR:
- ri->pppcfg |= SC_DC_FERROR;
- /* Kick ipppd to recognize the error */
- isdn_ppp_ccp_kickup(ri);
- break;
- }
- /* Did I see a leak here ? */
- dev_kfree_skb(skb_out);
- return NULL;
+ // Set up reset params for the decompressor
+ memset(&rsparm, 0, sizeof(rsparm));
+ rsparm.data = rsdata;
+ rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+
+ /* !!!HACK,HACK,HACK!!! 2048 is only assumed */
+ skb_out = dev_alloc_skb(2048);
+ len = ipc->decompress(stat, skb, skb_out, &rsparm);
+ kfree_skb(skb);
+ if (len <= 0) {
+ switch(len) {
+ case DECOMP_ERROR:
+ ri->pppcfg |= SC_DC_ERROR;
+ printk(KERN_INFO "ippp: decomp wants reset %s params\n",
+ rsparm.valid ? "with" : "without");
+
+ isdn_ppp_ccp_reset_trans(ri, &rsparm);
+ break;
+ case DECOMP_FATALERROR:
+ ri->pppcfg |= SC_DC_FERROR;
+ /* Kick ipppd to recognize the error */
+ isdn_ppp_ccp_kickup(ri);
+ break;
+ }
+ kfree_skb(skb_out);
+ return NULL;
+ }
+
+ if (isdn_ppp_skip_ac(ri, skb) < 0) {
+ kfree_skb(skb);
+ return NULL;
+ }
+ *proto = isdn_ppp_strip_proto(skb);
+ if (*proto < 0) {
+ kfree_skb(skb);
+ return NULL;
}
return skb_out;
- }
- else {
- /*
- printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit);
- */
- ipc->incomp(stat,skb,proto);
+ } else {
+ // uncompressed packets are fed through the decompressor to
+ // update the decompressor state
+ ipc->incomp(stat, skb, *proto);
return skb;
}
}
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index 9168aca8c..f91723bbe 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.9 1999/09/06 07:29:36 fritz Exp $
+/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $
* ISDN low-level module implementing a dummy loop driver.
*
@@ -18,48 +18,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: isdnloop.c,v $
- * Revision 1.9 1999/09/06 07:29:36 fritz
- * Changed my mail-address.
- *
- * Revision 1.8 1998/11/18 18:59:43 armin
- * changes for 2.1.127
- *
- * Revision 1.7 1998/10/30 18:58:03 he
- * typecast to suppress a compiler warning
- *
- * Revision 1.6 1998/06/17 19:51:37 he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
- *
- * Revision 1.5 1998/04/14 20:59:32 he
- * merged 2.1.94 changes
- *
- * Revision 1.4 1998/02/24 21:39:05 he
- * L2_PROT_X25DTE / DCE
- * additional state 17 and new internal signal messages "BCON_I"
- * (for reliable connect confirmation primitive as needed by x.25 upper layer)
- * Changes for new LL-HL interface
- *
- * Revision 1.3 1998/02/20 17:33:30 fritz
- * Changes for recent kernels.
- *
- * Revision 1.2 1997/10/01 09:22:03 fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.1 1997/03/24 23:02:04 fritz
- * Added isdnloop driver.
- *
*/
#include <linux/config.h>
#include "isdnloop.h"
static char
-*revision = "$Revision: 1.9 $";
+*revision = "$Revision: 1.11 $";
static int isdnloop_addcard(char *);
@@ -865,6 +830,7 @@ isdnloop_parse_cmd(isdnloop_card * card)
if (card->rcard[ch - 1]) {
isdnloop_fake(card->rcard[ch - 1], "BCON_I",
card->rch[ch - 1] + 1);
+ isdnloop_fake(card, "BCON_C", ch);
}
break;
case 17:
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
index 82266edbe..e0ddaaf36 100644
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.4 1999/09/06 07:29:36 fritz Exp $
+/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $
* Loopback lowlevel module for testing of linklevel.
*
@@ -18,21 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: isdnloop.h,v $
- * Revision 1.4 1999/09/06 07:29:36 fritz
- * Changed my mail-address.
- *
- * Revision 1.3 1998/04/14 20:59:35 he
- * merged 2.1.94 changes
- *
- * Revision 1.2 1997/10/01 09:22:07 fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.1 1997/03/24 23:02:05 fritz
- * Added isdnloop driver.
- *
*/
#ifndef isdnloop_h
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index cd58e0d3b..125742e6a 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -114,9 +114,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
if (!dev->b1) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
return -ENOMEM;
}
@@ -124,9 +124,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
if (!dev->b2) {
printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
kfree(dev->b1);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
return -ENOMEM;
}
@@ -148,9 +148,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
{
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
@@ -170,9 +170,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
free_irq(irq, dev);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
@@ -201,9 +201,9 @@ int pcbit_init_dev(int board, int mem_base, int irq)
free_irq(irq, dev);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
dev_pcbit[board] = NULL;
return -EIO;
}
@@ -239,9 +239,9 @@ void pcbit_terminate(int board)
del_timer(&dev->b2->fsm_timer);
kfree(dev->b1);
kfree(dev->b2);
- kfree(dev);
iounmap((unsigned char*)dev->sh_mem);
release_mem_region(dev->ph_mem, 4096);
+ kfree(dev);
}
}
#endif
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
index b1bdf57af..09c11f57d 100644
--- a/drivers/isdn/sc/debug.c
+++ b/drivers/isdn/sc/debug.c
@@ -1,5 +1,5 @@
/*
- * $Id: debug.c,v 1.3 1997/10/01 09:22:20 fritz Exp $
+ * $Id: debug.c,v 1.5 2000/11/12 15:29:37 kai Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,11 +27,6 @@
*/
#include <linux/kernel.h>
-#define NULL 0x0
-
-#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
-#define FREE_IRQ(a,b) free_irq(a,b)
-
inline char *strcpy(char *, const char *);
int dbg_level = 0;
@@ -61,7 +56,7 @@ inline char *strcpy(char *dest, const char *src)
*i = *j;
i++; j++;
}
- *(++i) = NULL;
+ *(++i) = 0;
return dest;
}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 9712ddbae..598e5d601 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -1296,6 +1296,33 @@ void pmu_blink(int n)
* Put the powerbook to sleep.
*/
+static u32 save_via[8];
+static void save_via_state(void)
+{
+ save_via[0] = in_8(&via[ANH]);
+ save_via[1] = in_8(&via[DIRA]);
+ save_via[2] = in_8(&via[B]);
+ save_via[3] = in_8(&via[DIRB]);
+ save_via[4] = in_8(&via[PCR]);
+ save_via[5] = in_8(&via[ACR]);
+ save_via[6] = in_8(&via[T1CL]);
+ save_via[7] = in_8(&via[T1CH]);
+}
+static void restore_via_state(void)
+{
+ out_8(&via[ANH], save_via[0]);
+ out_8(&via[DIRA], save_via[1]);
+ out_8(&via[B], save_via[2]);
+ out_8(&via[DIRB], save_via[3]);
+ out_8(&via[PCR], save_via[4]);
+ out_8(&via[ACR], save_via[5]);
+ out_8(&via[T1CL], save_via[6]);
+ out_8(&via[T1CH], save_via[7]);
+ out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
+ out_8(&via[IFR], 0x7f); /* clear IFR */
+ out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+}
+
#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38))
#define GRACKLE_PM (1<<7)
#define GRACKLE_DOZE (1<<5)
@@ -1304,11 +1331,11 @@ void pmu_blink(int n)
int __openfirmware powerbook_sleep_G3(void)
{
- int ret;
unsigned long save_l2cr;
unsigned long wait;
unsigned short pmcr1;
struct adb_request req;
+ int ret, timeout;
/* Notify device drivers */
ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
@@ -1333,24 +1360,54 @@ int __openfirmware powerbook_sleep_G3(void)
}
/* Give the disks a little time to actually finish writing */
- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ for (wait = jiffies + (HZ/2); time_before(jiffies, wait); )
mb();
+ /* Wait for completion of async backlight requests */
+ while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+ pmu_poll();
+
+ /* Turn off various things. Darwin does some retry tests here... */
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+ while (!req.complete)
+ pmu_poll();
+
/* Disable all interrupts except pmu */
sleep_save_intrs(vias->intrs[0].line);
+ /* Make sure the PMU is idle */
+ while (pmu_state != idle)
+ pmu_poll();
+
/* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
- feature_prepare_for_sleep();
+ /* Make sure any pending DEC interrupt occuring while we did
+ * the above didn't re-enable the DEC */
+ mb();
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Giveup the FPU */
+ if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
+ giveup_fpu(current);
/* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
if (save_l2cr)
_set_L2CR(0);
- if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
- giveup_fpu(current);
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
+ pmu_poll();
+
+ /* The VIA is supposed not to be restored correctly*/
+ save_via_state();
+ /* We shut down some HW */
+ feature_prepare_for_sleep();
grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);
/* Apparently, MacOS uses NAP mode for Grackle ??? */
@@ -1358,15 +1415,6 @@ int __openfirmware powerbook_sleep_G3(void)
pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
- /* Ask the PMU to put us to sleep */
- pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!req.complete)
- pmu_poll();
-
- cli();
- while (pmu_state != idle)
- pmu_poll();
-
/* Call low-level ASM sleep handler */
low_sleep_handler();
@@ -1374,33 +1422,54 @@ int __openfirmware powerbook_sleep_G3(void)
grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);
pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
-
- /* Make sure the PMU is idle */
- while (pmu_state != idle)
- pmu_poll();
-
- sti();
-
+
+ /* Restore things */
feature_wake_up();
-
- /* The PGD is only a placeholder until Dan finds a way to make
- * this work properly on the 8xx processors. It is only used on
- * 8xx processors, it is ignored here.
- */
- set_context(current->mm->context, current->mm->pgd);
-
+ restore_via_state();
+
/* Restore L2 cache */
if (save_l2cr)
- _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+ _set_L2CR(save_l2cr);
+
+ /* Restore userland MMU context */
+ set_context(current->mm->context, current->mm->pgd);
- /* reenable interrupts */
- sleep_restore_intrs();
+ /* Re-enable DEC interrupts and kick DEC */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ sti();
+ asm volatile("mtdec %0" : : "r" (0x10000000));
- /* Tell PMU we are ready */
- pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+ /* Power things up */
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
while (!req.complete)
pmu_poll();
-
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
+ PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+ while (!req.complete)
+ pmu_poll();
+
+ /* ack all pending interrupts */
+ timeout = 100000;
+ interrupt_data[0] = 1;
+ while (interrupt_data[0] || pmu_state != idle) {
+ if (--timeout < 0)
+ break;
+ if (pmu_state == idle)
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, 0, 0);
+ udelay(10);
+ }
+
+ /* reenable interrupt controller */
+ sleep_restore_intrs();
+
+ /* Leave some time for HW to settle down */
+ mdelay(100);
+
/* Notify drivers */
mdelay(10);
broadcast_wake();
diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c
index 239ed99aa..5aa88df9e 100644
--- a/drivers/md/lvm.c
+++ b/drivers/md/lvm.c
@@ -1928,7 +1928,7 @@ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv)
{
int l, le, l_new, p, size;
ulong lv_status_save;
- char *lv_tmp, *lv_buf;
+ char *lv_tmp, *lv_buf = NULL;
lv_block_exception_t *lvbe = lv->lv_block_exception;
vg_t *vg_ptr = vg[VG_CHR(minor)];
lv_t *lv_ptr = NULL;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c89314c78..091551597 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/config.h>
#include <linux/raid/md.h>
+#include <linux/sysctl.h>
#include <linux/raid/xor.h>
#include <linux/devfs_fs_kernel.h>
@@ -2836,14 +2837,13 @@ int md_thread(void * arg)
mdk_thread_t *thread = arg;
md_lock_kernel();
- exit_mm(current);
- exit_files(current);
- exit_fs(current);
/*
* Detach thread
*/
+
daemonize();
+
sprintf(current->comm, thread->name);
md_init_signals();
md_flush_signals();
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index b39c87e0e..85073b564 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -91,7 +91,8 @@ static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt)
static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh)
{
- md_spin_lock_irq(&conf->device_lock);
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
while (bh) {
struct buffer_head *t = bh;
bh=bh->b_next;
@@ -103,7 +104,7 @@ static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh)
conf->freebh_cnt++;
}
}
- md_spin_unlock_irq(&conf->device_lock);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
wake_up(&conf->wait_buffer);
}
@@ -182,10 +183,11 @@ static inline void raid1_free_r1bh(struct raid1_bh *r1_bh)
r1_bh->mirror_bh_list = NULL;
if (test_bit(R1BH_PreAlloc, &r1_bh->state)) {
- md_spin_lock_irq(&conf->device_lock);
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
r1_bh->next_r1 = conf->freer1;
conf->freer1 = r1_bh;
- md_spin_unlock_irq(&conf->device_lock);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
} else {
kfree(r1_bh);
}
@@ -229,14 +231,15 @@ static void raid1_shrink_r1bh(raid1_conf_t *conf)
static inline void raid1_free_buf(struct raid1_bh *r1_bh)
{
+ unsigned long flags;
struct buffer_head *bh = r1_bh->mirror_bh_list;
raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev);
r1_bh->mirror_bh_list = NULL;
- md_spin_lock_irq(&conf->device_lock);
+ spin_lock_irqsave(&conf->device_lock, flags);
r1_bh->next_r1 = conf->freebuf;
conf->freebuf = r1_bh;
- md_spin_unlock_irq(&conf->device_lock);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
raid1_free_bh(conf, bh);
}
@@ -599,7 +602,7 @@ static int raid1_make_request (mddev_t *mddev, int rw,
bh_req = &r1_bh->bh_req;
memcpy(bh_req, bh, sizeof(*bh));
- bh_req->b_blocknr = bh->b_rsector * sectors;
+ bh_req->b_blocknr = bh->b_rsector / sectors;
bh_req->b_dev = mirror->dev;
bh_req->b_rdev = mirror->dev;
/* bh_req->b_rsector = bh->n_rsector; */
@@ -643,7 +646,7 @@ static int raid1_make_request (mddev_t *mddev, int rw,
/*
* prepare mirrored mbh (fields ordered for max mem throughput):
*/
- mbh->b_blocknr = bh->b_rsector * sectors;
+ mbh->b_blocknr = bh->b_rsector / sectors;
mbh->b_dev = conf->mirrors[i].dev;
mbh->b_rdev = conf->mirrors[i].dev;
mbh->b_rsector = bh->b_rsector;
@@ -1181,7 +1184,7 @@ static void raid1d (void *data)
struct buffer_head *bh1 = mbh;
mbh = mbh->b_next;
generic_make_request(WRITE, bh1);
- md_sync_acct(bh1->b_rdev, bh1->b_size/512);
+ md_sync_acct(bh1->b_dev, bh1->b_size/512);
}
} else {
dev = bh->b_dev;
@@ -1406,7 +1409,7 @@ static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr)
init_waitqueue_head(&bh->b_wait);
generic_make_request(READ, bh);
- md_sync_acct(bh->b_rdev, bh->b_size/512);
+ md_sync_acct(bh->b_dev, bh->b_size/512);
return (bsize >> 10);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index cff836dc4..4103b0ea5 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -858,13 +858,16 @@ static void compute_parity(struct stripe_head *sh, int method)
PRINTK("compute_parity, stripe %lu, method %d\n", sh->sector, method);
for (i = 0; i < disks; i++) {
+ char *bdata;
if (i == pd_idx || !sh->bh_new[i])
continue;
if (!sh->bh_copy[i])
sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size);
raid5_build_block(sh, sh->bh_copy[i], i);
atomic_set_buffer_dirty(sh->bh_copy[i]);
- memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size);
+ bdata = bh_kmap(sh->bh_new[i]);
+ memcpy(sh->bh_copy[i]->b_data, bdata, sh->size);
+ bh_kunmap(sh->bh_new[i]);
}
if (sh->bh_copy[pd_idx] == NULL) {
sh->bh_copy[pd_idx] = raid5_alloc_buffer(sh, sh->size);
@@ -965,12 +968,14 @@ static void complete_stripe(struct stripe_head *sh)
if (!sh->new[i]) {
#if 0
if (sh->cmd == STRIPE_WRITE) {
- if (memcmp(sh->bh_new[i]->b_data, sh->bh_copy[i]->b_data, sh->size)) {
+ char *bdata = bh_kmap(sh->bh_new[i]);
+ if (memcmp(bdata, sh->bh_copy[i]->b_data, sh->size)) {
printk("copy differs, %s, sector %lu ",
test_bit(BH_Dirty, &sh->bh_new[i]->b_state) ? "dirty" : "clean",
sh->sector);
} else if (test_bit(BH_Dirty, &sh->bh_new[i]->b_state))
printk("sector %lu dirty\n", sh->sector);
+ bh_kunmap(sh->bh_new[i]);
}
#endif
if (sh->cmd == STRIPE_WRITE)
@@ -1136,11 +1141,14 @@ static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf,
if (!method1 || (method1 == 1 && nr_cache == disks - 1)) {
PRINTK("read %lu completed from cache\n", sh->sector);
for (i = 0; i < disks; i++) {
+ char *bdata;
if (!sh->bh_new[i])
continue;
if (!sh->bh_old[i])
compute_block(sh, i);
- memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size);
+ bdata = bh_kmap(sh->bh_new[i]);
+ memcpy(bdata, sh->bh_old[i]->b_data, sh->size);
+ bh_kunmap(sh->bh_new[i]);
}
complete_stripe(sh);
return;
@@ -1168,7 +1176,9 @@ static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf,
if (!sh->bh_new[i])
continue;
if (sh->bh_old[i]) {
- memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size);
+ char *bdata = bh_kmap(sh->bh_new[i]);
+ memcpy(bdata, sh->bh_old[i]->b_data, sh->size);
+ bh_kunmap(sh->bh_new[i]);
continue;
}
#if RAID5_PARANOIA
@@ -2344,18 +2354,7 @@ static mdk_personality_t raid5_personality=
int raid5_init (void)
{
- int err;
-
- err = register_md_personality (RAID5, &raid5_personality);
- if (err)
- return err;
-
- /*
- * pick a XOR routine, runtime.
- */
- calibrate_xor_block();
-
- return 0;
+ return register_md_personality (RAID5, &raid5_personality);
}
#ifdef MODULE
diff --git a/drivers/md/xor.c b/drivers/md/xor.c
index 4fe04fb89..f58463ebc 100644
--- a/drivers/md/xor.c
+++ b/drivers/md/xor.c
@@ -1,10 +1,10 @@
/*
* xor.c : Multiple Devices driver for Linux
*
- * Copyright (C) 1996, 1997, 1998, 1999 Ingo Molnar, Matti Aarnio, Jakub Jelinek
+ * Copyright (C) 1996, 1997, 1998, 1999, 2000,
+ * Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson.
*
- *
- * optimized RAID-5 checksumming functions.
+ * Dispatch optimized RAID-5 checksumming functions.
*
* 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
@@ -15,2584 +15,66 @@
* (for example /usr/src/linux/COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
#include <linux/config.h>
#define BH_TRACE 0
#include <linux/module.h>
#include <linux/raid/md.h>
-#ifdef __sparc_v9__
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/visasm.h>
-#endif
-
-/*
- * we use the 'XOR function template' to register multiple xor
- * functions runtime. The kernel measures their speed upon bootup
- * and decides which one to use. (compile-time registration is
- * not enough as certain CPU features like MMX can only be detected
- * runtime)
- *
- * this architecture makes it pretty easy to add new routines
- * that are faster on certain CPUs, without killing other CPU's
- * 'native' routine. Although the current routines are belived
- * to be the physically fastest ones on all CPUs tested, but
- * feel free to prove me wrong and add yet another routine =B-)
- * --mingo
- */
-
-#define MAX_XOR_BLOCKS 5
-
-#define XOR_ARGS (unsigned int count, struct buffer_head **bh_ptr)
-
-typedef void (*xor_block_t) XOR_ARGS;
-xor_block_t xor_block = NULL;
-
-#ifndef __sparc_v9__
-
-struct xor_block_template;
-
-struct xor_block_template {
- char * name;
- xor_block_t xor_block;
- int speed;
- struct xor_block_template * next;
-};
-
-struct xor_block_template * xor_functions = NULL;
-
-#define XORBLOCK_TEMPLATE(x) \
-static void xor_block_##x XOR_ARGS; \
-static struct xor_block_template t_xor_block_##x = \
- { #x, xor_block_##x, 0, NULL }; \
-static void xor_block_##x XOR_ARGS
-
-#ifdef __i386__
-
-#ifdef CONFIG_X86_XMM
-/*
- * Cache avoiding checksumming functions utilizing KNI instructions
- * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
- */
-
-XORBLOCK_TEMPLATE(pIII_kni)
-{
- char xmm_save[16*4];
- int cr0;
- int lines = (bh_ptr[0]->b_size>>8);
-
- __asm__ __volatile__ (
- "movl %%cr0,%0 ;\n\t"
- "clts ;\n\t"
- "movups %%xmm0,(%1) ;\n\t"
- "movups %%xmm1,0x10(%1) ;\n\t"
- "movups %%xmm2,0x20(%1) ;\n\t"
- "movups %%xmm3,0x30(%1) ;\n\t"
- : "=r" (cr0)
- : "r" (xmm_save)
- : "memory" );
-
-#define OFFS(x) "8*("#x"*2)"
-#define PF0(x) \
- " prefetcht0 "OFFS(x)"(%1) ;\n"
-#define LD(x,y) \
- " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n"
-#define ST(x,y) \
- " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n"
-#define PF1(x) \
- " prefetchnta "OFFS(x)"(%2) ;\n"
-#define PF2(x) \
- " prefetchnta "OFFS(x)"(%3) ;\n"
-#define PF3(x) \
- " prefetchnta "OFFS(x)"(%4) ;\n"
-#define PF4(x) \
- " prefetchnta "OFFS(x)"(%5) ;\n"
-#define PF5(x) \
- " prefetchnta "OFFS(x)"(%6) ;\n"
-#define XO1(x,y) \
- " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n"
-#define XO2(x,y) \
- " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n"
-#define XO3(x,y) \
- " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n"
-#define XO4(x,y) \
- " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n"
-#define XO5(x,y) \
- " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n"
-
- switch(count) {
- case 2:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- LD(i,0) \
- LD(i+1,1) \
- PF1(i) \
- PF1(i+2) \
- LD(i+2,2) \
- LD(i+3,3) \
- PF0(i+4) \
- PF0(i+6) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- ST(i,0) \
- ST(i+1,1) \
- ST(i+2,2) \
- ST(i+3,3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data)
- : "memory" );
- break;
- case 3:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i+2) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- PF2(i) \
- PF2(i+2) \
- PF0(i+4) \
- PF0(i+6) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- XO2(i,0) \
- XO2(i+1,1) \
- XO2(i+2,2) \
- XO2(i+3,3) \
- ST(i,0) \
- ST(i+1,1) \
- ST(i+2,2) \
- ST(i+3,3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data)
- : "memory" );
- break;
- case 4:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i+2) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- PF2(i) \
- PF2(i+2) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- PF3(i) \
- PF3(i+2) \
- PF0(i+4) \
- PF0(i+6) \
- XO2(i,0) \
- XO2(i+1,1) \
- XO2(i+2,2) \
- XO2(i+3,3) \
- XO3(i,0) \
- XO3(i+1,1) \
- XO3(i+2,2) \
- XO3(i+3,3) \
- ST(i,0) \
- ST(i+1,1) \
- ST(i+2,2) \
- ST(i+3,3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
+#include <linux/raid/xor.h>
+#include <asm/xor.h>
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " addl $256, %4 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
+/* The xor routines to use. */
+static struct xor_block_template *active_template;
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data)
- : "memory" );
- break;
- case 5:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- PF1(i) \
- PF1(i+2) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- PF2(i) \
- PF2(i+2) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- PF3(i) \
- PF3(i+2) \
- XO2(i,0) \
- XO2(i+1,1) \
- XO2(i+2,2) \
- XO2(i+3,3) \
- PF4(i) \
- PF4(i+2) \
- PF0(i+4) \
- PF0(i+6) \
- XO3(i,0) \
- XO3(i+1,1) \
- XO3(i+2,2) \
- XO3(i+3,3) \
- XO4(i,0) \
- XO4(i+1,1) \
- XO4(i+2,2) \
- XO4(i+3,3) \
- ST(i,0) \
- ST(i+1,1) \
- ST(i+2,2) \
- ST(i+3,3) \
-
-
- PF0(0)
- PF0(2)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $256, %1 ;\n"
- " addl $256, %2 ;\n"
- " addl $256, %3 ;\n"
- " addl $256, %4 ;\n"
- " addl $256, %5 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data),
- "r" (bh_ptr[4]->b_data)
- : "memory");
- break;
- }
-
- __asm__ __volatile__ (
- "sfence ;\n\t"
- "movups (%1),%%xmm0 ;\n\t"
- "movups 0x10(%1),%%xmm1 ;\n\t"
- "movups 0x20(%1),%%xmm2 ;\n\t"
- "movups 0x30(%1),%%xmm3 ;\n\t"
- "movl %0,%%cr0 ;\n\t"
- :
- : "r" (cr0), "r" (xmm_save)
- : "memory" );
-}
-
-#undef OFFS
-#undef LD
-#undef ST
-#undef PF0
-#undef PF1
-#undef PF2
-#undef PF3
-#undef PF4
-#undef PF5
-#undef XO1
-#undef XO2
-#undef XO3
-#undef XO4
-#undef XO5
-#undef BLOCK
-
-#endif /* CONFIG_X86_XMM */
-
-/*
- * high-speed RAID5 checksumming functions utilizing MMX instructions
- * Copyright (C) 1998 Ingo Molnar
- */
-XORBLOCK_TEMPLATE(pII_mmx)
+void
+xor_block(unsigned int count, struct buffer_head **bh_ptr)
{
- char fpu_save[108];
- int lines = (bh_ptr[0]->b_size>>7);
-
- if (!(current->flags & PF_USEDFPU))
- __asm__ __volatile__ ( " clts;\n");
-
- __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) );
-
-#define LD(x,y) \
- " movq 8*("#x")(%1), %%mm"#y" ;\n"
-#define ST(x,y) \
- " movq %%mm"#y", 8*("#x")(%1) ;\n"
-#define XO1(x,y) \
- " pxor 8*("#x")(%2), %%mm"#y" ;\n"
-#define XO2(x,y) \
- " pxor 8*("#x")(%3), %%mm"#y" ;\n"
-#define XO3(x,y) \
- " pxor 8*("#x")(%4), %%mm"#y" ;\n"
-#define XO4(x,y) \
- " pxor 8*("#x")(%5), %%mm"#y" ;\n"
-
- switch(count) {
- case 2:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- XO1(i,0) \
- ST(i,0) \
- XO1(i+1,1) \
- ST(i+1,1) \
- XO1(i+2,2) \
- ST(i+2,2) \
- XO1(i+3,3) \
- ST(i+3,3)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
+ unsigned long *p0, *p1, *p2, *p3, *p4;
+ unsigned long bytes = bh_ptr[0]->b_size;
- " addl $128, %1 ;\n"
- " addl $128, %2 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data)
- : "memory");
- break;
- case 3:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- XO2(i,0) \
- ST(i,0) \
- XO2(i+1,1) \
- ST(i+1,1) \
- XO2(i+2,2) \
- ST(i+2,2) \
- XO2(i+3,3) \
- ST(i+3,3)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $128, %1 ;\n"
- " addl $128, %2 ;\n"
- " addl $128, %3 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data)
- : "memory");
- break;
- case 4:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- XO2(i,0) \
- XO2(i+1,1) \
- XO2(i+2,2) \
- XO2(i+3,3) \
- XO3(i,0) \
- ST(i,0) \
- XO3(i+1,1) \
- ST(i+1,1) \
- XO3(i+2,2) \
- ST(i+2,2) \
- XO3(i+3,3) \
- ST(i+3,3)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $128, %1 ;\n"
- " addl $128, %2 ;\n"
- " addl $128, %3 ;\n"
- " addl $128, %4 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data)
- : "memory");
- break;
- case 5:
- __asm__ __volatile__ (
-#undef BLOCK
-#define BLOCK(i) \
- LD(i,0) \
- LD(i+1,1) \
- LD(i+2,2) \
- LD(i+3,3) \
- XO1(i,0) \
- XO1(i+1,1) \
- XO1(i+2,2) \
- XO1(i+3,3) \
- XO2(i,0) \
- XO2(i+1,1) \
- XO2(i+2,2) \
- XO2(i+3,3) \
- XO3(i,0) \
- XO3(i+1,1) \
- XO3(i+2,2) \
- XO3(i+3,3) \
- XO4(i,0) \
- ST(i,0) \
- XO4(i+1,1) \
- ST(i+1,1) \
- XO4(i+2,2) \
- ST(i+2,2) \
- XO4(i+3,3) \
- ST(i+3,3)
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
-
- BLOCK(0)
- BLOCK(4)
- BLOCK(8)
- BLOCK(12)
-
- " addl $128, %1 ;\n"
- " addl $128, %2 ;\n"
- " addl $128, %3 ;\n"
- " addl $128, %4 ;\n"
- " addl $128, %5 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
- :
- : "g" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data),
- "r" (bh_ptr[4]->b_data)
- : "memory");
- break;
+ p0 = (unsigned long *) bh_ptr[0]->b_data;
+ p1 = (unsigned long *) bh_ptr[1]->b_data;
+ if (count == 2) {
+ active_template->do_2(bytes, p0, p1);
+ return;
}
- __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) );
-
- if (!(current->flags & PF_USEDFPU))
- stts();
-}
-
-#undef LD
-#undef XO1
-#undef XO2
-#undef XO3
-#undef XO4
-#undef ST
-#undef BLOCK
-
-XORBLOCK_TEMPLATE(p5_mmx)
-{
- char fpu_save[108];
- int lines = (bh_ptr[0]->b_size>>6);
-
- if (!(current->flags & PF_USEDFPU))
- __asm__ __volatile__ ( " clts;\n");
-
- __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) );
-
- switch(count) {
- case 2:
- __asm__ __volatile__ (
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
- " movq (%1), %%mm0 ;\n"
- " movq 8(%1), %%mm1 ;\n"
- " pxor (%2), %%mm0 ;\n"
- " movq 16(%1), %%mm2 ;\n"
- " movq %%mm0, (%1) ;\n"
- " pxor 8(%2), %%mm1 ;\n"
- " movq 24(%1), %%mm3 ;\n"
- " movq %%mm1, 8(%1) ;\n"
- " pxor 16(%2), %%mm2 ;\n"
- " movq 32(%1), %%mm4 ;\n"
- " movq %%mm2, 16(%1) ;\n"
- " pxor 24(%2), %%mm3 ;\n"
- " movq 40(%1), %%mm5 ;\n"
- " movq %%mm3, 24(%1) ;\n"
- " pxor 32(%2), %%mm4 ;\n"
- " movq 48(%1), %%mm6 ;\n"
- " movq %%mm4, 32(%1) ;\n"
- " pxor 40(%2), %%mm5 ;\n"
- " movq 56(%1), %%mm7 ;\n"
- " movq %%mm5, 40(%1) ;\n"
- " pxor 48(%2), %%mm6 ;\n"
- " pxor 56(%2), %%mm7 ;\n"
- " movq %%mm6, 48(%1) ;\n"
- " movq %%mm7, 56(%1) ;\n"
-
- " addl $64, %1 ;\n"
- " addl $64, %2 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data)
- : "memory" );
- break;
- case 3:
- __asm__ __volatile__ (
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
- " movq (%1), %%mm0 ;\n"
- " movq 8(%1), %%mm1 ;\n"
- " pxor (%2), %%mm0 ;\n"
- " movq 16(%1), %%mm2 ;\n"
- " pxor 8(%2), %%mm1 ;\n"
- " pxor (%3), %%mm0 ;\n"
- " pxor 16(%2), %%mm2 ;\n"
- " movq %%mm0, (%1) ;\n"
- " pxor 8(%3), %%mm1 ;\n"
- " pxor 16(%3), %%mm2 ;\n"
- " movq 24(%1), %%mm3 ;\n"
- " movq %%mm1, 8(%1) ;\n"
- " movq 32(%1), %%mm4 ;\n"
- " movq 40(%1), %%mm5 ;\n"
- " pxor 24(%2), %%mm3 ;\n"
- " movq %%mm2, 16(%1) ;\n"
- " pxor 32(%2), %%mm4 ;\n"
- " pxor 24(%3), %%mm3 ;\n"
- " pxor 40(%2), %%mm5 ;\n"
- " movq %%mm3, 24(%1) ;\n"
- " pxor 32(%3), %%mm4 ;\n"
- " pxor 40(%3), %%mm5 ;\n"
- " movq 48(%1), %%mm6 ;\n"
- " movq %%mm4, 32(%1) ;\n"
- " movq 56(%1), %%mm7 ;\n"
- " pxor 48(%2), %%mm6 ;\n"
- " movq %%mm5, 40(%1) ;\n"
- " pxor 56(%2), %%mm7 ;\n"
- " pxor 48(%3), %%mm6 ;\n"
- " pxor 56(%3), %%mm7 ;\n"
- " movq %%mm6, 48(%1) ;\n"
- " movq %%mm7, 56(%1) ;\n"
-
- " addl $64, %1 ;\n"
- " addl $64, %2 ;\n"
- " addl $64, %3 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data)
- : "memory" );
- break;
- case 4:
- __asm__ __volatile__ (
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
- " movq (%1), %%mm0 ;\n"
- " movq 8(%1), %%mm1 ;\n"
- " pxor (%2), %%mm0 ;\n"
- " movq 16(%1), %%mm2 ;\n"
- " pxor 8(%2), %%mm1 ;\n"
- " pxor (%3), %%mm0 ;\n"
- " pxor 16(%2), %%mm2 ;\n"
- " pxor 8(%3), %%mm1 ;\n"
- " pxor (%4), %%mm0 ;\n"
- " movq 24(%1), %%mm3 ;\n"
- " pxor 16(%3), %%mm2 ;\n"
- " pxor 8(%4), %%mm1 ;\n"
- " movq %%mm0, (%1) ;\n"
- " movq 32(%1), %%mm4 ;\n"
- " pxor 24(%2), %%mm3 ;\n"
- " pxor 16(%4), %%mm2 ;\n"
- " movq %%mm1, 8(%1) ;\n"
- " movq 40(%1), %%mm5 ;\n"
- " pxor 32(%2), %%mm4 ;\n"
- " pxor 24(%3), %%mm3 ;\n"
- " movq %%mm2, 16(%1) ;\n"
- " pxor 40(%2), %%mm5 ;\n"
- " pxor 32(%3), %%mm4 ;\n"
- " pxor 24(%4), %%mm3 ;\n"
- " movq %%mm3, 24(%1) ;\n"
- " movq 56(%1), %%mm7 ;\n"
- " movq 48(%1), %%mm6 ;\n"
- " pxor 40(%3), %%mm5 ;\n"
- " pxor 32(%4), %%mm4 ;\n"
- " pxor 48(%2), %%mm6 ;\n"
- " movq %%mm4, 32(%1) ;\n"
- " pxor 56(%2), %%mm7 ;\n"
- " pxor 40(%4), %%mm5 ;\n"
- " pxor 48(%3), %%mm6 ;\n"
- " pxor 56(%3), %%mm7 ;\n"
- " movq %%mm5, 40(%1) ;\n"
- " pxor 48(%4), %%mm6 ;\n"
- " pxor 56(%4), %%mm7 ;\n"
- " movq %%mm6, 48(%1) ;\n"
- " movq %%mm7, 56(%1) ;\n"
-
- " addl $64, %1 ;\n"
- " addl $64, %2 ;\n"
- " addl $64, %3 ;\n"
- " addl $64, %4 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "r" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data)
- : "memory" );
- break;
- case 5:
- __asm__ __volatile__ (
-
- " .align 32,0x90 ;\n"
- " 1: ;\n"
- " movq (%1), %%mm0 ;\n"
- " movq 8(%1), %%mm1 ;\n"
- " pxor (%2), %%mm0 ;\n"
- " pxor 8(%2), %%mm1 ;\n"
- " movq 16(%1), %%mm2 ;\n"
- " pxor (%3), %%mm0 ;\n"
- " pxor 8(%3), %%mm1 ;\n"
- " pxor 16(%2), %%mm2 ;\n"
- " pxor (%4), %%mm0 ;\n"
- " pxor 8(%4), %%mm1 ;\n"
- " pxor 16(%3), %%mm2 ;\n"
- " movq 24(%1), %%mm3 ;\n"
- " pxor (%5), %%mm0 ;\n"
- " pxor 8(%5), %%mm1 ;\n"
- " movq %%mm0, (%1) ;\n"
- " pxor 16(%4), %%mm2 ;\n"
- " pxor 24(%2), %%mm3 ;\n"
- " movq %%mm1, 8(%1) ;\n"
- " pxor 16(%5), %%mm2 ;\n"
- " pxor 24(%3), %%mm3 ;\n"
- " movq 32(%1), %%mm4 ;\n"
- " movq %%mm2, 16(%1) ;\n"
- " pxor 24(%4), %%mm3 ;\n"
- " pxor 32(%2), %%mm4 ;\n"
- " movq 40(%1), %%mm5 ;\n"
- " pxor 24(%5), %%mm3 ;\n"
- " pxor 32(%3), %%mm4 ;\n"
- " pxor 40(%2), %%mm5 ;\n"
- " movq %%mm3, 24(%1) ;\n"
- " pxor 32(%4), %%mm4 ;\n"
- " pxor 40(%3), %%mm5 ;\n"
- " movq 48(%1), %%mm6 ;\n"
- " movq 56(%1), %%mm7 ;\n"
- " pxor 32(%5), %%mm4 ;\n"
- " pxor 40(%4), %%mm5 ;\n"
- " pxor 48(%2), %%mm6 ;\n"
- " pxor 56(%2), %%mm7 ;\n"
- " movq %%mm4, 32(%1) ;\n"
- " pxor 48(%3), %%mm6 ;\n"
- " pxor 56(%3), %%mm7 ;\n"
- " pxor 40(%5), %%mm5 ;\n"
- " pxor 48(%4), %%mm6 ;\n"
- " pxor 56(%4), %%mm7 ;\n"
- " movq %%mm5, 40(%1) ;\n"
- " pxor 48(%5), %%mm6 ;\n"
- " pxor 56(%5), %%mm7 ;\n"
- " movq %%mm6, 48(%1) ;\n"
- " movq %%mm7, 56(%1) ;\n"
-
- " addl $64, %1 ;\n"
- " addl $64, %2 ;\n"
- " addl $64, %3 ;\n"
- " addl $64, %4 ;\n"
- " addl $64, %5 ;\n"
- " decl %0 ;\n"
- " jnz 1b ;\n"
-
- :
- : "g" (lines),
- "r" (bh_ptr[0]->b_data),
- "r" (bh_ptr[1]->b_data),
- "r" (bh_ptr[2]->b_data),
- "r" (bh_ptr[3]->b_data),
- "r" (bh_ptr[4]->b_data)
- : "memory" );
- break;
+ p2 = (unsigned long *) bh_ptr[2]->b_data;
+ if (count == 3) {
+ active_template->do_3(bytes, p0, p1, p2);
+ return;
}
- __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) );
-
- if (!(current->flags & PF_USEDFPU))
- stts();
-}
-#endif /* __i386__ */
-#endif /* !__sparc_v9__ */
-
-#ifdef __sparc_v9__
-/*
- * High speed xor_block operation for RAID4/5 utilizing the
- * UltraSparc Visual Instruction Set.
- *
- * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- * Requirements:
- * !(((long)dest | (long)sourceN) & (64 - 1)) &&
- * !(len & 127) && len >= 256
- *
- * It is done in pure assembly, as otherwise gcc makes it
- * a non-leaf function, which is not what we want.
- * Also, we don't measure the speeds as on other architectures,
- * as the measuring routine does not take into account cold caches
- * and the fact that xor_block_VIS bypasses the caches.
- * xor_block_32regs might be 5% faster for count 2 if caches are hot
- * and things just right (for count 3 VIS is about as fast as 32regs for
- * hot caches and for count 4 and 5 VIS is faster by good margin always),
- * but I think it is better not to pollute the caches.
- * Actually, if I'd just fight for speed for hot caches, I could
- * write a hybrid VIS/integer routine, which would do always two
- * 64B blocks in VIS and two in IEUs, but I really care more about
- * caches.
- */
-extern void *VISenter(void);
-extern void xor_block_VIS XOR_ARGS;
-
-void __xor_block_VIS(void)
-{
-__asm__ ("
- .globl xor_block_VIS
-xor_block_VIS:
- ldx [%%o1 + 0], %%o4
- ldx [%%o1 + 8], %%o3
- ldx [%%o4 + %1], %%g5
- ldx [%%o4 + %0], %%o4
- ldx [%%o3 + %0], %%o3
- rd %%fprs, %%o5
- andcc %%o5, %2, %%g0
- be,pt %%icc, 297f
- sethi %%hi(%5), %%g1
- jmpl %%g1 + %%lo(%5), %%g7
- add %%g7, 8, %%g7
-297: wr %%g0, %4, %%fprs
- membar #LoadStore|#StoreLoad|#StoreStore
- sub %%g5, 64, %%g5
- ldda [%%o4] %3, %%f0
- ldda [%%o3] %3, %%f16
- cmp %%o0, 4
- bgeu,pt %%xcc, 10f
- cmp %%o0, 3
- be,pn %%xcc, 13f
- mov -64, %%g1
- sub %%g5, 64, %%g5
- rd %%asi, %%g1
- wr %%g0, %3, %%asi
-
-2: ldda [%%o4 + 64] %%asi, %%f32
- fxor %%f0, %%f16, %%f16
- fxor %%f2, %%f18, %%f18
- fxor %%f4, %%f20, %%f20
- fxor %%f6, %%f22, %%f22
- fxor %%f8, %%f24, %%f24
- fxor %%f10, %%f26, %%f26
- fxor %%f12, %%f28, %%f28
- fxor %%f14, %%f30, %%f30
- stda %%f16, [%%o4] %3
- ldda [%%o3 + 64] %%asi, %%f48
- ldda [%%o4 + 128] %%asi, %%f0
- fxor %%f32, %%f48, %%f48
- fxor %%f34, %%f50, %%f50
- add %%o4, 128, %%o4
- fxor %%f36, %%f52, %%f52
- add %%o3, 128, %%o3
- fxor %%f38, %%f54, %%f54
- subcc %%g5, 128, %%g5
- fxor %%f40, %%f56, %%f56
- fxor %%f42, %%f58, %%f58
- fxor %%f44, %%f60, %%f60
- fxor %%f46, %%f62, %%f62
- stda %%f48, [%%o4 - 64] %%asi
- bne,pt %%xcc, 2b
- ldda [%%o3] %3, %%f16
-
- ldda [%%o4 + 64] %%asi, %%f32
- fxor %%f0, %%f16, %%f16
- fxor %%f2, %%f18, %%f18
- fxor %%f4, %%f20, %%f20
- fxor %%f6, %%f22, %%f22
- fxor %%f8, %%f24, %%f24
- fxor %%f10, %%f26, %%f26
- fxor %%f12, %%f28, %%f28
- fxor %%f14, %%f30, %%f30
- stda %%f16, [%%o4] %3
- ldda [%%o3 + 64] %%asi, %%f48
- membar #Sync
- fxor %%f32, %%f48, %%f48
- fxor %%f34, %%f50, %%f50
- fxor %%f36, %%f52, %%f52
- fxor %%f38, %%f54, %%f54
- fxor %%f40, %%f56, %%f56
- fxor %%f42, %%f58, %%f58
- fxor %%f44, %%f60, %%f60
- fxor %%f46, %%f62, %%f62
- stda %%f48, [%%o4 + 64] %%asi
- membar #Sync|#StoreStore|#StoreLoad
- wr %%g0, 0, %%fprs
- retl
- wr %%g1, %%g0, %%asi
-
-13: ldx [%%o1 + 16], %%o2
- ldx [%%o2 + %0], %%o2
-
-3: ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f48
- fxor %%f2, %%f18, %%f50
- add %%o4, 64, %%o4
- fxor %%f4, %%f20, %%f52
- fxor %%f6, %%f22, %%f54
- add %%o3, 64, %%o3
- fxor %%f8, %%f24, %%f56
- fxor %%f10, %%f26, %%f58
- fxor %%f12, %%f28, %%f60
- fxor %%f14, %%f30, %%f62
- ldda [%%o4] %3, %%f0
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- add %%o2, 64, %%o2
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- subcc %%g5, 64, %%g5
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- stda %%f48, [%%o4 + %%g1] %3
- bne,pt %%xcc, 3b
- ldda [%%o3] %3, %%f16
-
- ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f48
- fxor %%f2, %%f18, %%f50
- fxor %%f4, %%f20, %%f52
- fxor %%f6, %%f22, %%f54
- fxor %%f8, %%f24, %%f56
- fxor %%f10, %%f26, %%f58
- fxor %%f12, %%f28, %%f60
- fxor %%f14, %%f30, %%f62
- membar #Sync
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- stda %%f48, [%%o4] %3
- membar #Sync|#StoreStore|#StoreLoad
- retl
- wr %%g0, 0, %%fprs
-
-10: cmp %%o0, 5
- be,pt %%xcc, 15f
- mov -64, %%g1
-
-14: ldx [%%o1 + 16], %%o2
- ldx [%%o1 + 24], %%o0
- ldx [%%o2 + %0], %%o2
- ldx [%%o0 + %0], %%o0
-
-4: ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f16
- fxor %%f2, %%f18, %%f18
- add %%o4, 64, %%o4
- fxor %%f4, %%f20, %%f20
- fxor %%f6, %%f22, %%f22
- add %%o3, 64, %%o3
- fxor %%f8, %%f24, %%f24
- fxor %%f10, %%f26, %%f26
- fxor %%f12, %%f28, %%f28
- fxor %%f14, %%f30, %%f30
- ldda [%%o0] %3, %%f48
- fxor %%f16, %%f32, %%f32
- fxor %%f18, %%f34, %%f34
- fxor %%f20, %%f36, %%f36
- fxor %%f22, %%f38, %%f38
- add %%o2, 64, %%o2
- fxor %%f24, %%f40, %%f40
- fxor %%f26, %%f42, %%f42
- fxor %%f28, %%f44, %%f44
- fxor %%f30, %%f46, %%f46
- ldda [%%o4] %3, %%f0
- fxor %%f32, %%f48, %%f48
- fxor %%f34, %%f50, %%f50
- fxor %%f36, %%f52, %%f52
- add %%o0, 64, %%o0
- fxor %%f38, %%f54, %%f54
- fxor %%f40, %%f56, %%f56
- fxor %%f42, %%f58, %%f58
- subcc %%g5, 64, %%g5
- fxor %%f44, %%f60, %%f60
- fxor %%f46, %%f62, %%f62
- stda %%f48, [%%o4 + %%g1] %3
- bne,pt %%xcc, 4b
- ldda [%%o3] %3, %%f16
-
- ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f16
- fxor %%f2, %%f18, %%f18
- fxor %%f4, %%f20, %%f20
- fxor %%f6, %%f22, %%f22
- fxor %%f8, %%f24, %%f24
- fxor %%f10, %%f26, %%f26
- fxor %%f12, %%f28, %%f28
- fxor %%f14, %%f30, %%f30
- ldda [%%o0] %3, %%f48
- fxor %%f16, %%f32, %%f32
- fxor %%f18, %%f34, %%f34
- fxor %%f20, %%f36, %%f36
- fxor %%f22, %%f38, %%f38
- fxor %%f24, %%f40, %%f40
- fxor %%f26, %%f42, %%f42
- fxor %%f28, %%f44, %%f44
- fxor %%f30, %%f46, %%f46
- membar #Sync
- fxor %%f32, %%f48, %%f48
- fxor %%f34, %%f50, %%f50
- fxor %%f36, %%f52, %%f52
- fxor %%f38, %%f54, %%f54
- fxor %%f40, %%f56, %%f56
- fxor %%f42, %%f58, %%f58
- fxor %%f44, %%f60, %%f60
- fxor %%f46, %%f62, %%f62
- stda %%f48, [%%o4] %3
- membar #Sync|#StoreStore|#StoreLoad
- retl
- wr %%g0, 0, %%fprs
-
-15: ldx [%%o1 + 16], %%o2
- ldx [%%o1 + 24], %%o0
- ldx [%%o1 + 32], %%o1
- ldx [%%o2 + %0], %%o2
- ldx [%%o0 + %0], %%o0
- ldx [%%o1 + %0], %%o1
-
-5: ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f48
- fxor %%f2, %%f18, %%f50
- add %%o4, 64, %%o4
- fxor %%f4, %%f20, %%f52
- fxor %%f6, %%f22, %%f54
- add %%o3, 64, %%o3
- fxor %%f8, %%f24, %%f56
- fxor %%f10, %%f26, %%f58
- fxor %%f12, %%f28, %%f60
- fxor %%f14, %%f30, %%f62
- ldda [%%o0] %3, %%f16
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- add %%o2, 64, %%o2
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- ldda [%%o1] %3, %%f32
- fxor %%f48, %%f16, %%f48
- fxor %%f50, %%f18, %%f50
- add %%o0, 64, %%o0
- fxor %%f52, %%f20, %%f52
- fxor %%f54, %%f22, %%f54
- add %%o1, 64, %%o1
- fxor %%f56, %%f24, %%f56
- fxor %%f58, %%f26, %%f58
- fxor %%f60, %%f28, %%f60
- fxor %%f62, %%f30, %%f62
- ldda [%%o4] %3, %%f0
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- subcc %%g5, 64, %%g5
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- stda %%f48, [%%o4 + %%g1] %3
- bne,pt %%xcc, 5b
- ldda [%%o3] %3, %%f16
-
- ldda [%%o2] %3, %%f32
- fxor %%f0, %%f16, %%f48
- fxor %%f2, %%f18, %%f50
- fxor %%f4, %%f20, %%f52
- fxor %%f6, %%f22, %%f54
- fxor %%f8, %%f24, %%f56
- fxor %%f10, %%f26, %%f58
- fxor %%f12, %%f28, %%f60
- fxor %%f14, %%f30, %%f62
- ldda [%%o0] %3, %%f16
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- ldda [%%o1] %3, %%f32
- fxor %%f48, %%f16, %%f48
- fxor %%f50, %%f18, %%f50
- fxor %%f52, %%f20, %%f52
- fxor %%f54, %%f22, %%f54
- fxor %%f56, %%f24, %%f56
- fxor %%f58, %%f26, %%f58
- fxor %%f60, %%f28, %%f60
- fxor %%f62, %%f30, %%f62
- membar #Sync
- fxor %%f48, %%f32, %%f48
- fxor %%f50, %%f34, %%f50
- fxor %%f52, %%f36, %%f52
- fxor %%f54, %%f38, %%f54
- fxor %%f56, %%f40, %%f56
- fxor %%f58, %%f42, %%f58
- fxor %%f60, %%f44, %%f60
- fxor %%f62, %%f46, %%f62
- stda %%f48, [%%o4] %3
- membar #Sync|#StoreStore|#StoreLoad
- retl
- wr %%g0, 0, %%fprs
- " : :
- "i" (&((struct buffer_head *)0)->b_data),
- "i" (&((struct buffer_head *)0)->b_size),
- "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P),
- "i" (FPRS_FEF), "i" (VISenter));
-}
-#endif /* __sparc_v9__ */
-
-#if defined(__sparc__) && !defined(__sparc_v9__)
-/*
- * High speed xor_block operation for RAID4/5 utilizing the
- * ldd/std SPARC instructions.
- *
- * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- */
-
-XORBLOCK_TEMPLATE(SPARC)
-{
- int size = bh_ptr[0]->b_size;
- int lines = size / (sizeof (long)) / 8, i;
- long *destp = (long *) bh_ptr[0]->b_data;
- long *source1 = (long *) bh_ptr[1]->b_data;
- long *source2, *source3, *source4;
-
- switch (count) {
- case 2:
- for (i = lines; i > 0; i--) {
- __asm__ __volatile__("
- ldd [%0 + 0x00], %%g2
- ldd [%0 + 0x08], %%g4
- ldd [%0 + 0x10], %%o0
- ldd [%0 + 0x18], %%o2
- ldd [%1 + 0x00], %%o4
- ldd [%1 + 0x08], %%l0
- ldd [%1 + 0x10], %%l2
- ldd [%1 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- std %%g2, [%0 + 0x00]
- std %%g4, [%0 + 0x08]
- std %%o0, [%0 + 0x10]
- std %%o2, [%0 + 0x18]
- " : : "r" (destp), "r" (source1) : "g2", "g3", "g4", "g5", "o0",
- "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5");
- destp += 8;
- source1 += 8;
- }
- break;
- case 3:
- source2 = (long *) bh_ptr[2]->b_data;
- for (i = lines; i > 0; i--) {
- __asm__ __volatile__("
- ldd [%0 + 0x00], %%g2
- ldd [%0 + 0x08], %%g4
- ldd [%0 + 0x10], %%o0
- ldd [%0 + 0x18], %%o2
- ldd [%1 + 0x00], %%o4
- ldd [%1 + 0x08], %%l0
- ldd [%1 + 0x10], %%l2
- ldd [%1 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%2 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%2 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%2 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%2 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- std %%g2, [%0 + 0x00]
- std %%g4, [%0 + 0x08]
- std %%o0, [%0 + 0x10]
- std %%o2, [%0 + 0x18]
- " : : "r" (destp), "r" (source1), "r" (source2)
- : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5",
- "l0", "l1", "l2", "l3", "l4", "l5");
- destp += 8;
- source1 += 8;
- source2 += 8;
- }
- break;
- case 4:
- source2 = (long *) bh_ptr[2]->b_data;
- source3 = (long *) bh_ptr[3]->b_data;
- for (i = lines; i > 0; i--) {
- __asm__ __volatile__("
- ldd [%0 + 0x00], %%g2
- ldd [%0 + 0x08], %%g4
- ldd [%0 + 0x10], %%o0
- ldd [%0 + 0x18], %%o2
- ldd [%1 + 0x00], %%o4
- ldd [%1 + 0x08], %%l0
- ldd [%1 + 0x10], %%l2
- ldd [%1 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%2 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%2 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%2 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%2 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%3 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%3 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%3 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%3 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- std %%g2, [%0 + 0x00]
- std %%g4, [%0 + 0x08]
- std %%o0, [%0 + 0x10]
- std %%o2, [%0 + 0x18]
- " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3)
- : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5",
- "l0", "l1", "l2", "l3", "l4", "l5");
- destp += 8;
- source1 += 8;
- source2 += 8;
- source3 += 8;
- }
- break;
- case 5:
- source2 = (long *) bh_ptr[2]->b_data;
- source3 = (long *) bh_ptr[3]->b_data;
- source4 = (long *) bh_ptr[4]->b_data;
- for (i = lines; i > 0; i--) {
- __asm__ __volatile__("
- ldd [%0 + 0x00], %%g2
- ldd [%0 + 0x08], %%g4
- ldd [%0 + 0x10], %%o0
- ldd [%0 + 0x18], %%o2
- ldd [%1 + 0x00], %%o4
- ldd [%1 + 0x08], %%l0
- ldd [%1 + 0x10], %%l2
- ldd [%1 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%2 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%2 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%2 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%2 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%3 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%3 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%3 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%3 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- ldd [%4 + 0x00], %%o4
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- ldd [%4 + 0x08], %%l0
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- ldd [%4 + 0x10], %%l2
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- ldd [%4 + 0x18], %%l4
- xor %%g2, %%o4, %%g2
- xor %%g3, %%o5, %%g3
- xor %%g4, %%l0, %%g4
- xor %%g5, %%l1, %%g5
- xor %%o0, %%l2, %%o0
- xor %%o1, %%l3, %%o1
- xor %%o2, %%l4, %%o2
- xor %%o3, %%l5, %%o3
- std %%g2, [%0 + 0x00]
- std %%g4, [%0 + 0x08]
- std %%o0, [%0 + 0x10]
- std %%o2, [%0 + 0x18]
- " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3), "r" (source4)
- : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5",
- "l0", "l1", "l2", "l3", "l4", "l5");
- destp += 8;
- source1 += 8;
- source2 += 8;
- source3 += 8;
- source4 += 8;
- }
- break;
+ p3 = (unsigned long *) bh_ptr[3]->b_data;
+ if (count == 4) {
+ active_template->do_4(bytes, p0, p1, p2, p3);
+ return;
}
-}
-#endif /* __sparc_v[78]__ */
-
-#ifdef __alpha__
-/*
- * High speed xor_block operation for RAID4/5 pipelined for Alpha EV5.
- * There is a second version using EV6 prefetch instructions.
- *
- * Copyright (C) 2000 Richard Henderson (rth@redhat.com)
- */
-
-XORBLOCK_TEMPLATE(alpha)
-{
- long lines = bh_ptr[0]->b_size / sizeof (long) / 8;
- long *d = (long *) bh_ptr[0]->b_data;
- long *s1 = (long *) bh_ptr[1]->b_data;
- long *s2, *s3, *s4;
-
- if (count == 2) goto two_blocks;
-
- s2 = (long *) bh_ptr[2]->b_data;
- if (count == 3) goto three_blocks;
-
- s3 = (long *) bh_ptr[3]->b_data;
- if (count == 4) goto four_blocks;
-
- s4 = (long *) bh_ptr[4]->b_data;
- goto five_blocks;
-
-two_blocks:
-asm volatile ("
- .align 4
-2:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,8(%0)
- ldq $3,8(%1)
-
- ldq $4,16(%0)
- ldq $5,16(%1)
- ldq $6,24(%0)
- ldq $7,24(%1)
-
- ldq $16,32(%0)
- ldq $17,32(%1)
- ldq $18,40(%0)
- ldq $19,40(%1)
-
- ldq $20,48(%0)
- ldq $21,48(%1)
- ldq $22,56(%0)
- xor $0,$1,$0 # 7 cycles from $1 load
-
- ldq $23,56(%1)
- xor $2,$3,$2
- stq $0,0(%0)
- xor $4,$5,$4
-
- stq $2,8(%0)
- xor $6,$7,$6
- stq $4,16(%0)
- xor $16,$17,$16
-
- stq $6,24(%0)
- xor $18,$19,$18
- stq $16,32(%0)
- xor $20,$21,$20
-
- stq $18,40(%0)
- xor $22,$23,$22
- stq $20,48(%0)
- subq %2,1,%2
-
- stq $22,56(%0)
- addq %0,64,%0
- addq %1,64,%1
- bgt %2,2b"
- : "=r"(d), "=r"(s1), "=r"(lines)
- : "0"(d), "1"(s1), "2"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23");
- return;
-
-three_blocks:
-asm volatile ("
- .align 4
-3:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,8(%0)
-
- ldq $4,8(%1)
- ldq $6,16(%0)
- ldq $7,16(%1)
- ldq $17,24(%0)
-
- ldq $18,24(%1)
- ldq $20,32(%0)
- ldq $21,32(%1)
- ldq $5,8(%2)
-
- ldq $16,16(%2)
- ldq $19,24(%2)
- ldq $22,32(%2)
- nop
-
- xor $0,$1,$1 # 8 cycles from $0 load
- xor $3,$4,$4 # 6 cycles from $4 load
- xor $6,$7,$7 # 6 cycles from $7 load
- xor $17,$18,$18 # 5 cycles from $18 load
-
- xor $1,$2,$2 # 9 cycles from $2 load
- xor $20,$21,$21 # 5 cycles from $21 load
- stq $2,0(%0)
- xor $4,$5,$5 # 6 cycles from $5 load
-
- stq $5,8(%0)
- xor $7,$16,$16 # 7 cycles from $16 load
- stq $16,16(%0)
- xor $18,$19,$19 # 7 cycles from $19 load
-
- stq $19,24(%0)
- xor $21,$22,$22 # 7 cycles from $22 load
- stq $22,32(%0)
- nop
-
- ldq $0,40(%0)
- ldq $1,40(%1)
- ldq $3,48(%0)
- ldq $4,48(%1)
-
- ldq $6,56(%0)
- ldq $7,56(%1)
- ldq $2,40(%2)
- ldq $5,48(%2)
-
- ldq $16,56(%2)
- xor $0,$1,$1 # 4 cycles from $1 load
- xor $3,$4,$4 # 5 cycles from $4 load
- xor $6,$7,$7 # 5 cycles from $7 load
-
- xor $1,$2,$2 # 4 cycles from $2 load
- xor $4,$5,$5 # 5 cycles from $5 load
- stq $2,40(%0)
- xor $7,$16,$16 # 4 cycles from $16 load
-
- stq $5,48(%0)
- subq %3,1,%3
- stq $16,56(%0)
- addq %2,64,%2
-
- addq %1,64,%1
- addq %0,64,%0
- bgt %3,3b"
- : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines)
- : "0"(d), "1"(s1), "2"(s2), "3"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22");
- return;
-
-four_blocks:
-asm volatile ("
- .align 4
-4:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,0(%3)
-
- ldq $4,8(%0)
- ldq $5,8(%1)
- ldq $6,8(%2)
- ldq $7,8(%3)
- ldq $16,16(%0)
- ldq $17,16(%1)
- ldq $18,16(%2)
- ldq $19,16(%3)
-
- ldq $20,24(%0)
- xor $0,$1,$1 # 6 cycles from $1 load
- ldq $21,24(%1)
- xor $2,$3,$3 # 6 cycles from $3 load
-
- ldq $0,24(%2)
- xor $1,$3,$3
- ldq $1,24(%3)
- xor $4,$5,$5 # 7 cycles from $5 load
-
- stq $3,0(%0)
- xor $6,$7,$7
- xor $16,$17,$17 # 7 cycles from $17 load
- xor $5,$7,$7
-
- stq $7,8(%0)
- xor $18,$19,$19 # 7 cycles from $19 load
- ldq $2,32(%0)
- xor $17,$19,$19
-
- ldq $3,32(%1)
- ldq $4,32(%2)
- ldq $5,32(%3)
- xor $20,$21,$21 # 8 cycles from $21 load
-
- ldq $6,40(%0)
- ldq $7,40(%1)
- ldq $16,40(%2)
- ldq $17,40(%3)
-
- stq $19,16(%0)
- xor $0,$1,$1 # 9 cycles from $1 load
- xor $2,$3,$3 # 5 cycles from $3 load
- xor $21,$1,$1
-
- ldq $18,48(%0)
- xor $4,$5,$5 # 5 cycles from $5 load
- ldq $19,48(%1)
- xor $3,$5,$5
-
- ldq $20,48(%2)
- ldq $21,48(%3)
- ldq $0,56(%0)
- ldq $1,56(%1)
-
- ldq $2,56(%2)
- xor $6,$7,$7 # 8 cycles from $6 load
- ldq $3,56(%3)
- xor $16,$17,$17 # 8 cycles from $17 load
-
- xor $7,$17,$17
- xor $18,$19,$19 # 5 cycles from $19 load
- xor $20,$21,$21 # 5 cycles from $21 load
- xor $19,$21,$21
-
- stq $1,24(%0)
- xor $0,$1,$1 # 5 cycles from $1 load
- stq $5,32(%0)
- xor $2,$3,$3 # 4 cycles from $3 load
-
- stq $17,40(%0)
- xor $1,$3,$3
- stq $21,48(%0)
- subq %4,1,%4
-
- stq $3,56(%0)
- addq %3,64,%3
- addq %2,64,%2
- addq %1,64,%1
-
- addq %0,64,%0
- bgt %4,4b"
- : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines)
- : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21");
- return;
-
-five_blocks:
-asm volatile ("
- ldq %0,0(%6)
- ldq %1,8(%6)
- ldq %2,16(%6)
- ldq %3,24(%6)
- ldq %4,32(%6)
- ldq %0,%7(%0)
- ldq %1,%7(%1)
- ldq %2,%7(%2)
- ldq %3,%7(%3)
- ldq %4,%7(%4)
- .align 4
-5:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,0(%3)
-
- ldq $4,0(%4)
- ldq $5,8(%0)
- ldq $6,8(%1)
- ldq $7,8(%2)
-
- ldq $16,8(%3)
- ldq $17,8(%4)
- ldq $18,16(%0)
- ldq $19,16(%1)
-
- ldq $20,16(%2)
- xor $0,$1,$1 # 6 cycles from $1 load
- ldq $21,16(%3)
- xor $2,$3,$3 # 6 cycles from $3 load
-
- ldq $0,16(%4)
- xor $1,$3,$3
- ldq $1,24(%0)
- xor $3,$4,$4 # 7 cycles from $4 load
-
- stq $4,0(%0)
- xor $5,$6,$6 # 7 cycles from $6 load
- xor $7,$16,$16 # 7 cycles from $16 load
- xor $6,$17,$17 # 7 cycles from $17 load
-
- ldq $2,24(%1)
- xor $16,$17,$17
- ldq $3,24(%2)
- xor $18,$19,$19 # 8 cycles from $19 load
-
- stq $17,8(%0)
- xor $19,$20,$20 # 8 cycles from $20 load
- ldq $4,24(%3)
- xor $21,$0,$0 # 7 cycles from $0 load
-
- ldq $5,24(%4)
- xor $20,$0,$0
- ldq $6,32(%0)
- ldq $7,32(%1)
-
- stq $0,16(%0)
- xor $1,$2,$2 # 6 cycles from $2 load
- ldq $16,32(%2)
- xor $3,$4,$4 # 4 cycles from $4 load
-
- ldq $17,32(%3)
- xor $2,$4,$4
- ldq $18,32(%4)
- ldq $19,40(%0)
-
- ldq $20,40(%1)
- ldq $21,40(%2)
- ldq $0,40(%3)
- xor $4,$5,$5 # 7 cycles from $5 load
-
- stq $5,24(%0)
- xor $6,$7,$7 # 7 cycles from $7 load
- ldq $1,40(%4)
- ldq $2,48(%0)
-
- ldq $3,48(%1)
- xor $7,$16,$16 # 7 cycles from $16 load
- ldq $4,48(%2)
- xor $17,$18,$18 # 6 cycles from $18 load
-
- ldq $5,48(%3)
- xor $16,$18,$18
- ldq $6,48(%4)
- xor $19,$20,$20 # 7 cycles from $20 load
-
- stq $18,32(%0)
- xor $20,$21,$21 # 8 cycles from $21 load
- ldq $7,56(%0)
- xor $0,$1,$1 # 6 cycles from $1 load
-
- ldq $16,56(%1)
- ldq $17,56(%2)
- ldq $18,56(%3)
- ldq $19,56(%4)
-
- xor $21,$1,$1
- xor $2,$3,$3 # 9 cycles from $3 load
- xor $3,$4,$4 # 9 cycles from $4 load
- xor $5,$6,$6 # 8 cycles from $6 load
-
- unop
- xor $4,$6,$6
- xor $7,$16,$16 # 7 cycles from $16 load
- xor $17,$18,$18 # 6 cycles from $18 load
-
- stq $6,48(%0)
- xor $16,$18,$18
- subq %5,1,%5
- xor $18,$19,$19 # 8 cycles from $19 load
-
- stq $19,56(%0)
- addq %4,64,%4
- addq %3,64,%3
- addq %2,64,%2
-
- addq %1,64,%1
- addq %0,64,%0
- bgt %5,5b"
- : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines)
- /* ARG! We've run out of asm arguments! We've got to reload
- all those pointers we just loaded. */
- : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21");
- return;
+ p4 = (unsigned long *) bh_ptr[4]->b_data;
+ active_template->do_5(bytes, p0, p1, p2, p3, p4);
}
-#define prefetch(base, ofs) \
- asm("ldq $31,%2(%0)" : "=r"(base) : "0"(base), "i"(ofs))
-
-XORBLOCK_TEMPLATE(alpha_prefetch)
-{
- long lines = bh_ptr[0]->b_size / sizeof (long) / 8;
- long *d = (long *) bh_ptr[0]->b_data;
- long *s1 = (long *) bh_ptr[1]->b_data;
- long *s2, *s3, *s4;
- long p;
-
- p = count == 2;
- prefetch(d, 0);
- prefetch(s1, 0);
- prefetch(d, 64);
- prefetch(s1, 64);
- prefetch(d, 128);
- prefetch(s1, 128);
- prefetch(d, 192);
- prefetch(s1, 192);
- if (p) goto two_blocks;
-
- s2 = (long *) bh_ptr[2]->b_data;
- p = count == 3;
- prefetch(s2, 0);
- prefetch(s2, 64);
- prefetch(s2, 128);
- prefetch(s2, 192);
- if (p) goto three_blocks;
-
- s3 = (long *) bh_ptr[3]->b_data;
- p = count == 4;
- prefetch(s3, 0);
- prefetch(s3, 64);
- prefetch(s3, 128);
- prefetch(s3, 192);
- if (p) goto four_blocks;
-
- s4 = (long *) bh_ptr[4]->b_data;
- prefetch(s4, 0);
- prefetch(s4, 64);
- prefetch(s4, 128);
- prefetch(s4, 192);
- goto five_blocks;
-
-two_blocks:
-asm volatile ("
- .align 4
-2:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,8(%0)
- ldq $3,8(%1)
-
- ldq $4,16(%0)
- ldq $5,16(%1)
- ldq $6,24(%0)
- ldq $7,24(%1)
-
- ldq $16,32(%0)
- ldq $17,32(%1)
- ldq $18,40(%0)
- ldq $19,40(%1)
-
- ldq $20,48(%0)
- ldq $21,48(%1)
- ldq $22,56(%0)
- ldq $23,56(%1)
-
- ldq $31,256(%0)
- xor $0,$1,$0 # 8 cycles from $1 load
- ldq $31,256(%1)
- xor $2,$3,$2
-
- stq $0,0(%0)
- xor $4,$5,$4
- stq $2,8(%0)
- xor $6,$7,$6
-
- stq $4,16(%0)
- xor $16,$17,$16
- stq $6,24(%0)
- xor $18,$19,$18
-
- stq $16,32(%0)
- xor $20,$21,$20
- stq $18,40(%0)
- xor $22,$23,$22
-
- stq $20,48(%0)
- subq %2,1,%2
- stq $22,56(%0)
- addq %0,64,%0
-
- addq %1,64,%1
- bgt %2,2b"
- : "=r"(d), "=r"(s1), "=r"(lines)
- : "0"(d), "1"(s1), "2"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23");
- return;
-
-three_blocks:
-asm volatile ("
- .align 4
-3:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,8(%0)
-
- ldq $4,8(%1)
- ldq $6,16(%0)
- ldq $7,16(%1)
- ldq $17,24(%0)
-
- ldq $18,24(%1)
- ldq $20,32(%0)
- ldq $21,32(%1)
- ldq $5,8(%2)
-
- ldq $16,16(%2)
- ldq $19,24(%2)
- ldq $22,32(%2)
- nop
-
- xor $0,$1,$1 # 8 cycles from $0 load
- xor $3,$4,$4 # 7 cycles from $4 load
- xor $6,$7,$7 # 6 cycles from $7 load
- xor $17,$18,$18 # 5 cycles from $18 load
-
- xor $1,$2,$2 # 9 cycles from $2 load
- xor $20,$21,$21 # 5 cycles from $21 load
- stq $2,0(%0)
- xor $4,$5,$5 # 6 cycles from $5 load
-
- stq $5,8(%0)
- xor $7,$16,$16 # 7 cycles from $16 load
- stq $16,16(%0)
- xor $18,$19,$19 # 7 cycles from $19 load
-
- stq $19,24(%0)
- xor $21,$22,$22 # 7 cycles from $22 load
- stq $22,32(%0)
- nop
-
- ldq $0,40(%0)
- ldq $1,40(%1)
- ldq $3,48(%0)
- ldq $4,48(%1)
-
- ldq $6,56(%0)
- ldq $7,56(%1)
- ldq $2,40(%2)
- ldq $5,48(%2)
-
- ldq $16,56(%2)
- ldq $31,256(%0)
- ldq $31,256(%1)
- ldq $31,256(%2)
-
- xor $0,$1,$1 # 6 cycles from $1 load
- xor $3,$4,$4 # 5 cycles from $4 load
- xor $6,$7,$7 # 5 cycles from $7 load
- xor $1,$2,$2 # 4 cycles from $2 load
-
- xor $4,$5,$5 # 5 cycles from $5 load
- xor $7,$16,$16 # 4 cycles from $16 load
- stq $2,40(%0)
- subq %3,1,%3
-
- stq $5,48(%0)
- addq %2,64,%2
- stq $16,56(%0)
- addq %1,64,%1
-
- addq %0,64,%0
- bgt %3,3b"
- : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines)
- : "0"(d), "1"(s1), "2"(s2), "3"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22");
- return;
-
-four_blocks:
-asm volatile ("
- .align 4
-4:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,0(%3)
-
- ldq $4,8(%0)
- ldq $5,8(%1)
- ldq $6,8(%2)
- ldq $7,8(%3)
-
- ldq $16,16(%0)
- ldq $17,16(%1)
- ldq $18,16(%2)
- ldq $19,16(%3)
-
- ldq $20,24(%0)
- xor $0,$1,$1 # 6 cycles from $1 load
- ldq $21,24(%1)
- xor $2,$3,$3 # 6 cycles from $3 load
-
- ldq $0,24(%2)
- xor $1,$3,$3
- ldq $1,24(%3)
- xor $4,$5,$5 # 7 cycles from $5 load
-
- stq $3,0(%0)
- xor $6,$7,$7
- xor $16,$17,$17 # 7 cycles from $17 load
- xor $5,$7,$7
-
- stq $7,8(%0)
- xor $18,$19,$19 # 7 cycles from $19 load
- ldq $2,32(%0)
- xor $17,$19,$19
-
- ldq $3,32(%1)
- ldq $4,32(%2)
- ldq $5,32(%3)
- xor $20,$21,$21 # 8 cycles from $21 load
-
- ldq $6,40(%0)
- ldq $7,40(%1)
- ldq $16,40(%2)
- ldq $17,40(%3)
-
- stq $19,16(%0)
- xor $0,$1,$1 # 9 cycles from $1 load
- xor $2,$3,$3 # 5 cycles from $3 load
- xor $21,$1,$1
-
- ldq $18,48(%0)
- xor $4,$5,$5 # 5 cycles from $5 load
- ldq $19,48(%1)
- xor $3,$5,$5
-
- ldq $20,48(%2)
- ldq $21,48(%3)
- ldq $0,56(%0)
- ldq $1,56(%1)
-
- ldq $2,56(%2)
- xor $6,$7,$7 # 8 cycles from $6 load
- ldq $3,56(%3)
- xor $16,$17,$17 # 8 cycles from $17 load
-
- ldq $31,256(%0)
- xor $7,$17,$17
- ldq $31,256(%1)
- xor $18,$19,$19 # 6 cycles from $19 load
+/* Set of all registered templates. */
+static struct xor_block_template *template_list;
- ldq $31,256(%2)
- xor $20,$21,$21 # 6 cycles from $21 load
- ldq $31,256(%3)
- xor $19,$21,$21
+/* The -6*32 shift factor colors the cache. */
+#define BENCH_SIZE (PAGE_SIZE-6*32)
- stq $1,24(%0)
- xor $0,$1,$1 # 7 cycles from $1 load
- stq $5,32(%0)
- xor $2,$3,$3 # 6 cycles from $3 load
-
- stq $17,40(%0)
- xor $1,$3,$3
- stq $21,48(%0)
- subq %4,1,%4
-
- stq $3,56(%0)
- addq %3,64,%3
- addq %2,64,%2
- addq %1,64,%1
-
- addq %0,64,%0
- bgt %4,4b"
- : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines)
- : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21");
- return;
-
-five_blocks:
-asm volatile ("
- ldq %0,0(%6)
- ldq %1,8(%6)
- ldq %2,16(%6)
- ldq %3,24(%6)
- ldq %4,32(%6)
- ldq %0,%7(%0)
- ldq %1,%7(%1)
- ldq %2,%7(%2)
- ldq %3,%7(%3)
- ldq %4,%7(%4)
- .align 4
-5:
- ldq $0,0(%0)
- ldq $1,0(%1)
- ldq $2,0(%2)
- ldq $3,0(%3)
-
- ldq $4,0(%4)
- ldq $5,8(%0)
- ldq $6,8(%1)
- ldq $7,8(%2)
-
- ldq $16,8(%3)
- ldq $17,8(%4)
- ldq $18,16(%0)
- ldq $19,16(%1)
-
- ldq $20,16(%2)
- xor $0,$1,$1 # 6 cycles from $1 load
- ldq $21,16(%3)
- xor $2,$3,$3 # 6 cycles from $3 load
-
- ldq $0,16(%4)
- xor $1,$3,$3
- ldq $1,24(%0)
- xor $3,$4,$4 # 7 cycles from $4 load
-
- stq $4,0(%0)
- xor $5,$6,$6 # 7 cycles from $6 load
- xor $7,$16,$16 # 7 cycles from $16 load
- xor $6,$17,$17 # 7 cycles from $17 load
-
- ldq $2,24(%1)
- xor $16,$17,$17
- ldq $3,24(%2)
- xor $18,$19,$19 # 8 cycles from $19 load
-
- stq $17,8(%0)
- xor $19,$20,$20 # 8 cycles from $20 load
- ldq $4,24(%3)
- xor $21,$0,$0 # 7 cycles from $0 load
-
- ldq $5,24(%4)
- xor $20,$0,$0
- ldq $6,32(%0)
- ldq $7,32(%1)
-
- stq $0,16(%0)
- xor $1,$2,$2 # 6 cycles from $2 load
- ldq $16,32(%2)
- xor $3,$4,$4 # 4 cycles from $4 load
-
- ldq $17,32(%3)
- xor $2,$4,$4
- ldq $18,32(%4)
- ldq $19,40(%0)
-
- ldq $20,40(%1)
- ldq $21,40(%2)
- ldq $0,40(%3)
- xor $4,$5,$5 # 7 cycles from $5 load
-
- stq $5,24(%0)
- xor $6,$7,$7 # 7 cycles from $7 load
- ldq $1,40(%4)
- ldq $2,48(%0)
-
- ldq $3,48(%1)
- xor $7,$16,$16 # 7 cycles from $16 load
- ldq $4,48(%2)
- xor $17,$18,$18 # 6 cycles from $18 load
-
- ldq $5,48(%3)
- xor $16,$18,$18
- ldq $6,48(%4)
- xor $19,$20,$20 # 7 cycles from $20 load
-
- stq $18,32(%0)
- xor $20,$21,$21 # 8 cycles from $21 load
- ldq $7,56(%0)
- xor $0,$1,$1 # 6 cycles from $1 load
-
- ldq $16,56(%1)
- ldq $17,56(%2)
- ldq $18,56(%3)
- ldq $19,56(%4)
-
- ldq $31,256(%0)
- xor $21,$1,$1
- ldq $31,256(%1)
- xor $2,$3,$3 # 9 cycles from $3 load
-
- ldq $31,256(%2)
- xor $3,$4,$4 # 9 cycles from $4 load
- ldq $31,256(%3)
- xor $5,$6,$6 # 8 cycles from $6 load
-
- ldq $31,256(%4)
- xor $4,$6,$6
- xor $7,$16,$16 # 7 cycles from $16 load
- xor $17,$18,$18 # 6 cycles from $18 load
-
- stq $6,48(%0)
- xor $16,$18,$18
- subq %5,1,%5
- xor $18,$19,$19 # 8 cycles from $19 load
-
- stq $19,56(%0)
- addq %4,64,%4
- addq %3,64,%3
- addq %2,64,%2
-
- addq %1,64,%1
- addq %0,64,%0
- bgt %5,5b"
- : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines)
- /* ARG! We've run out of asm arguments! We've got to reload
- all those pointers we just loaded. */
- : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines)
- : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$16", "$17", "$18", "$19", "$20", "$21");
- return;
-}
-
-#undef prefetch
-
-#endif /* __alpha__ */
-
-#ifndef __sparc_v9__
-
-/*
- * this one works reasonably on any x86 CPU
- * (send me an assembly version for inclusion if you can make it faster)
- *
- * this one is just as fast as written in pure assembly on x86.
- * the reason for this separate version is that the
- * fast open-coded xor routine "32reg" produces suboptimal code
- * on x86, due to lack of registers.
- */
-XORBLOCK_TEMPLATE(8regs)
-{
- int len = bh_ptr[0]->b_size;
- long *destp = (long *) bh_ptr[0]->b_data;
- long *source1, *source2, *source3, *source4;
- long lines = len / (sizeof (long)) / 8, i;
-
- switch(count) {
- case 2:
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- *(destp + 0) ^= *(source1 + 0);
- *(destp + 1) ^= *(source1 + 1);
- *(destp + 2) ^= *(source1 + 2);
- *(destp + 3) ^= *(source1 + 3);
- *(destp + 4) ^= *(source1 + 4);
- *(destp + 5) ^= *(source1 + 5);
- *(destp + 6) ^= *(source1 + 6);
- *(destp + 7) ^= *(source1 + 7);
- source1 += 8;
- destp += 8;
- }
- break;
- case 3:
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- *(destp + 0) ^= *(source1 + 0);
- *(destp + 0) ^= *(source2 + 0);
- *(destp + 1) ^= *(source1 + 1);
- *(destp + 1) ^= *(source2 + 1);
- *(destp + 2) ^= *(source1 + 2);
- *(destp + 2) ^= *(source2 + 2);
- *(destp + 3) ^= *(source1 + 3);
- *(destp + 3) ^= *(source2 + 3);
- *(destp + 4) ^= *(source1 + 4);
- *(destp + 4) ^= *(source2 + 4);
- *(destp + 5) ^= *(source1 + 5);
- *(destp + 5) ^= *(source2 + 5);
- *(destp + 6) ^= *(source1 + 6);
- *(destp + 6) ^= *(source2 + 6);
- *(destp + 7) ^= *(source1 + 7);
- *(destp + 7) ^= *(source2 + 7);
- source1 += 8;
- source2 += 8;
- destp += 8;
- }
- break;
- case 4:
- source3 = (long *) bh_ptr[3]->b_data;
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- *(destp + 0) ^= *(source1 + 0);
- *(destp + 0) ^= *(source2 + 0);
- *(destp + 0) ^= *(source3 + 0);
- *(destp + 1) ^= *(source1 + 1);
- *(destp + 1) ^= *(source2 + 1);
- *(destp + 1) ^= *(source3 + 1);
- *(destp + 2) ^= *(source1 + 2);
- *(destp + 2) ^= *(source2 + 2);
- *(destp + 2) ^= *(source3 + 2);
- *(destp + 3) ^= *(source1 + 3);
- *(destp + 3) ^= *(source2 + 3);
- *(destp + 3) ^= *(source3 + 3);
- *(destp + 4) ^= *(source1 + 4);
- *(destp + 4) ^= *(source2 + 4);
- *(destp + 4) ^= *(source3 + 4);
- *(destp + 5) ^= *(source1 + 5);
- *(destp + 5) ^= *(source2 + 5);
- *(destp + 5) ^= *(source3 + 5);
- *(destp + 6) ^= *(source1 + 6);
- *(destp + 6) ^= *(source2 + 6);
- *(destp + 6) ^= *(source3 + 6);
- *(destp + 7) ^= *(source1 + 7);
- *(destp + 7) ^= *(source2 + 7);
- *(destp + 7) ^= *(source3 + 7);
- source1 += 8;
- source2 += 8;
- source3 += 8;
- destp += 8;
- }
- break;
- case 5:
- source4 = (long *) bh_ptr[4]->b_data;
- source3 = (long *) bh_ptr[3]->b_data;
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- *(destp + 0) ^= *(source1 + 0);
- *(destp + 0) ^= *(source2 + 0);
- *(destp + 0) ^= *(source3 + 0);
- *(destp + 0) ^= *(source4 + 0);
- *(destp + 1) ^= *(source1 + 1);
- *(destp + 1) ^= *(source2 + 1);
- *(destp + 1) ^= *(source3 + 1);
- *(destp + 1) ^= *(source4 + 1);
- *(destp + 2) ^= *(source1 + 2);
- *(destp + 2) ^= *(source2 + 2);
- *(destp + 2) ^= *(source3 + 2);
- *(destp + 2) ^= *(source4 + 2);
- *(destp + 3) ^= *(source1 + 3);
- *(destp + 3) ^= *(source2 + 3);
- *(destp + 3) ^= *(source3 + 3);
- *(destp + 3) ^= *(source4 + 3);
- *(destp + 4) ^= *(source1 + 4);
- *(destp + 4) ^= *(source2 + 4);
- *(destp + 4) ^= *(source3 + 4);
- *(destp + 4) ^= *(source4 + 4);
- *(destp + 5) ^= *(source1 + 5);
- *(destp + 5) ^= *(source2 + 5);
- *(destp + 5) ^= *(source3 + 5);
- *(destp + 5) ^= *(source4 + 5);
- *(destp + 6) ^= *(source1 + 6);
- *(destp + 6) ^= *(source2 + 6);
- *(destp + 6) ^= *(source3 + 6);
- *(destp + 6) ^= *(source4 + 6);
- *(destp + 7) ^= *(source1 + 7);
- *(destp + 7) ^= *(source2 + 7);
- *(destp + 7) ^= *(source3 + 7);
- *(destp + 7) ^= *(source4 + 7);
- source1 += 8;
- source2 += 8;
- source3 += 8;
- source4 += 8;
- destp += 8;
- }
- break;
- }
-}
-
-/*
- * platform independent RAID5 checksum calculation, this should
- * be very fast on any platform that has a decent amount of
- * registers. (32 or more)
- */
-XORBLOCK_TEMPLATE(32regs)
-{
- int size = bh_ptr[0]->b_size;
- int lines = size / (sizeof (long)) / 8, i;
- long *destp = (long *) bh_ptr[0]->b_data;
- long *source1, *source2, *source3, *source4;
-
- /* LOTS of registers available...
- We do explicite loop-unrolling here for code which
- favours RISC machines. In fact this is almoast direct
- RISC assembly on Alpha and SPARC :-) */
-
-
- switch(count) {
- case 2:
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- register long d0, d1, d2, d3, d4, d5, d6, d7;
- d0 = destp[0]; /* Pull the stuff into registers */
- d1 = destp[1]; /* ... in bursts, if possible. */
- d2 = destp[2];
- d3 = destp[3];
- d4 = destp[4];
- d5 = destp[5];
- d6 = destp[6];
- d7 = destp[7];
- d0 ^= source1[0];
- d1 ^= source1[1];
- d2 ^= source1[2];
- d3 ^= source1[3];
- d4 ^= source1[4];
- d5 ^= source1[5];
- d6 ^= source1[6];
- d7 ^= source1[7];
- destp[0] = d0; /* Store the result (in burts) */
- destp[1] = d1;
- destp[2] = d2;
- destp[3] = d3;
- destp[4] = d4; /* Store the result (in burts) */
- destp[5] = d5;
- destp[6] = d6;
- destp[7] = d7;
- source1 += 8;
- destp += 8;
- }
- break;
- case 3:
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- register long d0, d1, d2, d3, d4, d5, d6, d7;
- d0 = destp[0]; /* Pull the stuff into registers */
- d1 = destp[1]; /* ... in bursts, if possible. */
- d2 = destp[2];
- d3 = destp[3];
- d4 = destp[4];
- d5 = destp[5];
- d6 = destp[6];
- d7 = destp[7];
- d0 ^= source1[0];
- d1 ^= source1[1];
- d2 ^= source1[2];
- d3 ^= source1[3];
- d4 ^= source1[4];
- d5 ^= source1[5];
- d6 ^= source1[6];
- d7 ^= source1[7];
- d0 ^= source2[0];
- d1 ^= source2[1];
- d2 ^= source2[2];
- d3 ^= source2[3];
- d4 ^= source2[4];
- d5 ^= source2[5];
- d6 ^= source2[6];
- d7 ^= source2[7];
- destp[0] = d0; /* Store the result (in burts) */
- destp[1] = d1;
- destp[2] = d2;
- destp[3] = d3;
- destp[4] = d4; /* Store the result (in burts) */
- destp[5] = d5;
- destp[6] = d6;
- destp[7] = d7;
- source1 += 8;
- source2 += 8;
- destp += 8;
- }
- break;
- case 4:
- source3 = (long *) bh_ptr[3]->b_data;
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- register long d0, d1, d2, d3, d4, d5, d6, d7;
- d0 = destp[0]; /* Pull the stuff into registers */
- d1 = destp[1]; /* ... in bursts, if possible. */
- d2 = destp[2];
- d3 = destp[3];
- d4 = destp[4];
- d5 = destp[5];
- d6 = destp[6];
- d7 = destp[7];
- d0 ^= source1[0];
- d1 ^= source1[1];
- d2 ^= source1[2];
- d3 ^= source1[3];
- d4 ^= source1[4];
- d5 ^= source1[5];
- d6 ^= source1[6];
- d7 ^= source1[7];
- d0 ^= source2[0];
- d1 ^= source2[1];
- d2 ^= source2[2];
- d3 ^= source2[3];
- d4 ^= source2[4];
- d5 ^= source2[5];
- d6 ^= source2[6];
- d7 ^= source2[7];
- d0 ^= source3[0];
- d1 ^= source3[1];
- d2 ^= source3[2];
- d3 ^= source3[3];
- d4 ^= source3[4];
- d5 ^= source3[5];
- d6 ^= source3[6];
- d7 ^= source3[7];
- destp[0] = d0; /* Store the result (in burts) */
- destp[1] = d1;
- destp[2] = d2;
- destp[3] = d3;
- destp[4] = d4; /* Store the result (in burts) */
- destp[5] = d5;
- destp[6] = d6;
- destp[7] = d7;
- source1 += 8;
- source2 += 8;
- source3 += 8;
- destp += 8;
- }
- break;
- case 5:
- source4 = (long *) bh_ptr[4]->b_data;
- source3 = (long *) bh_ptr[3]->b_data;
- source2 = (long *) bh_ptr[2]->b_data;
- source1 = (long *) bh_ptr[1]->b_data;
- for (i = lines; i > 0; i--) {
- register long d0, d1, d2, d3, d4, d5, d6, d7;
- d0 = destp[0]; /* Pull the stuff into registers */
- d1 = destp[1]; /* ... in bursts, if possible. */
- d2 = destp[2];
- d3 = destp[3];
- d4 = destp[4];
- d5 = destp[5];
- d6 = destp[6];
- d7 = destp[7];
- d0 ^= source1[0];
- d1 ^= source1[1];
- d2 ^= source1[2];
- d3 ^= source1[3];
- d4 ^= source1[4];
- d5 ^= source1[5];
- d6 ^= source1[6];
- d7 ^= source1[7];
- d0 ^= source2[0];
- d1 ^= source2[1];
- d2 ^= source2[2];
- d3 ^= source2[3];
- d4 ^= source2[4];
- d5 ^= source2[5];
- d6 ^= source2[6];
- d7 ^= source2[7];
- d0 ^= source3[0];
- d1 ^= source3[1];
- d2 ^= source3[2];
- d3 ^= source3[3];
- d4 ^= source3[4];
- d5 ^= source3[5];
- d6 ^= source3[6];
- d7 ^= source3[7];
- d0 ^= source4[0];
- d1 ^= source4[1];
- d2 ^= source4[2];
- d3 ^= source4[3];
- d4 ^= source4[4];
- d5 ^= source4[5];
- d6 ^= source4[6];
- d7 ^= source4[7];
- destp[0] = d0; /* Store the result (in burts) */
- destp[1] = d1;
- destp[2] = d2;
- destp[3] = d3;
- destp[4] = d4; /* Store the result (in burts) */
- destp[5] = d5;
- destp[6] = d6;
- destp[7] = d7;
- source1 += 8;
- source2 += 8;
- source3 += 8;
- source4 += 8;
- destp += 8;
- }
- break;
- }
-}
-
-/*
- * (the -6*32 shift factor colors the cache)
- */
-#define SIZE (PAGE_SIZE-6*32)
-
-static void xor_speed ( struct xor_block_template * func,
- struct buffer_head *b1, struct buffer_head *b2)
+static void
+do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
{
int speed;
unsigned long now;
int i, count, max;
- struct buffer_head *bh_ptr[6];
- func->next = xor_functions;
- xor_functions = func;
- bh_ptr[0] = b1;
- bh_ptr[1] = b2;
+ tmpl->next = template_list;
+ template_list = tmpl;
/*
- * count the number of XORs done during a whole jiffy.
- * calculate the speed of checksumming from this.
- * (we use a 2-page allocation to have guaranteed
- * color L1-cache layout)
+ * Count the number of XORs done during a whole jiffy, and use
+ * this to calculate the speed of checksumming. We use a 2-page
+ * allocation to have guaranteed color L1-cache layout.
*/
max = 0;
for (i = 0; i < 5; i++) {
@@ -2600,7 +82,7 @@ static void xor_speed ( struct xor_block_template * func,
count = 0;
while (jiffies == now) {
mb();
- func->xor_block(2,bh_ptr);
+ tmpl->do_2(BENCH_SIZE, b1, b2);
mb();
count++;
mb();
@@ -2609,120 +91,53 @@ static void xor_speed ( struct xor_block_template * func,
max = count;
}
- speed = max * (HZ*SIZE/1024);
- func->speed = speed;
+ speed = max * (HZ * BENCH_SIZE / 1024);
+ tmpl->speed = speed;
- printk( " %-10s: %5d.%03d MB/sec\n", func->name,
- speed / 1000, speed % 1000);
+ printk(" %-10s: %5d.%03d MB/sec\n", tmpl->name,
+ speed / 1000, speed % 1000);
}
-static inline void pick_fastest_function(void)
+static int
+calibrate_xor_block(void)
{
+ void *b1, *b2;
struct xor_block_template *f, *fastest;
- fastest = xor_functions;
- for (f = fastest; f; f = f->next) {
- if (f->speed > fastest->speed)
- fastest = f;
- }
-#ifdef CONFIG_X86_XMM
- if (cpu_has_xmm) {
- /* we force the use of the KNI xor block because it
- can write around l2. we may also be able
- to load into the l1 only depending on how
- the cpu deals with a load to a line that is
- being prefetched.
- */
- fastest = &t_xor_block_pIII_kni;
+ b1 = (void *) md__get_free_pages(GFP_KERNEL, 2);
+ if (! b1) {
+ printk("raid5: Yikes! No memory available.\n");
+ return -ENOMEM;
}
-#endif
-#ifdef __alpha__
- if (implver() == IMPLVER_EV6) {
- /* Force the use of alpha_prefetch if EV6, as it
- is significantly faster in the cold cache case. */
- fastest = &t_xor_block_alpha_prefetch;
- }
-#endif
- xor_block = fastest->xor_block;
- printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name,
- fastest->speed / 1000, fastest->speed % 1000);
-}
-
-static struct buffer_head b1, b2;
-
-void calibrate_xor_block(void)
-{
- if (xor_block)
- return;
- memset(&b1,0,sizeof(b1));
- b2 = b1;
-
- b1.b_data = (char *) md__get_free_pages(GFP_KERNEL,2);
- if (!b1.b_data) {
- pick_fastest_function();
- return;
- }
- b2.b_data = b1.b_data + 2*PAGE_SIZE + SIZE;
-
- b1.b_size = SIZE;
+ b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
printk(KERN_INFO "raid5: measuring checksumming speed\n");
+ sti();
- sti(); /* should be safe */
+#define xor_speed(templ) do_xor_speed((templ), b1, b2)
-#if defined(__sparc__) && !defined(__sparc_v9__)
- printk(KERN_INFO "raid5: trying high-speed SPARC checksum routine\n");
- xor_speed(&t_xor_block_SPARC,&b1,&b2);
-#endif
+ XOR_TRY_TEMPLATES;
-#ifdef CONFIG_X86_XMM
- if (cpu_has_xmm) {
- printk(KERN_INFO
- "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n");
- xor_speed(&t_xor_block_pIII_kni,&b1,&b2);
- }
-#endif /* CONFIG_X86_XMM */
+#undef xor_speed
-#ifdef __i386__
- if (md_cpu_has_mmx()) {
- printk(KERN_INFO
- "raid5: MMX detected, trying high-speed MMX checksum routines\n");
- xor_speed(&t_xor_block_pII_mmx,&b1,&b2);
- xor_speed(&t_xor_block_p5_mmx,&b1,&b2);
- }
-#endif /* __i386__ */
+ free_pages((unsigned long)b1, 2);
-#ifdef __alpha__
- xor_speed(&t_xor_block_alpha,&b1,&b2);
- xor_speed(&t_xor_block_alpha_prefetch,&b1,&b2);
-#endif
-
- xor_speed(&t_xor_block_8regs,&b1,&b2);
- xor_speed(&t_xor_block_32regs,&b1,&b2);
+ fastest = template_list;
+ for (f = fastest; f; f = f->next)
+ if (f->speed > fastest->speed)
+ fastest = f;
- free_pages((unsigned long)b1.b_data,2);
- pick_fastest_function();
-}
+#ifdef XOR_SELECT_TEMPLATE
+ fastest = XOR_SELECT_TEMPLATE(fastest);
+#endif
-#else /* __sparc_v9__ */
+ active_template = fastest;
+ printk("raid5: using function: %s (%d.%03d MB/sec)\n",
+ fastest->name, fastest->speed / 1000, fastest->speed % 1000);
-void calibrate_xor_block(void)
-{
- if (xor_block)
- return;
- printk(KERN_INFO "raid5: using high-speed VIS checksum routine\n");
- xor_block = xor_block_VIS;
+ return 0;
}
-#endif /* __sparc_v9__ */
-
MD_EXPORT_SYMBOL(xor_block);
-MD_EXPORT_SYMBOL(calibrate_xor_block);
-#ifdef MODULE
-int init_module(void)
-{
- calibrate_xor_block();
- return 0;
-}
-#endif
+module_init(calibrate_xor_block);
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index d716c54bd..b01c1562f 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -322,17 +322,12 @@ static struct rt_device rtrack_unit;
static struct video_device rtrack_radio=
{
- "RadioTrack radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_RTRACK,
- rt_open,
- rt_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* No poll */
- rt_ioctl,
- NULL,
- NULL
+ name: "RadioTrack radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_RTRACK,
+ open: rt_open,
+ close: rt_close,
+ ioctl: rt_ioctl,
};
static int __init rtrack_init(void)
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 2fb8714ad..06999d806 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -273,17 +273,12 @@ static struct az_device aztech_unit;
static struct video_device aztech_radio=
{
- "Aztech radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_AZTECH,
- az_open,
- az_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* No poll */
- az_ioctl,
- NULL,
- NULL
+ name: "Aztech radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_AZTECH,
+ open: az_open,
+ close: az_close,
+ ioctl: az_ioctl,
};
static int __init aztech_init(void)
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index ed2056dea..15ec8515a 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -12,6 +12,10 @@
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
+ * History:
+ * 2000-04-29 Russell Kroll <rkroll@exploits.org>
+ * Added ISAPnP detection for Linux 2.3/2.4
+ *
*/
#include <linux/module.h> /* Modules */
@@ -40,6 +44,17 @@ static __u8 rdsin=0,rdsout=0,rdsstat=0;
static unsigned char rdsbuf[RDS_BUFFER];
static int cadet_lock=0;
+#ifndef MODULE
+static int cadet_probe(void);
+#endif
+
+#ifdef CONFIG_ISAPNP
+#include <linux/isapnp.h>
+
+struct pci_dev *dev;
+static int isapnp_cadet_probe(void);
+#endif
+
/*
* Signal Strength Threshold Values
* The V4L API spec does not define any particular unit for the signal
@@ -47,8 +62,6 @@ static int cadet_lock=0;
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
-
-
void cadet_wake(unsigned long qnum)
{
switch(qnum) {
@@ -529,20 +542,41 @@ static void cadet_close(struct video_device *dev)
static struct video_device cadet_radio=
{
- "Cadet radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_CADET,
- cadet_open,
- cadet_close,
- cadet_read,
- NULL, /* Can't write */
- NULL, /* No poll */
- cadet_ioctl,
- NULL,
- NULL
+ name: "Cadet radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_CADET,
+ open: cadet_open,
+ close: cadet_close,
+ read: cadet_read,
+ ioctl: cadet_ioctl,
};
-#ifndef MODULE
+#ifdef CONFIG_ISAPNP
+static int isapnp_cadet_probe(void)
+{
+ dev = isapnp_find_dev (NULL, ISAPNP_VENDOR('M','S','M'),
+ ISAPNP_FUNCTION(0x0c24), NULL);
+
+ if (!dev)
+ return -ENODEV;
+ if (dev->prepare(dev)<0)
+ return -EAGAIN;
+ if (!(dev->resource[0].flags & IORESOURCE_IO))
+ return -ENODEV;
+ if (dev->activate(dev)<0) {
+ printk ("radio-cadet: isapnp configure failed (out of resources?)\n");
+ return -ENOMEM;
+ }
+
+ io = dev->resource[0].start;
+
+ printk ("radio-cadet: ISAPnP reports card at %#x\n", io);
+
+ return io;
+}
+#endif /* CONFIG_ISAPNP */
+
+#ifdef MODULE
static int cadet_probe(void)
{
static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
@@ -559,13 +593,20 @@ static int cadet_probe(void)
}
return -1;
}
-#endif
+#endif /* MODULE */
static int __init cadet_init(void)
{
-#ifndef MODULE
+#ifdef CONFIG_ISAPNP
+ io = isapnp_cadet_probe();
+
+ if (io < 0)
+ return (io);
+#else
+#ifndef MODULE /* only probe on non-ISAPnP monolithic compiles */
io = cadet_probe ();
-#endif
+#endif /* MODULE */
+#endif /* CONFIG_ISAPNP */
if(io < 0) {
#ifdef MODULE
@@ -596,6 +637,11 @@ static void __exit cadet_cleanup_module(void)
{
video_unregister_device(&cadet_radio);
release_region(io,2);
+
+#ifdef CONFIG_ISAPNP
+ if (dev)
+ dev->deactivate(dev);
+#endif
}
module_init(cadet_init);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 8b53dbd0d..4bac8dcfe 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -249,17 +249,12 @@ static struct gemtek_device gemtek_unit;
static struct video_device gemtek_radio=
{
- "GemTek radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_GEMTEK,
- gemtek_open,
- gemtek_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* Can't poll */
- gemtek_ioctl,
- NULL,
- NULL
+ name: "GemTek radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_GEMTEK,
+ open: gemtek_open,
+ close: gemtek_close,
+ ioctl: gemtek_ioctl,
};
static int __init gemtek_init(void)
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index d4278fe9f..8040afd90 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -69,17 +69,12 @@ static void radio_close(struct video_device *);
static struct video_device maestro_radio=
{
- "Maestro radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_SF16MI,
- radio_open,
- radio_close,
- NULL,
- NULL,
- NULL,
- radio_ioctl,
- NULL,
- NULL
+ name: "Maestro radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_SF16MI,
+ open: radio_open,
+ close: radio_close,
+ ioctl: radio_ioctl,
};
static struct radio_device
@@ -300,21 +295,17 @@ static void radio_close(struct video_device *dev)
inline static __u16 radio_install(struct pci_dev *pcidev);
-#ifdef MODULE
MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
EXPORT_NO_SYMBOLS;
-void cleanup_module(void)
+void __exit maestro_radio_exit(void)
{
video_unregister_device(&maestro_radio);
}
-int init_module(void)
-#else
-int __init maestro_radio_init(struct video_init *v)
-#endif
+int __init maestro_radio_init(void)
{
register __u16 found=0;
struct pci_dev *pcidev = NULL;
@@ -335,6 +326,9 @@ int __init maestro_radio_init(struct video_init *v)
return 0;
}
+module_init(maestro_radio_init);
+module_exit(maestro_radio_exit);
+
inline static __u16 radio_power_on(struct radio_device *dev)
{
register __u16 io=dev->io;
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 1068467c8..036ca6f51 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -192,17 +192,12 @@ static struct pcm20_device pcm20_unit;
static struct video_device pcm20_radio=
{
- "Miro PCM 20 radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_RTRACK,
- pcm20_open,
- pcm20_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* Can't poll */
- pcm20_ioctl,
- NULL,
- NULL
+ name: "Miro PCM 20 radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_RTRACK,
+ open: pcm20_open,
+ close: pcm20_close,
+ ioctl: pcm20_ioctl,
};
static int __init pcm20_init(void)
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index c060ded4a..ad479af32 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -215,17 +215,12 @@ static struct rt_device rtrack2_unit;
static struct video_device rtrack2_radio=
{
- "RadioTrack II radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_RTRACK2,
- rt_open,
- rt_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* Can't poll */
- rt_ioctl,
- NULL,
- NULL
+ name: "RadioTrack II radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_RTRACK2,
+ open: rt_open,
+ close: rt_close,
+ ioctl: rt_ioctl,
};
static int __init rtrack2_init(void)
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 55328a96f..13a155316 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -276,17 +276,12 @@ static struct fmi_device fmi_unit;
static struct video_device fmi_radio=
{
- "SF16FMx radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_SF16MI,
- fmi_open,
- fmi_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* Can't poll */
- fmi_ioctl,
- NULL,
- NULL
+ name: "SF16FMx radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_SF16MI,
+ open: fmi_open,
+ close: fmi_close,
+ ioctl: fmi_ioctl,
};
static int __init fmi_init(void)
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 1dda1618e..28094e3cd 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -294,17 +294,12 @@ static struct tt_device terratec_unit;
static struct video_device terratec_radio=
{
- "TerraTec ActiveRadio",
- VID_TYPE_TUNER,
- VID_HARDWARE_TERRATEC,
- tt_open,
- tt_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* No poll */
- tt_ioctl,
- NULL,
- NULL
+ name: "TerraTec ActiveRadio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_TERRATEC,
+ open: tt_open,
+ close: tt_close,
+ ioctl: tt_ioctl,
};
static int __init terratec_init(void)
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 4e86bda90..2fb6ed26d 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -286,17 +286,12 @@ static void tr_close(struct video_device *dev)
static struct video_device trust_radio=
{
- "Trust FM Radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_TRUST,
- tr_open,
- tr_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* No poll */
- tr_ioctl,
- NULL,
- NULL
+ name: "Trust FM Radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_TRUST,
+ open: tr_open,
+ close: tr_close,
+ ioctl: tr_ioctl,
};
static int __init trust_init(void)
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index a0bbf343f..c550fd45c 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -273,27 +273,19 @@ static void typhoon_close(struct video_device *dev)
static struct typhoon_device typhoon_unit =
{
- 0, /* users */
- CONFIG_RADIO_TYPHOON_PORT, /* iobase */
- 0, /* curvol */
- 0, /* muted */
- CONFIG_RADIO_TYPHOON_MUTEFREQ, /* curfreq */
- CONFIG_RADIO_TYPHOON_MUTEFREQ /* mutefreq */
+ iobase: CONFIG_RADIO_TYPHOON_PORT,
+ curfreq: CONFIG_RADIO_TYPHOON_MUTEFREQ,
+ mutefreq: CONFIG_RADIO_TYPHOON_MUTEFREQ,
};
static struct video_device typhoon_radio =
{
- "Typhoon Radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_TYPHOON,
- typhoon_open,
- typhoon_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* Can't poll */
- typhoon_ioctl,
- NULL,
- NULL
+ name: "Typhoon Radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_TYPHOON,
+ open: typhoon_open,
+ close: typhoon_close,
+ ioctl: typhoon_ioctl,
};
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index dd688935a..940447bb9 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -341,17 +341,12 @@ static struct zol_device zoltrix_unit;
static struct video_device zoltrix_radio =
{
- "Zoltrix Radio Plus",
- VID_TYPE_TUNER,
- VID_HARDWARE_ZOLTRIX,
- zol_open,
- zol_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL,
- zol_ioctl,
- NULL,
- NULL
+ name: "Zoltrix Radio Plus",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_ZOLTRIX,
+ open: zol_open,
+ close: zol_close,
+ ioctl: zol_ioctl,
};
static int __init zoltrix_init(void)
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index fac6990c4..6bd9d7d15 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -39,8 +39,8 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o
obj-$(CONFIG_BUS_I2C) += i2c-old.o
-obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \
- tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o
+obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
+ tda7432.o tda9875.o tuner.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o
diff --git a/drivers/media/video/audiochip.h b/drivers/media/video/audiochip.h
index 23d1b1259..dec29511a 100644
--- a/drivers/media/video/audiochip.h
+++ b/drivers/media/video/audiochip.h
@@ -11,6 +11,16 @@
/* select from TV,radio,extern,MUTE */
#define AUDC_SET_INPUT _IOW('m',17,int)
+/* audio inputs */
+#define AUDIO_TUNER 0x00
+#define AUDIO_RADIO 0x01
+#define AUDIO_EXTERN 0x02
+#define AUDIO_INTERN 0x03
+#define AUDIO_OFF 0x04
+#define AUDIO_ON 0x05
+#define AUDIO_MUTE 0x80
+#define AUDIO_UNMUTE 0x81
+
/* all the stuff below is obsolete and just here for reference. I'll
* remove it once the driver is tested and works fine.
*
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index b2c26e35b..11c6474c7 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -1,7 +1,6 @@
/*
bttv-cards.c -- this file has card-specific stuff
-
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
@@ -31,21 +30,32 @@
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/init.h>
+#include <linux/pci.h>
#include <asm/io.h>
-#include "bttv.h"
+#include "bttvp.h"
#include "tuner.h"
/* fwd decl */
static void hauppauge_eeprom(struct bttv *btv);
-static void hauppauge_boot_msp34xx(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
+#if 0
static void init_tea5757(struct bttv *btv);
+#endif
+
+static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
+ int set);
+static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
+static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
MODULE_PARM(card,"1-4i");
+MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
MODULE_PARM(pll,"1-4i");
+MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)");
MODULE_PARM(autoload,"i");
+MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)");
static unsigned int card[4] = { -1, -1, -1, -1 };
static unsigned int pll[4] = { -1, -1, -1, -1 };
@@ -55,6 +65,14 @@ static unsigned int autoload = 1;
static unsigned int autoload = 0;
#endif
+MODULE_PARM(gpiomask,"i");
+MODULE_PARM(audioall,"i");
+MODULE_PARM(audiomux,"1-5i");
+static unsigned int gpiomask = -1;
+static unsigned int audioall = -1;
+static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 };
+
+
/* ----------------------------------------------------------------------- */
/* list of card IDs for bt878+ cards */
@@ -66,8 +84,9 @@ static struct CARD {
{ 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" },
{ 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
{ 0x00021461, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" },
+ { 0x00031002, BTTV_HAUPPAUGE878, "ATI TV Wonder/VE" },
{ 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
- { 0x00041461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
+ { 0x00041461, BTTV_AVERMEDIA98, "AVerMedia TVCapture 98" },
{ 0x10b42636, BTTV_HAUPPAUGE878, "STB ???" },
{ 0x1118153b, BTTV_TERRATVALUE, "Terratec TV Value" },
{ 0x1123153b, BTTV_TERRATVRADIO, "Terratec TV/Radio+" },
@@ -77,12 +96,17 @@ static struct CARD {
{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
{ 0x217d6606, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
{ 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" },
+ { 0x3000121a, 0/* no entry yet */,"VoodooTV 200" },
{ 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" },
+ { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" },
{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
- { 0x402010fc, 0 /* no tvcards entry yet */, "I-O Data Co. GV-BCV3/PCI" },
+ { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
+ { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCV3/PCI" },
+ { 0xff000070, BTTV_HAUPPAUGE878, "Osprey-100" },
+ { 0xff010070, BTTV_HAUPPAUGE878, "Osprey-200" },
#if 0 /* probably wrong */
{ 0x14610002, BTTV_AVERMEDIA98, "Avermedia TVCapture 98" },
{ 0x6606217d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" },
@@ -93,286 +117,694 @@ static struct CARD {
/* ----------------------------------------------------------------------- */
/* array with description for bt848 / bt878 tv/grabber cards */
-struct tvcard bttv_tvcards[] =
+struct tvcard bttv_tvcards[] = {
{
- /* 0x00 */
- { " *** UNKNOWN *** ",
- 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "MIRO PCTV",
- 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Hauppauge old",
- 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
- 1,1,0,1,0,0,0,1, PLL_NONE, -1 },
- { "STB",
- 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
- 0,1,1,1,1,0,0,1, PLL_NONE, -1 },
-
- { "Intel",
- 3, 1, 0, -1, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Diamond DTV2000",
- 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "AVerMedia TVPhone",
- 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
- { "MATRIX-Vision MV-Delta",
- 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
-
- /* 0x08 */
- { "Fly Video II",
- 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},
- { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "TurboTV",
- 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Hauppauge new (bt878)",
- 4, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
- 1,1,0,1,0,0,0,1, PLL_28, -1 },
- { "MIRO PCTV pro",
- 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0,
- /* 3, 1, 0, 2, 0x3004F, { 2, 3, 1, 1}, {1, 0x10011, 5, 0,10}, 0x3004F, */
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
-
- { "ADS Technologies Channel Surfer TV",
- 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "AVerMedia TVCapture 98",
- 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
- { "Aimslab VHX",
- 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Zoltrix TV-Max",
- 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
-
- /* 0x10 */
- { "Pixelview PlayTV (bt878)",
- 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1},
- { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
- { "Leadtek WinView 601",
- 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0},
- { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "AVEC Intercapture",
- 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "LifeView FlyKit w/o Tuner",
- 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0,
- 0,0,0,0,0,0,0,1, PLL_NONE, -1 },
-
- { "CEI Raffles Card",
- 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Lucky Star Image World ConferenceTV",
- 3, 1, 0, 2, 0x00fffe07, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0,
- 1,1,1,1,0,0,0,1, PLL_28, TUNER_PHILIPS_PAL_I },
- { "Phoebe Tv Master + FM",
- 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Modular Technology MM205 PCTV, bt878",
- 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
-
- /* 0x18 */
- { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
- 3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
- { "Terratec/Vobis TV-Boostar",
- 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Newer Hauppauge WinCam (bt878)",
- 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "MAXI TV Video PCI2",
- 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, TUNER_PHILIPS_SECAM },
-
- { "Terratec TerraTV+",
- 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1},
- { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Imagenation PXC200",
- 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "FlyVideo 98",
- 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1},
- { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "iProTV",
- 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
-
- /* 0x20 */
- { "Intel Create and Share PCI",
- 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Terratec TerraTValue",
- 3, 1, 0, 2, 0xffff00, { 2, 3, 1, 1},
- { 0x500, 0, 0x300, 0x900, 0x900},0,
- 1,1,1,1,0,0,0,1, PLL_NONE, -1 },
- { "Leadtek WinFast 2000",
- 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0},
- { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},0,
- 1,1,1,1,1,0,0,1, PLL_28, -1 },
- { "Chronos Video Shuttle II",
- 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
-
- { "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,0,0,1, PLL_28, -1 },
- { "PixelView PlayTV pro",
- 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 },
- { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0,
- 0,0,0,0,0,0,0,1, PLL_28, -1 },
- { "TView99 CPH063",
- 3, 1, 0, 2, 0x551e00, { 2, 3, 1, 1},
- { 0x551400, 0x551200, 0, 0, 0, 0x551200 }, 0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
- { "Pinnacle PCTV Rave",
- 3, 1, 0, 2, 0x03000F, { 2, 3, 1, 1}, { 2, 0, 0, 0, 1},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
-
- /* 0x28 */
- { "STB2",
- 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0,
- 0,1,1,1,0,1,1,1, PLL_NONE, -1 },
- { "AVerMedia TVPhone 98",
- 3, 4, 0, 2, 4, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0,
- 1,1,1,1,0,0,0,1, PLL_28, 5 },
- { "ProVideo PV951", /* pic16c54 */
- 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
- 0,0,0,0,0,0,0,0, PLL_28, 1 },
- { "Little OnAir TV",
- 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1},
- {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0,
- 0,0,0,0,0,0,0,0, PLL_NONE, -1 },
-
- { "Sigma TVII-FM",
- 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0,
- 0,0,0,0,0,0,0,0, PLL_NONE, -1 },
- { "MATRIX-Vision MV-Delta 2",
- 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0,
- 0,0,0,0,0,0,0,0, PLL_28, -1 },
- { "Zoltrix Genie TV",
- 3, 1, 0, 2, 0xbcf03f, { 2, 3, 1, 1},
- { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f}, 0,
- 0,0,0,0,0,0,0,0, PLL_28, 5 },
- { "Terratec TV/Radio+", /* Radio ?? */
- 3, 1, 0, 2, 0x1f0000, { 2, 3, 1, 1},
- { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },0,
- 0,0,0,0,0,0,0,0, PLL_35, 1 },
-
- /* 0x30 */
- { "Dynalink Magic TView ",
- 3, 1, 0, 2, 15, { 2, 3, 1, 1}, {2,0,0,0,1},0,
- 1,1,1,1,0,0,0,1, PLL_28, -1 },
-};
+/* ---- card 0x00 ---------------------------------- */
+ name: " *** UNKNOWN *** ",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ muxsel: { 2, 3, 1, 0},
+ tuner_type: -1,
+},{
+ name: "MIRO PCTV",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 2, 0, 0, 0, 10},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Hauppauge old",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "STB",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 4, 0, 2, 3, 1},
+ no_msp34xx: 1,
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x04 ---------------------------------- */
+ name: "Intel",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: -1,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Diamond DTV2000",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 3,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 1, 0, 1, 3},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "AVerMedia TVPhone",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 3,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {12, 4,11,11, 0},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "MATRIX-Vision MV-Delta",
+ video_inputs: 5,
+ audio_inputs: 1,
+ tuner: -1,
+ svhs: 3,
+ gpiomask: 0,
+ muxsel: { 2, 3, 1, 0, 0},
+ audiomux: {0 },
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x08 ---------------------------------- */
+ name: "Fly Video II",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xc00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "TurboTV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 3,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 1, 1, 2, 3, 0},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Hauppauge new (bt878)",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 0, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "MIRO PCTV pro",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 65551,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {1,65537, 0, 0,10},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x0c ---------------------------------- */
+ name: "ADS Technologies Channel Surfer TV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 13, 14, 11, 7, 0, 0},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "AVerMedia TVCapture 98",
+ video_inputs: 3,
+ audio_inputs: 4,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 13, 14, 11, 7, 0, 0},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: 5,
+},{
+ name: "Aimslab VHX",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Zoltrix TV-Max",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {0 , 0, 1 , 0, 10},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x10 ---------------------------------- */
+ name: "Pixelview PlayTV (bt878)",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x01fe00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Leadtek WinView 601",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x8300f8,
+ muxsel: { 2, 3, 1, 1,0},
+ audiomux: { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+ audio_hook: winview_audio,
+},{
+ name: "AVEC Intercapture",
+ video_inputs: 3,
+ audio_inputs: 2,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0,
+ muxsel: {2, 3, 1, 1},
+ audiomux: {1, 0, 0, 0, 0},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "LifeView FlyKit w/o Tuner",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: -1,
+ svhs: -1,
+ gpiomask: 0x8dff00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0 },
+ no_msp34xx: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x14 ---------------------------------- */
+ name: "CEI Raffles Card",
+ video_inputs: 3,
+ audio_inputs: 3,
+ tuner: 0,
+ svhs: 2,
+ muxsel: {2, 3, 1, 1},
+ tuner_type: -1,
+},{
+ name: "Lucky Star Image World ConferenceTV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x00fffe07,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 131072, 1, 1638400, 3, 4},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: TUNER_PHILIPS_PAL_I,
+},{
+ name: "Phoebe Tv Master + FM",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xc00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {0, 1, 0x800, 0x400, 0xc00, 0},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Modular Technology MM205 PCTV, bt878",
+ video_inputs: 2,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: -1,
+ gpiomask: 7,
+ muxsel: { 2, 3 },
+ audiomux: { 0, 0, 0, 0, 0 },
+ no_msp34xx: 1,
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x18 ---------------------------------- */
+ name: "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xe00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {0x400, 0x400, 0x400, 0x400, 0},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Terratec/Vobis TV-Boostar",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 16777215,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 131072, 1, 1638400, 3,4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Newer Hauppauge WinCam (bt878)",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 3,
+ gpiomask: 7,
+ muxsel: { 2, 0, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "MAXI TV Video PCI2",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xffff,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 1, 2, 3, 0xc00},
+ needs_tvaudio: 1,
+ tuner_type: TUNER_PHILIPS_SECAM,
+},{
+
+/* ---- card 0x1c ---------------------------------- */
+ name: "Terratec TerraTV+",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x70000,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+ audio_hook: terratv_audio,
+},{
+ name: "Imagenation PXC200",
+ video_inputs: 5,
+ audio_inputs: 1,
+ tuner: -1,
+ svhs: 4,
+ gpiomask: 0,
+ muxsel: { 2, 3, 1, 0, 0},
+ audiomux: { 0 },
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "FlyVideo 98",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x8dfe00,
+ muxsel: {2, 3, 1, 1},
+ audiomux: { 0, 0x8dff00, 0x8df700, 0x8de700, 0x8dff00, 0 },
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "iProTV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 1,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 1, 0, 0, 0, 0 },
+ tuner_type: -1,
+},{
+
+/* ---- card 0x20 ---------------------------------- */
+ name: "Intel Create and Share PCI",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 4, 4, 4, 4, 4},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Terratec TerraTValue",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xffff00,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0x500, 0, 0x300, 0x900, 0x900},
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "Leadtek WinFast 2000",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xfff000,
+ muxsel: { 2, 3, 1, 1,0},
+ audiomux: { 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Chronos Video Shuttle II",
+ video_inputs: 3,
+ audio_inputs: 3,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x1800,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 0, 0x1000, 0x1000, 0x0800},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x24 ---------------------------------- */
+ name: "Typhoon TView TV/FM Tuner",
+ video_inputs: 3,
+ audio_inputs: 3,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x1800,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 0x800, 0, 0, 0x1800, 0 },
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "PixelView PlayTV pro",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xff,
+ muxsel: { 2, 3, 1, 1 },
+ audiomux: { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "TView99 CPH063",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x551e00,
+ muxsel: { 2, 3, 1, 0},
+ audiomux: { 0x551400, 0x551200, 0, 0, 0, 0x551200 },
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Pinnacle PCTV Rave",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x03000F,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 2, 0, 0, 0, 1},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x28 ---------------------------------- */
+ name: "STB2",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 4, 0, 2, 3, 1},
+ no_msp34xx: 1,
+ needs_tvaudio: 1,
+ tuner_type: -1,
+},{
+ name: "AVerMedia TVPhone 98",
+ video_inputs: 3,
+ audio_inputs: 4,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 4,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 13, 14, 11, 7, 0, 0},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: 5,
+ audio_hook: avermedia_tvphone_audio,
+},{
+ name: "ProVideo PV951", /* pic16c54 */
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0, 0, 0, 0, 0},
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: 1,
+},{
+ name: "Little OnAir TV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xe00b,
+ muxsel: {2, 3, 1, 1},
+ audiomux: {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+ no_msp34xx: 1,
+ tuner_type: -1,
+},{
+
+/* ---- card 0x2c ---------------------------------- */
+ name: "Sigma TVII-FM",
+ video_inputs: 2,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: -1,
+ gpiomask: 3,
+ muxsel: {2, 3, 1, 1},
+ audiomux: {1, 1, 0, 2, 3},
+ no_msp34xx: 1,
+ pll: PLL_NONE,
+ tuner_type: -1,
+},{
+ name: "MATRIX-Vision MV-Delta 2",
+ video_inputs: 5,
+ audio_inputs: 1,
+ tuner: -1,
+ svhs: 3,
+ gpiomask: 0,
+ muxsel: { 2, 3, 1, 0, 0},
+ audiomux: {0 },
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Zoltrix Genie TV",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xbcf03f,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0xbc803f, 0, 0xbcb03f, 0, 0xbcb03f},
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: 5,
+},{
+ name: "Terratec TV/Radio+",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x1f0000,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0xe2ffff, 0xebffff, 0, 0, 0xe0ffff, 0xe2ffff },
+ no_msp34xx: 1,
+ pll: PLL_35,
+ tuner_type: 1,
+},{
+
+/* ---- card 0x30 ---------------------------------- */
+ name: "Dynalink Magic TView ",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 15,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: {2,0,0,0,1},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "GV-BCTV3",
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x010f00,
+ muxsel: {2, 3, 0, 0},
+ audiomux: {0x10000, 0, 0x10000, 0, 0, 0},
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: TUNER_ALPS_TSHC6_NTSC,
+ audio_hook: gvbctv3pci_audio,
+},{
+ name: "Prolink PV-BT878P+4E (PixelView PlayTV PAK)",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xAA0000,
+ muxsel: { 2,3,1,1 },
+ audiomux: { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000 },
+ no_msp34xx: 1,
+ pll: PLL_28,
+ tuner_type: TUNER_PHILIPS_PAL_I,
+},{
+ name: "Eagle Wireless Capricorn2 (bt878A)",
+ video_inputs: 4,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 7,
+ muxsel: { 2, 0, 1, 1},
+ audiomux: { 0, 1, 2, 3, 4},
+ pll: PLL_28,
+ tuner_type: -1 /* TUNER_ALPS_TMDH2_NTSC */,
+},{
+
+/* ---- card 0x34 ---------------------------------- */
+ name: "Pinnacle Studio PCTV Pro", /* David Härdeman <david@2gen.com> */
+ video_inputs: 3,
+ audio_inputs: 1,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0x03000F,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 1, 65537, 0, 0, 10},
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: -1,
+},{
+ name: "Typhoon TView RDS", /* Claas Langbehn <claas@bigfoot.com> */
+ video_inputs: 3,
+ audio_inputs: 3,
+ tuner: 0,
+ svhs: 2,
+ gpiomask: 0xffff,
+ muxsel: { 2, 3, 1, 1},
+ audiomux: { 0xb002, 0, 0x12, 0x12, 0x3007 },
+ needs_tvaudio: 1,
+ pll: PLL_28,
+ tuner_type: TUNER_PHILIPS_PAL_I,
+}};
+
const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
/* ----------------------------------------------------------------------- */
static unsigned char eeprom_data[256];
-static void __devinit bttv_dump_eeprom(struct bttv *btv,int addr)
-{
- int i;
-
- if (bttv_verbose < 2)
- return;
- /* for debugging: dump eeprom to syslog */
- printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
- for (i = 0; i < 256;) {
- printk(KERN_DEBUG " %02x:",i);
- do {
- printk(" %02x",eeprom_data[i++]);
- } while (i % 16);
- printk("\n");
- }
-}
-
-static int __devinit bttv_idcard_eeprom(struct bttv *btv)
-{
- unsigned id;
- int i,n;
-
- 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 */
- btv->cardid = id;
- 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: card id: %s (0x%08x) => card=%d\n",
- btv->nr,cards[n].name,id,cards[n].cardnr);
- return cards[n].cardnr;
- } else {
- /* 404 */
- 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;
- }
-}
-
-#ifndef HAVE_TVAUDIO
-/* can tda9855.c handle this too maybe? */
-static void __devinit init_tda9840(struct bttv *btv)
-{
- /* Horrible Hack */
- bttv_I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */
- /* 00 - mute
- 10 - mono / averaged stereo
- 2a - stereo
- 12 - dual A
- 1a - dual AB
- 16 - dual BA
- 1e - dual B
- 7a - external */
-}
-#endif
-
+/*
+ * identify card
+ */
void __devinit bttv_idcard(struct bttv *btv)
{
- int type,eeprom = 0;
-
- btwrite(0, BT848_GPIO_OUT_EN);
-
- /* try to autodetect the card */
- /* many bt878 cards have a eeprom @ 0xa0 => read ID
- and try to identify it */
- if (bttv_I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) {
- eeprom = 0xa0;
- bttv_readee(btv,eeprom_data,0xa0);
- bttv_dump_eeprom(btv,0xa0); /* DEBUG */
- type = bttv_idcard_eeprom(btv);
- if (-1 != type) {
- btv->type = type;
- } else if (btv->id <= 849) {
- /* for unknown bt848, assume old Hauppauge */
- btv->type=BTTV_HAUPPAUGE;
- }
+ unsigned int gpiobits;
+ int i,type;
+ unsigned short tmp;
+
+ /* read PCI subsystem ID */
+ pci_read_config_word(btv->dev, PCI_SUBSYSTEM_ID, &tmp);
+ btv->cardid = tmp << 16;
+ pci_read_config_word(btv->dev, PCI_SUBSYSTEM_VENDOR_ID, &tmp);
+ btv->cardid |= tmp;
+
+ if (0 != btv->cardid && 0xffffffff != btv->cardid) {
+ /* look for the card */
+ for (type = -1, i = 0; cards[i].id != 0; i++)
+ if (cards[i].id == btv->cardid)
+ type = i;
- /* STB cards have a eeprom @ 0xae (old bt848) */
- } else if (bttv_I2CRead(btv, I2C_STBEE, "eeprom")>=0) {
- btv->type=BTTV_STB;
+ if (type != -1) {
+ /* found it */
+ printk(KERN_INFO "bttv%d: subsystem: %04x:%04x => %s => card=%d\n",
+ btv->nr, btv->cardid & 0xffff, btv->cardid >> 16,
+ cards[type].name,cards[type].cardnr);
+ btv->type = cards[type].cardnr;
+ } else {
+ /* 404 */
+ printk(KERN_INFO "bttv%d: subsystem: %04x:%04x (UNKNOWN)\n",
+ btv->nr, btv->cardid&0xffff, btv->cardid>>16);
+ printk(KERN_DEBUG "please mail id, board name and "
+ "the correct card= insmod option to "
+ "kraxel@goldbach.in-berlin.de\n");
+ }
}
/* let the user override the autodetected type */
@@ -387,8 +819,39 @@ void __devinit bttv_idcard(struct bttv *btv)
printk(KERN_INFO "bttv%d: model: %s [%s]\n",btv->nr,btv->video_dev.name,
(card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
"insmod option" : "autodetected");
-
- /* board specific initialisations */
+
+ /* overwrite gpio stuff ?? */
+ if (-1 == audioall && -1 == audiomux[0])
+ return;
+
+ if (-1 != audiomux[0]) {
+ gpiobits = 0;
+ for (i = 0; i < 5; i++) {
+ bttv_tvcards[btv->type].audiomux[i] = audiomux[i];
+ gpiobits |= audiomux[i];
+ }
+ } else {
+ gpiobits = audioall;
+ for (i = 0; i < 5; i++) {
+ bttv_tvcards[btv->type].audiomux[i] = audioall;
+ }
+ }
+ bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits;
+ printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
+ btv->nr,bttv_tvcards[btv->type].gpiomask);
+ for (i = 0; i < 5; i++) {
+ printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->type].audiomux[i]);
+ }
+ printk("\n");
+}
+
+/*
+ * (most) board specific initialisations goes here
+ */
+void __devinit bttv_init_card(struct bttv *btv)
+{
+ int eeprom = 0;
+
if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
/* auto detect tuner for MIRO cards */
btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
@@ -407,7 +870,6 @@ void __devinit bttv_idcard(struct bttv *btv)
bttv_readee(btv,eeprom_data,0xa0);
}
hauppauge_eeprom(btv);
- hauppauge_boot_msp34xx(btv);
}
if (btv->type == BTTV_PXC200)
init_PXC200(btv);
@@ -419,6 +881,10 @@ void __devinit bttv_idcard(struct bttv *btv)
btv->pll.pll_ifreq=28636363;
btv->pll.pll_crystal=BT848_IFORM_XT0;
}
+ if (PLL_35 == bttv_tvcards[btv->type].pll) {
+ btv->pll.pll_ifreq=35468950;
+ btv->pll.pll_crystal=BT848_IFORM_XT1;
+ }
/* insmod options can override */
switch (pll[btv->nr]) {
case 0: /* none */
@@ -427,18 +893,19 @@ void __devinit bttv_idcard(struct bttv *btv)
btv->pll.pll_ofreq = 0;
break;
case 1: /* 28 MHz */
+ case 28:
btv->pll.pll_ifreq = 28636363;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal=BT848_IFORM_XT0;
+ btv->pll.pll_crystal = BT848_IFORM_XT0;
break;
case 2: /* 35 MHz */
+ case 35:
btv->pll.pll_ifreq = 35468950;
btv->pll.pll_ofreq = 0;
- btv->pll.pll_crystal=BT848_IFORM_XT1;
+ btv->pll.pll_crystal = BT848_IFORM_XT1;
break;
}
}
-
/* tuner configuration */
if (-1 != bttv_tvcards[btv->type].tuner_type)
@@ -447,62 +914,25 @@ void __devinit bttv_idcard(struct bttv *btv)
bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
/* try to detect audio/fader chips */
- if (bttv_tvcards[btv->type].msp34xx &&
+ if (!bttv_tvcards[btv->type].no_msp34xx &&
bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
if (autoload)
request_module("msp3400");
}
-#ifndef HAVE_TVAUDIO
- if (bttv_tvcards[btv->type].tda8425 &&
- bttv_I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) {
- if (autoload)
- request_module("tda8425");
- }
-
- if (bttv_tvcards[btv->type].tda9840 &&
- bttv_I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) {
- init_tda9840(btv);
- btv->audio_chip = TDA9840;
- /* move this to a module too? */
- init_tda9840(btv);
- }
-
- if (bttv_tvcards[btv->type].tda985x &&
- bttv_I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) {
- if (autoload)
- request_module("tda985x");
- }
- if (bttv_tvcards[btv->type].tea63xx) {
- if (autoload)
- request_module("tea6300");
- }
-#else
- if (bttv_tvcards[btv->type].tda8425 ||
- bttv_tvcards[btv->type].tda9840 ||
- bttv_tvcards[btv->type].tda985x ||
- bttv_tvcards[btv->type].tea63xx) {
- if (autoload)
- request_module("tvaudio");
- }
-#endif
-
- if (bttv_tvcards[btv->type].tda9875 &&
- bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
+ if (bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
if (autoload)
request_module("tda9875");
}
- if (bttv_tvcards[btv->type].tda7432 &&
- bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
+ if (bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
if (autoload)
request_module("tda7432");
}
-
- if (bttv_tvcards[btv->type].tea64xx) {
+ if (bttv_tvcards[btv->type].needs_tvaudio) {
if (autoload)
- request_module("tea6420");
+ request_module("tvaudio");
}
if (bttv_tvcards[btv->type].tuner != -1) {
@@ -574,40 +1004,25 @@ static void __devinit hauppauge_eeprom(struct bttv *btv)
{
btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
if (bttv_verbose)
- printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
+ printk("bttv%d: Hauppauge eeprom: model=%d, tuner=%s (%d)\n",btv->nr,
+ eeprom_data[12] << 8 | eeprom_data[11],
hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
}
}
-static void __devinit hauppauge_boot_msp34xx(struct bttv *btv)
+void __devinit bttv_hauppauge_boot_msp34xx(struct bttv *btv)
{
- int i;
-
/* reset/enable the MSP on some Hauppauge cards */
/* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
btaor(32, ~32, BT848_GPIO_OUT_EN);
btaor(0, ~32, BT848_GPIO_DATA);
udelay(2500);
btaor(32, ~32, BT848_GPIO_DATA);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"msp34xx");
if (bttv_verbose)
printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr);
-
- /* look if the msp3400 driver is already registered */
- for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- if (btv->i2c_clients[i] != NULL &&
- btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) {
- return;
- }
- }
-
- /* if not: look for the chip ... */
- if (bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx")) {
- /* ... if found re-register to trigger a i2c bus rescan, */
- /* this time with the msp34xx chip activated */
- i2c_bit_del_bus(&btv->i2c_adap);
- i2c_bit_add_bus(&btv->i2c_adap);
- }
}
@@ -632,6 +1047,8 @@ static void __devinit init_PXC200(struct bttv *btv)
/* GPIO inputs are pulled up, so no need to drive
* reset pin any longer */
btwrite(0,BT848_GPIO_OUT_EN);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"pxc200");
/* we could/should try and reset/control the AD pots? but
right now we simply turned off the crushing. Without
@@ -716,6 +1133,8 @@ static int tea_read(struct bttv *btv)
/* better safe than sorry */
btaor((1<<TEA_CLK) | (1<<TEA_WE), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"miro tea read");
BUS_LOW(WE);
BUS_LOW(CLK);
@@ -753,7 +1172,10 @@ static int tea_write(struct bttv *btv, int value)
int reg = value;
btaor((1<<TEA_CLK) | (1<<TEA_WE) | (1<<TEA_DATA), ~((1<<TEA_CLK) | (1<<TEA_DATA) | (1<<TEA_WE) | (1<<TEA_MOST)), BT848_GPIO_OUT_EN);
- if (bttv_debug) printk("tea5757: write 0x%X\n", value);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"miro tea write");
+ if (bttv_debug)
+ printk("tea5757: write 0x%X\n", value);
BUS_LOW(CLK);
BUS_HIGH(WE);
for(i = 0; i < 25; i++)
@@ -778,6 +1200,7 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
if (bttv_debug) tea_read(btv);
}
+#if 0
void init_tea5757(struct bttv *btv)
{
BUS_LOW(CLK);
@@ -788,14 +1211,20 @@ void init_tea5757(struct bttv *btv)
/* normal mode for GPIO */
btaor(0, BT848_GPIO_DMA_CTL_GPIOMODE, BT848_GPIO_DMA_CTL);
}
+#endif
/* ----------------------------------------------------------------------- */
/* winview */
-void winview_setvol(struct bttv *btv, struct video_audio *v)
+void winview_audio(struct bttv *btv, struct video_audio *v, int set)
{
/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
int bits_out, loops, vol, data;
+
+ if (!set) {
+ v->mode |= VIDEO_AUDIO_VOLUME;
+ return;
+ }
/* 32 levels logarithmic */
vol = 32 - ((v->volume>>11));
@@ -828,6 +1257,68 @@ void winview_setvol(struct bttv *btv, struct video_audio *v)
btwrite(data, BT848_GPIO_DATA);
}
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but */
+/* connect something to the GPIO pins */
+
+static void
+gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+ unsigned int con = 0;
+
+ if (set) {
+ btor(0x100, BT848_GPIO_OUT_EN);
+ if (v->mode & VIDEO_SOUND_LANG1)
+ con = 0x000;
+ if (v->mode & VIDEO_SOUND_LANG2)
+ con = 0x300;
+ if (v->mode & VIDEO_SOUND_STEREO)
+ con = 0x200;
+// if (v->mode & VIDEO_SOUND_MONO)
+// con = 0x100;
+ btaor(con, ~0x300, BT848_GPIO_DATA);
+ } else {
+ v->mode = VIDEO_SOUND_STEREO |
+ VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+ }
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ * 0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ * input/output sound connection, so both must be set for output mode.
+ *
+ */
+static void
+avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+ /* TODO */
+}
+
+static void
+terratv_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+ unsigned int con = 0;
+
+ if (set) {
+ btor(0x180000, BT848_GPIO_OUT_EN);
+ if (v->mode & VIDEO_SOUND_LANG2)
+ con = 0x080000;
+ if (v->mode & VIDEO_SOUND_STEREO)
+ con = 0x180000;
+ btaor(con, ~0x180000, BT848_GPIO_DATA);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"terratv");
+ } else {
+ v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+ }
+}
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index fe0d72e69..6bc9c554e 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -44,34 +44,40 @@
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#ifdef HACKING
-# include <linux/iobuf.h>
-#endif
-#include "bttv.h"
+#include "bttvp.h"
#include "tuner.h"
#define DEBUG(x) /* Debug driver */
-#define IDEBUG(x) /* Debug interrupt handler */
#define MIN(a,b) (((a)>(b))?(b):(a))
#define MAX(a,b) (((a)>(b))?(a):(b))
-
static void bt848_set_risc_jmps(struct bttv *btv, int state);
int bttv_num; /* number of Bt848s in use */
struct bttv bttvs[BTTV_MAX];
-
/* insmod args */
MODULE_PARM(triton1,"i");
MODULE_PARM(radio,"1-4i");
+MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
MODULE_PARM(bigendian,"i");
+MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
MODULE_PARM(fieldnr,"i");
+MODULE_PARM_DESC(fieldnr,"count fields, default is 0 (no)");
MODULE_PARM(bttv_verbose,"i");
+MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
+MODULE_PARM(bttv_gpio,"i");
+MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
MODULE_PARM(bttv_debug,"i");
+MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
+MODULE_PARM(irq_debug,"i");
+MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
MODULE_PARM(gbuffers,"i");
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
MODULE_PARM(gbufsize,"i");
+MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM(combfilter,"i");
MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
@@ -84,10 +90,13 @@ static unsigned int bigendian=0;
static int triton1=0;
static unsigned int radio[BTTV_MAX];
static unsigned int fieldnr = 0;
+static unsigned int irq_debug = 0;
static unsigned int gbuffers = 2;
static unsigned int gbufsize = BTTV_MAX_FBUF;
+static unsigned int combfilter = 0;
unsigned int bttv_debug = 0;
unsigned int bttv_verbose = 1;
+unsigned int bttv_gpio = 0;
#define I2C_TIMING (0x7<<4)
#define I2C_DELAY 10
@@ -133,8 +142,9 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
ptep = pte_offset(pmd, adr);
pte = *ptep;
if(pte_present(pte)) {
- ret = (unsigned long) page_address(pte_page(pte));
- ret |= (adr & (PAGE_SIZE - 1));
+ ret = (unsigned long) page_address(pte_page(pte));
+ ret |= (adr & (PAGE_SIZE - 1));
+
}
}
}
@@ -239,9 +249,9 @@ static int fbuffer_alloc(struct bttv *btv)
}
+/* init + register i2c algo-bit adapter */
static int __devinit init_bttv_i2c(struct bttv *btv)
{
- /* i2c bit_adapter */
memcpy(&btv->i2c_adap, &bttv_i2c_adap_template, sizeof(struct i2c_adapter));
memcpy(&btv->i2c_algo, &bttv_i2c_algo_template, sizeof(struct i2c_algo_bit_data));
memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client));
@@ -256,13 +266,25 @@ static int __devinit init_bttv_i2c(struct bttv *btv)
bttv_bit_setscl(btv,1);
bttv_bit_setsda(btv,1);
- btv->i2c_ok = i2c_bit_add_bus(&btv->i2c_adap);
- return btv->i2c_ok;
+ btv->i2c_rc = i2c_bit_add_bus(&btv->i2c_adap);
+ return btv->i2c_rc;
}
/* ----------------------------------------------------------------------- */
+void bttv_gpio_tracking(struct bttv *btv, char *comment)
+{
+ unsigned int outbits, data;
+ outbits = btread(BT848_GPIO_OUT_EN);
+ data = btread(BT848_GPIO_DATA);
+ printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
+ btv->nr,outbits,data & outbits, data & ~outbits, comment);
+}
+
+static char *audio_modes[] = { "audio: tuner", "audio: radio", "audio: extern",
+ "audio: intern", "audio: off" };
+
static void audio(struct bttv *btv, int mode, int no_irq_context)
{
btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,
@@ -295,6 +317,8 @@ static void audio(struct bttv *btv, int mode, int no_irq_context)
mode = AUDIO_RADIO;
btaor(bttv_tvcards[btv->type].audiomux[mode],
~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,audio_modes[mode]);
if (no_irq_context)
bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));
}
@@ -406,14 +430,16 @@ static int set_pll(struct bttv *btv)
static void bt848_muxsel(struct bttv *btv, unsigned int input)
{
+
+#if 0 /* seems no card uses this ... */
btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,
BT848_GPIO_OUT_EN);
+#endif
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
mdelay(10);
-
input %= bttv_tvcards[btv->type].video_inputs;
if (input==bttv_tvcards[btv->type].svhs)
{
@@ -428,8 +454,13 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
audio(btv, (input!=bttv_tvcards[btv->type].tuner) ?
AUDIO_EXTERN : AUDIO_TUNER, 1);
+
+#if 0 /* seems no card uses this ... */
btaor(bttv_tvcards[btv->type].muxsel[input]>>4,
~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"muxsel");
+#endif
}
@@ -942,9 +973,9 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
lastbit=cbit;
sx += dx;
dx = 1;
- if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16)
+ if (ro - btv->risc_scr_odd>(RISCMEM_LEN>>3) - 16)
outofmem++;
- if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16)
+ if (re - btv->risc_scr_even>(RISCMEM_LEN>>3) - 16)
outofmem++;
}
x++;
@@ -997,17 +1028,17 @@ static inline void bt848_set_eogeo(struct bttv *btv, struct tvnorm *tvn,
((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
+ if (combfilter) {
+ /* Some people say interpolation looks bad ... */
+ vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ if (width < 769)
+ 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);
-#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);
@@ -1133,131 +1164,6 @@ static void bt848_set_winsize(struct bttv *btv)
bt848_set_geo(btv,1);
}
-#ifdef HACKING
-/* playing with kiobufs and dma-to-userspace. 2.4.x only
- Yes, I know: cut+paste programming is ugly.
- will fix later, this is proof-of-concept right now. */
-static int make_vrisctab_kiobuf(struct bttv *btv, unsigned int *ro,
- unsigned int *re, struct kiobuf *iobuf,
- unsigned short width, unsigned short height,
- unsigned short palette)
-{
- unsigned long bpl; /* bytes per line */
- unsigned long bl;
- unsigned long todo;
- unsigned long pageaddr;
- unsigned int **rp;
- unsigned long line,inter,offset,page;
-
- inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0;
- bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
-
- *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
- *(ro++)=cpu_to_le32(0);
- *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
- *(re++)=cpu_to_le32(0);
-
- offset = iobuf->offset;
- page = 0;
- pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
- for (line=0; line < (height<<(1^inter)); line++)
- {
- if (inter)
- rp= (line&1) ? &re : &ro;
- else
- rp= (line>=height) ? &ro : &re;
-
- bl = PAGE_SIZE - offset;
- if (bpl <= bl) {
- *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|
- BT848_RISC_EOL|bpl);
- *((*rp)++)=cpu_to_le32(pageaddr+offset);
- offset+=bpl;
- } else {
- todo = bpl;
- *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL|bl);
- *((*rp)++)=cpu_to_le32(pageaddr+offset);
- todo -= bl;
- offset = 0;
- page++;
- pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
- while (todo>PAGE_SIZE)
- {
- *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|PAGE_SIZE);
- *((*rp)++)=cpu_to_le32(pageaddr);
- page++;
- pageaddr = virt_to_bus(page_address(iobuf->maplist[page]));
- }
- *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|todo);
- *((*rp)++)=cpu_to_le32(pageaddr);
- offset += todo;
- }
- }
-
- *(ro++)=cpu_to_le32(BT848_RISC_JUMP);
- *(ro++)=cpu_to_le32(btv->bus_vbi_even);
- *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
- *(re++)=cpu_to_le32(btv->bus_vbi_odd);
-
- return 0;
-}
-
-static int vgrab_kiobuf(struct bttv *btv, struct bttv_just_hacking *mp,
- struct kiobuf *iobuf)
-{
- unsigned int *ro, *re;
- unsigned long flags;
-
- if(btv->gbuf[0].stat != GBUFFER_UNUSED)
- return -EBUSY;
-
- if(mp->height < 32 || mp->width < 32)
- return -EINVAL;
- if (mp->format >= 12 /* more is'nt yet ... PALETTEFMT_MAX */)
- return -EINVAL;
-
- if(-1 == palette2fmt[mp->format])
- return -EINVAL;
-
- /*
- * Ok load up the BT848
- */
-
- ro=btv->gbuf[0].risc;
- re=ro+2048;
- make_vrisctab_kiobuf(btv, ro, re, iobuf, mp->width, mp->height, mp->format);
-
- if (bttv_debug)
- printk("bttv%d: cap vgrab_kiobuf: queue %d (%d:%dx%d)\n",
- btv->nr,0,mp->format,mp->width,mp->height);
- spin_lock_irqsave(&btv->s_lock, flags);
- btv->gbuf[0].stat = GBUFFER_GRABBING;
- btv->gbuf[0].fmt = palette2fmt[mp->format];
- btv->gbuf[0].width = mp->width;
- btv->gbuf[0].height = mp->height;
- btv->gbuf[0].ro = virt_to_bus(ro);
- btv->gbuf[0].re = virt_to_bus(re);
-
-#if 1
- if (mp->height <= tvnorms[btv->win.norm].sheight/2 &&
- mp->format != VIDEO_PALETTE_RAW)
- btv->gbuf[0].ro = 0;
-#endif
-
- if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) {
- btv->gq_start = 1;
- btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
- }
- btv->gqueue[btv->gq_in++] = 0;
- btv->gq_in = btv->gq_in % MAX_GBUFFERS;
-
- btor(3, BT848_CAP_CTL);
- btor(3, BT848_GPIO_DMA_CTL);
- spin_unlock_irqrestore(&btv->s_lock, flags);
- return 0;
-}
-#endif
-
/*
* Grab into virtual memory.
*/
@@ -1393,6 +1299,39 @@ static inline void burst(int on)
tvnorms[2].hdelayx1 = 186 - (on?BURSTOFFSET :0);
}
+/*
+ * called from irq handler on fatal errors. Takes the grabber chip
+ * offline, flag it needs a reinitialization (which can't be done
+ * from irq context) and wake up all sleeping proccesses. They would
+ * block forever else. We also need someone who actually does the
+ * reinitialization from process context...
+ */
+static void bt848_offline(struct bttv *btv)
+{
+ int i;
+ spin_lock(&btv->s_lock);
+
+ /* cancel all outstanding grab requests */
+ btv->gq_in = 0;
+ btv->gq_out = 0;
+ btv->gq_grab = -1;
+ for (i = 0; i < gbuffers; i++)
+ if (btv->gbuf[i].stat == GBUFFER_GRABBING)
+ btv->gbuf[i].stat = GBUFFER_ERROR;
+
+ /* disable screen overlay and DMA */
+ btv->risc_cap_odd = 0;
+ btv->risc_cap_even = 0;
+ bt848_set_risc_jmps(btv,0);
+
+ /* flag the chip needs a restart */
+ btv->needs_restart = 1;
+ spin_unlock(&btv->s_lock);
+
+ wake_up_interruptible(&btv->vbiq);
+ wake_up_interruptible(&btv->capq);
+}
+
static void bt848_restart(struct bttv *btv)
{
unsigned long irq_flags;
@@ -1427,6 +1366,8 @@ static int bttv_open(struct video_device *dev, int flags)
int i,ret;
ret = -EBUSY;
+ if (bttv_debug)
+ printk("bttv%d: open called\n",btv->nr);
MOD_INC_USE_COUNT;
down(&btv->lock);
@@ -1724,6 +1665,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
btv->scr_on = 0;
bt848_set_risc_jmps(btv,-1);
spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+ up(&btv->lock);
return -EINVAL;
}
if (btv->win.bpp < 4)
@@ -1747,20 +1689,26 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
* Do any clips.
*/
if(vw.clipcount<0) {
- if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
+ if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
+ up(&btv->lock);
return -ENOMEM;
+ }
if(copy_from_user(vcp, vw.clips,
VIDEO_CLIPMAP_SIZE)) {
+ up(&btv->lock);
vfree(vcp);
return -EFAULT;
}
} else if (vw.clipcount) {
if((vcp=vmalloc(sizeof(struct video_clip)*
- (vw.clipcount))) == NULL)
+ (vw.clipcount))) == NULL) {
+ up(&btv->lock);
return -ENOMEM;
+ }
if(copy_from_user(vcp,vw.clips,
sizeof(struct video_clip)*
vw.clipcount)) {
+ up(&btv->lock);
vfree(vcp);
return -EFAULT;
}
@@ -1898,21 +1846,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.mode = VIDEO_SOUND_MONO;
bttv_call_i2c_clients(btv,cmd,&v);
- if (btv->type == BTTV_TERRATV) {
- v.mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
- VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- }
-#ifndef HAVE_TVAUDIO
- else if (btv->audio_chip == TDA9840) {
- /* begin of Horrible Hack <grin@tolna.net> */
- v.flags|=VIDEO_AUDIO_VOLUME;
- v.mode = VIDEO_SOUND_MONO;
- v.mode |= VIDEO_SOUND_STEREO;
- v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
- v.volume = 32768; /* fixme */
- v.step = 4096;
- }
-#endif
+ /* card specific hooks */
+ if (bttv_tvcards[btv->type].audio_hook)
+ bttv_tvcards[btv->type].audio_hook(btv,&v,0);
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
@@ -1938,17 +1874,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
bttv_call_i2c_clients(btv,cmd,&v);
- if (btv->type == BTTV_TERRATV) {
- unsigned int con = 0;
- btor(0x180000, BT848_GPIO_OUT_EN);
- if (v.mode & VIDEO_SOUND_LANG2)
- con = 0x080000;
- if (v.mode & VIDEO_SOUND_STEREO)
- con = 0x180000;
- btaor(con, ~0x180000, BT848_GPIO_DATA);
-
- } else if (btv->type == BTTV_WINVIEW_601)
- winview_setvol(btv,&v);
+ /* card specific hooks */
+ if (bttv_tvcards[btv->type].audio_hook)
+ bttv_tvcards[btv->type].audio_hook(btv,&v,0);
btv->audio_dev=v;
up(&btv->lock);
@@ -2082,90 +2010,12 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
}
-#ifdef HACKING
- /* playing with kiobufs and dma-to-userspace */
- case BTTV_JUST_HACKING:
- {
- DECLARE_WAITQUEUE(wait, current);
- struct bttv_just_hacking hack;
- struct kiobuf *iobuf;
- int err;
-
- if(copy_from_user((void *) &hack, (void *) arg, sizeof(hack)))
- return -EFAULT;
- printk("bttv%d: hack: userland args: %dx%d, fmt=%d, buf=%lx, len=%d\n",
- btv->nr,hack.width,hack.height,hack.format,
- hack.buf,hack.len);
-
- /* pin down */
- err = alloc_kiovec(1,&iobuf);
- if (err)
- goto hack_oops;
- err = map_user_kiobuf(READ, iobuf, hack.buf, hack.len);
- if (err)
- goto hack_oops;
- err = lock_kiovec(1,&iobuf,1);
- if (err)
- goto hack_oops;
-
- /* have a look */
- printk("bttv%d: hack: kiobuf: nr_pages=%d, offset=%d, length=%d, locked=%d\n",
- btv->nr,iobuf->nr_pages,iobuf->offset,iobuf->length,
- iobuf->locked);
- printk("bttv%d: hack: pages (bus addr):",btv->nr);
- for (i = 0; i < iobuf->nr_pages; i++) {
- printk(" %lx", virt_to_bus(page_address(iobuf->maplist[i])));
- }
- printk("\n");
-
- /* start capture */
- err = -EINVAL;
- if (hack.height * hack.width * 2 * /* fixme: *2 */
- fmtbppx2[palette2fmt[hack.format]&0x0f]/2 > hack.len)
- goto hack_oops;
- err = vgrab_kiobuf(btv,&hack,iobuf);
- if (err)
- goto hack_oops;
- printk("bttv%d: hack: capture started\n",btv->nr);
-
- /* wait */
- add_wait_queue(&btv->capq, &wait);
- current->state = TASK_INTERRUPTIBLE;
- while(btv->gbuf[0].stat==GBUFFER_GRABBING) {
- if (bttv_debug)
- printk("bttv%d: hack: cap sync: sleep on %d\n",btv->nr,0);
- schedule();
-#if 0
- if(signal_pending(current)) {
- remove_wait_queue(&btv->capq, &wait);
- current->state = TASK_RUNNING;
- return -EINTR;
- }
-#endif
- }
- remove_wait_queue(&btv->capq, &wait);
- current->state = TASK_RUNNING;
- printk("bttv%d: hack: capture done\n",btv->nr);
-
- /* release */
- err = 0;
- hack_oops:
- free_kiovec(1,&iobuf);
- return 0;
- }
-#endif
-
default:
return -ENOIOCTLCMD;
}
return 0;
}
-static int bttv_init_done(struct video_device *dev)
-{
- return 0;
-}
-
/*
* This maps the vmalloced and reserved fbuffer to user space.
*
@@ -2212,20 +2062,16 @@ static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long si
static struct video_device bttv_template=
{
- "UNSET",
- VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
- VID_HARDWARE_BT848,
- bttv_open,
- bttv_close,
- bttv_read,
- bttv_write,
- NULL,
- bttv_ioctl,
- bttv_mmap,
- bttv_init_done,
- NULL,
- 0,
- -1
+ name: "UNSET",
+ type: VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
+ hardware: VID_HARDWARE_BT848,
+ open: bttv_open,
+ close: bttv_close,
+ read: bttv_read,
+ write: bttv_write,
+ ioctl: bttv_ioctl,
+ mmap: bttv_mmap,
+ minor: -1,
};
@@ -2353,7 +2199,8 @@ static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
}
case VIDIOCGFREQ:
case VIDIOCSFREQ:
- return bttv_ioctl((struct video_device *)btv,cmd,arg);
+ case BTTV_VERSION:
+ return bttv_ioctl(dev,cmd,arg);
case BTTV_VBISIZE:
/* make alevt happy :-) */
return VBIBUF_SIZE;
@@ -2364,20 +2211,16 @@ static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
static struct video_device vbi_template=
{
- "bttv vbi",
- VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
- VID_HARDWARE_BT848,
- vbi_open,
- vbi_close,
- vbi_read,
- bttv_write,
- vbi_poll,
- vbi_ioctl,
- NULL, /* no mmap yet */
- bttv_init_done,
- NULL,
- 0,
- -1
+ name: "bttv vbi",
+ type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+ hardware: VID_HARDWARE_BT848,
+ open: vbi_open,
+ close: vbi_close,
+ read: vbi_read,
+ write: bttv_write,
+ poll: vbi_poll,
+ ioctl: vbi_ioctl,
+ minor: -1,
};
@@ -2456,6 +2299,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.rangehigh=(int)(108*16); /* eu: 87.5MHz - 108.0MHz */
v.flags= 0; /* XXX */
v.mode = 0; /* XXX */
+ bttv_call_i2c_clients(btv,cmd,&v);
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -2485,20 +2329,15 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
static struct video_device radio_template=
{
- "bttv radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_BT848,
- radio_open,
- radio_close,
- radio_read, /* just returns -EINVAL */
- bttv_write, /* just returns -EINVAL */
- NULL, /* no poll */
- radio_ioctl,
- NULL, /* no mmap */
- bttv_init_done, /* just returns 0 */
- NULL,
- 0,
- -1
+ name: "bttv radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_BT848,
+ open: radio_open,
+ close: radio_close,
+ read: radio_read, /* just returns -EINVAL */
+ write: bttv_write, /* just returns -EINVAL */
+ ioctl: radio_ioctl,
+ minor: -1,
};
@@ -2579,7 +2418,8 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
flags |= 3;
btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
- } else if (flags&2) {
+ } else if ((flags&2) &&
+ (!btv->win.interlace || 0 == btv->risc_cap_even)) {
if (bttv_debug > 1)
printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
@@ -2614,7 +2454,8 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
flags |= 3;
btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
- } else if (flags&1) {
+ } else if ((flags&1) &&
+ btv->win.interlace) {
if (bttv_debug > 1)
printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
@@ -2648,7 +2489,6 @@ static int __devinit init_video_dev(struct bttv *btv)
memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
- bttv_idcard(btv);
audio(btv, AUDIO_MUTE, 1);
if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
@@ -2680,12 +2520,8 @@ static int __devinit init_bt848(struct bttv *btv)
/* dump current state of the gpio registers before changing them,
* might help to make a new card work */
- if (bttv_verbose >= 2)
- printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n",
- btv->nr,
- btread(BT848_GPIO_OUT_EN),
- btread(BT848_GPIO_DATA),
- btread(BT848_GPIO_REG_INP));
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"init #1");
/* reset the bt848 */
btwrite(0, BT848_SRESET);
@@ -2724,10 +2560,6 @@ static int __devinit init_bt848(struct bttv *btv)
btv->errors=0;
btv->needs_restart=0;
- /* i2c */
- btv->tuner_type=-1;
- init_bttv_i2c(btv);
-
if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
return -1;
if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
@@ -2772,6 +2604,9 @@ static int __devinit init_bt848(struct bttv *btv)
/* select direct input */
btwrite(0x00, BT848_GPIO_REG_INP);
+ btwrite(0x00, BT848_GPIO_OUT_EN);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"init #2");
btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO,
BT848_IFORM);
@@ -2814,6 +2649,17 @@ static int __devinit init_bt848(struct bttv *btv)
bt848_set_risc_jmps(btv,-1);
spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+ /* needs to be done before i2c is registered */
+ if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878)
+ bttv_hauppauge_boot_msp34xx(btv);
+
+ /* register i2c */
+ btv->tuner_type=-1;
+ init_bttv_i2c(btv);
+
+ /* some card-specific stuff (needs working i2c) */
+ bttv_init_card(btv);
+
/*
* Now add the template and register the device unit.
*/
@@ -2822,11 +2668,18 @@ static int __devinit init_bt848(struct bttv *btv)
return 0;
}
+/* ----------------------------------------------------------------------- */
+
+static char *irq_name[] = { "FMTCHG", "VSYNC", "HSYNC", "OFLOW", "HLOCK",
+ "VPRES", "6", "7", "I2CDONE", "GPINT", "10",
+ "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
+ "RIPERR", "PABORT", "OCERR", "SCERR" };
+
static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
u32 stat,astat;
u32 dstat;
- int count,i;
+ int count;
struct bttv *btv;
btv=(struct bttv *)dev_id;
@@ -2838,33 +2691,39 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
astat=stat&btread(BT848_INT_MASK);
if (!astat)
return;
- btwrite(astat,BT848_INT_STAT);
- IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat));
- IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat));
+ btwrite(stat,BT848_INT_STAT);
/* get device status bits */
dstat=btread(BT848_DSTATUS);
-
- if (astat&BT848_INT_GPINT) {
- IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr));
- wake_up_interruptible(&btv->gpioq);
- }
- if (astat&BT848_INT_FMTCHG)
- {
- IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
- /*btv->win.norm&=
- (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
- }
- if (astat&BT848_INT_VPRES)
- {
- IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
+ if (irq_debug) {
+ int i;
+ printk(KERN_DEBUG "bttv%d: irq loop=%d risc=%x, bits:",
+ btv->nr, count, stat>>28);
+ for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
+ if (stat & (1 << i))
+ printk(" %s",irq_name[i]);
+ if (astat & (1 << i))
+ printk("*");
+ }
+ if (stat & BT848_INT_HLOCK)
+ printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
+ ? "yes" : "no");
+ if (stat & BT848_INT_VPRES)
+ printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
+ ? "yes" : "no");
+ if (stat & BT848_INT_FMTCHG)
+ printk(" NUML => %s", (dstat & BT848_DSTATUS_PRES)
+ ? "625" : "525");
+ printk("\n");
}
+
+ if (astat&BT848_INT_GPINT)
+ wake_up_interruptible(&btv->gpioq);
+
if (astat&BT848_INT_VSYNC)
- {
- IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
btv->field++;
- }
+
if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) {
if (bttv_verbose)
printk("bttv%d: irq:%s%s risc_count=%08x\n",
@@ -2884,23 +2743,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
} else {
if (bttv_verbose)
printk("bttv%d: aiee: error loops\n",btv->nr);
- /* cancel all outstanding grab requests */
- spin_lock(&btv->s_lock);
- btv->gq_in = 0;
- btv->gq_out = 0;
- btv->gq_grab = -1;
- for (i = 0; i < gbuffers; i++)
- if (btv->gbuf[i].stat == GBUFFER_GRABBING)
- btv->gbuf[i].stat = GBUFFER_ERROR;
- /* disable DMA */
- btv->risc_cap_odd = 0;
- btv->risc_cap_even = 0;
- bt848_set_risc_jmps(btv,0);
- btv->needs_restart = 1;
- spin_unlock(&btv->s_lock);
-
- wake_up_interruptible(&btv->vbiq);
- wake_up_interruptible(&btv->capq);
+ bt848_offline(btv);
}
}
if (astat&BT848_INT_RISCI)
@@ -2968,55 +2811,20 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
spin_unlock(&btv->s_lock);
}
}
- if (astat&BT848_INT_OCERR)
- {
- IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
- }
- if (astat&BT848_INT_PABORT)
- {
- IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
- }
- if (astat&BT848_INT_RIPERR)
- {
- IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
- }
- if (astat&BT848_INT_PPERR)
- {
- IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
- }
- if (astat&BT848_INT_FDSR)
- {
- IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
- }
- if (astat&BT848_INT_FTRGT)
- {
- IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
- }
- if (astat&BT848_INT_FBUS)
- {
- IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
- }
- if (astat&BT848_INT_HLOCK)
- {
+
+ if (astat&BT848_INT_HLOCK) {
if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
audio(btv, AUDIO_ON,0);
else
audio(btv, AUDIO_OFF,0);
}
- if (astat&BT848_INT_I2CDONE)
- {
- IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
- }
count++;
- if (count > 10)
- printk (KERN_WARNING "bttv%d: irq loop %d\n",
- btv->nr,count);
- if (count > 20)
- {
+ if (count > 20) {
btwrite(0, BT848_INT_MASK);
printk(KERN_ERR
"bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
+ bt848_offline(btv);
}
}
}
@@ -3033,8 +2841,11 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
int j;
struct bttv *btv = pci_get_drvdata(pci_dev);
+ if (bttv_verbose)
+ printk("bttv%d: unloading\n",btv->nr);
+
/* unregister i2c_bus */
- if (0 == btv->i2c_ok)
+ if (0 == btv->i2c_rc)
i2c_bit_del_bus(&btv->i2c_adap);
/* turn off all capturing, DMA and IRQs */
@@ -3044,6 +2855,8 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
btwrite(0, BT848_INT_MASK);
btwrite(~0x0UL,BT848_INT_STAT);
btwrite(0x0, BT848_GPIO_OUT_EN);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"cleanup");
/* disable PCI bus-mastering */
pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
@@ -3084,7 +2897,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
if (radio[btv->nr] && btv->radio_dev.minor != -1)
video_unregister_device(&btv->radio_dev);
- release_mem_region(btv->bt848_adr,
+ release_mem_region(pci_resource_start(btv->dev,0),
pci_resource_len(btv->dev,0));
/* wake up any waiting processes
because shutdown flag is set, no new processes (in this queue)
@@ -3094,7 +2907,6 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
wake_up(&btv->gpioq);
pci_set_drvdata(pci_dev, NULL);
-
return;
}
@@ -3102,7 +2914,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
{
int result;
- unsigned char command;
+ unsigned char command,lat;
struct bttv *btv;
#if defined(__powerpc__)
unsigned int cmd;
@@ -3141,11 +2953,14 @@ static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id
btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
- printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
- bttv_num,btv->id, btv->revision);
- printk("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn);
- printk("irq: %d, ",btv->irq);
- printk("memory: 0x%lx.\n", btv->bt848_adr);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
+ bttv_num,btv->id, btv->revision, dev->bus->number,
+ PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn));
+ printk("irq: %d, latency: %d, memory: 0x%lx\n",
+ btv->irq, lat, btv->bt848_adr);
+
+ bttv_idcard(btv);
#if defined(__powerpc__)
/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
diff --git a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
index a58e441db..d2ed39307 100644
--- a/drivers/media/video/bttv-if.c
+++ b/drivers/media/video/bttv-if.c
@@ -3,7 +3,6 @@
all the i2c code is here
also the gpio interface exported by bttv (used by lirc)
-
bttv - Bt848 frame grabber driver
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
@@ -34,7 +33,7 @@
#include <asm/io.h>
-#include "bttv.h"
+#include "bttvp.h"
#include "tuner.h"
@@ -79,6 +78,8 @@ int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data)
btv = &bttvs[card];
btaor(data, ~mask, BT848_GPIO_OUT_EN);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"extern enable");
return 0;
}
@@ -115,6 +116,8 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
/* prior setting BT848_GPIO_REG_INP is (probably) not needed
because direct input is set on init */
btaor(data & mask, ~mask, BT848_GPIO_DATA);
+ if (bttv_gpio)
+ bttv_gpio_tracking(btv,"extern write");
return 0;
}
@@ -195,8 +198,7 @@ static int attach_inform(struct i2c_client *client)
int i;
for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- if (btv->i2c_clients[i] == NULL ||
- btv->i2c_clients[i]->driver->id == client->driver->id) {
+ if (btv->i2c_clients[i] == NULL) {
btv->i2c_clients[i] = client;
break;
}
@@ -216,8 +218,7 @@ static int detach_inform(struct i2c_client *client)
if (bttv_verbose)
printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name);
for (i = 0; i < I2C_CLIENTS_MAX; i++) {
- if (NULL != btv->i2c_clients[i] &&
- btv->i2c_clients[i]->driver->id == client->driver->id) {
+ if (btv->i2c_clients[i] == client) {
btv->i2c_clients[i] = NULL;
break;
}
@@ -240,33 +241,27 @@ void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
}
struct i2c_algo_bit_data bttv_i2c_algo_template = {
- NULL,
- bttv_bit_setsda,
- bttv_bit_setscl,
- bttv_bit_getsda,
- bttv_bit_getscl,
- 10, 10, 100,
+ setsda: bttv_bit_setsda,
+ setscl: bttv_bit_setscl,
+ getsda: bttv_bit_getsda,
+ getscl: bttv_bit_getscl,
+ udelay: 40,
+ mdelay: 10,
+ timeout: 200,
};
struct i2c_adapter bttv_i2c_adap_template = {
- "bt848",
- I2C_HW_B_BT848,
- NULL,
- NULL,
- bttv_inc_use,
- bttv_dec_use,
- attach_inform,
- detach_inform,
- NULL,
+ name: "bt848",
+ id: I2C_HW_B_BT848,
+ inc_use: bttv_inc_use,
+ dec_use: bttv_dec_use,
+ client_register: attach_inform,
+ client_unregister: detach_inform,
};
struct i2c_client bttv_i2c_client_template = {
- "bttv internal",
- -1,
- 0,
- 0,
- NULL,
- NULL
+ name: "bttv internal use only",
+ id: -1,
};
@@ -275,7 +270,7 @@ int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
unsigned char buffer = 0;
- if (0 != btv->i2c_ok)
+ if (0 != btv->i2c_rc)
return -1;
if (bttv_verbose && NULL != probe_for)
printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ",
@@ -302,7 +297,7 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char buffer[2];
int bytes = both ? 2 : 1;
- if (0 != btv->i2c_ok)
+ if (0 != btv->i2c_rc)
return -1;
btv->i2c_client.addr = addr >> 1;
buffer[0] = b1;
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 5b9c178cb..c7aaa8bf3 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -1,42 +1,19 @@
/*
- bttv - Bt848 frame grabber driver
-
- Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ * bttv - Bt848 frame grabber driver
+ *
+ * card ID's and external interfaces of the bttv driver
+ * basically stuff needed by other drivers (i2c, lirc, ...)
+ * and is supported not to change much over time.
+ *
+ * Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38)
-
-#include <linux/types.h>
-#include <linux/wait.h>
#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "audiochip.h"
-#include "bt848.h"
-
-#ifdef __KERNEL__
-
-/* fwd decl */
-struct bttv;
-
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
@@ -90,6 +67,35 @@ struct bttv;
#define BTTV_ZOLTRIX_GENIE 0x2e
#define BTTV_TERRATVRADIO 0x2f
#define BTTV_DYNALINK 0x30
+#define BTTV_GVBCTV3PCI 0x31
+#define BTTV_PXELVWPLTVPAK 0x32
+#define BTTV_EAGLE 0x33
+#define BTTV_PINNACLESTUDIO 0x34
+
+/* i2c address list */
+#define I2C_TSA5522 0xc2
+#define I2C_TDA7432 0x8a
+#define I2C_TDA8425 0x82
+#define I2C_TDA9840 0x84
+#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */
+#define I2C_TDA9875 0xb0
+#define I2C_HAUPEE 0xa0
+#define I2C_STBEE 0xae
+#define I2C_VHX 0xc0
+#define I2C_MSP3400 0x80
+#define I2C_TEA6300 0x80
+#define I2C_DPL3518 0x84
+
+/* more card-specific defines */
+#define PT2254_L_CHANEL 0x10
+#define PT2254_R_CHANEL 0x08
+#define PT2254_DBS_IN_2 0x400
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK 0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
+
+struct bttv;
struct tvcard
{
@@ -103,15 +109,9 @@ struct tvcard
u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
u32 gpiomask2; /* GPIO MUX mask */
- /* look for these i2c audio chips */
- int msp34xx:1;
- int tda8425:1;
- int tda9840:1;
- int tda985x:1;
- int tea63xx:1;
- int tea64xx:1;
- int tda7432:1;
- int tda9875:1;
+ /* i2c audio flags */
+ int no_msp34xx:1;
+ int needs_tvaudio:1;
/* other settings */
int pll;
@@ -120,6 +120,7 @@ struct tvcard
#define PLL_35 2
int tuner_type;
+ void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
};
extern struct tvcard bttv_tvcards[];
@@ -127,10 +128,11 @@ extern const int bttv_num_tvcards;
/* identification / initialization of the card */
extern void bttv_idcard(struct bttv *btv);
+extern void bttv_init_card(struct bttv *btv);
/* card-specific funtions */
extern void tea5757_set_freq(struct bttv *btv, unsigned short freq);
-extern void winview_setvol(struct bttv *btv, struct video_audio *v);
+extern void bttv_hauppauge_boot_msp34xx(struct bttv *btv);
/* ---------------------------------------------------------- */
/* exported by bttv-if.c */
@@ -176,6 +178,7 @@ extern int bttv_write_gpio(unsigned int card,
extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
/* i2c */
+#define I2C_CLIENTS_MAX 8
struct i2c_algo_bit_data bttv_i2c_algo_template;
struct i2c_adapter bttv_i2c_adap_template;
struct i2c_client bttv_i2c_client_template;
@@ -187,234 +190,4 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both);
void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
-
-/* ---------------------------------------------------------- */
-/* bttv-driver.c */
-
-/* insmod options */
-extern unsigned int bttv_verbose;
-extern unsigned int bttv_debug;
-
-/* Anybody who uses more than four? */
-#define BTTV_MAX 4
-extern int bttv_num; /* number of Bt848s in use */
-extern struct bttv bttvs[BTTV_MAX];
-
-
-#ifndef O_NONCAP
-#define O_NONCAP O_TRUNC
-#endif
-
-#define MAX_GBUFFERS 64
-#define RISCMEM_LEN (32744*2)
-#define VBI_MAXLINES 16
-#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
-
-#define BTTV_MAX_FBUF 0x208000
-#define I2C_CLIENTS_MAX 8
-
-struct bttv_window
-{
- int x, y;
- ushort width, height;
- ushort bpp, bpl;
- ushort swidth, sheight;
- unsigned long vidadr;
- ushort freq;
- int norm;
- int interlace;
- int color_fmt;
- ushort depth;
-};
-
-struct bttv_pll_info {
- unsigned int pll_ifreq; /* PLL input frequency */
- unsigned int pll_ofreq; /* PLL output frequency */
- unsigned int pll_crystal; /* Crystal used for input */
- unsigned int pll_current; /* Currently programmed ofreq */
-};
-
-struct bttv_gbuf {
- int stat;
-#define GBUFFER_UNUSED 0
-#define GBUFFER_GRABBING 1
-#define GBUFFER_DONE 2
-#define GBUFFER_ERROR 3
- struct timeval tv;
-
- u16 width;
- u16 height;
- u16 fmt;
-
- u32 *risc;
- unsigned long ro;
- unsigned long re;
-};
-
-struct bttv {
- struct video_device video_dev;
- struct video_device radio_dev;
- struct video_device vbi_dev;
- struct video_picture picture; /* Current picture params */
- struct video_audio audio_dev; /* Current audio params */
-
- spinlock_t s_lock;
- struct semaphore lock;
- int user;
- int capuser;
-
- /* i2c */
- struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
- struct i2c_client i2c_client;
- int i2c_state, i2c_ok;
- struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
-
- int tuner_type;
- int channel;
-
- unsigned int nr;
- unsigned short id;
- struct pci_dev *dev;
- unsigned int irq; /* IRQ used by Bt848 card */
- unsigned char revision;
- unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */
- unsigned char *bt848_mem; /* pointer to mapped IO memory */
- unsigned long busriscmem;
- u32 *riscmem;
-
- unsigned char *vbibuf;
- struct bttv_window win;
- int fb_color_ctl;
- int type; /* card type */
- int cardid;
- int audio; /* audio mode */
- int audio_chip; /* set to one of the chips supported by bttv.c */
- int radio;
-
- u32 *risc_jmp;
- u32 *vbi_odd;
- u32 *vbi_even;
- u32 bus_vbi_even;
- u32 bus_vbi_odd;
- wait_queue_head_t vbiq;
- wait_queue_head_t capq;
- int vbip;
-
- u32 *risc_scr_odd;
- u32 *risc_scr_even;
- u32 risc_cap_odd;
- u32 risc_cap_even;
- int scr_on;
- int vbi_on;
- struct video_clip *cliprecs;
-
- struct bttv_gbuf *gbuf;
- int gqueue[MAX_GBUFFERS];
- int gq_in,gq_out,gq_grab,gq_start;
- char *fbuffer;
-
- struct bttv_pll_info pll;
- unsigned int Fsc;
- unsigned int field;
- unsigned int last_field; /* number of last grabbed field */
- int i2c_command;
- int triton1;
-
- int errors;
- int needs_restart;
-
- wait_queue_head_t gpioq;
- int shutdown;
-};
-#endif
-
-#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
-{
- __asm__ __volatile__ ("stwbrx %1,0,%2" : \
- "=m" (*addr) : "r" (val), "r" (addr));
- __asm__ __volatile__ ("eieio" : : : "memory");
-}
-
-#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
-#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr)))
-#else
-#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr)))
-#define btread(adr) readl(btv->bt848_mem+(adr))
-#endif
-
-#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
-#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
-#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-
-/* bttv ioctls */
-
-#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
-#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
-#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
-#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
-#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
-#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
-#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
-#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
-#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-
-#define AUDIO_TUNER 0x00
-#define AUDIO_RADIO 0x01
-#define AUDIO_EXTERN 0x02
-#define AUDIO_INTERN 0x03
-#define AUDIO_OFF 0x04
-#define AUDIO_ON 0x05
-#define AUDIO_MUTE 0x80
-#define AUDIO_UNMUTE 0x81
-
-#define TDA9850 0x01
-#define TDA9840 0x02
-#define TDA8425 0x03
-#define TEA6300 0x04
-
-#define I2C_TSA5522 0xc2
-#define I2C_TDA7432 0x8a
-#define I2C_TDA8425 0x82
-#define I2C_TDA9840 0x84
-#define I2C_TDA9850 0xb6 /* also used by 9855,9873 */
-#define I2C_TDA9875 0xb0
-#define I2C_HAUPEE 0xa0
-#define I2C_STBEE 0xae
-#define I2C_VHX 0xc0
-#define I2C_MSP3400 0x80
-#define I2C_TEA6300 0x80
-#define I2C_DPL3518 0x84
-
-#ifndef HAVE_TVAUDIO
-#define TDA9840_SW 0x00
-#define TDA9840_LVADJ 0x02
-#define TDA9840_STADJ 0x03
-#define TDA9840_TEST 0x04
-#endif
-
-#define PT2254_L_CHANEL 0x10
-#define PT2254_R_CHANEL 0x08
-#define PT2254_DBS_IN_2 0x400
-#define PT2254_DBS_IN_10 0x20000
-#define WINVIEW_PT2254_CLK 0x40
-#define WINVIEW_PT2254_DATA 0x20
-#define WINVIEW_PT2254_STROBE 0x80
-
-struct bttv_just_hacking {
- int height,width; /* size */
- unsigned int format; /* should be VIDEO_PALETTE_* */
- long buf;
- int len;
-};
-
-#define BTTV_JUST_HACKING _IOR('v' , BASE_VIDIOCPRIVATE+31,struct bttv_just_hacking)
-
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#endif /* _BTTV_H_ */
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
new file mode 100644
index 000000000..4676ee61b
--- /dev/null
+++ b/drivers/media/video/bttvp.h
@@ -0,0 +1,226 @@
+/*
+ bttv - Bt848 frame grabber driver
+
+ bttv's *private* header file -- nobody else than bttv itself
+ should ever include this file.
+
+ Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _BTTVP_H_
+#define _BTTVP_H_
+
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,48)
+
+
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "bt848.h"
+#include "bttv.h"
+#include "audiochip.h"
+
+#ifdef __KERNEL__
+
+/* ---------------------------------------------------------- */
+/* bttv-driver.c */
+
+/* insmod options */
+extern unsigned int bttv_verbose;
+extern unsigned int bttv_debug;
+extern unsigned int bttv_gpio;
+extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
+
+/* Anybody who uses more than four? */
+#define BTTV_MAX 4
+extern int bttv_num; /* number of Bt848s in use */
+extern struct bttv bttvs[BTTV_MAX];
+
+
+#ifndef O_NONCAP
+#define O_NONCAP O_TRUNC
+#endif
+
+#define MAX_GBUFFERS 64
+#define RISCMEM_LEN (32744*2)
+#define VBI_MAXLINES 16
+#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
+
+#define BTTV_MAX_FBUF 0x208000
+
+struct bttv_window
+{
+ int x, y;
+ ushort width, height;
+ ushort bpp, bpl;
+ ushort swidth, sheight;
+ unsigned long vidadr;
+ ushort freq;
+ int norm;
+ int interlace;
+ int color_fmt;
+ ushort depth;
+};
+
+struct bttv_pll_info {
+ unsigned int pll_ifreq; /* PLL input frequency */
+ unsigned int pll_ofreq; /* PLL output frequency */
+ unsigned int pll_crystal; /* Crystal used for input */
+ unsigned int pll_current; /* Currently programmed ofreq */
+};
+
+struct bttv_gbuf {
+ int stat;
+#define GBUFFER_UNUSED 0
+#define GBUFFER_GRABBING 1
+#define GBUFFER_DONE 2
+#define GBUFFER_ERROR 3
+ struct timeval tv;
+
+ u16 width;
+ u16 height;
+ u16 fmt;
+
+ u32 *risc;
+ unsigned long ro;
+ unsigned long re;
+};
+
+struct bttv {
+ struct video_device video_dev;
+ struct video_device radio_dev;
+ struct video_device vbi_dev;
+ struct video_picture picture; /* Current picture params */
+ struct video_audio audio_dev; /* Current audio params */
+
+ spinlock_t s_lock;
+ struct semaphore lock;
+ int user;
+ int capuser;
+
+ /* i2c */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ int i2c_state, i2c_rc;
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+ int tuner_type;
+ int channel;
+
+ unsigned int nr;
+ unsigned short id;
+ struct pci_dev *dev;
+ unsigned int irq; /* IRQ used by Bt848 card */
+ unsigned char revision;
+ unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */
+ unsigned char *bt848_mem; /* pointer to mapped IO memory */
+ unsigned long busriscmem;
+ u32 *riscmem;
+
+ unsigned char *vbibuf;
+ struct bttv_window win;
+ int fb_color_ctl;
+ int type; /* card type */
+ int cardid;
+ int audio; /* audio mode */
+ int audio_chip; /* set to one of the chips supported by bttv.c */
+ int radio;
+
+ u32 *risc_jmp;
+ u32 *vbi_odd;
+ u32 *vbi_even;
+ u32 bus_vbi_even;
+ u32 bus_vbi_odd;
+ wait_queue_head_t vbiq;
+ wait_queue_head_t capq;
+ int vbip;
+
+ u32 *risc_scr_odd;
+ u32 *risc_scr_even;
+ u32 risc_cap_odd;
+ u32 risc_cap_even;
+ int scr_on;
+ int vbi_on;
+ struct video_clip *cliprecs;
+
+ struct bttv_gbuf *gbuf;
+ int gqueue[MAX_GBUFFERS];
+ int gq_in,gq_out,gq_grab,gq_start;
+ char *fbuffer;
+
+ struct bttv_pll_info pll;
+ unsigned int Fsc;
+ unsigned int field;
+ unsigned int last_field; /* number of last grabbed field */
+ int i2c_command;
+ int triton1;
+
+ int errors;
+ int needs_restart;
+
+ wait_queue_head_t gpioq;
+ int shutdown;
+};
+#endif
+
+#if defined(__powerpc__) /* big-endian */
+extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
+{
+ __asm__ __volatile__ ("stwbrx %1,0,%2" : \
+ "=m" (*addr) : "r" (val), "r" (addr));
+ __asm__ __volatile__ ("eieio" : : : "memory");
+}
+
+#define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
+#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr)))
+#else
+#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr)))
+#define btread(adr) readl(btv->bt848_mem+(adr))
+#endif
+
+#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
+#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
+#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
+
+/* bttv ioctls */
+
+#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
+#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
+#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
+#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
+#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
+#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
+#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
+#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
+
+#define TDA9850 0x01
+#define TDA9840 0x02
+#define TDA8425 0x03
+#define TEA6300 0x04
+
+#endif /* _BTTVP_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/buz.c b/drivers/media/video/buz.c
index e23346772..baaa8f4ae 100644
--- a/drivers/media/video/buz.c
+++ b/drivers/media/video/buz.c
@@ -3027,28 +3027,18 @@ static int zoran_mmap(struct video_device *dev, const char *adr, unsigned long s
return 0;
}
-static int zoran_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static struct video_device zoran_template =
{
- BUZ_NAME,
- VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
- VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
- VID_HARDWARE_ZR36067,
- zoran_open,
- zoran_close,
- zoran_read,
- zoran_write,
- NULL,
- zoran_ioctl,
- zoran_mmap,
- zoran_init_done,
- NULL,
- 0,
- 0
+ name: BUZ_NAME,
+ type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
+ VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
+ hardware: VID_HARDWARE_ZR36067,
+ open: zoran_open,
+ close: zoran_close,
+ read: zoran_read,
+ write: zoran_write,
+ ioctl: zoran_ioctl,
+ mmap: zoran_mmap,
};
static int zr36057_init(int i)
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 17f7d25dc..92d71ba59 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -705,11 +705,6 @@ static void qcam_close(struct video_device *dev)
MOD_DEC_USE_COUNT;
}
-static int qcam_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
@@ -926,20 +921,14 @@ static long qcam_read(struct video_device *v, char *buf, unsigned long count, i
static struct video_device qcam_template=
{
- "Connectix Quickcam",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_QCAM_BW,
- qcam_open,
- qcam_close,
- qcam_read,
- qcam_write,
- NULL,
- qcam_ioctl,
- NULL,
- qcam_init_done,
- NULL,
- 0,
- 0
+ name: "Connectix Quickcam",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_QCAM_BW,
+ open: qcam_open,
+ close: qcam_close,
+ read: qcam_read,
+ write: qcam_write,
+ ioctl: qcam_ioctl,
};
#define MAX_CAMS 4
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index fa96cc925..2b0444582 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -509,11 +509,6 @@ static void qcam_close(struct video_device *dev)
MOD_DEC_USE_COUNT;
}
-static int qcam_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
@@ -733,20 +728,14 @@ static long qcam_read(struct video_device *v, char *buf, unsigned long count, i
/* video device template */
static struct video_device qcam_template=
{
- "Colour QuickCam",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_QCAM_C,
- qcam_open,
- qcam_close,
- qcam_read,
- qcam_write,
- NULL,
- qcam_ioctl,
- NULL,
- qcam_init_done,
- NULL,
- 0,
- 0
+ name: "Colour QuickCam",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_QCAM_C,
+ open: qcam_open,
+ close: qcam_close,
+ read: qcam_read,
+ write: qcam_write,
+ ioctl: qcam_ioctl,
};
/* Initialize the QuickCam driver control structure. */
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index d7d007f01..0241b55ab 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3031,20 +3031,16 @@ int cpia_video_init(struct video_device *vdev)
}
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 */
+ name: "CPiA Camera",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_CPIA, /* FIXME */
+ open: cpia_open,
+ close: cpia_close,
+ read: cpia_read,
+ ioctl: cpia_ioctl,
+ mmap: cpia_mmap,
+ initialize: cpia_video_init,
+ minor: -1,
};
/* initialise cam_data structure */
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 79687ebba..e893ea978 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -432,11 +432,21 @@ static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
ucpia->sbuf[1].urb = NULL;
}
+ if (ucpia->sbuf[1].data) {
+ kfree(ucpia->sbuf[1].data);
+ ucpia->sbuf[1].data = 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;
}
+
+ if (ucpia->sbuf[0].data) {
+ kfree(ucpia->sbuf[0].data);
+ ucpia->sbuf[0].data = NULL;
+ }
}
static int cpia_usb_close(void *privdata)
@@ -461,7 +471,8 @@ int cpia_usb_init(void)
/* Probing and initializing */
-static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+static void *cpia_probe(struct usb_device *udev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_interface_descriptor *interface;
struct usb_cpia *ucpia;
@@ -474,13 +485,6 @@ static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
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);
@@ -552,11 +556,18 @@ fail_alloc_0:
static void cpia_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_device_id cpia_id_table [] = {
+ { idVendor: 0x0553, idProduct: 0x0002 },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, cpia_id_table);
+
static struct usb_driver cpia_driver = {
- "cpia",
- cpia_probe,
- cpia_disconnect,
- { NULL, NULL }
+ name: "cpia",
+ probe: cpia_probe,
+ disconnect: cpia_disconnect,
+ id_table: cpia_id_table,
};
/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
diff --git a/drivers/media/video/id.h b/drivers/media/video/id.h
new file mode 100644
index 000000000..d1f99ee06
--- /dev/null
+++ b/drivers/media/video/id.h
@@ -0,0 +1,26 @@
+/* FIXME: this temporarely, until these are included in linux/i2c-id.h */
+
+/* drivers */
+#ifndef I2C_DRIVERID_TVMIXER
+# define I2C_DRIVERID_TVMIXER I2C_DRIVERID_EXP0
+#endif
+#ifndef I2C_DRIVERID_TVAUDIO
+# define I2C_DRIVERID_TVAUDIO I2C_DRIVERID_EXP1
+#endif
+
+/* chips */
+#ifndef I2C_DRIVERID_DPL3518
+# define I2C_DRIVERID_DPL3518 I2C_DRIVERID_EXP2
+#endif
+#ifndef I2C_DRIVERID_TDA9873
+# define I2C_DRIVERID_TDA9873 I2C_DRIVERID_EXP3
+#endif
+#ifndef I2C_DRIVERID_TDA9875
+# define I2C_DRIVERID_TDA9875 I2C_DRIVERID_EXP0+4
+#endif
+#ifndef I2C_DRIVERID_PIC16C54_PV951
+# define I2C_DRIVERID_PIC16C54_PV951 I2C_DRIVERID_EXP0+5
+#endif
+#ifndef I2C_DRIVERID_TDA7432
+# define I2C_DRIVERID_TDA7432 I2C_DRIVERID_EXP0+6
+#endif
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index 2d2b1e89c..385beb49c 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -88,8 +88,10 @@ struct msp3400c {
int norm;
int stereo;
int nicam_on;
+ int acb;
int main, second; /* sound carrier */
+ int muted;
int left, right; /* volume */
int bass, treble;
@@ -299,6 +301,43 @@ static struct CARRIER_DETECT carrier_detect_65[] = {
#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
+/* ----------------------------------------------------------------------- */
+
+#define SCART_MASK 0
+#define SCART_IN1 1
+#define SCART_IN2 2
+#define SCART_IN1_DA 3
+#define SCART_IN2_DA 4
+#define SCART_IN3 5
+#define SCART_IN4 6
+#define SCART_MONO 7
+#define SCART_MUTE 8
+
+static int scarts[3][9] = {
+ /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */
+ { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 },
+ { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 },
+ { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 },
+};
+
+static char *scart_names[] = {
+ "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute"
+};
+
+static void
+msp3400c_set_scart(struct i2c_client *client, int in, int out)
+{
+ struct msp3400c *msp = client->data;
+
+ if (-1 == scarts[out][in])
+ return;
+
+ dprintk("msp34xx: scart switch: %s => %d\n",scart_names[in],out);
+ msp->acb &= ~scarts[out][SCART_MASK];
+ msp->acb |= scarts[out][in];
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
+}
+
/* ------------------------------------------------------------------------ */
static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
@@ -310,18 +349,21 @@ static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2)
msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
}
-static void msp3400c_setvolume(struct i2c_client *client, int left, int right)
+static void msp3400c_setvolume(struct i2c_client *client,
+ int muted, int left, int right)
{
- int vol,val,balance;
+ int vol = 0,val = 0,balance = 0;
- vol = (left > right) ? left : right;
- val = (vol * 0x73 / 65535) << 8;
- balance = 0;
- if (vol > 0)
+ if (!muted) {
+ vol = (left > right) ? left : right;
+ val = (vol * 0x73 / 65535) << 8;
+ }
+ if (vol > 0) {
balance = ((right-left) * 127) / vol;
+ }
- dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n",
- left,right,val>>8,balance);
+ dprintk("msp34xx: setvolume: mute=%s %d:%d v=0x%02x b=0x%02x\n",
+ muted ? "on" : "off", left, right, val>>8, balance);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
/* scart - on/off only */
@@ -470,11 +512,8 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode)
if (msp->mode == MSP_MODE_AM_NICAM) {
dprintk("msp3400: switching to AM mono\n");
/* AM mono decoding is handled by tuner, not MSP chip */
- /* so let's redirect sound from tuner via SCART */
- /* volume prescale for SCART */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
- /* SCART switching control register*/
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900);
+ /* SCART switching control register */
+ msp3400c_set_scart(client,SCART_MONO,0);
src = 0x0200;
break;
}
@@ -711,7 +750,7 @@ static int msp3400c_thread(void *data)
restart:
msp->restart = 0;
- msp3400c_setvolume(client, 0, 0);
+ msp3400c_setvolume(client, msp->muted, 0, 0);
msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
val1 = val2 = 0;
max1 = max2 = -1;
@@ -829,6 +868,8 @@ static int msp3400c_thread(void *data)
msp->nicam_on = 0;
msp3400c_setstereo(client, VIDEO_SOUND_MONO);
msp3400c_setcarrier(client, msp->second, msp->main);
+ /* volume prescale for SCART (AM mono input) */
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
msp->watch_stereo = 1;
} else if (max2 == 0 && msp->nicam) {
/* D/K NICAM */
@@ -854,7 +895,7 @@ static int msp3400c_thread(void *data)
}
/* unmute */
- msp3400c_setvolume(client, msp->left, msp->right);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
if (msp->watch_stereo)
mod_timer(&msp->wake_stereo, jiffies+5*HZ);
@@ -941,9 +982,6 @@ static int msp3410d_thread(void *data)
if (msp->rmmod || signal_pending(current))
goto done;
- if (VIDEO_MODE_RADIO == msp->norm)
- continue; /* nothing to do */
-
msp->active = 1;
if (msp->watch_stereo) {
@@ -966,6 +1004,11 @@ static int msp3410d_thread(void *data)
/* put into sane state (and mute) */
msp3400c_reset(client);
+ /* set various prescales */
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x0d, 0x1900); /* scart */
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
+ msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* nicam */
+
/* start autodetect */
switch (msp->norm) {
case VIDEO_MODE_PAL:
@@ -978,7 +1021,11 @@ static int msp3410d_thread(void *data)
break;
case VIDEO_MODE_SECAM:
mode = 0x0003;
- std = 1;
+ std = 1;
+ break;
+ case VIDEO_MODE_RADIO:
+ mode = 0x0003;
+ std = 0x0040;
break;
default:
mode = 0x0003;
@@ -987,8 +1034,7 @@ static int msp3410d_thread(void *data)
}
msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode);
msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std);
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403);
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00);
+
if (debug) {
int i;
for (i = 0; modelist[i].name != NULL; i++)
@@ -1019,7 +1065,7 @@ static int msp3410d_thread(void *data)
}
}
for (i = 0; modelist[i].name != NULL; i++)
- if (modelist[i].retval == val)
+ if (modelist[i].retval == val)
break;
dprintk("msp3410: current mode: %s (0x%04x)\n",
modelist[i].name ? modelist[i].name : "unknown",
@@ -1035,11 +1081,24 @@ static int msp3410d_thread(void *data)
msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
}
- /* set prescale / stereo */
+ /* set stereo */
switch (val) {
+ case 0x0008: /* B/G NICAM */
+ case 0x000a: /* I NICAM */
+ if (val == 0x0008)
+ msp->mode = MSP_MODE_FM_NICAM1;
+ else
+ msp->mode = MSP_MODE_FM_NICAM2;
+ /* just turn on stereo */
+ msp->stereo = VIDEO_SOUND_STEREO;
+ msp->nicam_on = 1;
+ msp->watch_stereo = 1;
+ msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
+ break;
case 0x0009:
msp->mode = MSP_MODE_AM_NICAM;
msp->stereo = VIDEO_SOUND_MONO;
+ msp->nicam_on = 1;
msp3400c_setstereo(client,VIDEO_SOUND_MONO);
msp->watch_stereo = 1;
break;
@@ -1047,26 +1106,31 @@ static int msp3410d_thread(void *data)
/* just turn on stereo */
msp->mode = MSP_MODE_BTSC;
msp->stereo = VIDEO_SOUND_STEREO;
+ msp->nicam_on = 0;
msp->watch_stereo = 1;
msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
- /* set prescale */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
+ break;
+ case 0x0040: /* FM radio */
+ msp->mode = MSP_MODE_FM_RADIO;
+ msp->stereo = VIDEO_SOUND_STEREO;
+ msp->nicam_on = 0;
+ msp->watch_stereo = 0;
+ /* scart routing */
+ msp3400c_set_scart(client,SCART_IN2,0);
+ msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
break;
case 0x0003:
msp->mode = MSP_MODE_FM_TERRA;
msp->stereo = VIDEO_SOUND_MONO;
+ msp->nicam_on = 0;
msp->watch_stereo = 1;
- /* fall */
- default:
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */
break;
}
-
+
/* unmute */
msp3400c_setbass(client, msp->bass);
msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->left, msp->right);
+ msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
if (msp->watch_stereo)
mod_timer(&msp->wake_stereo, jiffies+HZ);
@@ -1093,22 +1157,18 @@ static int msp_probe(struct i2c_adapter *adap);
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
static struct i2c_driver driver = {
- "i2c msp3400 driver",
- I2C_DRIVERID_MSP3400,
- I2C_DF_NOTIFY,
- msp_probe,
- msp_detach,
- msp_command,
+ name: "i2c msp3400 driver",
+ id: I2C_DRIVERID_MSP3400,
+ flags: I2C_DF_NOTIFY,
+ attach_adapter: msp_probe,
+ detach_client: msp_detach,
+ command: msp_command,
};
static struct i2c_client client_template =
{
- "unset",
- -1,
- 0,
- 0,
- NULL,
- &driver
+ name: "(unset)",
+ driver: &driver,
};
static int msp_attach(struct i2c_adapter *adap, int addr,
@@ -1150,8 +1210,9 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
}
rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
- rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
- if (0 == rev1 && 0 == rev2) {
+ if (-1 != rev1)
+ rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+ if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
kfree(msp);
printk("msp3400: error while reading chip version\n");
return -1;
@@ -1180,7 +1241,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
msp->wake_stereo.data = (unsigned long)msp;
/* hello world :-) */
- printk(KERN_INFO "msp3400: init: chip=%s",c->name);
+ printk(KERN_INFO "msp34xx: init: chip=%s",c->name);
if (msp->nicam)
printk(", has NICAM support");
printk("\n");
@@ -1194,11 +1255,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
msp->notify = NULL;
wake_up_interruptible(&msp->wq);
-#ifdef REGISTER_MIXER
- if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0)
- printk(KERN_ERR "msp3400c: cannot allocate mixer device\n");
-#endif
-
/* update our own array */
for (i = 0; i < MSP3400_MAX; i++) {
if (NULL == msps[i]) {
@@ -1218,11 +1274,6 @@ static int msp_detach(struct i2c_client *client)
struct msp3400c *msp = (struct msp3400c*)client->data;
int i;
-#ifdef REGISTER_MIXER
- if (msp->mixer_num >= 0)
- unregister_sound_mixer(msp->mixer_num);
-#endif
-
/* shutdown control thread */
del_timer(&msp->wake_stereo);
if (msp->thread)
@@ -1260,29 +1311,47 @@ static int msp_probe(struct i2c_adapter *adap)
static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
{
struct msp3400c *msp = (struct msp3400c*)client->data;
+ __u16 *sarg = arg;
#if 0
int *iarg = (int*)arg;
- __u16 *sarg = arg;
#endif
switch (cmd) {
+ case AUDC_SET_INPUT:
+#if 1
+ /* hauppauge 44xxx scart switching */
+ switch (*sarg) {
+ case AUDIO_RADIO:
+ msp3400c_set_scart(client,SCART_IN2,0);
+ break;
+ case AUDIO_EXTERN:
+ msp3400c_set_scart(client,SCART_IN1,0);
+ break;
+ default:
+ if (*sarg & AUDIO_MUTE)
+ msp3400c_set_scart(client,SCART_MUTE,0);
+ break;
+ }
+#endif
+ break;
+
case AUDC_SET_RADIO:
msp->norm = VIDEO_MODE_RADIO;
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
+ dprintk("msp34xx: switching to radio mode\n");
if (msp->simple) {
- msp3400c_reset(client);
- msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic */
- msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio */
- msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */
- msp3400c_setbass(client, msp->bass);
- msp3400c_settreble(client, msp->treble);
- msp3400c_setvolume(client, msp->left, msp->right);
+ /* the thread will do for us */
+ msp3400c_setvolume(client,msp->muted,0,0);
+ if (msp->active)
+ msp->restart = 1;
+ wake_up_interruptible(&msp->wq);
} else {
+ /* set msp3400 to FM radio mode */
msp3400c_setmode(client,MSP_MODE_FM_RADIO);
msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
- msp3400c_setvolume(client,msp->left, msp->right);
+ msp3400c_setvolume(client,msp->muted,msp->left,msp->right);
}
break;
@@ -1295,7 +1364,10 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
va->flags |= VIDEO_AUDIO_VOLUME |
VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
+ VIDEO_AUDIO_TREBLE |
+ VIDEO_AUDIO_MUTABLE;
+ if (msp->muted)
+ va->flags |= VIDEO_AUDIO_MUTE;
va->volume=MAX(msp->left,msp->right);
va->balance=(32768*MIN(msp->left,msp->right))/
(va->volume ? va->volume : 1);
@@ -1304,21 +1376,24 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
va->bass = msp->bass;
va->treble = msp->treble;
- autodetect_stereo(client);
- va->mode = msp->stereo;
+ if (msp->norm != VIDEO_MODE_RADIO) {
+ autodetect_stereo(client);
+ va->mode = msp->stereo;
+ }
break;
}
case VIDIOCSAUDIO:
{
struct video_audio *va = arg;
+ msp->muted = (va->flags & VIDEO_AUDIO_MUTE);
msp->left = (MIN(65536 - va->balance,32768) *
va->volume) / 32768;
msp->right = (MIN(va->balance,32768) *
va->volume) / 32768;
msp->bass = va->bass;
msp->treble = va->treble;
- msp3400c_setvolume(client,msp->left, msp->right);
+ msp3400c_setvolume(client,msp->muted,msp->left,msp->right);
msp3400c_setbass(client,msp->bass);
msp3400c_settreble(client,msp->treble);
@@ -1334,13 +1409,14 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
{
struct video_channel *vc = arg;
+ dprintk("msp34xx: switching to TV mode\n");
msp->norm = vc->norm;
break;
}
case VIDIOCSFREQ:
{
/* new channel -- kick audio carrier scan */
- msp3400c_setvolume(client,0,0);
+ msp3400c_setvolume(client,msp->muted,0,0);
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
if (msp->active)
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 94707619d..7fcfcc945 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -2035,31 +2035,17 @@ static int planb_mmap(struct video_device *dev, const char *adr, unsigned long s
return 0;
}
-/* This gets called upon device registration */
-/* we could do some init here */
-static int planb_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static struct video_device planb_template=
{
- PLANB_DEVICE_NAME,
- VID_TYPE_OVERLAY,
- VID_HARDWARE_PLANB,
- planb_open,
- planb_close,
- planb_read,
- planb_write,
-#if LINUX_VERSION_CODE >= 0x020100
- NULL, /* poll */
-#endif
- planb_ioctl,
- planb_mmap, /* mmap? */
- planb_init_done,
- NULL, /* pointer to private data */
- 0,
- 0
+ name: PLANB_DEVICE_NAME,
+ type: VID_TYPE_OVERLAY,
+ hardware: VID_HARDWARE_PLANB,
+ open: planb_open,
+ close: planb_close,
+ read: planb_read,
+ write: planb_write,
+ ioctl: planb_ioctl,
+ mmap: planb_mmap, /* mmap? */
};
static int init_planb(struct planb *pb)
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 1e50880a0..77893ad78 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -681,11 +681,6 @@ static void pms_close(struct video_device *dev)
MOD_DEC_USE_COUNT;
}
-static int pms_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static long pms_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
@@ -907,20 +902,14 @@ static long pms_read(struct video_device *v, char *buf, unsigned long count, in
struct video_device pms_template=
{
- "Mediavision PMS",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_PMS,
- pms_open,
- pms_close,
- pms_read,
- pms_write,
- NULL, /* FIXME - we can use POLL on this board with the irq */
- pms_ioctl,
- NULL,
- pms_init_done,
- NULL,
- 0,
- 0
+ name: "Mediavision PMS",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_PMS,
+ open: pms_open,
+ close: pms_close,
+ read: pms_read,
+ write: pms_write,
+ ioctl: pms_ioctl,
};
struct pms_device pms_device;
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 1213e2ee5..85d18315e 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -669,15 +669,12 @@ module_exit(cleanup_saa_5249);
static struct video_device saa_template =
{
- IF_NAME,
- VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */
- VID_HARDWARE_SAA5249,
- saa5249_open,
- saa5249_release,
- NULL, /* read */
- saa5249_write,
- NULL, /* poll */
- saa5249_ioctl,
- /* the rest are null */
+ name: IF_NAME,
+ type: VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */
+ hardware: VID_HARDWARE_SAA5249,
+ open: saa5249_open,
+ close: saa5249_release,
+ write: saa5249_write,
+ ioctl: saa5249_ioctl,
};
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 03ca27a25..37e671b81 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1827,11 +1827,6 @@ static int saa_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
}
-static int saa_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static int saa_mmap(struct video_device *dev, const char *adr,
unsigned long size)
{
@@ -1993,20 +1988,15 @@ static void saa_close(struct video_device *dev)
/* template for video_device-structure */
static struct video_device saa_template =
{
- "SAA7146A",
- VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
- VID_HARDWARE_SAA7146,
- saa_open,
- saa_close,
- saa_read,
- saa_write,
- NULL, /* poll */
- saa_ioctl,
- saa_mmap,
- saa_init_done,
- NULL,
- 0,
- 0
+ name: "SAA7146A",
+ type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
+ hardware: VID_HARDWARE_SAA7146,
+ open: saa_open,
+ close: saa_close,
+ read: saa_read,
+ write: saa_write,
+ ioctl: saa_ioctl,
+ mmap: saa_mmap,
};
static int configure_saa7146(struct pci_dev *dev, int num)
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 6b8c9063f..889856738 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -25,10 +25,6 @@
* Added I2C_DRIVERID_TDA7432
* added loudness insmod control
* Revision: 0.1 - initial version
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tda7432_attach
*/
#include <linux/module.h>
@@ -45,12 +41,7 @@
#include "bttv.h"
#include "audiochip.h"
-
-/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
-#ifndef I2C_DRIVERID_TDA7432
- #define I2C_DRIVERID_TDA7432 27
-#endif
-
+#include "id.h"
MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
@@ -87,6 +78,7 @@ struct tda7432 {
int tone;
int lf, lr, rf, rr;
int loud;
+ struct i2c_client c;
};
static struct i2c_driver driver;
@@ -316,19 +308,18 @@ static int tda7432_attach(struct i2c_adapter *adap, int addr,
struct tda7432 *t;
struct i2c_client *client;
d2printk("tda7432: In tda7432_attach\n");
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
+
+ t = kmalloc(sizeof *t,GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ memset(t,0,sizeof *t);
+
+ client = &t->c;
memcpy(client,&client_template,sizeof(struct i2c_client));
client->adapter = adap;
client->addr = addr;
+ client->data = t;
- client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
- if (!t) {
- kfree(client);
- return -ENOMEM;
- }
- memset(t,0,sizeof *t);
do_tda7432_init(client);
MOD_INC_USE_COUNT;
strcpy(client->name,"TDA7432");
@@ -353,7 +344,6 @@ static int tda7432_detach(struct i2c_client *client)
i2c_detach_client(client);
kfree(t);
- kfree(client);
MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/media/video/tda8425.c b/drivers/media/video/tda8425.c
deleted file mode 100644
index 54f1935b6..000000000
--- a/drivers/media/video/tda8425.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * for the TDA8425 chip (I don't know which cards have this)
- * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT
- * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a
- * device acknowledging that address)
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * All of this should work, though it would be nice to eventually support
- * balance (different left,right values). Also, the chip seems (?) to have
- * two stereo inputs, so if someone has this card, could they tell me if the
- * second one can be used for anything (i.e., does it have an external input
- * that you can't hear even if you set input to composite?)
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tda8425_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
- I2C_TDA8425 >> 1,
- I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
- normal_i2c, normal_i2c_range,
- probe, probe_range,
- ignore, ignore_range,
- force
-};
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-#define dprintk if (debug) printk
-
-
-struct tda8425 {
- int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
- int stereo;
- __u16 left,right;
- __u16 bass,treble;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-
-#define TDA8425_VL 0x00 /* volume left */
-#define TDA8425_VR 0x01 /* volume right */
-#define TDA8425_BA 0x02 /* bass */
-#define TDA8425_TR 0x03 /* treble */
-#define TDA8425_S1 0x08 /* switch functions */
- /* values for those registers: */
-#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */
-#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */
-
-
-/* ******************************** *
- * functions for talking to TDA8425 *
- * ******************************** */
-
-static int tda8425_write(struct i2c_client *client, int addr, int val)
-{
- unsigned char buffer[2];
-
- buffer[0] = addr;
- buffer[1] = val;
- if (2 != i2c_master_send(client,buffer,2)) {
- printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n",
- addr, val);
- return -1;
- }
- return 0;
-}
-
-static void tda8425_set(struct i2c_client *client)
-{
- struct tda8425 *tda = client->data;
-
- /* mode is ignored today */
- dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12);
- tda8425_write(client, TDA8425_VL, tda->left>>10 |0xC0);
- tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0);
- tda8425_write(client, TDA8425_BA, tda->bass>>12 |0xF0);
- tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0);
-}
-
-static void do_tda8425_init(struct i2c_client *client)
-{
- struct tda8425 *tda = client->data;
-
- tda->left=tda->right =61440; /* 0dB */
- tda->bass=tda->treble=24576; /* 0dB */
- tda->mode=AUDIO_OFF;
- tda->stereo=1;
- /* left=right=0x27<<10, bass=treble=0x07<<12 */
- tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */
- tda8425_set(client);
-}
-
-static void tda8425_audio(struct i2c_client *client, int mode)
-{
- struct tda8425 *tda = client->data;
-
- /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
- dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode);
- tda->mode=mode;
- tda8425_write(client, TDA8425_S1,
- (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON);
- /* this is the function we'll need to change if it turns out the
- * input-selecting capabilities should be used. */
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda8425_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-{
- struct tda8425 *tda;
- struct i2c_client *client;
-
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
-
- client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL);
- if (!tda) {
- kfree(client);
- return -ENOMEM;
- }
- memset(tda,0,sizeof *tda);
- do_tda8425_init(client);
- MOD_INC_USE_COUNT;
- strcpy(client->name,"TDA8425");
- printk(KERN_INFO "tda8425: init\n");
-
- i2c_attach_client(client);
- return 0;
-}
-
-static int tda8425_probe(struct i2c_adapter *adap)
-{
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
- return i2c_probe(adap, &addr_data, tda8425_attach);
- return 0;
-}
-
-
-static int tda8425_detach(struct i2c_client *client)
-{
- struct tda8425 *tda = client->data;
-
- do_tda8425_init(client);
- i2c_detach_client(client);
-
- kfree(tda);
- kfree(client);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int tda8425_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct tda8425 *tda = client->data;
- __u16 *sarg = arg;
-
- switch (cmd) {
- case AUDC_SET_RADIO:
- tda8425_audio(client,AUDIO_RADIO);
- break;
- case AUDC_SET_INPUT:
- tda8425_audio(client,*sarg);
- break;
-
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- va->flags |= VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
- va->volume=MAX(tda->left,tda->right);
- va->balance=(32768*MIN(tda->left,tda->right))/
- (va->volume ? va->volume : 1);
- va->balance=(tda->left<tda->right)?
- (65535-va->balance) : va->balance;
- va->bass = tda->bass;
- va->treble = tda->treble;
- break;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio *va = arg;
-
- tda->left = (MIN(65536 - va->balance,32768) *
- va->volume) / 32768;
- tda->right = (MIN(va->balance,32768) *
- va->volume) / 32768;
- tda->bass = va->bass;
- tda->treble = va->treble;
- tda8425_set(client);
- break;
- }
-
-#if 0
- /* --- old, obsolete interface --- */
- case AUDC_GET_VOLUME_LEFT:
- *sarg = tda->left;
- break;
- case AUDC_GET_VOLUME_RIGHT:
- *sarg = tda->right;
- break;
- case AUDC_SET_VOLUME_LEFT:
- tda->left = *sarg;
- tda8425_set(client);
- break;
- case AUDC_SET_VOLUME_RIGHT:
- tda->right = *sarg;
- tda8425_set(client);
- break;
-
- case AUDC_GET_BASS:
- *sarg = tda->bass;
- break;
- case AUDC_SET_BASS:
- tda->bass = *sarg;
- tda8425_set(client);
- break;
-
- case AUDC_GET_TREBLE:
- *sarg = tda->treble;
- break;
- case AUDC_SET_TREBLE:
- tda->treble = *sarg;
- tda8425_set(client);
- break;
-
- case AUDC_GET_STEREO:
- *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO;
- break;
- case AUDC_SET_STEREO:
- tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1;
- /* TODO: make this write to the TDA9850? */
- break;
-
-/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to
- case AUDC_NEWCHANNEL: it and it would require preserving state
- case AUDC_GET_DC: huh?? (not used by bttv.c)
-*/
-#endif
- default:
- /* nothing */
- }
- return 0;
-}
-
-
-static struct i2c_driver driver = {
- "i2c tda8424 driver",
- I2C_DRIVERID_TDA8425,
- I2C_DF_NOTIFY,
- tda8425_probe,
- tda8425_detach,
- tda8425_command,
-};
-
-static struct i2c_client client_template =
-{
- "(unset)", /* name */
- -1,
- 0,
- 0,
- NULL,
- &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tda8425_init(void)
-#endif
-{
- i2c_add_driver(&driver);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tda985x.c b/drivers/media/video/tda985x.c
deleted file mode 100644
index 2bf161827..000000000
--- a/drivers/media/video/tda985x.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * For the TDA9850 and TDA9855 chips
- * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used
- * on STB cards. Other cards probably use these chips as well.)
- * This driver will not complain if used with any
- * other i2c device with the same address.
- *
- * Copyright (c) 1999 Gerd Knorr
- * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com)
- * This code is placed under the terms of the GNU General Public License
- * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * Which was based on tda8425.c by Greg Alexander (c) 1998
- *
- * Contributors:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * OPTIONS:
- * debug - set to 1 if you'd like to see debug messages
- * - set to 2 if you'd like to be flooded with debug messages
- * chip - set to 9850 or 9855 to select your chip (default 9855)
- *
- * TODO:
- * Fix channel change bug - sound goes out when changeing channels, mute
- * and unmote to fix. - Is this still here?
- * Fine tune sound
- * Get rest of capabilities into video_audio struct...
- *
- * Revision 0.6 - resource allocation fixes in tda985x_attach (08/14/2000)
- * Revision 0.5 - cleaned up debugging messages, added debug level=2
- * Revision: 0.4 - check for correct chip= insmod value
- * also cleaned up comments a bit
- * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command
- * Revision: 0.2 - added insmod option chip=
- * Revision: 0.1 - original version
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-MODULE_PARM(debug,"i");
-MODULE_PARM(chip,"i");
-MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855");
-
-static int debug = 0; /* insmod parameter */
-static int chip = 9855; /* insmod parameter */
-
-/* Addresses to scan */
-#define I2C_TDA985x_L 0xb4
-#define I2C_TDA985x_H 0xb6
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {
- I2C_TDA985x_L >> 1,
- I2C_TDA985x_H >> 1,
- I2C_CLIENT_END
-};
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
- normal_i2c, normal_i2c_range,
- probe, probe_range,
- ignore, ignore_range,
- force
-};
-
-/* This is a superset of the TDA9850 and TDA9855 members */
-
-struct tda985x {
- int addr;
- int rvol, lvol;
- int bass, treble, sub;
- int c4, c5, c6, c7;
- int a1, a2, a3;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define dprintk if (debug) printk
-#define d2printk if (debug == 2) printk
-
-/* The TDA9850 and TDA9855 are both made by Philips Semiconductor
- * http://www.semiconductors.philips.com
- * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder
- * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor
- *
- * The TDA9850 has more or less a subset of the functions that the TDA9855
- * has. As a result, we can re-use many of these defines. Anything with
- * TDA9855 is specific to that chip, anything with TDA9850 is specific
- * to that chip, and anything with TDA985x is valid for either.
- *
- * To complicate things further, the TDA9850 uses labels C1 through C4
- * for subaddresses 0x04 through 0x07, while the TDA9855 uses
- * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing.
- * To help keep things straight, I have renamed the various C[1,4] labels
- * to C[4,7] so that the numerical label matches the hex value of the
- * subaddress for both chips. At least the A[1,3] labels line up. :)
- */
-
- /* subaddresses for TDA9855 */
-#define TDA9855_VR 0x00 /* Volume, right */
-#define TDA9855_VL 0x01 /* Volume, left */
-#define TDA9855_BA 0x02 /* Bass */
-#define TDA9855_TR 0x03 /* Treble */
-#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */
-
- /* subaddresses for TDA9850 */
-#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */
-
- /* subaddesses for both chips */
-#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
-#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
-#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
-#define TDA985x_A1 0x08 /* Alignment 1 for both chips */
-#define TDA985x_A2 0x09 /* Alignment 2 for both chips */
-#define TDA985x_A3 0x0a /* Alignment 3 for both chips */
-
- /* Masks for bits in TDA9855 subaddresses */
-/* 0x00 - VR in TDA9855 */
-/* 0x01 - VL in TDA9855 */
-/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
- * in 1dB steps - mute is 0x27 */
-
-
-/* 0x02 - BA in TDA9855 */
-/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
- * in .5dB steps - 0 is 0x0E */
-
-
-/* 0x03 - TR in TDA9855 */
-/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
- * in 3dB steps - 0 is 0x7 */
-
- /* Masks for bits in both chips' subaddresses */
-/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
-/* Unique to TDA9855: */
-/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
- * in 3dB steps - mute is 0x0 */
-
-/* Unique to TDA9850: */
-/* lower 4 bits control stereo noise threshold, over which stereo turns off
- * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
-
-
-/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
-/* Unique to TDA9855: */
-#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */
-#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */
-#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */
-#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
- /* Bits 0 to 3 select various combinations
- * of line in and line out, only the
- * interesting ones are defined */
-#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */
-#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */
-
-/* Unique to TDA9850: */
-/* lower 4 bits contol SAP noise threshold, over which SAP turns off
- * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
-
-
-/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
-/* Common to TDA9855 and TDA9850: */
-#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */
-#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
-#define TDA985x_MONO 0 /* Forces Mono output */
-#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
-
-/* Unique to TDA9855: */
-#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */
-#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/
-#define TDA9855_LINEAR 0 /* Linear Stereo */
-#define TDA9855_PSEUDO 1 /* Pseudo Stereo */
-#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */
-#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */
-#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/
-
-
-/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
- * in .5dB steps - 0dB is 0x7 */
-
-
-/* 0x08, 0x09 - A1 and A2 (read/write) */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 5 bites are wideband and spectral expander alignment
- * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
-#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */
-#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */
-#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
-
-
-/* 0x0a - A3 */
-/* Common to both TDA9855 and TDA9850: */
-/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
- * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
-#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */
-
-/* Unique to TDA9855: */
-/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2),
- * 1200ohm (0x1), 2100ohm (0x3) */
-
-
-/* Begin code */
-
-static int tda985x_write(struct i2c_client *client, int subaddr, int val)
-{
- unsigned char buffer[2];
- d2printk("tda985x: In tda985x_write\n");
- dprintk("tda985x: Writing %d 0x%x\n", subaddr, val);
- buffer[0] = subaddr;
- buffer[1] = val;
- if (2 != i2c_master_send(client,buffer,2)) {
- printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n",
- subaddr, val);
- return -1;
- }
- return 0;
-}
-
-static int tda985x_read(struct i2c_client *client)
-{
- unsigned char buffer;
- d2printk("tda985x: In tda985x_read\n");
- if (1 != i2c_master_recv(client,&buffer,1)) {
- printk(KERN_WARNING "tda985x: I/O error, trying (read)\n");
- return -1;
- }
- dprintk("tda985x: Read 0x%02x\n", buffer);
- return buffer;
-}
-
-static int tda985x_set(struct i2c_client *client)
-{
- struct tda985x *t = client->data;
- unsigned char buf[16];
- d2printk("tda985x: In tda985x_set\n");
-
- if (chip == 9855)
- {
- dprintk(KERN_INFO
- "tda985x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
- t->rvol,t->lvol,t->bass,t->treble,t->sub,
- t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
- buf[0] = TDA9855_VR;
- buf[1] = t->rvol;
- buf[2] = t->lvol;
- buf[3] = t->bass;
- buf[4] = t->treble;
- buf[5] = t->sub;
- buf[6] = t->c5;
- buf[7] = t->c6;
- buf[8] = t->c7;
- buf[9] = t->a1;
- buf[10] = t->a2;
- buf[11] = t->a3;
- if (12 != i2c_master_send(client,buf,12)) {
- printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
- return -1;
- }
- }
-
- else if (chip == 9850)
- {
- dprintk(KERN_INFO
- "tda986x: tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
- t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3);
- buf[0] = TDA9850_C4;
- buf[1] = t->c4;
- buf[2] = t->c5;
- buf[3] = t->c6;
- buf[4] = t->c7;
- buf[5] = t->a1;
- buf[6] = t->a2;
- buf[7] = t->a3;
- if (8 != i2c_master_send(client,buf,8)) {
- printk(KERN_WARNING "tda985x: I/O error, trying tda985x_set\n");
- return -1;
- }
- }
-
- return 0;
-}
-
-static void do_tda985x_init(struct i2c_client *client)
-{
- struct tda985x *t = client->data;
- d2printk("tda985x: In tda985x_init\n");
-
- if (chip == 9855)
- {
- printk("tda985x: Using tda9855 options\n");
- t->rvol = 0x6f; /* 0dB */
- t->lvol = 0x6f; /* 0dB */
- t->bass = 0x0e; /* 0dB */
- t->treble = (0x07 << 1); /* 0dB */
- t->sub = 0x8 << 2; /* 0dB */
- t->c5 = TDA9855_MUTE | TDA9855_AVL |
- TDA9855_LOUD | TDA9855_INT;
- /* Set Mute, AVL, Loudness off, Internal sound */
- t->c6 = TDA985x_STEREO | TDA9855_LINEAR |
- TDA9855_TZCM | TDA9855_VZCM;
- /* Stereo linear mode, also wait til zero crossings */
- t->c7 = 0x07; /* 0dB input gain */
- }
-
- else if (chip == 9850)
- {
- printk("tda985x: Using tda9850 options\n");
- t->c4 = 0x08; /* Set stereo noise thresh to nominal */
- t->c5 = 0x08; /* Set SAP noise threshold to nominal */
- t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */
- t->c7 = 0x07; /* 0dB input gain */
- }
-
- /* The following is valid for both chip types */
- t->a1 = 0x10; /* Select nominal wideband expander */
- t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */
- t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */
-
- tda985x_set(client);
-}
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda985x_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-{
- struct tda985x *t;
- struct i2c_client *client;
- d2printk("tda985x: In tda985x_attach\n");
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
-
- client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
- if (!t) {
- kfree(client);
- return -ENOMEM;
- }
- memset(t,0,sizeof *t);
- do_tda985x_init(client);
- MOD_INC_USE_COUNT;
- strcpy(client->name,"TDA985x");
- printk(KERN_INFO "tda985x: init\n");
-
- i2c_attach_client(client);
- return 0;
-}
-
-static int tda985x_probe(struct i2c_adapter *adap)
-{
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
- return i2c_probe(adap, &addr_data, tda985x_attach);
- return 0;
-}
-
-static int tda985x_detach(struct i2c_client *client)
-{
- struct tda985x *t = client->data;
-
- do_tda985x_init(client);
- i2c_detach_client(client);
-
- kfree(t);
- kfree(client);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int tda985x_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct tda985x *t = client->data;
- d2printk("tda985x: In tda985x_command\n");
-#if 0
- __u16 *sarg = arg;
-#endif
-
- switch (cmd) {
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
- dprintk("tda985x: VIDIOCGAUDIO\n");
- if (chip == 9855)
- {
- int left,right;
-
- va->flags |= VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
-
- /* min is 0x27 max is 0x7f, vstep is 2e8 */
- left = (t->lvol-0x27)*0x2e8;
- right = (t->rvol-0x27)*0x2e8;
- va->volume=MAX(left,right);
- va->balance=(32768*MIN(left,right))/
- (va->volume ? va->volume : 1);
- va->balance=(left<right)?
- (65535-va->balance) : va->balance;
- va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */
- va->treble = ((t->treble>>1)-0x3)*0x1c71;
- }
-
- /* Valid for both chips: */
- {
- va->mode = ((TDA985x_STP | TDA985x_SAPP) &
- tda985x_read(client)) >> 4;
- /* Add mono mode regardless of SAP and stereo */
- /* Allows forced mono */
- va->mode |= VIDEO_SOUND_MONO;
- }
-
- break; /* VIDIOCGAUDIO case */
- }
-
- case VIDIOCSAUDIO:
- {
- struct video_audio *va = arg;
- dprintk("tda985x: VIDEOCSAUDIO\n");
- if (chip == 9855)
- {
- int left,right;
-
- left = (MIN(65536 - va->balance,32768) *
- va->volume) / 32768;
- right = (MIN(va->balance,32768) *
- va->volume) / 32768;
- t->lvol = left/0x2e8+0x27;
- t->rvol = right/0x2e8+0x27;
- t->bass = va->bass/0xccc+0x6;
- t->treble = (va->treble/0x1c71+0x3)<<1;
- tda985x_write(client,TDA9855_VL,t->lvol);
- tda985x_write(client,TDA9855_VR,t->rvol);
- tda985x_write(client,TDA9855_BA, t->bass);
- tda985x_write(client,TDA9855_TR,t->treble);
- }
-
- /* The following is valid for both chips */
-
- switch (va->mode) {
- case VIDEO_SOUND_MONO:
- dprintk("tda985x: VIDEO_SOUND_MONO\n");
- t->c6= TDA985x_MONO | (t->c6 & 0x3f);
- tda985x_write(client,TDA985x_C6,t->c6);
- break;
- case VIDEO_SOUND_STEREO:
- dprintk("tda985x: VIDEO_SOUND_STEREO\n");
- t->c6= TDA985x_STEREO | (t->c6 & 0x3f);
- tda985x_write(client,TDA985x_C6,t->c6);
- break;
- case VIDEO_SOUND_LANG1:
- dprintk("tda985x: VIDEO_SOUND_LANG1\n");
- t->c6= TDA985x_SAP | (t->c6 & 0x3f);
- tda985x_write(client,TDA985x_C6,t->c6);
- break;
- } /* End of (va->mode) switch */
-
- break;
-
- } /* end of VIDEOCSAUDIO case */
-
- default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
-
- /* nothing */
- d2printk("tda985x: Default\n");
-
- } /* end of (cmd) switch */
-
- return 0;
-}
-
-
-static struct i2c_driver driver = {
- "i2c tda985x driver",
- I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */
- I2C_DF_NOTIFY,
- tda985x_probe,
- tda985x_detach,
- tda985x_command,
-};
-
-static struct i2c_client client_template =
-{
- "(unset)", /* name */
- -1,
- 0,
- 0,
- NULL,
- &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tda985x_init(void)
-#endif
-{
- if ( (chip != 9850) && (chip != 9855) )
- {
- printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n");
- return -EINVAL;
- }
- i2c_add_driver(&driver);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 7bfc319a6..0cead825f 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -11,13 +11,9 @@
* Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
* Which was based on tda8425.c by Greg Alexander (c) 1998
*
- * Contributors:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.2)
- *
* OPTIONS:
* debug - set to 1 if you'd like to see debug messages
*
- * Revision 0.2 - resource allocation fixes in tda9875_attach (08/14/2000)
* Revision: 0.1 - original version
*/
@@ -35,12 +31,7 @@
#include "bttv.h"
#include "audiochip.h"
-
-/* This driver ID is brand new, so define it if it's not in i2c-id.h yet */
-#ifndef I2C_DRIVERID_TDA9875
- #define I2C_DRIVERID_TDA9875 28
-#endif
-
+#include "id.h"
MODULE_PARM(debug,"i");
@@ -68,6 +59,7 @@ struct tda9875 {
int mode;
int rvol, lvol;
int bass, treble;
+ struct i2c_client c;
};
@@ -228,19 +220,18 @@ static int tda9875_attach(struct i2c_adapter *adap, int addr,
struct tda9875 *t;
struct i2c_client *client;
dprintk("In tda9875_attach\n");
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
+
+ t = kmalloc(sizeof *t,GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+ memset(t,0,sizeof *t);
+
+ client = &t->c;
memcpy(client,&client_template,sizeof(struct i2c_client));
client->adapter = adap;
client->addr = addr;
+ client->data = t;
- client->data = t = kmalloc(sizeof *t,GFP_KERNEL);
- if (!t) {
- kfree(client);
- return -ENOMEM;
- }
- memset(t,0,sizeof *t);
do_tda9875_init(client);
MOD_INC_USE_COUNT;
strcpy(client->name,"TDA9875");
@@ -265,7 +256,6 @@ static int tda9875_detach(struct i2c_client *client)
i2c_detach_client(client);
kfree(t);
- kfree(client);
MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/media/video/tea6300.c b/drivers/media/video/tea6300.c
deleted file mode 100644
index 9dc13e610..000000000
--- a/drivers/media/video/tea6300.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best
- * of my knowledge)
- * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG
- * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to
- * make sure that there is a device acknowledging that address). This
- * is a potential problem because the MSP3400 is very popular and does
- * use this address! You have been warned!
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * All of this should work, though it would be nice to eventually support
- * balance (different left,right values) and, if someone ever finds a card
- * with the support (or if you're careful with a soldering iron), fade
- * (front/back).
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tea6300_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-
-/* Addresses to scan */
-#define I2C_TEA6300 0x80
-static unsigned short normal_i2c[] = {
- I2C_TEA6300 >> 1,
- I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
- normal_i2c, normal_i2c_range,
- probe, probe_range,
- ignore, ignore_range,
- force
-};
-
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-
-#define dprintk if (debug) printk
-
-
-struct tea6300 {
- int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
- int stereo;
- __u16 left,right;
- __u16 bass,treble;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define TEA6300_VL 0x00 /* volume left */
-#define TEA6300_VR 0x01 /* volume right */
-#define TEA6300_BA 0x02 /* bass */
-#define TEA6300_TR 0x03 /* treble */
-#define TEA6300_FA 0x04 /* fader control */
-#define TEA6300_S 0x05 /* switch register */
- /* values for those registers: */
-#define TEA6300_S_SA 0x01 /* stereo A input */
-#define TEA6300_S_SB 0x02 /* stereo B */
-#define TEA6300_S_SC 0x04 /* stereo C */
-#define TEA6300_S_GMU 0x80 /* general mute */
-
-
-/* ******************************** *
- * functions for talking to TEA6300 *
- * ******************************** */
-
-static int tea6300_write(struct i2c_client *client, int addr, int val)
-{
- unsigned char buffer[2];
-
- buffer[0] = addr;
- buffer[1] = val;
- if (2 != i2c_master_send(client,buffer,2)) {
- printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n",
- addr, val);
- return -1;
- }
- return 0;
-}
-
-static void tea6300_set(struct i2c_client *client)
-{
- struct tea6300 *tea = client->data;
-
- /* mode is ignored today */
- dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12);
- tea6300_write(client, TEA6300_VL, tea->left>>10 );
- tea6300_write(client, TEA6300_VR, tea->right>>10 );
- tea6300_write(client, TEA6300_BA, tea->bass>>12 );
- tea6300_write(client, TEA6300_TR, tea->treble>>12);
-}
-
-static void do_tea6300_init(struct i2c_client *client)
-{
- struct tea6300 *tea = client->data;
-
- tea->left=tea->right =49152; /* -10dB (loud enough, but not beyond
- normal line levels - so as to avoid
- clipping */
- tea->bass=tea->treble=28672; /* 0dB */
- tea->mode=AUDIO_OFF;
- tea->stereo=1;
- /* left=right=0x27<<10, bass=treble=0x07<<12 */
- tea6300_write(client, TEA6300_FA, 0x3f ); /* fader off */
- tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */
- tea6300_set(client);
-}
-
-static void tea6300_audio(struct i2c_client *client, int mode)
-{
- struct tea6300 *tea = client->data;
-
- /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
- dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode);
- tea->mode=mode;
- if (mode==AUDIO_OFF) { /* just mute it */
- tea6300_write(client, TEA6300_S, TEA6300_S_GMU);
- return;
- }
- switch(mode) {
- case AUDIO_TUNER:
- tea6300_write(client, TEA6300_S, TEA6300_S_SA);
- break;
- case AUDIO_RADIO:
- tea6300_write(client, TEA6300_S, TEA6300_S_SB);
- break;
- case AUDIO_EXTERN:
- tea6300_write(client, TEA6300_S, TEA6300_S_SC);
- break;
- }
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tea6300_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-{
- struct tea6300 *tea;
- struct i2c_client *client;
-
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
-
- client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL);
- if (!tea) {
- kfree(client);
- return -ENOMEM;
- }
- memset(tea,0,sizeof *tea);
- do_tea6300_init(client);
-
- MOD_INC_USE_COUNT;
- strcpy(client->name,"TEA6300T");
- printk(KERN_INFO "tea6300: initialized\n");
-
- i2c_attach_client(client);
- return 0;
-}
-
-static int tea6300_probe(struct i2c_adapter *adap)
-{
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
- return i2c_probe(adap, &addr_data, tea6300_attach);
- return 0;
-}
-
-static int tea6300_detach(struct i2c_client *client)
-{
- struct tea6300 *tea = client->data;
-
- do_tea6300_init(client);
- i2c_detach_client(client);
-
- kfree(tea);
- kfree(client);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int
-tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct tea6300 *tea = client->data;
- __u16 *sarg = arg;
-
- switch (cmd) {
- case AUDC_SET_RADIO:
- tea6300_audio(client,AUDIO_RADIO);
- break;
- case AUDC_SET_INPUT:
- tea6300_audio(client,*sarg);
- break;
-
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- va->flags |= VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
- va->volume=MAX(tea->left,tea->right);
- va->balance=(32768*MIN(tea->left,tea->right))/
- (va->volume ? va->volume : 1);
- va->balance=(tea->left<tea->right)?
- (65535-va->balance) : va->balance;
- va->bass = tea->bass;
- va->treble = tea->treble;
- break;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio *va = arg;
-
- tea->left = (MIN(65536 - va->balance,32768) *
- va->volume) / 32768;
- tea->right = (MIN(va->balance,32768) *
- va->volume) / 32768;
- tea->bass = va->bass;
- tea->treble = va->treble;
- tea6300_set(client);
- break;
- }
-#if 0
- /* --- old, obsolete interface --- */
- case AUDC_GET_VOLUME_LEFT:
- *sarg = tea->left;
- break;
- case AUDC_GET_VOLUME_RIGHT:
- *sarg = tea->right;
- break;
- case AUDC_SET_VOLUME_LEFT:
- tea->left = *sarg;
- tea6300_set(client);
- break;
- case AUDC_SET_VOLUME_RIGHT:
- tea->right = *sarg;
- tea6300_set(client);
- break;
-
- case AUDC_GET_BASS:
- *sarg = tea->bass;
- break;
- case AUDC_SET_BASS:
- tea->bass = *sarg;
- tea6300_set(client);
- break;
-
- case AUDC_GET_TREBLE:
- *sarg = tea->treble;
- break;
- case AUDC_SET_TREBLE:
- tea->treble = *sarg;
- tea6300_set(client);
- break;
-
- case AUDC_GET_STEREO:
- *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO;
- break;
- case AUDC_SET_STEREO:
- tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1;
- /* TODO: make this write to the TDA9850? */
- break;
-
-/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to
- case AUDC_NEWCHANNEL: it and it would require preserving state
- case AUDC_GET_DC: huh?? (not used by bttv.c)
-*/
-#endif
- default:
- /* nothing */
- }
- return 0;
-}
-
-static struct i2c_driver driver = {
- "i2c tea6300 driver",
- I2C_DRIVERID_TEA6300,
- I2C_DF_NOTIFY,
- tea6300_probe,
- tea6300_detach,
- tea6300_command,
-};
-
-static struct i2c_client client_template =
-{
- "(unset)", /* name */
- -1,
- 0,
- 0,
- NULL,
- &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tea6300_init(void)
-#endif
-{
- i2c_add_driver(&driver);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
deleted file mode 100644
index 3a1d63517..000000000
--- a/drivers/media/video/tea6420.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * for the TEA6420 chip (only found on 3DFX (STB) TV/FM cards to the best
- * of my knowledge)
- * Copyright (C) 2000 Dave Stuart <justdave@ynn.com>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from tea6300 by . . .
- *
- * Copyright (c) 1998 Greg Alexander <galexand@acm.org>
- * This code is placed under the terms of the GNU General Public License
- * Code liberally copied from msp3400.c, which is by Gerd Knorr
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/14/2000
- * - resource allocation fixes in tea6300_attach
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/videodev.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include "bttv.h"
-#include "audiochip.h"
-
-
-/* Addresses to scan */
-#define I2C_TEA6420 0x98
-static unsigned short normal_i2c[] = {
- I2C_TEA6420 >> 1,
- I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
- normal_i2c, normal_i2c_range,
- probe, probe_range,
- ignore, ignore_range,
- force
-};
-
-
-MODULE_PARM(debug,"i");
-static int debug = 0; /* insmod parameter */
-
-#define dprintk if (debug) printk
-
-
-struct tea6420 {
- int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */
- int stereo;
-};
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-#define TEA6420_S_SA 0x00 /* stereo A input */
-#define TEA6420_S_SB 0x01 /* stereo B */
-#define TEA6420_S_SC 0x02 /* stereo C */
-#define TEA6420_S_SD 0x03 /* stereo D */
-#define TEA6420_S_SE 0x04 /* stereo E */
-#define TEA6420_S_GMU 0x05 /* general mute */
-
-
-/* ******************************** *
- * functions for talking to TEA6420 *
- * ******************************** */
-
-static int tea6420_write(struct i2c_client *client, int val)
-{
- unsigned char buffer[2];
- int result;
-
-/* buffer[0] = addr; */
- buffer[0] = val;
- result = i2c_master_send(client,buffer,1);
- if (1 != result) {
- printk(KERN_WARNING "tea6420: I/O error, trying (write
-0x%x) result = %d\n", val, result);
- return -1;
- }
- return 0;
-}
-
-
-static void do_tea6420_init(struct i2c_client *client)
-{
- struct tea6420 *tea = client->data;
-
- tea->mode=AUDIO_OFF;
- tea->stereo=1;
- tea6420_write(client, TEA6420_S_GMU); /* mute */
-}
-
-static void tea6420_audio(struct i2c_client *client, int mode)
-{
- struct tea6420 *tea = client->data;
-
- /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */
- dprintk(KERN_DEBUG "tea6420_audio:%d (T,R,E,I,O)\n",mode);
- tea->mode=mode;
- if (mode==AUDIO_OFF) { /* just mute it */
- tea6420_write(client, TEA6420_S_GMU);
- return;
- }
- switch(mode) {
- case AUDIO_TUNER:
- tea6420_write(client, TEA6420_S_SA);
- break;
- case AUDIO_RADIO:
- tea6420_write(client, TEA6420_S_SB);
- break;
- case AUDIO_EXTERN:
- tea6420_write(client, TEA6420_S_SC);
- break;
- }
-}
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tea6420_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
-{
- struct tea6420 *tea;
- struct i2c_client *client;
-
- client = kmalloc(sizeof *client,GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- memcpy(client,&client_template,sizeof(struct i2c_client));
- client->adapter = adap;
- client->addr = addr;
-
- client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL);
- if (!tea) {
- kfree(client);
- return -ENOMEM;
- }
- memset(tea,0,sizeof *tea);
- do_tea6420_init(client);
-
- MOD_INC_USE_COUNT;
- strcpy(client->name,"TEA6420");
- printk(KERN_INFO "tea6420: initialized\n");
-
- i2c_attach_client(client);
- return 0;
-}
-
-static int tea6420_probe(struct i2c_adapter *adap)
-{
- if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
- return i2c_probe(adap, &addr_data, tea6420_attach);
- return 0;
-}
-
-static int tea6420_detach(struct i2c_client *client)
-{
- struct tea6420 *tea = client->data;
-
- do_tea6420_init(client);
- i2c_detach_client(client);
-
- kfree(tea);
- kfree(client);
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int
-tea6420_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- __u16 *sarg = arg;
-
- switch (cmd) {
- case AUDC_SET_RADIO:
- tea6420_audio(client,AUDIO_RADIO);
- break;
- case AUDC_SET_INPUT:
- tea6420_audio(client,*sarg);
- break;
-
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- va->flags |= VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE;
-/* va->volume=MAX(tea->left,tea->right);
- va->balance=(32768*MIN(tea->left,tea->right))/
- (va->volume ? va->volume : 1);
- va->balance=(tea->left<tea->right)?
- (65535-va->balance) : va->balance;
- va->bass = tea->bass;
- va->treble = tea->treble;
-*/ break;
- }
- case VIDIOCSAUDIO:
- {
-
-/* tea->left = (MIN(65536 - va->balance,32768) *
- va->volume) / 32768;
- tea->right = (MIN(va->balance,32768) *
- va->volume) / 32768;
- tea->bass = va->bass;
- tea->treble = va->treble;
- tea6420_set(client);
-*/ break;
- }
-
-default:
- /* nothing */
- }
- return 0;
-}
-
-static struct i2c_driver driver = {
- "i2c tea6420 driver",
- I2C_DRIVERID_TEA6420,
- I2C_DF_NOTIFY,
- tea6420_probe,
- tea6420_detach,
- tea6420_command,
-};
-
-static struct i2c_client client_template =
-{
- "(unset)", /* name */
- -1,
- 0,
- 0,
- NULL,
- &driver
-};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int tea6420_init(void)
-#endif
-{
- i2c_add_driver(&driver);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- i2c_del_driver(&driver);
-}
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c
index dfbf0f6af..9316ef72f 100644
--- a/drivers/media/video/tuner.c
+++ b/drivers/media/video/tuner.c
@@ -113,6 +113,8 @@ static struct tunertype tuners[] = {
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},
+ { "Alps TSCH6",Alps,NTSC,
+ 16*137.25,16*385.25,0x14,0x12,0x11,0x8e,732},
};
#define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
@@ -132,6 +134,20 @@ static int tuner_getstatus(struct i2c_client *c)
#define TUNER_MODE 0x38
#define TUNER_AFC 0x07
+#define TUNER_STEREO 0x10 /* radio mode */
+#define TUNER_SIGNAL 0x07 /* radio mode */
+
+static int tuner_signal(struct i2c_client *c)
+{
+ return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+}
+
+static int tuner_stereo(struct i2c_client *c)
+{
+ return (tuner_getstatus (c) & TUNER_STEREO);
+}
+
+
static int tuner_islocked (struct i2c_client *c)
{
return (tuner_getstatus (c) & TUNER_FL);
@@ -229,7 +245,7 @@ static void set_radio_freq(struct i2c_client *c, int freq)
}
tun=&tuners[t->type];
- config = 0xa5;
+ config = 0xa4 /* 0xa5 */; /* bit 0 is AFC (set) vs. RF-Signal (clear) */
div=freq + (int)(16*10.7);
div&=0x7fff;
@@ -248,8 +264,12 @@ static void set_radio_freq(struct i2c_client *c, int freq)
printk ("tuner: PLL locked\n");
else
printk ("tuner: PLL not locked\n");
-
- printk ("tuner: AFC: %d\n", tuner_afcstatus (c));
+
+ if (config & 1) {
+ printk ("tuner: AFC: %d\n", tuner_afcstatus(c));
+ } else {
+ printk ("tuner: Signal: %d\n", tuner_signal(c));
+ }
}
}
/* ---------------------------------------------------------------------- */
@@ -370,6 +390,22 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
return 0;
}
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner *vt = arg;
+
+ if (t->radio)
+ vt->signal = tuner_signal(client);
+ return 0;
+ }
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *va = arg;
+ if (t->radio)
+ va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
+ return 0;
+ }
+
#if 0
/* --- old, obsolete interface --- */
case TUNER_SET_TVFREQ:
diff --git a/drivers/media/video/tuner.h b/drivers/media/video/tuner.h
index 96fcd3021..1929afe04 100644
--- a/drivers/media/video/tuner.h
+++ b/drivers/media/video/tuner.h
@@ -36,6 +36,8 @@
#define TUNER_ALPS_TSBB5_PAL_I 11
#define TUNER_ALPS_TSBE5_PAL 12
#define TUNER_ALPS_TSBC5_PAL 13
+#define TUNER_TEMIC_4006FH5_PAL 14
+#define TUNER_ALPS_TSHC6_NTSC 15
#define NOTUNER 0
#define PAL 1
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
new file mode 100644
index 000000000..5ed1a1097
--- /dev/null
+++ b/drivers/media/video/tvaudio.c
@@ -0,0 +1,1107 @@
+/*
+ * experimental driver for simple i2c audio chips.
+ *
+ * Copyright (c) 2000 Gerd Knorr
+ * based on code by:
+ * Eric Sandeen (eric_sandeen@bigfoot.com)
+ * Steve VanDeBogart (vandebo@uclink.berkeley.edu)
+ * Greg Alexander (galexand@acm.org)
+ *
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * OPTIONS:
+ * debug - set to 1 if you'd like to see debug messages
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+
+#include "audiochip.h"
+#include "tvaudio.h"
+#include "id.h"
+
+
+/* ---------------------------------------------------------------------- */
+/* insmod args */
+
+MODULE_PARM(debug,"i");
+static int debug = 0; /* insmod parameter */
+
+#define dprintk if (debug) printk
+
+
+/* ---------------------------------------------------------------------- */
+/* our structs */
+
+#define MAXREGS 64
+
+struct CHIPSTATE;
+typedef int (*getvalue)(int);
+typedef int (*checkit)(struct CHIPSTATE*);
+typedef int (*getmode)(struct CHIPSTATE*);
+typedef void (*setmode)(struct CHIPSTATE*, int mode);
+typedef void (*checkmode)(struct CHIPSTATE*);
+
+/* i2c command */
+typedef struct AUDIOCMD {
+ int count; /* # of bytes to send */
+ unsigned char bytes[MAXREGS+1]; /* addr, data, data, ... */
+} audiocmd;
+
+/* chip description */
+struct CHIPDESC {
+ char *name; /* chip name */
+ int id; /* ID */
+ int addr_lo, addr_hi; /* i2c address range */
+ int registers; /* # of registers */
+
+ int *insmodopt;
+ checkit checkit;
+ int flags;
+#define CHIP_HAS_VOLUME 1
+#define CHIP_HAS_BASSTREBLE 2
+#define CHIP_HAS_INPUTSEL 4
+
+ /* various i2c command sequences */
+ audiocmd init;
+
+ /* which register has which value */
+ int leftreg,rightreg,treblereg,bassreg;
+
+ /* initialize with (defaults to 65535/65535/32768/32768 */
+ int leftinit,rightinit,trebleinit,bassinit;
+
+ /* functions to convert the values (v4l -> chip) */
+ getvalue volfunc,treblefunc,bassfunc;
+
+ /* get/set mode */
+ getmode getmode;
+ setmode setmode;
+
+ /* check / autoswitch audio after channel switches */
+ checkmode checkmode;
+
+ /* input switch register + values for v4l inputs */
+ int inputreg;
+ int inputmap[8];
+ int inputmute;
+};
+static struct CHIPDESC chiplist[];
+
+/* current state of the chip */
+struct CHIPSTATE {
+ struct i2c_client c;
+
+ /* index into CHIPDESC array */
+ int type;
+
+ /* shadow register set */
+ audiocmd shadow;
+
+ /* current settings */
+ __u16 left,right,treble,bass;
+
+ /* thread */
+ struct task_struct *thread;
+ struct semaphore *notify;
+ wait_queue_head_t wq;
+ int wake,done;
+};
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c adresses */
+
+static unsigned short normal_i2c[] = {
+ I2C_TDA8425 >> 1,
+ I2C_TEA6300 >> 1,
+ I2C_TEA6420 >> 1,
+ I2C_TDA9840 >> 1,
+ I2C_TDA985x_L >> 1,
+ I2C_TDA985x_H >> 1,
+ I2C_PIC16C54 >> 1,
+ I2C_CLIENT_END };
+static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static struct i2c_client_address_data addr_data = {
+ normal_i2c, normal_i2c_range,
+ probe, probe_range,
+ ignore, ignore_range,
+ force
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c I/O functions */
+
+static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
+{
+ unsigned char buffer[2];
+
+ if (-1 == subaddr) {
+ dprintk("%s: chip_write: 0x%x\n", chip->c.name, val);
+ chip->shadow.bytes[1] = val;
+ buffer[0] = val;
+ if (1 != i2c_master_send(&chip->c,buffer,1)) {
+ printk(KERN_WARNING "%s: I/O error (write 0x%x)\n",
+ chip->c.name, val);
+ return -1;
+ }
+ } else {
+ dprintk("%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val);
+ chip->shadow.bytes[subaddr+1] = val;
+ buffer[0] = subaddr;
+ buffer[1] = val;
+ if (2 != i2c_master_send(&chip->c,buffer,2)) {
+ printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n",
+ chip->c.name, subaddr, val);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int chip_read(struct CHIPSTATE *chip)
+{
+ unsigned char buffer;
+
+ if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
+ printk(KERN_WARNING "%s: I/O error (read)\n",
+ chip->c.name);
+ return -1;
+ }
+ dprintk("%s: chip_read: 0x%x\n",chip->c.name,buffer);
+ return buffer;
+}
+
+static int chip_read2(struct CHIPSTATE *chip, int subaddr)
+{
+ unsigned char write[1];
+ unsigned char read[1];
+ struct i2c_msg msgs[2] = {
+ { chip->c.addr, 0, 1, write },
+ { chip->c.addr, I2C_M_RD, 1, read }
+ };
+ write[1] = subaddr;
+
+ if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
+ printk(KERN_WARNING "%s: I/O error (read2)\n",
+ chip->c.name);
+ return -1;
+ }
+ dprintk("%s: chip_read2: reg%d=0x%x\n",
+ chip->c.name,subaddr,read[0]);
+ return read[0];
+}
+
+static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
+{
+ int i;
+
+ if (0 == cmd->count)
+ return 0;
+
+ /* update our shadow register set; print bytes if (debug > 0) */
+ dprintk("%s: chip_cmd(%s): reg=%d, data:",
+ chip->c.name,name,cmd->bytes[0]);
+ for (i = 1; i < cmd->count; i++) {
+ dprintk(" 0x%x",cmd->bytes[i]);
+ chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
+ }
+ dprintk("\n");
+
+ /* send data to the chip */
+ if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
+ printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name);
+ return -1;
+ }
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* kernel thread for doing i2c stuff asyncronly
+ * right now it is used only to check the audio mode (mono/stereo/whatever)
+ * some time after switching to another TV channel, then turn on stereo
+ * if available, ...
+ */
+
+static int chip_thread(void *data)
+{
+ struct CHIPSTATE *chip = data;
+ struct CHIPDESC *desc = chiplist + chip->type;
+
+#ifdef CONFIG_SMP
+ lock_kernel();
+#endif
+ daemonize();
+ sigfillset(&current->blocked);
+ strcpy(current->comm,chip->c.name);
+ chip->thread = current;
+#ifdef CONFIG_SMP
+ unlock_kernel();
+#endif
+
+ dprintk("%s: thread started\n", chip->c.name);
+ if(chip->notify != NULL)
+ up(chip->notify);
+
+ for (;;) {
+ if (chip->done)
+ break;
+ if (!chip->wake) {
+ interruptible_sleep_on(&chip->wq);
+ dprintk("%s: thread wakeup\n", chip->c.name);
+ if (chip->done || signal_pending(current))
+ break;
+ }
+ chip->wake = 0;
+
+ /* wait some time -- let the audio hardware
+ figure the current mode */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ);
+ if (signal_pending(current))
+ break;
+ if (chip->wake)
+ continue;
+
+ dprintk("%s: thread checkmode\n", chip->c.name);
+ desc->checkmode(chip);
+ }
+
+ chip->thread = NULL;
+ dprintk("%s: thread exiting\n", chip->c.name);
+ if(chip->notify != NULL)
+ up(chip->notify);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9840 */
+
+#define TDA9840_SW 0x00
+#define TDA9840_LVADJ 0x02
+#define TDA9840_STADJ 0x03
+#define TDA9840_TEST 0x04
+
+#define TDA9840_MONO 0x10
+#define TDA9840_STEREO 0x2a
+#define TDA9840_DUALA 0x12
+#define TDA9840_DUALB 0x1e
+#define TDA9840_DUALAB 0x1a
+#define TDA9840_DUALBA 0x16
+#define TDA9840_EXTERNAL 0x7a
+
+int tda9840_getmode(struct CHIPSTATE *chip)
+{
+ return VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+ VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+}
+
+void tda9840_setmode(struct CHIPSTATE *chip, int mode)
+{
+ int update = 1;
+ int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
+
+ switch (mode) {
+ case VIDEO_SOUND_MONO:
+ t |= TDA9840_MONO;
+ break;
+ case VIDEO_SOUND_STEREO:
+ t |= TDA9840_STEREO;
+ break;
+ case VIDEO_SOUND_LANG1:
+ t |= TDA9840_DUALA;
+ break;
+ case VIDEO_SOUND_LANG2:
+ t |= TDA9840_DUALB;
+ break;
+ default:
+ update = 0;
+ }
+
+ if (update)
+ chip_write(chip, TDA9840_SW, t);
+}
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda985x */
+
+/* subaddresses for TDA9855 */
+#define TDA9855_VR 0x00 /* Volume, right */
+#define TDA9855_VL 0x01 /* Volume, left */
+#define TDA9855_BA 0x02 /* Bass */
+#define TDA9855_TR 0x03 /* Treble */
+#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */
+
+/* subaddresses for TDA9850 */
+#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */
+
+/* subaddesses for both chips */
+#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */
+#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */
+#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */
+#define TDA985x_A1 0x08 /* Alignment 1 for both chips */
+#define TDA985x_A2 0x09 /* Alignment 2 for both chips */
+#define TDA985x_A3 0x0a /* Alignment 3 for both chips */
+
+/* Masks for bits in TDA9855 subaddresses */
+/* 0x00 - VR in TDA9855 */
+/* 0x01 - VL in TDA9855 */
+/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f)
+ * in 1dB steps - mute is 0x27 */
+
+
+/* 0x02 - BA in TDA9855 */
+/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19)
+ * in .5dB steps - 0 is 0x0E */
+
+
+/* 0x03 - TR in TDA9855 */
+/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb)
+ * in 3dB steps - 0 is 0x7 */
+
+/* Masks for bits in both chips' subaddresses */
+/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */
+/* Unique to TDA9855: */
+/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf)
+ * in 3dB steps - mute is 0x0 */
+
+/* Unique to TDA9850: */
+/* lower 4 bits control stereo noise threshold, over which stereo turns off
+ * set to values of 0x00 through 0x0f for Ster1 through Ster16 */
+
+
+/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/
+/* Unique to TDA9855: */
+#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */
+#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */
+#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */
+#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */
+ /* Bits 0 to 3 select various combinations
+ * of line in and line out, only the
+ * interesting ones are defined */
+#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */
+#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */
+
+/* Unique to TDA9850: */
+/* lower 4 bits contol SAP noise threshold, over which SAP turns off
+ * set to values of 0x00 through 0x0f for SAP1 through SAP16 */
+
+
+/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */
+/* Common to TDA9855 and TDA9850: */
+#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */
+#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */
+#define TDA985x_MONO 0 /* Forces Mono output */
+#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */
+
+/* Unique to TDA9855: */
+#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */
+#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/
+#define TDA9855_LINEAR 0 /* Linear Stereo */
+#define TDA9855_PSEUDO 1 /* Pseudo Stereo */
+#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */
+#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */
+#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/
+
+/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF)
+ * in .5dB steps - 0dB is 0x7 */
+
+/* 0x08, 0x09 - A1 and A2 (read/write) */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 5 bites are wideband and spectral expander alignment
+ * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */
+#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */
+#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */
+#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/
+
+/* 0x0a - A3 */
+/* Common to both TDA9855 and TDA9850: */
+/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1),
+ * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */
+#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */
+
+int tda9855_volume(int val) { return val/0x2e8+0x27; }
+int tda9855_bass(int val) { return val/0xccc+0x06; }
+int tda9855_treble(int val) { return (val/0x1c71+0x3)<<1; }
+
+int tda985x_getmode(struct CHIPSTATE *chip)
+{
+ int mode;
+
+ mode = ((TDA985x_STP | TDA985x_SAPP) &
+ chip_read(chip)) >> 4;
+ /* Add mono mode regardless of SAP and stereo */
+ /* Allows forced mono */
+ return mode | VIDEO_SOUND_MONO;
+}
+
+void tda985x_setmode(struct CHIPSTATE *chip, int mode)
+{
+ int update = 1;
+ int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
+
+ switch (mode) {
+ case VIDEO_SOUND_MONO:
+ c6 |= TDA985x_MONO;
+ break;
+ case VIDEO_SOUND_STEREO:
+ c6 |= TDA985x_STEREO;
+ break;
+ case VIDEO_SOUND_LANG1:
+ c6 |= TDA985x_SAP;
+ break;
+ default:
+ update = 0;
+ }
+ if (update)
+ chip_write(chip,TDA985x_C6,c6);
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda9873h */
+
+/* Subaddresses for TDA9873H */
+
+#define TDA9873_SW 0x00 /* Switching */
+#define TDA9873_AD 0x01 /* Adjust */
+#define TDA9873_PT 0x02 /* Port */
+
+/* Subaddress 0x00: Switching Data
+ * B7..B0:
+ *
+ * B1, B0: Input source selection
+ * 0, 0 internal
+ * 1, 0 external stereo
+ * 0, 1 external mono
+ */
+#define TDA9873_INTERNAL 0
+#define TDA9873_EXT_STEREO 2
+#define TDA9873_EXT_MONO 1
+
+/* B3, B2: output signal select
+ * B4 : transmission mode
+ * 0, 0, 1 Mono
+ * 1, 0, 0 Stereo
+ * 1, 1, 1 Stereo (reversed channel)
+ * 0, 0, 0 Dual AB
+ * 0, 0, 1 Dual AA
+ * 0, 1, 0 Dual BB
+ * 0, 1, 1 Dual BA
+ */
+
+#define TDA9873_TR_MONO 4
+#define TDA9873_TR_STEREO 1 << 4
+#define TDA9873_TR_REVERSE (1 << 3) & (1 << 2)
+#define TDA9873_TR_DUALA 1 << 2
+#define TDA9873_TR_DUALB 1 << 3
+
+/* output level controls
+ * B5: output level switch (0 = reduced gain, 1 = normal gain)
+ * B6: mute (1 = muted)
+ * B7: auto-mute (1 = auto-mute enabled)
+ */
+
+#define TDA9873_GAIN_NORMAL 1 << 5
+#define TDA9873_MUTE 1 << 6
+#define TDA9873_AUTOMUTE 1 << 7
+
+/* Subaddress 0x01: Adjust/standard */
+
+/* Lower 4 bits (C3..C0) control stereo adjustment on R channel (-0.6 - +0.7 dB)
+ * Recommended value is +0 dB
+ */
+
+#define TDA9873_STEREO_ADJ 0x06 /* 0dB gain */
+
+/* Bits C6..C4 control FM stantard
+ * C6, C5, C4
+ * 0, 0, 0 B/G (PAL FM)
+ * 0, 0, 1 M
+ * 0, 1, 0 D/K(1)
+ * 0, 1, 1 D/K(2)
+ * 1, 0, 0 D/K(3)
+ * 1, 0, 1 I
+ */
+#define TDA9873_BG 0
+#define TDA9873_M 1
+#define TDA9873_DK1 2
+#define TDA9873_DK2 3
+#define TDA9873_DK3 4
+#define TDA9873_I 5
+
+/* C7 controls identification response time (1=fast/0=normal)
+ */
+#define TDA9873_IDR_NORM 0
+#define TDA9873_IDR_FAST 1 << 7
+
+
+/* Subaddress 0x02: Port data */
+
+/* E1, E0 free programmable ports P1/P2
+ 0, 0 both ports low
+ 0, 1 P1 high
+ 1, 0 P2 high
+ 1, 1 both ports high
+*/
+
+#define TDA9873_PORTS 3
+
+/* E2: test port */
+#define TDA9873_TST_PORT 1 << 2
+
+/* E5..E3 control mono output channel (together with transmission mode bit B4)
+ *
+ * E5 E4 E3 B4 OUTM
+ * 0 0 0 0 mono
+ * 0 0 1 0 DUAL B
+ * 0 1 0 1 mono (from stereo decoder)
+ */
+#define TDA9873_MOUT_MONO 0
+#define TDA9873_MOUT_FMONO 0
+#define TDA9873_MOUT_DUALA 0
+#define TDA9873_MOUT_DUALB 1 << 3
+#define TDA9873_MOUT_ST 1 << 4
+#define TDA9873_MOUT_EXTM (1 << 4 ) & (1 << 3)
+#define TDA9873_MOUT_EXTL 1 << 5
+#define TDA9873_MOUT_EXTR (1 << 5 ) & (1 << 3)
+#define TDA9873_MOUT_EXTLR (1 << 5 ) & (1 << 4)
+#define TDA9873_MOUT_MUTE (1 << 5 ) & (1 << 4) & (1 << 3)
+
+/* Status bits: (chip read) */
+#define TDA9873_PONR 0 /* Power-on reset detected if = 1 */
+#define TDA9873_STEREO 2 /* Stereo sound is identified */
+#define TDA9873_DUAL 4 /* Dual sound is identified */
+
+int tda9873_getmode(struct CHIPSTATE *chip)
+{
+ int val,mode;
+
+ val = chip_read(chip);
+ mode = VIDEO_SOUND_MONO;
+ if (val & TDA9873_STEREO)
+ mode |= VIDEO_SOUND_STEREO;
+ if (val & TDA9873_DUAL)
+ mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+ dprintk ("tda9873_getmode(): raw chip read: %d, return: %d\n",
+ val, mode);
+ return mode;
+}
+
+void tda9873_setmode(struct CHIPSTATE *chip, int mode)
+{
+ int sw_data = chip->shadow.bytes[TDA9873_SW+1] & 0xe3;
+ /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
+ dprintk("tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+ dprintk("tda9873_setmode(): sw_data = %d\n", sw_data);
+
+ switch (mode) {
+ case VIDEO_SOUND_MONO:
+ sw_data |= TDA9873_TR_MONO;
+ break;
+ case VIDEO_SOUND_STEREO:
+ sw_data |= TDA9873_TR_STEREO;
+ break;
+ case VIDEO_SOUND_LANG1:
+ sw_data |= TDA9873_TR_DUALA;
+ break;
+ case VIDEO_SOUND_LANG2:
+ sw_data |= TDA9873_TR_DUALB;
+ break;
+ }
+ dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data);
+ chip_write(chip,TDA9873_SW,sw_data);
+}
+
+void tda9873_checkmode(struct CHIPSTATE *chip)
+{
+ int mode = tda9873_getmode(chip);
+
+ if (mode & VIDEO_SOUND_STEREO)
+ tda9873_setmode(chip,VIDEO_SOUND_STEREO);
+ if (mode & VIDEO_SOUND_LANG1)
+ tda9873_setmode(chip,VIDEO_SOUND_LANG1);
+}
+
+int tda9873_checkit(struct CHIPSTATE *chip)
+{
+ int rc;
+
+ if (-1 == (rc = chip_read2(chip,254)))
+ return 0;
+ return (rc & ~0x1f) == 0x80;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tea6420 */
+
+#define TEA6300_VL 0x00 /* volume left */
+#define TEA6300_VR 0x01 /* volume right */
+#define TEA6300_BA 0x02 /* bass */
+#define TEA6300_TR 0x03 /* treble */
+#define TEA6300_FA 0x04 /* fader control */
+#define TEA6300_S 0x05 /* switch register */
+ /* values for those registers: */
+#define TEA6300_S_SA 0x01 /* stereo A input */
+#define TEA6300_S_SB 0x02 /* stereo B */
+#define TEA6300_S_SC 0x04 /* stereo C */
+#define TEA6300_S_GMU 0x80 /* general mute */
+
+#define TEA6420_S_SA 0x00 /* stereo A input */
+#define TEA6420_S_SB 0x01 /* stereo B */
+#define TEA6420_S_SC 0x02 /* stereo C */
+#define TEA6420_S_SD 0x03 /* stereo D */
+#define TEA6420_S_SE 0x04 /* stereo E */
+#define TEA6420_S_GMU 0x05 /* general mute */
+
+int tea6300_shift10(int val) { return val >> 10; }
+int tea6300_shift12(int val) { return val >> 12; }
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for tda8425 */
+
+#define TDA8425_VL 0x00 /* volume left */
+#define TDA8425_VR 0x01 /* volume right */
+#define TDA8425_BA 0x02 /* bass */
+#define TDA8425_TR 0x03 /* treble */
+#define TDA8425_S1 0x08 /* switch functions */
+ /* values for those registers: */
+#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */
+#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */
+
+int tda8425_shift10(int val) { return val >> 10 | 0xc0; }
+int tda8425_shift12(int val) { return val >> 12 | 0xf0; }
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for pic16c54 (PV951) */
+
+/* the registers of 16C54, I2C sub address. */
+#define PIC16C54_REG_KEY_CODE 0x01 /* Not use. */
+#define PIC16C54_REG_MISC 0x02
+
+/* bit definition of the RESET register, I2C data. */
+#define PIC16C54_MISC_RESET_REMOTE_CTL 0x01 /* bit 0, Reset to receive the key */
+ /* code of remote controller */
+#define PIC16C54_MISC_MTS_MAIN 0x02 /* bit 1 */
+#define PIC16C54_MISC_MTS_SAP 0x04 /* bit 2 */
+#define PIC16C54_MISC_MTS_BOTH 0x08 /* bit 3 */
+#define PIC16C54_MISC_SND_MUTE 0x10 /* bit 4, Mute Audio(Line-in and Tuner) */
+#define PIC16C54_MISC_SND_NOTMUTE 0x20 /* bit 5 */
+#define PIC16C54_MISC_SWITCH_TUNER 0x40 /* bit 6 , Switch to Line-in */
+#define PIC16C54_MISC_SWITCH_LINE 0x80 /* bit 7 , Switch to Tuner */
+
+
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - struct CHIPDESC */
+
+/* insmod options to enable/disable individual audio chips */
+int tda8425 = 1;
+int tda9840 = 1;
+int tda9850 = 1;
+int tda9855 = 1;
+int tda9873 = 1;
+int tea6300 = 0;
+int tea6420 = 1;
+int pic16c54 = 1;
+MODULE_PARM(tda8425,"i");
+MODULE_PARM(tda9840,"i");
+MODULE_PARM(tda9850,"i");
+MODULE_PARM(tda9855,"i");
+MODULE_PARM(tda9873,"i");
+MODULE_PARM(tea6300,"i");
+MODULE_PARM(tea6420,"i");
+MODULE_PARM(pic16c54,"i");
+
+static struct CHIPDESC chiplist[] = {
+ {
+ name: "tda9840",
+ id: I2C_DRIVERID_TDA9840,
+ insmodopt: &tda9840,
+ addr_lo: I2C_TDA9840 >> 1,
+ addr_hi: I2C_TDA9840 >> 1,
+ registers: 5,
+
+ getmode: tda9840_getmode,
+ setmode: tda9840_setmode,
+
+ init: { 2, { TDA9840_SW, 0x2a } }
+ },
+ {
+ name: "tda9873h",
+ id: I2C_DRIVERID_TDA9873,
+ checkit: tda9873_checkit,
+ insmodopt: &tda9873,
+ addr_lo: I2C_TDA985x_L >> 1,
+ addr_hi: I2C_TDA985x_H >> 1,
+ registers: 3,
+
+ getmode: tda9873_getmode,
+ setmode: tda9873_setmode,
+ checkmode: tda9873_checkmode,
+
+ init: { 4, { TDA9873_SW, 0xa0, 0x06, 0x03 } }
+ },
+ {
+ name: "tda9850",
+ id: I2C_DRIVERID_TDA9850,
+ insmodopt: &tda9850,
+ addr_lo: I2C_TDA985x_L >> 1,
+ addr_hi: I2C_TDA985x_H >> 1,
+ registers: 11,
+
+ getmode: tda985x_getmode,
+ setmode: tda985x_setmode,
+
+ init: { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+ },
+ {
+ name: "tda9855",
+ id: I2C_DRIVERID_TDA9855,
+ insmodopt: &tda9855,
+ addr_lo: I2C_TDA985x_L >> 1,
+ addr_hi: I2C_TDA985x_H >> 1,
+ registers: 11,
+ flags: CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+ leftreg: TDA9855_VR,
+ rightreg: TDA9855_VL,
+ bassreg: TDA9855_BA,
+ treblereg: TDA9855_TR,
+ volfunc: tda9855_volume,
+ bassfunc: tda9855_bass,
+ treblefunc: tda9855_treble,
+
+ getmode: tda985x_getmode,
+ setmode: tda985x_setmode,
+
+ init: { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
+ TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
+ TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
+ 0x07, 0x10, 0x10, 0x03 }}
+ },
+ {
+ name: "tea6300",
+ id: I2C_DRIVERID_TEA6300,
+ insmodopt: &tea6300,
+ addr_lo: I2C_TEA6300 >> 1,
+ addr_hi: I2C_TEA6300 >> 1,
+ registers: 6,
+ flags: CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+ leftreg: TEA6300_VR,
+ rightreg: TEA6300_VL,
+ bassreg: TEA6300_BA,
+ treblereg: TEA6300_TR,
+ volfunc: tea6300_shift10,
+ bassfunc: tea6300_shift12,
+ treblefunc: tea6300_shift12,
+
+ inputreg: TEA6300_S,
+ inputmap: { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
+ inputmute: TEA6300_S_GMU,
+ },
+ {
+ name: "tea6420",
+ id: I2C_DRIVERID_TEA6420,
+ insmodopt: &tea6420,
+ addr_lo: I2C_TEA6420 >> 1,
+ addr_hi: I2C_TEA6420 >> 1,
+ registers: 1,
+ flags: CHIP_HAS_INPUTSEL,
+
+ inputreg: -1,
+ inputmap: { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
+ inputmute: TEA6300_S_GMU,
+ },
+ {
+ name: "tda8425",
+ id: I2C_DRIVERID_TDA8425,
+ insmodopt: &tda8425,
+ addr_lo: I2C_TDA8425 >> 1,
+ addr_hi: I2C_TDA8425 >> 1,
+ registers: 9,
+ flags: CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+ leftreg: TDA8425_VR,
+ rightreg: TDA8425_VL,
+ bassreg: TDA8425_BA,
+ treblereg: TDA8425_TR,
+ volfunc: tda8425_shift10,
+ bassfunc: tda8425_shift12,
+ treblefunc: tda8425_shift12,
+
+ inputreg: TDA8425_S1,
+ inputmap: { TDA8425_S1_ON, TDA8425_S1_ON, TDA8425_S1_ON },
+ inputmute: TDA8425_S1_OFF,
+ },
+ {
+ name: "pic16c54 (PV951)",
+ id: I2C_DRIVERID_PIC16C54_PV951,
+ insmodopt: &pic16c54,
+ addr_lo: I2C_PIC16C54 >> 1,
+ addr_hi: I2C_PIC16C54>> 1,
+ registers: 2,
+ flags: CHIP_HAS_INPUTSEL,
+
+ inputreg: PIC16C54_REG_MISC,
+ inputmap: {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
+ PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE},
+ inputmute: PIC16C54_MISC_SND_MUTE,
+ },
+ { name: NULL } /* EOF */
+};
+
+
+/* ---------------------------------------------------------------------- */
+/* i2c registration */
+
+static int chip_attach(struct i2c_adapter *adap, int addr,
+ unsigned short flags, int kind)
+{
+ struct CHIPSTATE *chip;
+ struct CHIPDESC *desc;
+
+ chip = kmalloc(sizeof(*chip),GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ memset(chip,0,sizeof(*chip));
+ memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
+ chip->c.adapter = adap;
+ chip->c.addr = addr;
+ chip->c.data = chip;
+
+ /* find description for the chip */
+ dprintk("tvaudio: chip @ addr=0x%x\n",addr<<1);
+ for (desc = chiplist; desc->name != NULL; desc++) {
+ if (0 == *(desc->insmodopt))
+ continue;
+ if (addr < desc->addr_lo ||
+ addr > desc->addr_hi)
+ continue;
+ if (desc->checkit && !desc->checkit(chip))
+ continue;
+ break;
+ }
+ if (desc->name == NULL) {
+ dprintk("tvaudio: no matching chip description found\n");
+ return -EIO;
+ }
+ dprintk("tvaudio: %s matches:%s%s%s\n",desc->name,
+ (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "",
+ (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+ (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : "");
+
+ /* fill required data structures */
+ strcpy(chip->c.name,desc->name);
+ chip->type = desc-chiplist;
+ chip->shadow.count = desc->registers+1;
+
+ /* register */
+ MOD_INC_USE_COUNT;
+ i2c_attach_client(&chip->c);
+
+ /* initialization */
+ chip_cmd(chip,"init",&desc->init);
+ if (desc->flags & CHIP_HAS_VOLUME) {
+ chip->left = desc->leftinit ? desc->leftinit : 65536;
+ chip->right = desc->rightinit ? desc->rightinit : 65536;
+ chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+ chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+ }
+ if (desc->flags & CHIP_HAS_BASSTREBLE) {
+ chip->treble = desc->trebleinit ? desc->trebleinit : 32768;
+ chip->bass = desc->bassinit ? desc->bassinit : 32768;
+ chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+ chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+ }
+
+ if (desc->checkmode) {
+ /* start async thread */
+ DECLARE_MUTEX_LOCKED(sem);
+ chip->notify = &sem;
+ init_waitqueue_head(&chip->wq);
+ kernel_thread(chip_thread,(void *)chip,0);
+ down(&sem);
+ chip->notify = NULL;
+ chip->wake++;
+ wake_up_interruptible(&chip->wq);
+ }
+ return 0;
+}
+
+static int chip_probe(struct i2c_adapter *adap)
+{
+ if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ return i2c_probe(adap, &addr_data, chip_attach);
+ return 0;
+}
+
+static int chip_detach(struct i2c_client *client)
+{
+ struct CHIPSTATE *chip = client->data;
+
+ if (NULL != chip->thread) {
+ /* shutdown async thread */
+ DECLARE_MUTEX_LOCKED(sem);
+ chip->notify = &sem;
+ chip->done = 1;
+ wake_up_interruptible(&chip->wq);
+ down(&sem);
+ chip->notify = NULL;
+ }
+
+ i2c_detach_client(&chip->c);
+ kfree(chip);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+/* video4linux interface */
+
+static int chip_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ __u16 *sarg = arg;
+ struct CHIPSTATE *chip = client->data;
+ struct CHIPDESC *desc = chiplist + chip->type;
+
+ dprintk("%s: chip_command 0x%x\n",chip->c.name,cmd);
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ if (desc->flags & CHIP_HAS_INPUTSEL) {
+ if (*sarg & 0x80)
+ chip_write(chip,desc->inputreg,desc->inputmute);
+ else
+ chip_write(chip,desc->inputreg,desc->inputmap[*sarg]);
+ }
+ break;
+ /* --- v4l ioctls --- */
+ /* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *va = arg;
+
+ if (desc->flags & CHIP_HAS_VOLUME) {
+ va->flags |= VIDEO_AUDIO_VOLUME;
+ va->volume = MAX(chip->left,chip->right);
+ va->balance = (32768*MIN(chip->left,chip->right))/
+ (va->volume ? va->volume : 1);
+ }
+ if (desc->flags & CHIP_HAS_BASSTREBLE) {
+ va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+ va->bass = chip->bass;
+ va->treble = chip->treble;
+ }
+ if (desc->getmode)
+ va->mode = desc->getmode(chip);
+ else
+ va->mode = VIDEO_SOUND_MONO;
+ break;
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio *va = arg;
+
+ if (desc->flags & CHIP_HAS_VOLUME) {
+ chip->left = (MIN(65536 - va->balance,32768) *
+ va->volume) / 32768;
+ chip->right = (MIN(va->balance,32768) *
+ va->volume) / 32768;
+ chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+ chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+ }
+ if (desc->flags & CHIP_HAS_BASSTREBLE) {
+ chip->bass = va->bass;
+ chip->treble = va->treble;
+ chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+ chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+ }
+ if (desc->setmode && va->mode)
+ desc->setmode(chip,va->mode);
+ break;
+ }
+ case VIDIOCSFREQ:
+ {
+ if (desc->checkmode) {
+ desc->setmode(chip,VIDEO_SOUND_MONO);
+ chip->wake++;
+ wake_up_interruptible(&chip->wq);
+ /* the thread will call checkmode() a second later */
+ }
+ }
+ }
+ return 0;
+}
+
+
+static struct i2c_driver driver = {
+ name: "generic i2c audio driver",
+ id: I2C_DRIVERID_TVAUDIO, /* FIXME */
+ flags: I2C_DF_NOTIFY,
+ attach_adapter: chip_probe,
+ detach_client: chip_detach,
+ command: chip_command,
+};
+
+static struct i2c_client client_template =
+{
+ name: "(unset)",
+ driver: &driver,
+};
+
+int audiochip_init_module(void)
+{
+ struct CHIPDESC *desc;
+ printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+ printk(KERN_INFO "tvaudio: known chips: ");
+ for (desc = chiplist; desc->name != NULL; desc++)
+ printk("%s%s", (desc == chiplist) ? "" : ",",desc->name);
+ printk("\n");
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+void audiochip_cleanup_module(void)
+{
+ i2c_del_driver(&driver);
+}
+
+module_init(audiochip_init_module);
+module_exit(audiochip_cleanup_module);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tvaudio.h b/drivers/media/video/tvaudio.h
new file mode 100644
index 000000000..702d2492d
--- /dev/null
+++ b/drivers/media/video/tvaudio.h
@@ -0,0 +1,13 @@
+/*
+ * i2c bus addresses for the chips supported by tvaudio.c
+ */
+
+#define I2C_TDA8425 0x82
+#define I2C_TDA9840 0x84
+#define I2C_TDA985x_L 0xb4 /* also used by 9873 */
+#define I2C_TDA985x_H 0xb6
+
+#define I2C_TEA6300 0x80
+#define I2C_TEA6420 0x98
+
+#define I2C_PIC16C54 0x96 /* PV951 */
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index e1034a152..1e406921e 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -16,6 +16,7 @@
#include <asm/uaccess.h>
#include "audiochip.h"
+#include "id.h"
#define DEV_MAX 4
@@ -45,11 +46,11 @@ static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin);
static struct i2c_driver driver = {
- "tv card mixer driver",
- 42 /* I2C_DRIVERID_FIXME */,
- I2C_DF_DUMMY,
- tvmixer_adapters,
- tvmixer_clients,
+ name: "tv card mixer driver",
+ id: I2C_DRIVERID_TVMIXER,
+ flags: I2C_DF_DUMMY,
+ attach_adapter: tvmixer_adapters,
+ detach_client: tvmixer_clients,
};
static struct file_operations tvmixer_fops = {
@@ -241,6 +242,15 @@ static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin)
static int tvmixer_adapters(struct i2c_adapter *adap)
{
+ int i;
+
+ if (debug)
+ printk("tvmixer: adapter %s\n",adap->name);
+ for (i=0; i<I2C_CLIENT_MAX; i++) {
+ if (!adap->clients[i])
+ continue;
+ tvmixer_clients(adap->clients[i]);
+ }
return 0;
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 1ef64ae81..b24591de4 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -224,20 +224,13 @@ static int vino_mmap(struct video_device *dev, const char *adr,
}
static struct video_device vino_dev = {
- "Vino IndyCam/TV",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_VINO,
- vino_open,
- vino_close,
- NULL, /* vino_read */
- NULL, /* vino_write */
- NULL, /* vino_poll */
- vino_ioctl,
- vino_mmap,
- NULL, /* vino_init */
- NULL,
- 0,
- 0
+ name: "Vino IndyCam/TV",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_VINO,
+ open: vino_open,
+ close: vino_close,
+ ioctl: vino_ioctl,
+ mmap: vino_mmap,
};
int __init init_vino(struct video_device *dev)
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index b4ef205d5..6027f8445 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1482,23 +1482,17 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size)
static struct video_device zr36120_template=
{
- "UNSET",
- VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
- VID_HARDWARE_ZR36120,
-
- zoran_open,
- zoran_close,
- zoran_read,
- zoran_write,
-#if LINUX_VERSION_CODE >= 0x020100
- zoran_poll, /* poll */
-#endif
- zoran_ioctl,
- zoran_mmap,
- NULL, /* initialize */
- NULL,
- 0,
- -1
+ name: "UNSET",
+ type: VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
+ hardware: VID_HARDWARE_ZR36120,
+ open: zoran_open,
+ close: zoran_close,
+ read: zoran_read,
+ write: zoran_write,
+ poll: zoran_poll,
+ ioctl: zoran_ioctl,
+ mmap: zoran_mmap,
+ minor: -1,
};
static
@@ -1825,23 +1819,16 @@ int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
static struct video_device vbi_template=
{
- "UNSET",
- VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
- VID_HARDWARE_ZR36120,
-
- vbi_open,
- vbi_close,
- vbi_read,
- zoran_write,
-#if LINUX_VERSION_CODE >= 0x020100
- vbi_poll, /* poll */
-#endif
- vbi_ioctl,
- NULL, /* no mmap */
- NULL, /* no initialize */
- NULL, /* priv */
- 0, /* busy */
- -1 /* minor */
+ name: "UNSET",
+ type: VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+ hardware: VID_HARDWARE_ZR36120,
+ open: vbi_open,
+ close: vbi_close,
+ read: vbi_read,
+ write: zoran_write,
+ poll: vbi_poll,
+ ioctl: vbi_ioctl,
+ minor: -1,
};
/*
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index fcbfd3175..3f28868e3 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -44,7 +44,7 @@ SUB_DIRS :=
ALL_SUB_DIRS :=
MOD_SUB_DIRS :=
-export-objs := mtdcore.o doc2000.o doc2001.o cfi_probe.o cfi_cmdset_0001.o cfi_cmdset_0002.o
+export-objs := mtdcore.o
list-multi :=
# MTD devices
diff --git a/drivers/mtd/cfi_cmdset_0001.c b/drivers/mtd/cfi_cmdset_0001.c
index 8c26d43b4..e765d91fc 100644
--- a/drivers/mtd/cfi_cmdset_0001.c
+++ b/drivers/mtd/cfi_cmdset_0001.c
@@ -32,12 +32,20 @@ static void cfi_intelext_resume (struct mtd_info *);
static void cfi_intelext_destroy(struct mtd_info *);
-void cfi_cmdset_0001(struct map_info *, int, unsigned long);
-EXPORT_SYMBOL(cfi_cmdset_0001);
+static void cfi_cmdset_0001(struct map_info *, int, unsigned long);
-struct mtd_info *cfi_intelext_setup (struct map_info *);
+static struct mtd_info *cfi_intelext_setup (struct map_info *);
-void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
+static const char im_name[] = "cfi_cmdset_0001";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
@@ -144,7 +152,7 @@ void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
/* If there was an old setup function, decrease its use count */
if (cfi->cmdset_setup)
- put_module_symbol((unsigned long)cfi->cmdset_setup);
+ inter_module_put(cfi->im_name);
if (cfi->cmdset_priv)
kfree(cfi->cmdset_priv);
@@ -156,14 +164,13 @@ void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
cfi->cmdset_setup = cfi_intelext_setup;
+ cfi->im_name = im_name;
cfi->cmdset_priv = extp;
- MOD_INC_USE_COUNT; /* So the setup function is still there
- * by the time it's called */
return;
}
-struct mtd_info *cfi_intelext_setup(struct map_info *map)
+static struct mtd_info *cfi_intelext_setup(struct map_info *map)
{
struct cfi_private *cfi = map->fldrv_priv;
struct mtd_info *mtd;
@@ -763,6 +770,8 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
spin_unlock_bh(chip->mutex);
schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
goto retry;
}
}
@@ -862,6 +871,21 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
kfree(cfi->cmdset_priv);
+ inter_module_put(cfi->im_name);
kfree(cfi);
}
+
+static int __init cfi_intelext_init(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0001);
+ return 0;
+}
+
+static void __exit cfi_intelext_exit(void)
+{
+ inter_module_unregister(im_name);
+}
+
+module_init(cfi_intelext_init);
+module_exit(cfi_intelext_exit);
diff --git a/drivers/mtd/cfi_cmdset_0002.c b/drivers/mtd/cfi_cmdset_0002.c
index 2797c768e..d6cce6474 100644
--- a/drivers/mtd/cfi_cmdset_0002.c
+++ b/drivers/mtd/cfi_cmdset_0002.c
@@ -36,12 +36,13 @@ static void cfi_amdext_resume (struct mtd_info *);
static void cfi_amdext_destroy(struct mtd_info *);
-void cfi_cmdset_0002(struct map_info *, int, unsigned long);
-EXPORT_SYMBOL(cfi_cmdset_0002);
+static void cfi_cmdset_0002(struct map_info *, int, unsigned long);
-struct mtd_info *cfi_amdext_setup (struct map_info *);
+static struct mtd_info *cfi_amdext_setup (struct map_info *);
-void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
+static const char im_name[] = "cfi_cmdset_0002";
+
+static void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
{
struct cfi_private *cfi = map->fldrv_priv;
int i;
@@ -54,7 +55,7 @@ void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
/* If there was an old setup function, decrease its use count */
if (cfi->cmdset_setup)
- put_module_symbol((unsigned long)cfi->cmdset_setup);
+ inter_module_put(cfi->im_name);
if (cfi->cmdset_priv)
kfree(cfi->cmdset_priv);
@@ -66,14 +67,13 @@ void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base)
cfi->cmdset_setup = cfi_amdext_setup;
+ cfi->im_name = im_name;
// cfi->cmdset_priv = extp;
- MOD_INC_USE_COUNT; /* So the setup function is still there
- * by the time it's called */
return;
}
-struct mtd_info *cfi_amdext_setup(struct map_info *map)
+static struct mtd_info *cfi_amdext_setup(struct map_info *map)
{
struct cfi_private *cfi = map->fldrv_priv;
struct mtd_info *mtd;
@@ -501,8 +501,11 @@ printk("sync\n");
add_wait_queue(&chip->wq, &wait);
spin_unlock_bh(chip->mutex);
+
schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
goto retry;
}
}
@@ -605,6 +608,21 @@ static void cfi_amdext_destroy(struct mtd_info *mtd)
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
kfree(cfi->cmdset_priv);
+ inter_module_put(cfi->im_name);
kfree(cfi);
}
+
+static int __init cfi_amdext_init(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
+ return 0;
+}
+
+static void __exit cfi_amdext_exit(void)
+{
+ inter_module_unregister(im_name);
+}
+
+module_init(cfi_amdext_init);
+module_exit(cfi_amdext_exit);
diff --git a/drivers/mtd/cfi_probe.c b/drivers/mtd/cfi_probe.c
index ccd33fb3c..392f7aa57 100644
--- a/drivers/mtd/cfi_probe.c
+++ b/drivers/mtd/cfi_probe.c
@@ -17,14 +17,22 @@
#include <linux/mtd/cfi.h>
-struct mtd_info *cfi_probe(struct map_info *);
-EXPORT_SYMBOL(cfi_probe);
+static struct mtd_info *cfi_probe(struct map_info *);
static void print_cfi_ident(struct cfi_ident *);
static void check_cmd_set(struct map_info *, int, unsigned long);
static struct cfi_private *cfi_cfi_probe(struct map_info *);
-struct mtd_info *cfi_probe(struct map_info *map)
+static const char im_name[] = "cfi_probe";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static struct mtd_info *cfi_probe(struct map_info *map)
{
struct mtd_info *mtd = NULL;
struct cfi_private *cfi;
@@ -35,13 +43,14 @@ struct mtd_info *cfi_probe(struct map_info *map)
return NULL;
map->fldrv_priv = cfi;
+ map->im_name = im_name;
/* OK we liked it. Now find a driver for the command set it talks */
check_cmd_set(map, 1, cfi->chips[0].start); /* First the primary cmdset */
check_cmd_set(map, 0, cfi->chips[0].start); /* Then the secondary */
- /* check_cmd_set() will have used get_module_symbol to increase
+ /* check_cmd_set() will have used inter_module_get to increase
the use count of the module which provides the command set
driver. If we're quitting, we have to decrease it again.
*/
@@ -51,7 +60,7 @@ struct mtd_info *cfi_probe(struct map_info *map)
if (mtd)
return mtd;
- put_module_symbol((unsigned long)cfi->cmdset_setup);
+ inter_module_put(cfi->im_name);
}
printk("No supported Vendor Command Set found\n");
@@ -239,7 +248,7 @@ static int cfi_probe_new_chip(struct map_info *map, unsigned long base,
}
}
default:
- printk(KERN_WARNING "cfi_cfi_probe called with strange buswidth %d\n", map->buswidth);
+ printk(KERN_WARNING "cfi_probe called with strange buswidth %d\n", map->buswidth);
return 0;
}
}
@@ -465,16 +474,9 @@ static void check_cmd_set(struct map_info *map, int primary, unsigned long base)
sprintf(probename, "cfi_cmdset_%4.4X", type);
- probe_function = (void *)get_module_symbol(NULL, probename);
- if (!probe_function) {
- request_module(probename);
-
- probe_function = (void *)get_module_symbol(NULL, probename);
- }
-
+ probe_function = inter_module_get_request(probename, probename);
if (probe_function) {
(*probe_function)(map, primary, base);
- put_module_symbol((unsigned long)probe_function);
return;
}
@@ -499,3 +501,17 @@ static void check_cmd_set(struct map_info *map, int primary, unsigned long base)
map->read8(map,base+((adr+4)*map->buswidth)));
}
}
+
+static int __init cfi_probe_init(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &cfi_probe);
+ return 0;
+}
+
+static void __exit cfi_probe_exit(void)
+{
+ inter_module_unregister(im_name);
+}
+
+module_init(cfi_probe_init);
+module_exit(cfi_probe_exit);
diff --git a/drivers/mtd/doc2000.c b/drivers/mtd/doc2000.c
index eeb49a4eb..cef67512b 100644
--- a/drivers/mtd/doc2000.c
+++ b/drivers/mtd/doc2000.c
@@ -392,7 +392,16 @@ static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
}
-void DoC2k_init(struct mtd_info *mtd)
+static const char im_name[] = "DoC2k_init";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoC2k_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
struct DiskOnChip *old = NULL;
@@ -460,8 +469,6 @@ void DoC2k_init(struct mtd_info *mtd)
}
-EXPORT_SYMBOL(DoC2k_init);
-
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
/* Just a special case of doc_read_ecc */
@@ -805,6 +812,12 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
+static int __init init_doc2000(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &DoC2k_init);
+ return 0;
+}
+
#if LINUX_VERSION_CODE < 0x20300
#ifdef MODULE
#define cleanup_doc2000 cleanup_module
@@ -828,10 +841,12 @@ static void __exit cleanup_doc2000(void)
kfree(this->chips);
kfree(mtd);
}
+ inter_module_unregister(im_name);
}
+module_init(init_doc2000);
+
#if LINUX_VERSION_CODE > 0x20300
module_exit(cleanup_doc2000);
#endif
-
diff --git a/drivers/mtd/doc2001.c b/drivers/mtd/doc2001.c
index 26a107722..8a9f03235 100644
--- a/drivers/mtd/doc2001.c
+++ b/drivers/mtd/doc2001.c
@@ -321,6 +321,15 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
return retval;
}
+static const char im_name[] = "DoCMil_init";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
void DoCMil_init(struct mtd_info *mtd)
{
struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
@@ -386,8 +395,6 @@ void DoCMil_init(struct mtd_info *mtd)
}
}
-EXPORT_SYMBOL(DoCMil_init);
-
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -780,6 +787,12 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
*
****************************************************************************/
+static int __init init_doc2001(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &DoCMil_init);
+ return 0;
+}
+
#if LINUX_VERSION_CODE < 0x20300
#ifdef MODULE
#define cleanup_doc2001 cleanup_module
@@ -803,10 +816,12 @@ static void __exit cleanup_doc2001(void)
kfree(this->chips);
kfree(mtd);
}
+ inter_module_unregister(im_name);
}
+module_init(init_doc2001);
+
#if LINUX_VERSION_CODE > 0x20300
module_exit(cleanup_doc2001);
#endif
-
diff --git a/drivers/mtd/docprobe.c b/drivers/mtd/docprobe.c
index 7ab0a2d74..b38b4352d 100644
--- a/drivers/mtd/docprobe.c
+++ b/drivers/mtd/docprobe.c
@@ -26,11 +26,8 @@
#define DOC_PASSIVE_PROBE
*/
-
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/kmod.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -62,12 +59,6 @@ static unsigned long __initdata doc_locations[] = {
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
-#ifdef CONFIG_MTD_DOC2000
-extern void DoC2k_init(struct mtd_info *);
-#endif
-#ifdef CONFIG_MTD_DOC2001
-extern void DoCMil_init(struct mtd_info *);
-#endif
/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
@@ -157,8 +148,9 @@ static void DoC_Probe(unsigned long physadr)
int ChipID;
char namebuf[15];
char *name = namebuf;
+ char *im_funcname = NULL;
+ char *im_modname = NULL;
void (*initroutine)(struct mtd_info *) = NULL;
- int initroutinedynamic = 0;
docptr = (unsigned long)ioremap(physadr, 0x2000);
@@ -189,42 +181,21 @@ static void DoC_Probe(unsigned long physadr)
switch(ChipID) {
case DOC_ChipID_Doc2k:
name="2000";
-#ifdef CONFIG_MTD_DOC2000
- initroutine = &DoC2k_init;
-#elif CONFIG_MODULES
- initroutinedynamic=1;
- initroutine = (void *)get_module_symbol(NULL, "DoC2k_init");
-#ifdef CONFIG_KMOD
- if (!initroutine) {
- request_module("doc2000");
- initroutine = (void *)get_module_symbol("doc2000", "DoC2k_init");
- }
-#endif /* CONFIG_KMOD */
-#endif
+ im_funcname = "DoC2k_init";
+ im_modname = "doc2000";
break;
case DOC_ChipID_DocMil:
name="Millennium";
-#ifdef CONFIG_MTD_DOC2001
- initroutine = &DoCMil_init;
-#elif CONFIG_MODULES
- initroutinedynamic=1;
- initroutine = (void *)get_module_symbol(NULL, "DoCMil_init");
-#ifdef CONFIG_KMOD
- if (!initroutine) {
- request_module("doc2001");
- initroutine = (void *)get_module_symbol("doc2001", "DoCMil_init");
- }
-#endif /* CONFIG_KMOD */
-#endif
+ im_funcname = "DoCMil_init";
+ im_modname = "doc2001";
break;
}
+ if (im_funcname)
+ initroutine = inter_module_get_request(im_funcname, im_modname);
if (initroutine) {
(*initroutine)(mtd);
-#if defined(CONFIG_MODULES) && LINUX_VERSION_CODE >= 0x20400
- if (initroutinedynamic)
- put_module_symbol(initroutine);
-#endif
+ inter_module_put(im_funcname);
return;
}
printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr);
diff --git a/drivers/mtd/map_ram.c b/drivers/mtd/map_ram.c
index 706f7f5ff..c62515406 100644
--- a/drivers/mtd/map_ram.c
+++ b/drivers/mtd/map_ram.c
@@ -20,10 +20,16 @@ static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_ch
static int mapram_erase (struct mtd_info *, struct erase_info *);
static void mapram_nop (struct mtd_info *);
-struct mtd_info *map_ram_probe(struct map_info *);
-EXPORT_SYMBOL(map_ram_probe);
-
-struct mtd_info *map_ram_probe(struct map_info *map)
+static const char im_name[] = "map_ram_probe";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static struct mtd_info *map_ram_probe(struct map_info *map)
{
struct mtd_info *mtd;
@@ -63,9 +69,9 @@ struct mtd_info *map_ram_probe(struct map_info *map)
mtd->read = mapram_read;
mtd->write = mapram_write;
mtd->sync = mapram_nop;
+ mtd->im_name = im_name;
mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
- MOD_INC_USE_COUNT;
return mtd;
}
@@ -108,3 +114,17 @@ static void mapram_nop(struct mtd_info *mtd)
{
/* Nothing to see here */
}
+
+static int __init map_ram_init(void)
+{
+ inter_module_register(im_name, THIS_MODULE, &map_ram_probe);
+ return 0;
+}
+
+static void __exit map_ram_exit(void)
+{
+ inter_module_unregister(im_name);
+}
+
+module_init(map_ram_init);
+module_exit(map_ram_exit);
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 76602ac54..c9be23bf6 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -234,7 +234,9 @@ struct net_local
int __init el1_probe(struct net_device *dev)
{
int i;
- int base_addr = dev ? dev->base_addr : 0;
+ int base_addr = dev->base_addr;
+
+ SET_MODULE_OWNER(dev);
if (base_addr > 0x1ff) /* Check a single specified location. */
return el1_probe1(dev, base_addr);
@@ -398,19 +400,16 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
static int el_open(struct net_device *dev)
{
+ int retval;
int ioaddr = dev->base_addr;
struct net_local *lp = (struct net_local *)dev->priv;
unsigned long flags;
- MOD_INC_USE_COUNT;
-
if (el_debug > 2)
printk("%s: Doing el_open()...", dev->name);
- if (request_irq(dev->irq, &el_interrupt, 0, "3c501", dev)) {
- MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
+ if ((retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev)))
+ return retval;
spin_lock_irqsave(&lp->lock, flags);
el_reset(dev);
@@ -862,7 +861,6 @@ static int el1_close(struct net_device *dev)
free_irq(dev->irq, dev);
outb(AX_RESET, AX_CMD); /* Reset the chip */
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -916,12 +914,10 @@ static void set_multicast_list(struct net_device *dev)
#ifdef MODULE
-static struct net_device dev_3c501 =
-{
- "", /* device name is inserted by linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0x280, 5,
- 0, 0, 0, NULL, el1_probe
+static struct net_device dev_3c501 = {
+ init: el1_probe,
+ base_addr: 0x280,
+ irq: 5,
};
static int io=0x280;
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 06745646c..6db67d817 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -87,6 +87,8 @@ el2_probe(struct net_device *dev)
int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
int base_addr = dev->base_addr;
+ SET_MODULE_OWNER(dev);
+
if (base_addr > 0x1ff) /* Check a single specified location. */
return el2_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -101,8 +103,6 @@ el2_probe(struct net_device *dev)
break;
if (base_bits != 1)
continue;
- if (check_region(netcard_portlist[i], EL2_IO_EXTENT))
- continue;
if (el2_probe1(dev, netcard_portlist[i]) == 0)
return 0;
}
@@ -126,13 +126,9 @@ el2_pio_probe(struct net_device *dev)
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
- for (i = 0; netcard_portlist[i]; i++) {
- int ioaddr = netcard_portlist[i];
- if (check_region(ioaddr, EL2_IO_EXTENT))
- continue;
- if (el2_probe1(dev, ioaddr) == 0)
+ for (i = 0; netcard_portlist[i]; i++)
+ if (el2_probe1(dev, netcard_portlist[i]) == 0)
return 0;
- }
return -ENODEV;
}
@@ -143,14 +139,18 @@ el2_pio_probe(struct net_device *dev)
int __init
el2_probe1(struct net_device *dev, int ioaddr)
{
- int i, iobase_reg, membase_reg, saved_406, wordlength;
- static unsigned version_printed = 0;
+ int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
+ static unsigned version_printed;
unsigned long vendor_id;
+ if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name))
+ return -EBUSY;
+
/* Reset and/or avoid any lurking NE2000 */
if (inb(ioaddr + 0x408) == 0xff) {
mdelay(1);
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
/* We verify that it's a 3C503 board by checking the first three octets
@@ -160,7 +160,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
/* ASIC location registers should be 0 or have only a single bit set. */
if ( (iobase_reg & (iobase_reg - 1))
|| (membase_reg & (membase_reg - 1))) {
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
saved_406 = inb_p(ioaddr + 0x406);
outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */
@@ -172,7 +173,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
if ((vendor_id != OLD_3COM_ID) && (vendor_id != NEW_3COM_ID)) {
/* Restore the register we frobbed. */
outb(saved_406, ioaddr + 0x406);
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
if (ei_debug && version_printed++ == 0)
@@ -182,8 +184,9 @@ el2_probe1(struct net_device *dev, int ioaddr)
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
printk ("3c503: unable to allocate memory for dev->priv.\n");
- return -ENOMEM;
- }
+ retval = -ENOMEM;
+ goto out;
+ }
printk("%s: 3c503 at i/o base %#3x, node ", dev->name, ioaddr);
@@ -282,8 +285,6 @@ el2_probe1(struct net_device *dev, int ioaddr)
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
- request_region(ioaddr, EL2_IO_EXTENT, ei_status.name);
-
if (dev->irq == 2)
dev->irq = 9;
else if (dev->irq > 5 && dev->irq != 9) {
@@ -310,6 +311,9 @@ el2_probe1(struct net_device *dev, int ioaddr)
dev->name, ei_status.name, (wordlength+1)<<3);
}
return 0;
+out:
+ release_region(ioaddr, EL2_IO_EXTENT);
+ return retval;
}
static int
@@ -324,10 +328,10 @@ el2_open(struct net_device *dev)
do {
if (request_irq (*irqp, NULL, 0, "bogus", dev) != -EBUSY) {
/* Twinkle the interrupt, and check if it's seen. */
- autoirq_setup(0);
+ unsigned long cookie = probe_irq_on();
outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
- if (*irqp == autoirq_report(0) /* It's a good IRQ line! */
+ if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */
&& request_irq (dev->irq = *irqp, ei_interrupt, 0, ei_status.name, dev) == 0)
break;
}
@@ -344,7 +348,6 @@ el2_open(struct net_device *dev)
el2_init_card(dev);
ei_open(dev);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -356,7 +359,6 @@ el2_close(struct net_device *dev)
outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
ei_close(dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -602,18 +604,10 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
#ifdef MODULE
#define MAX_EL2_CARDS 4 /* Max number of EL2 cards per module */
-static struct net_device dev_el2[MAX_EL2_CARDS] = {
- {
- "",
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, NULL
- },
-};
-
-static int io[MAX_EL2_CARDS] = { 0, };
-static int irq[MAX_EL2_CARDS] = { 0, };
-static int xcvr[MAX_EL2_CARDS] = { 0, }; /* choose int. or ext. xcvr */
+static struct net_device dev_el2[MAX_EL2_CARDS];
+static int io[MAX_EL2_CARDS];
+static int irq[MAX_EL2_CARDS];
+static int xcvr[MAX_EL2_CARDS]; /* choose int. or ext. xcvr */
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
@@ -625,9 +619,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("3c503.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_EL2_CARDS; this_dev++) {
struct net_device *dev = &dev_el2[this_dev];
dev->irq = irq[this_dev];
@@ -643,7 +634,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -666,7 +656,6 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 22485f1d8..d967bb176 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -854,6 +854,7 @@ static void elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
static int elp_open(struct net_device *dev)
{
elp_device *adapter;
+ int retval;
adapter = dev->priv;
@@ -893,16 +894,21 @@ static int elp_open(struct net_device *dev)
/*
* install our interrupt service routine
*/
- if (request_irq(dev->irq, &elp_interrupt, 0, "3c505", dev)) {
- return -EAGAIN;
+ if ((retval = request_irq(dev->irq, &elp_interrupt, 0, dev->name, dev))) {
+ printk(KERN_ERR "%s: could not allocate IRQ%d\n", dev->name, dev->irq);
+ return retval;
}
- if (request_dma(dev->dma, "3c505")) {
- printk("%s: could not allocate DMA channel\n", dev->name);
- return -EAGAIN;
+ if ((retval = request_dma(dev->dma, dev->name))) {
+ free_irq(dev->irq, dev);
+ printk(KERN_ERR "%s: could not allocate DMA%d channel\n", dev->name, dev->dma);
+ return retval;
}
adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
if (!adapter->dma_buffer) {
- printk("Could not allocate DMA buffer\n");
+ printk(KERN_ERR "%s: could not allocate DMA buffer\n", dev->name);
+ free_dma(dev->dma);
+ free_irq(dev->irq, dev);
+ return -ENOMEM;
}
adapter->dmaing = 0;
@@ -915,7 +921,7 @@ static int elp_open(struct net_device *dev)
* configure adapter memory: we need 10 multicast addresses, default==0
*/
if (elp_debug >= 3)
- printk("%s: sending 3c505 memory configuration command\n", dev->name);
+ printk(KERN_DEBUG "%s: sending 3c505 memory configuration command\n", dev->name);
adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
adapter->tx_pcb.data.memconf.cmd_q = 10;
adapter->tx_pcb.data.memconf.rcv_q = 20;
@@ -967,10 +973,8 @@ static int elp_open(struct net_device *dev)
* device is now officially open!
*/
- netif_wake_queue(dev);
- MOD_INC_USE_COUNT;
-
- return 0; /* Always succeed */
+ netif_start_queue(dev);
+ return 0;
}
@@ -1178,8 +1182,6 @@ static int elp_close(struct net_device *dev)
free_dma(dev->dma);
free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -1412,6 +1414,9 @@ int __init elplus_probe(struct net_device *dev)
{
elp_device *adapter;
int i, tries, tries1, timeout, okay;
+ unsigned long cookie = 0;
+
+ SET_MODULE_OWNER(dev);
/*
* setup adapter structure
@@ -1479,21 +1484,21 @@ int __init elplus_probe(struct net_device *dev)
*/
adapter->tx_pcb.command = CMD_STATION_ADDRESS;
adapter->tx_pcb.length = 0;
- autoirq_setup(0);
+ cookie = probe_irq_on();
if (!send_pcb(dev, &adapter->tx_pcb)) {
printk("%s: could not send first PCB\n", dev->name);
- autoirq_report(0);
+ probe_irq_off(cookie);
continue;
}
if (!receive_pcb(dev, &adapter->rx_pcb)) {
printk("%s: could not read first PCB\n", dev->name);
- autoirq_report(0);
+ probe_irq_off(cookie);
continue;
}
if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
(adapter->rx_pcb.length != 6)) {
printk("%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length);
- autoirq_report(0);
+ probe_irq_off(cookie);
continue;
}
goto okay;
@@ -1511,13 +1516,13 @@ int __init elplus_probe(struct net_device *dev)
okay:
if (dev->irq) { /* Is there a preset IRQ? */
- int rpt = autoirq_report(0);
+ int rpt = probe_irq_off(cookie);
if (dev->irq != rpt) {
printk("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
}
- /* if dev->irq == autoirq_report(0), all is well */
+ /* if dev->irq == probe_irq_off(cookie), all is well */
} else /* No preset IRQ; just use what we can detect */
- dev->irq = autoirq_report(0);
+ dev->irq = probe_irq_off(cookie);
switch (dev->irq) { /* Legal, sane? */
case 0:
printk("%s: IRQ probe failed: check 3c505 jumpers.\n",
@@ -1527,7 +1532,7 @@ int __init elplus_probe(struct net_device *dev)
case 6:
case 8:
case 13:
- printk("%s: Impossible IRQ %d reported by autoirq_report().\n",
+ printk("%s: Impossible IRQ %d reported by probe_irq_off().\n",
dev->name, dev->irq);
return -ENODEV;
}
@@ -1607,17 +1612,10 @@ int __init elplus_probe(struct net_device *dev)
}
#ifdef MODULE
-static struct net_device dev_3c505[ELP_MAX_CARDS] =
-{
- { "", /* device name is inserted by net_init.c */
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, NULL, elplus_probe},
-};
-
-static int io[ELP_MAX_CARDS] = { 0, };
-static int irq[ELP_MAX_CARDS] = { 0, };
-static int dma[ELP_MAX_CARDS] = { 0, };
+static struct net_device dev_3c505[ELP_MAX_CARDS];
+static int io[ELP_MAX_CARDS];
+static int irq[ELP_MAX_CARDS];
+static int dma[ELP_MAX_CARDS];
MODULE_PARM(io, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
MODULE_PARM(dma, "1-" __MODULE_STRING(ELP_MAX_CARDS) "i");
@@ -1630,6 +1628,7 @@ int init_module(void)
struct net_device *dev = &dev_3c505[this_dev];
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
+ dev->init = elplus_probe;
if (dma[this_dev]) {
dev->dma = dma[this_dev];
} else {
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index b792c4dd1..8d7e1a163 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -304,9 +304,11 @@ static void init_82586_mem(struct net_device *dev);
int __init el16_probe(struct net_device *dev)
{
- int base_addr = dev ? dev->base_addr : 0;
+ int base_addr = dev->base_addr;
int i;
+ SET_MODULE_OWNER(dev);
+
if (base_addr > 0x1ff) /* Check a single specified location. */
return el16_probe1(dev, base_addr);
else if (base_addr != 0)
@@ -339,7 +341,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
init_ID_done = 1;
}
- if (!request_region(ioaddr, EL16_IO_EXTENT, "3c507"))
+ if (!request_region(ioaddr, EL16_IO_EXTENT, dev->name))
return -ENODEV;
if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
@@ -358,7 +360,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
- irqval = request_irq(irq, &el16_interrupt, 0, "3c507", dev);
+ irqval = request_irq(irq, &el16_interrupt, 0, dev->name, dev);
if (irqval) {
printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval);
retval = -EAGAIN;
@@ -439,9 +441,6 @@ static int el16_open(struct net_device *dev)
init_82586_mem(dev);
netif_start_queue(dev);
-
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -624,8 +623,6 @@ static int el16_close(struct net_device *dev)
/* Update the statistics here. */
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -857,8 +854,7 @@ static void el16_rx(struct net_device *dev)
lp->rx_tail = rx_tail;
}
#ifdef MODULE
-static struct net_device dev_3c507 = { init: el16_probe };
-
+static struct net_device dev_3c507;
static int io = 0x300;
static int irq = 0;
MODULE_PARM(io, "i");
@@ -870,6 +866,7 @@ int init_module(void)
printk("3c507: You should not use auto-probing with insmod!\n");
dev_3c507.base_addr = io;
dev_3c507.irq = irq;
+ dev_3c507.init = el16_probe;
if (register_netdev(&dev_3c507) != 0) {
printk("3c507: register_netdev() returned non-zero.\n");
return -EIO;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index ae3523a7c..7cb2ff7be 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -200,6 +200,8 @@ int el3_probe(struct net_device *dev)
static int pnp_cards = 0;
#endif /* __ISAPNP__ */
+ if (dev) SET_MODULE_OWNER(dev);
+
/* First check all slots of the EISA bus. The next slot address to
probe is kept in 'eisa_addr' to support multiple probe() calls. */
if (EISA_bus) {
@@ -434,6 +436,14 @@ no_pnp:
/* Free the interrupt so that some other card can use it. */
outw(0x0f00, ioaddr + WN0_IRQ);
found:
+ if (dev == NULL) {
+ dev = init_etherdev(dev, sizeof(struct el3_private));
+ if (dev == NULL) {
+ release_region(ioaddr, EL3_IO_EXTENT);
+ return -ENOMEM;
+ }
+ SET_MODULE_OWNER(dev);
+ }
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -523,9 +533,8 @@ el3_open(struct net_device *dev)
outw(RxReset, ioaddr + EL3_CMD);
outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
- if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) {
- return -EAGAIN;
- }
+ i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev);
+ if (i) return i;
EL3WINDOW(0);
if (el3_debug > 3)
@@ -584,8 +593,7 @@ el3_open(struct net_device *dev)
printk("%s: Opened 3c509 IRQ %d status %4.4x.\n",
dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
- MOD_INC_USE_COUNT;
- return 0; /* Always succeed */
+ return 0;
}
static void
@@ -962,7 +970,6 @@ el3_close(struct net_device *dev)
outw(0x0f00, ioaddr + WN0_IRQ);
update_stats(dev);
- MOD_DEC_USE_COUNT;
return 0;
}
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index da7d27ac5..df9786b81 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -428,6 +428,8 @@ int tc515_probe(struct net_device *dev)
{
int cards_found = 0;
+ SET_MODULE_OWNER(dev);
+
cards_found = corkscrew_scan(dev);
if (corkscrew_debug > 0 && cards_found)
@@ -561,6 +563,8 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
sizeof(struct corkscrew_private) + 15; /* Pad for alignment */
dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL);
+ if (!dev)
+ return NULL;
memset(dev, 0, dev_size);
/* Align the Rx and Tx ring entries. */
dev->priv =
@@ -586,15 +590,16 @@ static struct net_device *corkscrew_found_device(struct net_device *dev,
ether_setup(dev);
vp->next_module = root_corkscrew_dev;
root_corkscrew_dev = dev;
- if (register_netdev(dev) != 0)
- return 0;
-#else /* not a MODULE */
- if (dev) {
- /* Caution: quad-word alignment required for rings! */
- dev->priv =
- kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct corkscrew_private));
+ if (register_netdev(dev) != 0) {
+ kfree(dev);
+ return NULL;
}
+ SET_MODULE_OWNER(dev);
+#else /* not a MODULE */
+ /* Caution: quad-word alignment required for rings! */
+ dev->priv =
+ kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct corkscrew_private));
dev = init_etherdev(dev, sizeof(struct corkscrew_private));
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -874,8 +879,6 @@ static int corkscrew_open(struct net_device *dev)
| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
ioaddr + EL3_CMD);
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -1500,8 +1503,6 @@ static int corkscrew_close(struct net_device *dev)
}
}
- MOD_DEC_USE_COUNT;
-
return 0;
}
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 7703e1415..12f9f0a9d 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -271,7 +271,6 @@ static int elmc_close(struct net_device *dev)
netif_stop_queue(dev);
elmc_id_reset586(); /* the hard way to stop the receiver */
free_irq(dev->irq, dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -281,21 +280,21 @@ static int elmc_close(struct net_device *dev)
static int elmc_open(struct net_device *dev)
{
+ int ret;
elmc_id_attn586(); /* disable interrupts */
- if (request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM,
- "3c523", dev)
- ) {
+ ret = request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM,
+ dev->name, dev);
+ if (ret) {
printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq);
elmc_id_reset586();
- return -EAGAIN;
+ return ret;
}
alloc586(dev);
init586(dev);
startrecv586(dev);
netif_start_queue(dev);
- MOD_INC_USE_COUNT;
return 0; /* most done by init */
}
@@ -409,13 +408,14 @@ static int elmc_getinfo(char *buf, int slot, void *d)
int __init elmc_probe(struct net_device *dev)
{
static int slot = 0;
- int base_addr = dev ? dev->base_addr : 0;
- int irq = dev ? dev->irq : 0;
+ int base_addr = dev->base_addr;
+ int irq = dev->irq;
u_char status = 0;
u_char revision = 0;
int i = 0;
unsigned int size = 0;
+ SET_MODULE_OWNER(dev);
if (MCA_bus == 0) {
return -ENODEV;
}
@@ -1208,15 +1208,9 @@ static void set_multicast_list(struct net_device *dev)
/* Increase if needed ;) */
#define MAX_3C523_CARDS 4
-static struct net_device dev_elmc[MAX_3C523_CARDS] =
-{
- {
- "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
- },
-};
-
-static int irq[MAX_3C523_CARDS] = {0,};
-static int io[MAX_3C523_CARDS] = {0,};
+static struct net_device dev_elmc[MAX_3C523_CARDS];
+static int irq[MAX_3C523_CARDS];
+static int io[MAX_3C523_CARDS];
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 2a8f82e83..73d3a35b3 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -184,6 +184,8 @@ int __init mc32_probe(struct net_device *dev)
int i;
int adapter_found = 0;
+ SET_MODULE_OWNER(dev);
+
/* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
@@ -347,25 +349,22 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
* Grab the IRQ
*/
- if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev))
- {
- printk("%s: unable to get IRQ %d.\n",
- dev->name, dev->irq);
- return -EAGAIN;
+ i = request_irq(dev->irq, &mc32_interrupt, 0, dev->name, dev);
+ if (i) {
+ printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return i;
}
/* Initialize the device structure. */
- if (dev->priv == NULL) {
- dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
- if (dev->priv == NULL)
- {
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
+ dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ {
+ free_irq(dev->irq, dev);
+ return -ENOMEM;
}
memset(dev->priv, 0, sizeof(struct mc32_local));
- lp = (struct mc32_local *)dev->priv;
+ lp = dev->priv;
lp->slot = slot;
i=0;
@@ -897,8 +896,6 @@ static int mc32_open(struct net_device *dev)
mc32_tx_begin(dev);
netif_start_queue(dev);
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -1318,8 +1315,6 @@ static int mc32_close(struct net_device *dev)
/* Update the statistics here. */
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -1444,7 +1439,7 @@ static void mc32_reset_multicast_list(struct net_device *dev)
#ifdef MODULE
-static struct net_device this_device = { init: mc32_probe };
+static struct net_device this_device;
/**
@@ -1459,6 +1454,7 @@ int init_module(void)
{
int result;
+ this_device.init = mc32_probe;
if ((result = register_netdev(&this_device)) != 0)
return result;
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 1eefdfb71..ae4054d35 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -98,7 +98,7 @@
- Added INVERT_LED_PWR, used it.
- Backed out the extra_reset stuff
- LK1.1.9 2 Sep 2000 andrewm
+ LK1.1.9 12 Sep 2000 andrewm
- Backed out the tx_reset_resume flags. It was a no-op.
- In vortex_error, don't reset the Tx on txReclaim errors
- In vortex_error, don't reset the Tx on maxCollisions errors.
@@ -110,6 +110,14 @@
is downed, it remains set when the interface is upped. Bad
things happen.
+ LK1.1.10 17 Sep 2000 andrewm
+ - Added EEPROM_8BIT for 3c555 (Fred Maciel)
+ - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg)
+ - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
+
+ LK1.1.11 13 Nov 2000 andrewm
+ - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER
+
- See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
- Also see Documentation/networking/vortex.txt
*/
@@ -195,7 +203,7 @@ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
#include <linux/delay.h>
static char version[] __devinitdata =
-"3c59x.c:LK1.1.9 2 Sep 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.38 $\n";
+"3c59x.c:LK1.1.11 13 Nov 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
@@ -315,8 +323,8 @@ enum pci_flags_bit {
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
- INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800 };
-
+ INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
+ EEPROM_OFFSET=0x1000 };
enum vortex_chips {
CH_3C590 = 0,
@@ -346,15 +354,16 @@ enum vortex_chips {
CH_3CSOHO100_TX,
CH_3C555,
CH_3C556,
+ CH_3C556B,
CH_3C575,
- CH_3C575_1,
+ CH_3C575_1,
CH_3CCFE575,
CH_3CCFE575CT,
CH_3CCFE656,
CH_3CCFEM656,
- CH_3CCFEM656_1,
+ CH_3CCFEM656_1,
CH_3C450,
};
@@ -388,7 +397,7 @@ static struct vortex_chip_info {
{"3c900 Boomerang 10Mbps Combo",
PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
{"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
{"3c900 Cyclone 10Mbps Combo",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
@@ -417,14 +426,16 @@ static struct vortex_chip_info {
{"3cSOHO100-TX Hurricane",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
{"3c555 Laptop Hurricane",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
- {"3c556 10/100 Mini PCI Adapter",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, },
+ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, },
+ {"3c556 Laptop Tornado",
+ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, },
+ {"3c556B Laptop Hurricane",
+ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR, 128, },
{"3c575 [Megahertz] 10/100 LAN CardBus",
PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+
{"3c575 Boomerang CardBus",
PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
-
{"3CCFE575BT Cyclone CardBus",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, },
{"3CCFE575CT Tornado CardBus",
@@ -433,9 +444,9 @@ static struct vortex_chip_info {
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
{"3CCFEM656B Cyclone+Winmodem CardBus",
PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
+
{"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */
PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, },
-
{"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */
PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
{0,}, /* 0 terminated list. */
@@ -470,15 +481,16 @@ static struct pci_device_id vortex_pci_tbl[] __devinitdata = {
{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
{ 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 },
+ { 0x10B7, 0x6056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556B },
{ 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 },
- { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
+ { 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
{ 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
- { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
+ { 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
{0,} /* 0 terminated list. */
};
@@ -869,7 +881,8 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
retval = -ENOMEM;
goto out;
}
-
+ SET_MODULE_OWNER(dev);
+
printk(KERN_INFO "%s: 3Com %s %s at 0x%lx, ",
dev->name,
pdev ? "PCI" : "EISA",
@@ -963,7 +976,15 @@ static int __devinit vortex_probe1(struct pci_dev *pdev,
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
{
- int base = (vci->drv_flags & EEPROM_8BIT) ? 0x230 : EEPROM_Read;
+ int base;
+
+ if (vci->drv_flags & EEPROM_8BIT)
+ base = 0x230;
+ else if (vci->drv_flags & EEPROM_OFFSET)
+ base = EEPROM_Read + 0x30;
+ else
+ base = EEPROM_Read;
+
for (i = 0; i < 0x40; i++) {
int timer;
outw(base + i, ioaddr + Wn0EepromCmd);
@@ -1338,8 +1359,6 @@ vortex_open(struct net_device *dev)
int i;
int retval;
- MOD_INC_USE_COUNT;
-
/* Use the now-standard shared IRQ implementation. */
if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
&boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) {
@@ -1388,7 +1407,6 @@ out_free_irq:
out:
if (vortex_debug > 1)
printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
- MOD_DEC_USE_COUNT;
return retval;
}
@@ -2265,7 +2283,6 @@ vortex_close(struct net_device *dev)
}
}
- MOD_DEC_USE_COUNT;
vp->open = 0;
return 0;
}
@@ -2550,7 +2567,6 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev)
vp = (void *)(dev->priv);
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
/* AKPM: FIXME: we should have
* if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
* here
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index f47ee2462..b26b06302 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -72,7 +72,7 @@
Jean-Jacques Michel - bug fix
- Tobias - Rx interrupt status checking suggestion
+ Tobias Ringström - Rx interrupt status checking suggestion
Submitting bug reports:
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 24cad4416..eb3253b82 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1092,7 +1092,7 @@ int __init i82596_probe(struct net_device *dev)
{
int i;
struct i596_private *lp;
- char eth_addr[6];
+ char eth_addr[8];
static int probed = 0;
if (probed)
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 2998ff93a..e1768d71e 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -63,23 +63,23 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool ' 3COM cards' CONFIG_NET_VENDOR_3COM
if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
- tristate ' 3c501 "EtherLink" support' CONFIG_EL1
- tristate ' 3c503 "EtherLink II" support' CONFIG_EL2
- tristate ' 3c505 "EtherLink Plus" support' CONFIG_ELPLUS
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' 3c507 "EtherLink 16" support (EXPERIMENTAL)' CONFIG_EL16
+ dep_tristate ' 3c501 "EtherLink" support' CONFIG_EL1 $CONFIG_ISA
+ dep_tristate ' 3c503 "EtherLink II" support' CONFIG_EL2 $CONFIG_ISA
+ dep_tristate ' 3c505 "EtherLink Plus" support' CONFIG_ELPLUS $CONFIG_ISA
+ dep_tristate ' 3c507 "EtherLink 16" support (EXPERIMENTAL)' CONFIG_EL16 $CONFIG_ISA $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+ tristate ' 3c509/3c529 (MCA)/3c579 "EtherLink III" support' CONFIG_EL3
fi
- tristate ' 3c509/3c529 (MCA)/3c579 "EtherLink III" support' CONFIG_EL3
- tristate ' 3c515 ISA "Fast EtherLink"' CONFIG_3C515
- if [ "$CONFIG_MCA" = "y" ]; then
- tristate ' 3c523 "EtherLink/MC" support' CONFIG_ELMC
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' 3c527 "EtherLink/MC 32" support (EXPERIMENTAL)' CONFIG_ELMC_II
- fi
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
+ tristate ' 3c515 ISA "Fast EtherLink"' CONFIG_3C515
+ fi
+ dep_tristate ' 3c523 "EtherLink/MC" support' CONFIG_ELMC $CONFIG_MCA
+ dep_tristate ' 3c527 "EtherLink/MC 32" support (EXPERIMENTAL)' CONFIG_ELMC_II $CONFIG_MCA $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+ tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
fi
- tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
fi
- tristate ' AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+ dep_tristate ' AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
bool ' Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
tristate ' WD80*3 support' CONFIG_WD80x3
@@ -87,23 +87,23 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA
fi
tristate ' SMC Ultra support' CONFIG_ULTRA
- tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32
+ dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
tristate ' SMC 9194 support' CONFIG_SMC9194
- fi
- bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
- if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010
- fi
- tristate ' NI5210 support' CONFIG_NI52
- tristate ' NI6510 support' CONFIG_NI65
- fi
+ fi
+ bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+ if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
+ dep_tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_EXPERIMENTAL
+ tristate ' NI5210 support' CONFIG_NI52
+ tristate ' NI6510 support' CONFIG_NI65
+ fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
fi
tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
- tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
- bool ' Other ISA cards' CONFIG_NET_ISA
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+ tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
+ fi
+ dep_bool ' Other ISA cards' CONFIG_NET_ISA $CONFIG_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
tristate ' Cabletron E21xx support' CONFIG_E2100
if [ "$CONFIG_OBSOLETE" = "y" ]; then
@@ -130,43 +130,38 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
if [ "$CONFIG_NET_PCI" = "y" ]; then
- tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
+ dep_tristate ' AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
dep_tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
+ dep_tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
fi
tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
- tristate ' CS89x0 support' CONFIG_CS89x0
- tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ dep_tristate ' CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
dep_tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
- tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+ tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
fi
+ dep_tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then
- bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM
- fi
- tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
- fi
+ dep_mbool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
+ dep_tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
- dep_tristate ' RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI
- fi
+ dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
+ dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
+ dep_tristate ' RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
- tristate ' TI ThunderLAN support' CONFIG_TLAN
+ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+ tristate ' TI ThunderLAN support' CONFIG_TLAN
+ fi
dep_tristate ' VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
dep_tristate ' Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
+ dep_tristate ' Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI
if [ "$CONFIG_OBSOLETE" = "y" ]; then
bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
fi
@@ -176,9 +171,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
bool ' Pocket and portable adapters' CONFIG_NET_POCKET
if [ "$CONFIG_NET_POCKET" = "y" ]; then
- if [ "$CONFIG_X86" = "y" ]; then
- tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
- fi
+ dep_tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP $CONFIG_ISA
tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
fi
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 1edf73833..ebdcd30e8 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -459,14 +459,6 @@ static int __init fddiif_probe(struct net_device *dev)
#endif
-/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
-#define __PAD6 "\0\0\0\0\0\0\0\0\0"
-#define __PAD5 __PAD6 "\0"
-#define __PAD4 __PAD5 "\0"
-#define __PAD3 __PAD4 "\0"
-#define __PAD2 __PAD3 "\0"
-
-
#ifdef CONFIG_NET_FC
static int fcif_probe(struct net_device *dev)
{
@@ -486,14 +478,14 @@ static int fcif_probe(struct net_device *dev)
#ifdef CONFIG_ETHERTAP
- static struct net_device tap0_dev = { "tap0" __PAD4, 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
+ static struct net_device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
# undef NEXT_DEV
# define NEXT_DEV (&tap0_dev)
#endif
#ifdef CONFIG_SDLA
extern int sdla_init(struct net_device *);
- static struct net_device sdla0_dev = { "sdla0" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, };
+ static struct net_device sdla0_dev = { "sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, };
# undef NEXT_DEV
# define NEXT_DEV (&sdla0_dev)
@@ -502,7 +494,7 @@ static int fcif_probe(struct net_device *dev)
#if defined(CONFIG_LTPC)
extern int ltpc_probe(struct net_device *);
static struct net_device dev_ltpc = {
- "lt0" __PAD3,
+ "lt0",
0, 0, 0, 0,
0x0, 0,
0, 0, 0, NEXT_DEV, ltpc_probe };
@@ -512,9 +504,9 @@ static int fcif_probe(struct net_device *dev)
#if defined(CONFIG_COPS)
extern int cops_probe(struct net_device *);
- static struct net_device cops2_dev = { "lt2" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe };
- static struct net_device cops1_dev = { "lt1" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe };
- static struct net_device cops0_dev = { "lt0" __PAD3, 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe };
+ static struct net_device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe };
+ static struct net_device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe };
+ static struct net_device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe };
# undef NEXT_DEV
# define NEXT_DEV (&cops0_dev)
#endif /* COPS */
@@ -535,22 +527,22 @@ static int fcif_probe(struct net_device *dev)
#define ETH_NOPROBE_ADDR 0xffe0
static struct net_device eth7_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
static struct net_device eth6_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
static struct net_device eth5_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
static struct net_device eth4_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
static struct net_device eth3_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
static struct net_device eth2_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
static struct net_device eth1_dev = {
- "eth%d" __PAD5, 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
+ "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
static struct net_device eth0_dev = {
- "eth%d" __PAD5, 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
+ "eth%d", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
# undef NEXT_DEV
# define NEXT_DEV (&eth0_dev)
@@ -582,21 +574,21 @@ trif_probe(struct net_device *dev)
return 0;
}
static struct net_device tr7_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe };
static struct net_device tr6_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe };
static struct net_device tr5_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe };
static struct net_device tr4_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe };
static struct net_device tr3_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe };
static struct net_device tr2_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe };
static struct net_device tr1_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe };
static struct net_device tr0_dev = {
- "tr%d" __PAD3,0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe };
+ "tr%d",0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe };
# undef NEXT_DEV
# define NEXT_DEV (&tr0_dev)
@@ -604,21 +596,21 @@ static struct net_device tr0_dev = {
#ifdef CONFIG_FDDI
static struct net_device fddi7_dev =
- {"fddi7" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe};
+ {"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe};
static struct net_device fddi6_dev =
- {"fddi6" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe};
+ {"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe};
static struct net_device fddi5_dev =
- {"fddi5" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe};
+ {"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe};
static struct net_device fddi4_dev =
- {"fddi4" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe};
+ {"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe};
static struct net_device fddi3_dev =
- {"fddi3" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe};
+ {"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe};
static struct net_device fddi2_dev =
- {"fddi2" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe};
+ {"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe};
static struct net_device fddi1_dev =
- {"fddi1" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe};
+ {"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe};
static struct net_device fddi0_dev =
- {"fddi0" __PAD5, 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe};
+ {"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe};
#undef NEXT_DEV
#define NEXT_DEV (&fddi0_dev)
#endif
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 498bd523f..af42b4441 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -261,7 +261,7 @@ static int init_restart_lance (struct lance_private *lp)
barrier();
if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
- return -1;
+ return -EIO;
}
/* Clear IDON by writing a "1", enable interrupts and start lance */
@@ -488,14 +488,14 @@ static int lance_open (struct net_device *dev)
{
struct lance_private *lp = (struct lance_private *)dev->priv;
volatile struct lance_regs *ll = lp->ll;
- int status = 0;
+ int ret;
last_dev = dev;
/* Install the Interrupt handler */
- if (request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
- "a2065 Ethernet", dev))
- return -EAGAIN;
+ ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
+ dev->name, dev);
+ if (ret) return ret;
/* Stop the Lance */
ll->rap = LE_CSR0;
@@ -506,11 +506,7 @@ static int lance_open (struct net_device *dev)
netif_start_queue(dev);
- status = init_restart_lance (lp);
-
- MOD_INC_USE_COUNT;
-
- return status;
+ return init_restart_lance (lp);
}
static int lance_close (struct net_device *dev)
@@ -526,9 +522,6 @@ static int lance_close (struct net_device *dev)
ll->rdp = LE_C0_STOP;
free_irq(IRQ_AMIGA_PORTS, dev);
-
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -727,6 +720,7 @@ static int __init a2065_probe(void)
while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
unsigned long board, base_addr, mem_start;
+ struct resource *r1, *r2;
int is_cbm;
if (z->id == ZORRO_PROD_CBM_A2065_1 ||
@@ -741,25 +735,27 @@ static int __init a2065_probe(void)
base_addr = board+A2065_LANCE;
mem_start = board+A2065_RAM;
- if (!request_mem_region(base_addr, sizeof(struct lance_regs),
- "Am7990"))
- continue;
- if (!request_mem_region(mem_start, A2065_RAM_SIZE, "RAM")) {
- release_mem_region(base_addr,
- sizeof(struct lance_regs));
+ r1 = request_mem_region(base_addr, sizeof(struct lance_regs),
+ "Am7990");
+ if (!r1) continue;
+ r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM");
+ if (!r2) {
+ release_resource(r1);
continue;
}
dev = init_etherdev(NULL, sizeof(struct lance_private));
if (dev == NULL) {
- release_mem_region(base_addr,
- sizeof(struct lance_regs));
- release_mem_region(mem_start, A2065_RAM_SIZE);
+ release_resource(r1);
+ release_resource(r2);
return -ENOMEM;
}
- priv = (struct lance_private *)dev->priv;
- memset(priv, 0, sizeof(struct lance_private));
+ SET_MODULE_OWNER(dev);
+ priv = dev->priv;
+
+ r1->name = dev->name;
+ r2->name = dev->name;
priv->dev = dev;
dev->dev_addr[0] = 0x00;
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 0e1c40bd4..c070fda58 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -99,6 +99,8 @@ int __init ac3200_probe(struct net_device *dev)
{
unsigned short ioaddr = dev->base_addr;
+ SET_MODULE_OWNER(dev);
+
if (ioaddr > 0x1ff) /* Check a single specified location. */
return ac_probe1(ioaddr, dev);
else if (ioaddr > 0) /* Don't probe at all. */
@@ -107,12 +109,9 @@ int __init ac3200_probe(struct net_device *dev)
if ( ! EISA_bus)
return -ENXIO;
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- if (check_region(ioaddr, AC_IO_EXTENT))
- continue;
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
if (ac_probe1(ioaddr, dev) == 0)
return 0;
- }
return -ENODEV;
}
@@ -121,8 +120,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
{
int i, retval;
- if (!request_region(ioaddr, AC_IO_EXTENT, "ac3200"))
- return -ENODEV;
+ if (!request_region(ioaddr, AC_IO_EXTENT, dev->name))
+ return -EBUSY;
if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
retval = -ENODEV;
@@ -172,9 +171,9 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
printk(", assigning");
}
- if (request_irq(dev->irq, ei_interrupt, 0, "ac3200", dev)) {
+ retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+ if (retval) {
printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
- retval = -EAGAIN;
goto out1;
}
@@ -262,15 +261,9 @@ static int ac_open(struct net_device *dev)
#ifdef notyet
/* Someday we may enable the IRQ and shared memory here. */
int ioaddr = dev->base_addr;
-
- if (request_irq(dev->irq, ei_interrupt, 0, "ac3200", dev))
- return -EAGAIN;
#endif
ei_open(dev);
-
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -339,9 +332,6 @@ static int ac_close_card(struct net_device *dev)
#endif
ei_close(dev);
-
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -360,9 +350,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("ac3200.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
struct net_device *dev = &dev_ac32[this_dev];
dev->irq = irq[this_dev];
@@ -376,7 +363,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -392,17 +378,16 @@ cleanup_module(void)
for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) {
struct net_device *dev = &dev_ac32[this_dev];
if (dev->priv != NULL) {
- void *priv = dev->priv;
/* Someday free_irq may be in ac_close_card() */
free_irq(dev->irq, dev);
release_region(dev->base_addr, AC_IO_EXTENT);
if (ei_status.reg0)
iounmap((void *)dev->mem_start);
unregister_netdev(dev);
- kfree(priv);
+ kfree(dev->priv);
+ dev->priv = NULL;
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 844961396..f73af0828 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -56,12 +56,9 @@
#include <linux/delay.h>
#include <linux/mm.h>
-#undef ETHTOOL
#undef INDEX_DEBUG
-#ifdef ETHTOOL
#include <linux/ethtool.h>
-#endif
#include <net/sock.h>
#include <net/ip.h>
@@ -1145,10 +1142,10 @@ static int __init ace_init(struct net_device *dev)
goto init_error;
}
- if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) {
+ ecode = request_irq(dev->irq, ace_interrupt, SA_SHIRQ, dev->name, dev);
+ if (ecode) {
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
- ecode = -EAGAIN;
goto init_error;
}
@@ -2427,7 +2424,6 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
-#ifdef ETHTOOL
struct ace_private *ap = dev->priv;
struct ace_regs *regs = ap->regs;
struct ethtool_cmd ecmd;
@@ -2453,7 +2449,7 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
return -EFAULT;
- if (ecmd.cmd == ETH_GSET) {
+ if (ecmd.cmd == ETHTOOL_GSET) {
ecmd.supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
@@ -2486,17 +2482,18 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
else
ecmd.autoneg = AUTONEG_DISABLE;
+#if 0
ecmd.trace = readl(&regs->TuneTrace);
-
ecmd.txcoal = readl(&regs->TuneTxCoalTicks);
ecmd.rxcoal = readl(&regs->TuneRxCoalTicks);
+#endif
ecmd.maxtxpkt = readl(&regs->TuneMaxTxDesc);
ecmd.maxrxpkt = readl(&regs->TuneMaxRxDesc);
if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
- } else if (ecmd.cmd == ETH_SSET) {
+ } else if (ecmd.cmd == ETHTOOL_SSET) {
if(!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -2554,7 +2551,6 @@ static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
return 0;
}
-#endif
return -EOPNOTSUPP;
}
diff --git a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c
index 11b6e2773..e581d6e32 100644
--- a/drivers/net/aironet4500_card.c
+++ b/drivers/net/aironet4500_card.c
@@ -164,16 +164,23 @@ int awc4500_pci_probe(struct net_device *dev)
static int awc_pci_init(struct net_device * dev, struct pci_dev *pdev,
int ioaddr, int cis_addr, int mem_addr, u8 pci_irq_line) {
- int i;
+ int i, allocd_dev = 0;
if (!dev) {
- dev = init_etherdev(dev, 0 );
+ dev = init_etherdev(NULL, 0);
+ if (!dev)
+ return -ENOMEM;
+ allocd_dev = 1;
}
dev->priv = kmalloc(sizeof(struct awc_private),GFP_KERNEL );
memset(dev->priv,0,sizeof(struct awc_private));
if (!dev->priv) {
printk(KERN_CRIT "aironet4x00: could not allocate device private, some unstability may follow\n");
- return -1;
+ if (allocd_dev) {
+ unregister_netdev(dev);
+ kfree(dev);
+ }
+ return -ENOMEM;
};
// ether_setup(dev);
@@ -194,7 +201,16 @@ static int awc_pci_init(struct net_device * dev, struct pci_dev *pdev,
dev->watchdog_timeo = AWC_TX_TIMEOUT;
- request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev);
+ i = request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
+ if (i) {
+ kfree(dev->priv);
+ dev->priv = NULL;
+ if (allocd_dev) {
+ unregister_netdev(dev);
+ kfree(dev);
+ }
+ return i;
+ }
awc_private_init( dev);
awc_init(dev);
diff --git a/drivers/net/aironet4500_core.c b/drivers/net/aironet4500_core.c
index c5def9e39..7d5e67b5c 100644
--- a/drivers/net/aironet4500_core.c
+++ b/drivers/net/aironet4500_core.c
@@ -2574,7 +2574,7 @@ MODULE_PARM(awc_simple_bridge,"i");
MODULE_PARM(max_mtu,"i");
MODULE_PARM(large_buff_mem,"i");
MODULE_PARM(small_buff_no,"i");
-MODULE_PARM(SSID,"1-4c31");
+MODULE_PARM(SSID,"c33");
#endif
/*EXPORT_SYMBOL(tx_queue_len);
diff --git a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
index cd84f0f56..c23158807 100644
--- a/drivers/net/am79c961a.c
+++ b/drivers/net/am79c961a.c
@@ -285,15 +285,13 @@ static int
am79c961_open(struct net_device *dev)
{
struct dev_priv *priv = (struct dev_priv *)dev->priv;
-
- MOD_INC_USE_COUNT;
+ int ret;
memset (&priv->stats, 0, sizeof (priv->stats));
- if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) {
- MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
+ ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
+ if (ret)
+ return ret;
am79c961_init_for_open(dev);
@@ -320,7 +318,6 @@ am79c961_close(struct net_device *dev)
free_irq (dev->irq, dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -657,7 +654,8 @@ static int __init am79c961_init(void)
if (!dev)
goto out;
- priv = (struct dev_priv *) dev->priv;
+ SET_MODULE_OWNER(dev);
+ priv = dev->priv;
/*
* Fixed address and IRQ lines here.
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index df60ad6b8..fe24effde 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -129,7 +129,9 @@ int __init apne_probe(struct net_device *dev)
if (apne_owned)
return -ENODEV;
-
+
+ SET_MODULE_OWNER(dev);
+
if ( !(AMIGAHW_PRESENT(PCMCIA)) )
return (-ENODEV);
@@ -285,10 +287,8 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
/* Install the Interrupt handler */
- if (request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ,
- "apne Ethernet", dev))
- return -EAGAIN;
-
+ i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, dev->name, dev);
+ if (i) return i;
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
@@ -301,8 +301,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
dev->dev_addr[i] = SA_prom[i];
}
- printk("\n%s: %s found.\n",
- dev->name, name);
+ printk("\n%s: %s found.\n", dev->name, name);
ei_status.name = name;
ei_status.tx_start_page = start_page;
@@ -332,7 +331,6 @@ static int
apne_open(struct net_device *dev)
{
ei_open(dev);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -342,7 +340,6 @@ apne_close(struct net_device *dev)
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
ei_close(dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -550,19 +547,16 @@ static void apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
#ifdef MODULE
-static struct net_device apne_dev = { init: apne_probe };
+static struct net_device apne_dev;
int init_module(void)
{
int err;
- if (load_8390_module("apne.c"))
- return -ENOSYS;
-
+ apne_dev.init = apne_probe;
if ((err = register_netdev(&apne_dev))) {
if (err == -EIO)
printk("No PCMCIA NEx000 ethernet card found.\n");
- unload_8390_module();
return (err);
}
return (0);
@@ -578,8 +572,6 @@ void cleanup_module(void)
pcmcia_reset();
- unload_8390_module();
-
apne_owned = 0;
}
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 255d845fd..5c00406b4 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -100,7 +100,6 @@ static int io = 0x240; /* Default IO for Dayna */
static int irq = 5; /* Default IRQ */
#else
static int io = 0; /* Default IO for Dayna */
-static int irq = 0; /* Default IRQ */
#endif
/*
@@ -1009,15 +1008,7 @@ static struct net_device_stats *cops_get_stats(struct net_device *dev)
}
#ifdef MODULE
-static struct net_device cops0_dev =
-{
- "", /* device name */
- 0, 0, 0, 0,
- 0x0, 0, /* I/O address, IRQ */
- 0, 0, 0, NULL, cops_probe
-};
-
-
+static struct net_device cops0_dev = { init: cops_probe };
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(board_type, "i");
diff --git a/drivers/net/ariadne2.c b/drivers/net/ariadne2.c
index 2197d067c..0283ff3b9 100644
--- a/drivers/net/ariadne2.c
+++ b/drivers/net/ariadne2.c
@@ -86,10 +86,12 @@ int __init ariadne2_probe(struct net_device *dev)
unsigned long board, ioaddr;
int err;
+ SET_MODULE_OWNER(dev);
+
while ((z = zorro_find_device(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, z))) {
board = z->resource.start;
ioaddr = board+ARIADNE2_BASE*2;
- if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, "RTL8019AS"))
+ if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name))
continue;
if ((err = ariadne2_init(dev, ZTWO_VADDR(board)))) {
release_mem_region(ioaddr, NE_IO_EXTENT*2);
@@ -170,9 +172,8 @@ static int __init ariadne2_init(struct net_device *dev, unsigned long board)
dev->irq = IRQ_AMIGA_PORTS;
/* Install the Interrupt handler */
- if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ,
- "AriadNE2 Ethernet", dev))
- return -EAGAIN;
+ i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev);
+ if (i) return i;
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
@@ -213,7 +214,6 @@ static int __init ariadne2_init(struct net_device *dev, unsigned long board)
static int ariadne2_open(struct net_device *dev)
{
ei_open(dev);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -222,7 +222,6 @@ static int ariadne2_close(struct net_device *dev)
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
ei_close(dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -381,19 +380,15 @@ static void ariadne2_block_output(struct net_device *dev, int count,
}
#ifdef MODULE
-static struct net_device ariadne2_dev = { init: ariadne2_probe };
+static struct net_device ariadne2_dev;
int init_module(void)
{
int err;
- if (load_8390_module("ariadne2.c"))
- return -ENOSYS;
-
+ ariadne2_dev.init = ariadne2_probe;
if ((err = register_netdev(&ariadne2_dev))) {
- if (err == -EIO)
- printk("No AriadNE2 ethernet card found.\n");
- unload_8390_module();
+ printk(KERN_WARNING "No AriadNE2 ethernet card found.\n");
return err;
}
return 0;
@@ -404,7 +399,6 @@ void cleanup_module(void)
free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev);
release_mem_region(ZTWO_PADDR(ariadne2_dev.base_addr), NE_IO_EXTENT*2);
unregister_netdev(&ariadne2_dev);
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c
index dfa7c218b..cec860fe0 100644
--- a/drivers/net/arlan.c
+++ b/drivers/net/arlan.c
@@ -1069,6 +1069,8 @@ int __init arlan_probe_everywhere(struct net_device *dev)
int probed = 0;
int found = 0;
+ SET_MODULE_OWNER(dev);
+
ARLAN_DEBUG_ENTRY("arlan_probe_everywhere");
if (mem != 0 && numDevices == 1) /* Check a single specified location. */
{
@@ -1276,11 +1278,12 @@ static int arlan_open(struct net_device *dev)
return ret;
arlan = ((struct arlan_private *) dev->priv)->card;
- if (request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev))
+ ret = request_irq(dev->irq, &arlan_interrupt, 0, dev->name, dev);
+ if (ret)
{
printk(KERN_ERR "%s: unable to get IRQ %d .\n",
dev->name, dev->irq);
- return -EAGAIN;
+ return ret;
}
@@ -1323,7 +1326,6 @@ static int arlan_open(struct net_device *dev)
udelay(200000);
add_timer(&priv->timer);
- MOD_INC_USE_COUNT;
#ifdef CONFIG_PROC_FS
#ifndef MODULE
if (arlan_device[0])
@@ -1887,7 +1889,6 @@ static int arlan_close(struct net_device *dev)
priv->open_time = 0;
netif_stop_queue(dev);
free_irq(dev->irq, dev);
- MOD_DEC_USE_COUNT;
ARLAN_DEBUG_EXIT("arlan_close");
return 0;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 42b4d118a..96689c384 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -117,7 +117,6 @@ struct net_local {
uint tx_started:1; /* Packets are on the Tx queue. */
uint tx_queue_ready:1; /* Tx queue is ready to be sent. */
uint rx_started:1; /* Packets are Rxing. */
- uint invalid_irq:1;
uchar tx_queue; /* Number of packet on the Tx queue. */
char mca_slot; /* -1 means ISA */
ushort tx_queue_len; /* Current length of the Tx queue. */
@@ -191,10 +190,12 @@ struct at1720_mca_adapters_struct at1720_mca_adapters[] = {
(detachable devices only).
*/
-int at1700_probe(struct net_device *dev)
+int __init at1700_probe(struct net_device *dev)
{
int i;
- int base_addr = dev ? dev->base_addr : 0;
+ int base_addr = dev->base_addr;
+
+ SET_MODULE_OWNER(dev);
if (base_addr > 0x1ff) /* Check a single specified location. */
return at1700_probe1(dev, base_addr);
@@ -203,8 +204,6 @@ int at1700_probe(struct net_device *dev)
for (i = 0; at1700_probe_list[i]; i++) {
int ioaddr = at1700_probe_list[i];
- if (check_region(ioaddr, AT1700_IO_EXTENT))
- continue;
if (at1700_probe1(dev, ioaddr) == 0)
return 0;
}
@@ -219,15 +218,18 @@ int at1700_probe(struct net_device *dev)
that can be done is checking a few bits and then diving right into an
EEPROM read. */
-int at1700_probe1(struct net_device *dev, int ioaddr)
+static int at1700_probe1(struct net_device *dev, int ioaddr)
{
char fmv_irqmap[4] = {3, 7, 10, 15};
char fmv_irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15};
unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
- int slot;
+ int slot, ret = -ENODEV;
struct net_local *lp;
+ if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
+ return -EBUSY;
+
/* Resetting the chip doesn't reset the ISA interface, so don't bother.
That means we have to be careful with the register values we probe for.
*/
@@ -306,8 +308,10 @@ int at1700_probe1(struct net_device *dev, int ioaddr)
&& inb(ioaddr + SAPROM + 1) == 0x00
&& inb(ioaddr + SAPROM + 2) == 0x0e)
is_fmv18x = 1;
- else
- return -ENODEV;
+ else {
+ ret = -ENODEV;
+ goto err_out;
+ }
#ifdef CONFIG_MCA
found:
@@ -328,8 +332,10 @@ found:
if (irq == fmv_irqmap_pnp[i])
break;
}
- if (i == 8)
- return -ENODEV;
+ if (i == 8) {
+ goto err_out;
+ ret = -ENODEV;
+ }
} else {
if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
return -ENODEV;
@@ -337,10 +343,6 @@ found:
}
}
- /* Grab the region so that we can find another board if the IRQ request
- fails. */
- request_region(ioaddr, AT1700_IO_EXTENT, dev->name);
-
printk("%s: %s found at %#3x, IRQ %d, address ", dev->name,
is_at1700 ? "AT1700" : "FMV-18X", ioaddr, irq);
@@ -413,8 +415,10 @@ found:
/* Initialize the device structure. */
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
+ if (dev->priv == NULL) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
memset(dev->priv, 0, sizeof(struct net_local));
dev->open = net_open;
@@ -434,14 +438,21 @@ found:
lp->jumpered = is_fmv18x;
lp->mca_slot = slot;
/* Snarf the interrupt vector now. */
- if (request_irq(irq, &net_interrupt, 0, dev->name, dev)) {
+ ret = request_irq(irq, &net_interrupt, 0, dev->name, dev);
+ if (ret) {
printk (" AT1700 at %#3x is unusable due to a conflict on"
"IRQ %d.\n", ioaddr, irq);
- lp->invalid_irq = 1;
- return 0;
+ goto err_out_priv;
}
return 0;
+
+err_out_priv:
+ kfree(dev->priv);
+ dev->priv = NULL;
+err_out:
+ release_region(ioaddr, AT1700_IO_EXTENT);
+ return ret;
}
@@ -523,9 +534,6 @@ static int net_open(struct net_device *dev)
}
netif_start_queue(dev);
-
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -775,9 +783,6 @@ static int net_close(struct net_device *dev)
/* Power-down the chip. Green, green, green! */
outb(0x00, ioaddr + CONFIG_1);
-
- MOD_DEC_USE_COUNT;
-
return 0;
}
@@ -866,8 +871,7 @@ set_rx_mode(struct net_device *dev)
}
#ifdef MODULE
-static struct net_device dev_at1700 = { init: at1700_probe };
-
+static struct net_device dev_at1700;
static int io = 0x260;
static int irq;
@@ -881,6 +885,7 @@ int init_module(void)
printk("at1700: You should not use auto-probing with insmod!\n");
dev_at1700.base_addr = io;
dev_at1700.irq = irq;
+ dev_at1700.init = at1700_probe;
if (register_netdev(&dev_at1700) != 0) {
printk("at1700: register_netdev() returned non-zero.\n");
return -EIO;
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 275ef3296..215198090 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -353,9 +353,8 @@ bionet_probe(struct net_device *dev){
return -ENODEV;
}
+ SET_MODULE_OWNER(dev);
- if (dev == NULL)
- return -ENODEV;
if (bionet_debug > 0 && version_printed++ == 0)
printk(version);
@@ -425,7 +424,6 @@ bionet_open(struct net_device *dev) {
bionet_timer.data = (long)dev;
bionet_timer.expires = jiffies + lp->poll_time;
add_timer(&bionet_timer);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -629,7 +627,6 @@ bionet_close(struct net_device *dev) {
dev->start = 0;
stdma_release();
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -645,19 +642,13 @@ static struct net_device_stats *net_get_stats(struct net_device *dev)
#ifdef MODULE
-static char bio_name[16];
-static struct net_device bio_dev =
- {
- bio_name, /* filled in by register_netdev() */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, bionet_probe,
- };
+static struct net_device bio_dev;
int
init_module(void) {
int err;
+ bio_dev.init = bionet_probe;
if ((err = register_netdev(&bio_dev))) {
if (err == -EEXIST) {
printk("BIONET: devices already present. Module not loaded.\n");
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index 6aeb737d5..a9b016519 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -561,7 +561,7 @@ bad:
/* Check for a network adaptor of this type, and return '0' if one exists.
*/
-extern int __init
+int __init
pamsnet_probe (dev)
struct net_device *dev;
{
@@ -576,6 +576,8 @@ pamsnet_probe (dev)
if (no_more_found)
return -ENODEV;
+ SET_MODULE_OWNER(dev);
+
no_more_found = 1;
printk("Probing for PAM's Net/GK Adapter...\n");
@@ -686,7 +688,6 @@ pamsnet_open(struct net_device *dev) {
pamsnet_timer.data = (long)dev;
pamsnet_timer.expires = jiffies + lp->poll_time;
add_timer(&pamsnet_timer);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -848,7 +849,6 @@ pamsnet_close(struct net_device *dev) {
ENABLE_IRQ();
stdma_release();
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -864,19 +864,13 @@ static struct net_device_stats *net_get_stats(struct net_device *dev)
#ifdef MODULE
-static char devicename[9] = { 0, };
-static struct net_device pam_dev =
- {
- devicename, /* filled in by register_netdev() */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, pamsnet_probe,
- };
+static struct net_device pam_dev;
int
init_module(void) {
int err;
+ pam_dev.init = pamsnet_probe;
if ((err = register_netdev(&pam_dev))) {
if (err == -EEXIST) {
printk("PAM's Net/GK: devices already present. Module not loaded.\n");
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index fa41fd3b7..4eb4b58ef 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -357,7 +357,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr );
-void *slow_memcpy( void *dst, const void *src, size_t len )
+static void *slow_memcpy( void *dst, const void *src, size_t len )
{ char *cto = dst;
const char *cfrom = src;
@@ -375,6 +375,8 @@ int __init atarilance_probe( struct net_device *dev )
int i;
static int found = 0;
+ SET_MODULE_OWNER(dev);
+
if (!MACH_IS_ATARI || found)
/* Assume there's only one board possible... That seems true, since
* the Riebl/PAM board's address cannot be changed. */
@@ -659,7 +661,6 @@ static int lance_open( struct net_device *dev )
dev->start = 1;
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
- MOD_INC_USE_COUNT;
return( 0 );
}
@@ -1062,7 +1063,6 @@ static int lance_close( struct net_device *dev )
memory if we don't. */
DREG = CSR0_STOP;
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -1152,20 +1152,13 @@ static int lance_set_mac_address( struct net_device *dev, void *addr )
#ifdef MODULE
-static char devicename[9] = { 0, };
-
-static struct net_device atarilance_dev =
-{
- devicename, /* filled in by register_netdev() */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, atarilance_probe,
-};
+static struct net_device atarilance_dev;
int init_module(void)
{ int err;
+ atarilance_dev.init = atarilance_probe;
if ((err = register_netdev( &atarilance_dev ))) {
if (err == -EIO) {
printk( "No Atari Lance board found. Module not loaded.\n");
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 25d2dbd62..21bdbab5d 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -46,9 +46,9 @@ static int max_interrupt_work = 15;
#define NUM_UNITS 2
/* The standard set of ISA module parameters. */
-static int io[NUM_UNITS] = {0, 0};
-static int irq[NUM_UNITS] = {0, 0};
-static int xcvr[NUM_UNITS] = {0, 0}; /* The data transfer mode. */
+static int io[NUM_UNITS];
+static int irq[NUM_UNITS];
+static int xcvr[NUM_UNITS]; /* The data transfer mode. */
/* Operational parameters that are set at compile time. */
@@ -292,6 +292,7 @@ static int __init atp_probe1(struct net_device *dev, long ioaddr)
dev = init_etherdev(dev, sizeof(struct net_local));
if (!dev)
return -ENOMEM;
+ SET_MODULE_OWNER(dev);
/* Find the IRQ used by triggering an interrupt. */
write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */
@@ -425,16 +426,14 @@ static unsigned short __init eeprom_op(long ioaddr, unsigned int cmd)
static int net_open(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
-
- MOD_INC_USE_COUNT;
+ int ret;
/* The interrupt line is turned off (tri-stated) when the device isn't in
use. That's especially important for "attached" interfaces where the
port or interrupt may be shared. */
- if (request_irq(dev->irq, &atp_interrupt, 0, "ATP Ethernet", dev)) {
- MOD_DEC_USE_COUNT;
- return -EAGAIN;
- }
+ ret = request_irq(dev->irq, &atp_interrupt, 0, dev->name, dev);
+ if (ret)
+ return ret;
hardware_init(dev);
@@ -835,10 +834,7 @@ net_close(struct net_device *dev)
free_irq(dev->irq, dev);
/* Reset the ethernet hardware and activate the printer pass-through. */
- write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
-
- MOD_DEC_USE_COUNT;
-
+ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
return 0;
}
diff --git a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c
index eeb6b77c5..9df9a4b1a 100644
--- a/drivers/net/bagetlance.c
+++ b/drivers/net/bagetlance.c
@@ -329,8 +329,7 @@ struct lance_addr {
static int addr_accessible( volatile void *regp, int wordflag, int
writeflag );
-static unsigned long lance_probe1( struct net_device *dev, struct lance_addr
- *init_rec );
+static int lance_probe1( struct net_device *dev, struct lance_addr *init_rec );
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
@@ -474,10 +473,12 @@ int __init bagetlance_probe( struct net_device *dev )
{ int i;
static int found = 0;
+ SET_MODULE_OWNER(dev);
+
if (found)
/* Assume there's only one board possible... That seems true, since
* the Riebl/PAM board's address cannot be changed. */
- return( ENODEV );
+ return( -ENODEV );
for( i = 0; i < N_LANCE_ADDR; ++i ) {
if (lance_probe1( dev, &lance_addr_list[i] )) {
@@ -486,7 +487,7 @@ int __init bagetlance_probe( struct net_device *dev )
}
}
- return( ENODEV );
+ return( -ENODEV );
}
@@ -508,8 +509,8 @@ static int __init addr_accessible( volatile void *regp,
#define IRQ_TYPE_PRIO SA_INTERRUPT
#define IRQ_SOURCE_TO_VECTOR(x) (x)
-static unsigned long __init lance_probe1( struct net_device *dev,
- struct lance_addr *init_rec )
+static int __init lance_probe1( struct net_device *dev,
+ struct lance_addr *init_rec )
{ volatile unsigned short *memaddr =
(volatile unsigned short *)init_rec->memaddr;
@@ -759,8 +760,6 @@ static int lance_open( struct net_device *dev )
dev->start = 1;
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
- MOD_INC_USE_COUNT;
-
return( 0 );
}
@@ -1222,7 +1221,6 @@ static int lance_close( struct net_device *dev )
memory if we don't. */
DREG = CSR0_STOP;
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -1324,20 +1322,13 @@ static int lance_set_mac_address( struct net_device *dev, void *addr )
#ifdef MODULE
-static char devicename[9] = { 0, };
-
-static struct net_device bagetlance_dev =
-{
- devicename, /* filled in by register_netdev() */
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, bagetlance_probe,
-};
+static struct net_device bagetlance_dev;
int init_module(void)
{ int err;
+ bagetlance_dev.init = bagetlance_probe;
if ((err = register_netdev( &bagetlance_dev ))) {
if (err == -EIO) {
printk( "No Vme Lance board found. Module not loaded.\n");
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 2542fa2d0..b9ff76f28 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1270,7 +1270,7 @@ static int __init bmac_probe(void)
static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
{
- int j, rev;
+ int j, rev, ret;
struct bmac_data *bp;
unsigned char *addr;
struct net_device *dev;
@@ -1291,15 +1291,17 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
}
dev = init_etherdev(NULL, PRIV_BYTES);
-
if (!dev) {
printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n",
bmac->full_name);
return;
}
+ SET_MODULE_OWNER(dev);
dev->base_addr = (unsigned long)
ioremap(bmac->addrs[0].address, bmac->addrs[0].size);
+ if (!dev->base_addr)
+ goto err_out;
dev->irq = bmac->intrs[0].line;
bmwrite(dev, INTDISABLE, DisableAll);
@@ -1322,18 +1324,19 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
bmac_get_station_address(dev, addr);
if (bmac_verify_checksum(dev) != 0)
- return;
-
- ether_setup(dev);
+ goto err_out_iounmap;
bp = (struct bmac_data *) dev->priv;
- memset(bp, 0, sizeof(struct bmac_data));
bp->is_bmac_plus = is_bmac_plus;
bp->tx_dma = (volatile struct dbdma_regs *)
ioremap(bmac->addrs[1].address, bmac->addrs[1].size);
+ if (!bp->tx_dma)
+ goto err_out_iounmap;
bp->tx_dma_intr = bmac->intrs[1].line;
bp->rx_dma = (volatile struct dbdma_regs *)
ioremap(bmac->addrs[2].address, bmac->addrs[2].size);
+ if (!bp->rx_dma)
+ goto err_out_iounmap_tx;
bp->rx_dma_intr = bmac->intrs[2].line;
bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
@@ -1343,23 +1346,44 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
skb_queue_head_init(bp->queue);
bp->node = bmac;
- memset(&bp->stats, 0, sizeof(bp->stats));
memset((char *) bp->tx_cmds, 0,
(N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
/* init_timer(&bp->tx_timeout); */
/* bp->timeout_active = 0; */
- if (request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev))
+ ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
+ if (ret) {
printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
- if (request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma",
- dev))
+ goto err_out_iounmap_rx;
+ }
+ ret = request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev);
+ if (ret) {
printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line);
- if (request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma",
- dev))
+ goto err_out_irq0;
+ }
+ ret = request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
+ if (ret) {
printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line);
+ goto err_out_irq1;
+ }
bp->next_bmac = bmac_devs;
bmac_devs = dev;
+ return;
+
+err_out_irq1:
+ free_irq(bmac->intrs[1].line, dev);
+err_out_irq0:
+ free_irq(dev->irq, dev);
+err_out_iounmap_rx:
+ iounmap((void *)bp->rx_dma);
+err_out_iounmap_tx:
+ iounmap((void *)bp->tx_dma);
+err_out_iounmap:
+ iounmap((void *)dev->base_addr);
+err_out:
+ unregister_netdev(dev);
+ kfree(dev);
}
static int bmac_open(struct net_device *dev)
@@ -1370,8 +1394,6 @@ static int bmac_open(struct net_device *dev)
return -ENOMEM;
dev->flags |= IFF_RUNNING;
-
- MOD_INC_USE_COUNT;
return 0;
}
@@ -1417,8 +1439,6 @@ static int bmac_close(struct net_device *dev)
bp->reset_and_enabled = 0;
XXDEBUG(("bmac: all bufs freed\n"));
- MOD_DEC_USE_COUNT;
-
return 0;
}
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 9577b4ffa..b419dd0b7 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -66,10 +66,18 @@
: abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
: (Jason Gunthorpe <jgg@ualberta.ca>)
+ Andrew Morton : Kernel 2.4.0-test11-pre4
+ : Use dev->name in request_*() (Andrey Panin)
+ : Fix an error-path memleak in init_module()
+ : Preserve return value from request_irq()
+ : Fix type of `media' module parm (Keith Owens)
+ : Use SET_MODULE_OWNER()
+ : Tidied up strange request_irq() abuse in net_open().
+
*/
-static char *version =
-"cs89x0.c: v2.3.99-pre1-2 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+static char version[] =
+"cs89x0.c: v2.4.0-test11-pre4 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
/* ======================= end of configuration ======================= */
@@ -77,13 +85,8 @@ static char *version =
/* Always include 'config.h' first in case the user wants to turn on
or override something. */
#include <linux/config.h>
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
/*
* Set this to zero to disable DMA code
@@ -97,7 +100,7 @@ static char *version =
* Set this to zero to remove all the debug statements via
* dead code elimination
*/
-#define DEBUGGING 0
+#define DEBUGGING 1
/*
Sources:
@@ -254,6 +257,8 @@ int __init cs89x0_probe(struct net_device *dev)
int i;
int base_addr = dev ? dev->base_addr : 0;
+ SET_MODULE_OWNER(dev);
+
if (net_debug)
printk("cs89x0:cs89x0_probe()\n");
@@ -378,8 +383,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr)
lp = (struct net_local *)dev->priv;
/* Grab the region so we can find another board if autoIRQ fails. */
- if (!request_region(ioaddr, NETCARD_IO_EXTENT, "cs89x0")) {
- retval = -ENODEV;
+ if (!request_region(ioaddr, NETCARD_IO_EXTENT, dev->name)) {
+ retval = -EBUSY;
goto out1;
}
@@ -985,7 +990,7 @@ write_irq(struct net_device *dev, int chip_type, int irq)
int i;
if (chip_type == CS8900) {
- /* Search the mapping table for the corrisponding IRQ pin. */
+ /* Search the mapping table for the corresponding IRQ pin. */
for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
if (cs8900_irq_map[i] == irq)
break;
@@ -1016,8 +1021,6 @@ net_open(struct net_device *dev)
int i;
int ret;
- MOD_INC_USE_COUNT;
-
if (dev->irq < 2) {
/* Allow interrupts to be generated by the chip */
/* Cirrus' release had this: */
@@ -1027,20 +1030,20 @@ net_open(struct net_device *dev)
/* And 2.3.47 had this: */
writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
- for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) {
- if (request_irq (i, NULL, 0, "cs89x0", dev) != -EBUSY) {
- write_irq(dev, lp->chip_type, i);
- writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT);
- if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0)
+ for (i = 2; i < CS8920_NO_INTS; i++) {
+ if ((1 << dev->irq) & lp->irq_map) {
+ if (request_irq(i, net_interrupt, 0, dev->name, dev) == 0) {
+ dev->irq = i;
+ write_irq(dev, lp->chip_type, i);
+ /* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */
break;
+ }
}
}
-
if (i >= CS8920_NO_INTS) {
writereg(dev, PP_BusCTL, 0); /* disable interrupts. */
- if (net_debug)
- printk("cs89x0: can't get an interrupt\n");
+ printk(KERN_ERR "cs89x0: can't get an interrupt\n");
ret = -EAGAIN;
goto bad_out;
}
@@ -1058,10 +1061,10 @@ net_open(struct net_device *dev)
writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
#endif
write_irq(dev, lp->chip_type, dev->irq);
- if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) {
+ ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
+ if (ret) {
if (net_debug)
- printk("cs89x0: request_irq(%d) failed\n", dev->irq);
- ret = -EAGAIN;
+ printk(KERN_DEBUG "cs89x0: request_irq(%d) failed\n", dev->irq);
goto bad_out;
}
}
@@ -1089,7 +1092,7 @@ net_open(struct net_device *dev)
goto release_irq;
}
memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */
- if (request_dma(dev->dma, "cs89x0")) {
+ if (request_dma(dev->dma, dev->name)) {
printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma);
goto release_irq;
}
@@ -1231,11 +1234,10 @@ net_open(struct net_device *dev)
#endif
);
netif_start_queue(dev);
- if (net_debug)
+ if (net_debug > 1)
printk("cs89x0: net_open() succeeded\n");
return 0;
bad_out:
- MOD_DEC_USE_COUNT;
return ret;
}
@@ -1482,7 +1484,6 @@ net_close(struct net_device *dev)
#endif
/* Update the statistics here. */
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -1576,7 +1577,7 @@ static int dmasize=16; /* or 64 */
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(debug, "i");
-MODULE_PARM(media, "s");
+MODULE_PARM(media, "c8");
MODULE_PARM(duplex, "i");
MODULE_PARM(dma , "i");
MODULE_PARM(dmasize , "i");
@@ -1616,6 +1617,7 @@ int
init_module(void)
{
struct net_local *lp;
+ int ret = 0;
#if DEBUGGING
net_debug = debug;
@@ -1661,21 +1663,27 @@ init_module(void)
if (io == 0) {
printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n");
printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n");
- return -EPERM;
+ ret = -EPERM;
+ goto out;
}
#if ALLOW_DMA
if (use_dma && dmasize != 16 && dmasize != 64) {
printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize);
- return -EPERM;
+ ret = -EPERM;
+ goto out;
}
#endif
if (register_netdev(&dev_cs89x0) != 0) {
printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
- return -ENXIO;
+ ret = -ENXIO;
+ goto out;
}
- return 0;
+out:
+ if (ret)
+ kfree(dev_cs89x0.priv);
+ return ret;
}
void
@@ -1695,7 +1703,6 @@ cleanup_module(void)
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS -c cs89x0.c"
* version-control: t
* kept-new-versions: 5
* c-indent-level: 8
diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c
index b749908bd..b8e1e297d 100644
--- a/drivers/net/de4x5.c
+++ b/drivers/net/de4x5.c
@@ -766,6 +766,20 @@ struct de4x5_desc {
#define DE4X5_PKT_BIN_SZ 128 /* Should be >=100 unless you
increase DE4X5_PKT_STAT_SZ */
+struct pkt_stats {
+ u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+ u_int unicast;
+ u_int multicast;
+ u_int broadcast;
+ u_int excessive_collisions;
+ u_int tx_underruns;
+ u_int excessive_underruns;
+ u_int rx_runt_frames;
+ u_int rx_collision;
+ u_int rx_dribble;
+ u_int rx_overflow;
+};
+
struct de4x5_private {
char adapter_name[80]; /* Adapter name */
u_long interrupt; /* Aligned ISR flag */
@@ -779,19 +793,7 @@ struct de4x5_private {
char frame[64]; /* Min sized packet for loopback*/
spinlock_t lock; /* Adapter specific spinlock */
struct net_device_stats stats; /* Public stats */
- struct {
- u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
- u_int unicast;
- u_int multicast;
- u_int broadcast;
- u_int excessive_collisions;
- u_int tx_underruns;
- u_int excessive_underruns;
- u_int rx_runt_frames;
- u_int rx_collision;
- u_int rx_dribble;
- u_int rx_overflow;
- } pktStats;
+ struct pkt_stats pktStats; /* Private stats counters */
char rxRingSize;
char txRingSize;
int bus; /* EISA or PCI */
@@ -5639,6 +5641,7 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
break;
case DE4X5_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
printk("%s: Boo!\n", dev->name);
break;
@@ -5650,12 +5653,16 @@ de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
break;
case DE4X5_GET_STATS: /* Get the driver statistics */
- ioc->len = sizeof(lp->pktStats);
+ {
+ struct pkt_stats statbuf;
+ ioc->len = sizeof(statbuf);
spin_lock_irqsave(&lp->lock, flags);
- if (copy_to_user(ioc->data, &lp->pktStats, ioc->len)) return -EFAULT;
+ memcpy(&statbuf, &lp->pktStats, ioc->len);
spin_unlock_irqrestore(&lp->lock, flags);
+ if (copy_to_user(ioc->data, &statbuf, ioc->len))
+ return -EFAULT;
break;
-
+ }
case DE4X5_CLR_STATS: /* Zero out the driver statistics */
if (!capable(CAP_NET_ADMIN)) return -EPERM;
spin_lock_irqsave(&lp->lock, flags);
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index b81074ee0..4549d2c5e 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -342,15 +342,14 @@ de600_read_byte(unsigned char type, struct net_device *dev) { /* dev used by mac
static int
de600_open(struct net_device *dev)
{
- if (request_irq(DE600_IRQ, de600_interrupt, 0, "de600", dev)) {
+ int ret = request_irq(DE600_IRQ, de600_interrupt, 0, dev->name, dev);
+ if (ret) {
printk ("%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
- return 1;
+ return ret;
}
- MOD_INC_USE_COUNT;
- if (adapter_init(dev)) {
- return 1;
- }
+ if (adapter_init(dev))
+ return -EIO;
return 0;
}
@@ -370,7 +369,6 @@ de600_close(struct net_device *dev)
if (netif_running(dev)) { /* perhaps not needed? */
free_irq(DE600_IRQ, dev);
- MOD_DEC_USE_COUNT;
}
return 0;
}
@@ -637,6 +635,8 @@ de600_probe(struct net_device *dev)
static struct net_device_stats de600_netstats;
/*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/
+ SET_MODULE_OWNER(dev);
+
printk("%s: D-Link DE-600 pocket adapter", dev->name);
/* Alpha testers must have the version number to report bugs. */
if (de600_debug > 1)
@@ -819,12 +819,12 @@ de600_rspace(struct sock *sk)
#endif
#ifdef MODULE
-static struct net_device de600_dev = {
- "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe };
+static struct net_device de600_dev;
int
init_module(void)
{
+ de600_dev.init = de600_probe;
if (register_netdev(&de600_dev) != 0)
return -EIO;
return 0;
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 22a41cd04..ecc71eb00 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -437,15 +437,15 @@ de620_get_register(struct net_device *dev, byte reg)
*/
static int de620_open(struct net_device *dev)
{
- if (request_irq(dev->irq, de620_interrupt, 0, "de620", dev)) {
+ int ret = request_irq(dev->irq, de620_interrupt, 0, dev->name, dev);
+ if (ret) {
printk (KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq);
- return 1;
+ return ret;
}
if (adapter_init(dev))
- return 1;
+ return -EIO;
- MOD_INC_USE_COUNT;
netif_start_queue(dev);
return 0;
}
@@ -462,7 +462,6 @@ static int de620_close(struct net_device *dev)
/* disable recv */
de620_set_register(dev, W_TCR, RXOFF);
free_irq(dev->irq, dev);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -812,6 +811,8 @@ int __init de620_probe(struct net_device *dev)
int i;
byte checkbyte = 0xa5;
+ SET_MODULE_OWNER(dev);
+
/*
* This is where the base_addr and irq gets set.
* Tunable at compile-time and insmod-time
@@ -985,11 +986,11 @@ static int __init read_eeprom(struct net_device *dev)
*
*/
#ifdef MODULE
-static struct net_device de620_dev = {
- "", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de620_probe };
+static struct net_device de620_dev;
int init_module(void)
{
+ de620_dev.init = de620_probe;
if (register_netdev(&de620_dev) != 0)
return -EIO;
return 0;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 53ded875a..3d632145c 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -395,9 +395,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("e2100.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_E21_CARDS; this_dev++) {
struct net_device *dev = &dev_e21[this_dev];
dev->irq = irq[this_dev];
@@ -414,7 +411,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -437,7 +433,6 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 6a825f436..86a09b4d4 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -401,9 +401,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("es3210.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) {
struct net_device *dev = &dev_es3210[this_dev];
dev->irq = irq[this_dev];
@@ -417,7 +414,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -440,6 +436,5 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index d6e9759bf..c8cab2062 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -451,20 +451,14 @@ int __init eth16i_probe(struct net_device *dev)
return -ENXIO;
/* Seek card from the ISA io address space */
- for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) {
- if(check_region(ioaddr, ETH16I_IO_EXTENT))
- continue;
+ for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++)
if(eth16i_probe1(dev, ioaddr) == 0)
return 0;
- }
/* Seek card from the EISA io address space */
- for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) {
- if(check_region(ioaddr, ETH16I_IO_EXTENT))
- continue;
+ for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++)
if(eth16i_probe1(dev, ioaddr) == 0)
return 0;
- }
return -ENODEV;
}
@@ -472,10 +466,15 @@ int __init eth16i_probe(struct net_device *dev)
static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
{
struct eth16i_local *lp;
-
- static unsigned version_printed = 0;
+ static unsigned version_printed;
+ int retval;
+
boot = 1; /* To inform initilization that we are in boot probe */
+ /* Let's grab the region */
+ if (!request_region(ioaddr, ETH16I_IO_EXTENT, dev->name))
+ return -EBUSY;
+
/*
The MB86985 chip has on register which holds information in which
io address the chip lies. First read this register and compare
@@ -485,14 +484,18 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
if(ioaddr < 0x1000) {
if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
- != ioaddr)
- return -ENODEV;
+ != ioaddr) {
+ retval = -ENODEV;
+ goto out;
+ }
}
/* Now we will go a bit deeper and try to find the chip's signature */
- if(eth16i_check_signature(ioaddr) != 0)
- return -ENODEV;
+ if(eth16i_check_signature(ioaddr) != 0) {
+ retval = -ENODEV;
+ goto out;
+ }
/*
Now it seems that we have found a ethernet chip in this particular
@@ -516,17 +519,15 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
/* Try to obtain interrupt vector */
- if (request_irq(dev->irq, (void *)&eth16i_interrupt, 0, "eth16i", dev)) {
+ if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, dev->name, dev))) {
printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n",
dev->name, cardname, ioaddr, dev->irq);
- return -EAGAIN;
+ goto out;
}
printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
dev->name, cardname, ioaddr, dev->irq);
- /* Let's grab the region */
- request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i");
/* Now we will have to lock the chip's io address */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
@@ -540,8 +541,11 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
/* Initialize the device structure */
if(dev->priv == NULL) {
dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL);
- if(dev->priv == NULL)
- return -ENOMEM;
+ if(dev->priv == NULL) {
+ free_irq(dev->irq, dev);
+ retval = -ENOMEM;
+ goto out;
+ }
}
memset(dev->priv, 0, sizeof(struct eth16i_local));
@@ -562,6 +566,9 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
boot = 0;
return 0;
+out:
+ release_region(ioaddr, ETH16I_IO_EXTENT);
+ return retval;
}
diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
index 8d4ebe1a3..5cdad9da4 100644
--- a/drivers/net/fc/iph5526.c
+++ b/drivers/net/fc/iph5526.c
@@ -3791,6 +3791,9 @@ struct pci_dev *pdev = NULL;
sprintf(fi->name, "fc%d", count);
host = scsi_register(tmpt, sizeof(struct iph5526_hostdata));
+ if(host==NULL)
+ return no_of_hosts;
+
hostdata = (struct iph5526_hostdata *)host->hostdata;
memset(hostdata, 0 , sizeof(struct iph5526_hostdata));
for (j = 0; j < MAX_SCSI_TARGETS; j++)
diff --git a/drivers/net/fmv18x.c b/drivers/net/fmv18x.c
index 8e76e9f6b..9c1423965 100644
--- a/drivers/net/fmv18x.c
+++ b/drivers/net/fmv18x.c
@@ -132,20 +132,16 @@ static void set_multicast_list(struct net_device *dev);
int __init fmv18x_probe(struct net_device *dev)
{
int i;
- int base_addr = dev ? dev->base_addr : 0;
+ int base_addr = dev->base_addr;
if (base_addr > 0x1ff) /* Check a single specified location. */
return fmv18x_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
- for (i = 0; fmv18x_probe_list[i]; i++) {
- int ioaddr = fmv18x_probe_list[i];
- if (check_region(ioaddr, FMV18X_IO_EXTENT))
- continue;
- if (fmv18x_probe1(dev, ioaddr) == 0)
+ for (i = 0; fmv18x_probe_list[i]; i++)
+ if (fmv18x_probe1(dev, fmv18x_probe_list[i]) == 0)
return 0;
- }
return -ENODEV;
}
@@ -158,21 +154,26 @@ int __init fmv18x_probe(struct net_device *dev)
that can be done is checking a few bits and then diving right into MAC
address check. */
-int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
+static int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
{
char irqmap[4] = {3, 7, 10, 15};
char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
- unsigned int i, irq;
+ unsigned int i, irq, retval;
/* Resetting the chip doesn't reset the ISA interface, so don't bother.
That means we have to be careful with the register values we probe for.
*/
+ if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name))
+ return -EBUSY;
+
/* Check I/O address configuration and Fujitsu vendor code */
if (inb(ioaddr+FJ_MACADDR ) != 0x00
|| inb(ioaddr+FJ_MACADDR+1) != 0x00
- || inb(ioaddr+FJ_MACADDR+2) != 0x0e)
- return -ENODEV;
+ || inb(ioaddr+FJ_MACADDR+2) != 0x0e) {
+ retval = -ENODEV;
+ goto out;
+ }
/* Check PnP mode for FMV-183/184/183A/184A. */
/* This PnP routine is very poor. IO and IRQ should be known. */
@@ -182,8 +183,10 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
if (irq == irqmap_pnp[i])
break;
}
- if (i == 8)
- return -ENODEV;
+ if (i == 8) {
+ retval = -ENODEV;
+ goto out;
+ }
} else {
if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr)
return -ENODEV;
@@ -191,16 +194,13 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
}
/* Snarf the interrupt vector now. */
- if (request_irq(irq, &net_interrupt, 0, "fmv18x", dev)) {
+ retval = request_irq(irq, &net_interrupt, 0, dev->name, dev);
+ if (retval) {
printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
"IRQ %d.\n", ioaddr, irq);
- return -EAGAIN;
+ goto out;
}
- /* Grab the region so that we can find another board if the IRQ request
- fails. */
- request_region(ioaddr, FMV18X_IO_EXTENT, "fmv18x");
-
printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name,
ioaddr, irq);
@@ -261,8 +261,10 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
/* Initialize the device structure. */
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
+ if (!dev->priv) {
+ retval = -ENOMEM;
+ goto out_irq;
+ }
memset(dev->priv, 0, sizeof(struct net_local));
dev->open = net_open;
@@ -277,6 +279,12 @@ int __init fmv18x_probe1(struct net_device *dev, short ioaddr)
ether_setup(dev);
return 0;
+
+out_irq:
+ free_irq(irq, dev);
+out:
+ release_region(ioaddr, FMV18X_IO_EXTENT);
+ return retval;
}
@@ -603,8 +611,7 @@ static void set_multicast_list(struct net_device *dev)
}
#ifdef MODULE
-static struct net_device dev_fmv18x = { init: fmv18x_probe };
-
+static struct net_device dev_fmv18x;
static int io = 0x220;
static int irq;
@@ -616,8 +623,9 @@ int init_module(void)
{
if (io == 0)
printk("fmv18x: You should not use auto-probing with insmod!\n");
- dev_fmv18x.base_addr = io;
- dev_fmv18x.irq = irq;
+ dev_fmv18x.base_addr = io;
+ dev_fmv18x.irq = irq;
+ dev_fmv18x.init = fmv18x_probe;
if (register_netdev(&dev_fmv18x) != 0) {
printk("fmv18x: register_netdev() returned non-zero.\n");
return -EIO;
diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c
index 81a9408df..f4c526044 100644
--- a/drivers/net/gmac.c
+++ b/drivers/net/gmac.c
@@ -343,7 +343,7 @@ mii_lookup_and_reset(struct gmac *gm)
mdelay(10);
/* Find the PHY */
- for(i=31; i>0; --i) {
+ for(i=0; i<=31; i++) {
mii_control = mii_read(gm, i, MII_CR);
mii_status = mii_read(gm, i, MII_SR);
if (mii_control != -1 && mii_status != -1 &&
@@ -351,7 +351,7 @@ mii_lookup_and_reset(struct gmac *gm)
break;
}
gm->phy_addr = i;
- if (gm->phy_addr < 0)
+ if (gm->phy_addr > 31)
return 0;
/* Reset it */
@@ -972,10 +972,11 @@ gmac_tx_timeout(struct net_device *dev)
{
struct gmac *gm = (struct gmac *) dev->priv;
int i, timeout;
-
+ unsigned long flags;
+
printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
- spin_lock_irq(&gm->lock);
+ spin_lock_irqsave(&gm->lock, flags);
/* Stop chip */
gmac_stop_dma(gm);
@@ -1011,7 +1012,7 @@ gmac_tx_timeout(struct net_device *dev)
/* Restart chip */
gmac_start_dma(gm);
- spin_unlock_irq(&gm->lock);
+ spin_unlock_irqrestore(&gm->lock, flags);
netif_wake_queue(dev);
}
@@ -1024,9 +1025,10 @@ gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
{
struct gmac *gm = (struct gmac *) dev->priv;
volatile struct gmac_dma_desc *dp;
+ unsigned long flags;
int i;
- spin_lock_irq(&gm->lock);
+ spin_lock_irqsave(&gm->lock, flags);
i = gm->next_tx;
if (gm->tx_buff[i] != 0) {
@@ -1036,7 +1038,7 @@ gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
* Can this ever happen in 2.4 ?
*/
netif_stop_queue(dev);
- spin_unlock_irq(&gm->lock);
+ spin_unlock_irqrestore(&gm->lock, flags);
return 1;
}
gm->next_tx = (i + 1) & (NTX - 1);
@@ -1058,7 +1060,7 @@ gmac_xmit_start(struct sk_buff *skb, struct net_device *dev)
if (gm->tx_buff[gm->next_tx] != 0)
netif_stop_queue(dev);
- spin_unlock_irq(&gm->lock);
+ spin_unlock_irqrestore(&gm->lock, flags);
dev->trans_start = jiffies;
@@ -1078,9 +1080,12 @@ gmac_tx_cleanup(struct net_device *dev, int force_cleanup)
int gone, i;
i = gm->tx_gone;
- gone = GM_IN(GM_TX_COMP);
-
- while (force_cleanup || i != gone) {
+
+ /* Note: If i==gone, we empty the entire ring. This works because
+ * if the ring was empty, we wouldn't have received the interrupt
+ */
+ do {
+ gone = GM_IN(GM_TX_COMP);
skb = gm->tx_buff[i];
if (skb == NULL)
break;
@@ -1095,14 +1100,12 @@ gmac_tx_cleanup(struct net_device *dev, int force_cleanup)
dev_kfree_skb_irq(skb);
if (++i >= NTX)
i = 0;
- }
+ } while (force_cleanup || i != gone);
gm->tx_gone = i;
if (!force_cleanup && netif_queue_stopped(dev) &&
(gm->tx_buff[gm->next_tx] == 0))
netif_wake_queue(dev);
-
- spin_unlock(&gm->lock);
}
/*
@@ -1373,6 +1376,8 @@ gmac_probe1(struct device_node *gmac)
dev->irq = gmac->intrs[0].line;
gm->dev = dev;
gm->of_node = gmac;
+
+ spin_lock_init(&gm->lock);
if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) {
gm->pci_bus = gm->pci_devfn = 0xff;
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 4e1bb8bf0..263ae384e 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -814,7 +814,7 @@ static int receive(struct net_device *dev, int cnt)
#ifdef __i386__
#define GETTICK(x) \
({ \
- if (current_cpu_data.x86_capability & X86_FEATURE_TSC) \
+ if (cpu_has_tsc) \
__asm__ __volatile__("rdtsc" : "=a" (x) : : "dx");\
})
#else /* __i386__ */
diff --git a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h
index 4608b3650..24a586740 100644
--- a/drivers/net/hamradio/soundmodem/sm.h
+++ b/drivers/net/hamradio/soundmodem/sm.h
@@ -299,8 +299,6 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
#ifdef __i386__
-#define HAS_RDTSC (current_cpu_data.x86_capability & X86_FEATURE_TSC)
-
/*
* only do 32bit cycle counter arithmetic; we hope we won't overflow.
* in fact, overflowing modems would require over 2THz CPU clock speeds :-)
@@ -308,7 +306,7 @@ extern inline unsigned int lcm(unsigned int x, unsigned int y)
#define time_exec(var,cmd) \
({ \
- if (HAS_RDTSC) { \
+ if (cpu_has_tsc) { \
unsigned int cnt1, cnt2, cnt3; \
__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3)); \
cmd; \
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 9d278a1cc..68fb88261 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -141,10 +141,10 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
unsigned char checksum = 0;
const char *name = "HP-PC-LAN+";
int mem_start;
- static unsigned version_printed = 0;
+ static unsigned version_printed;
- if (!request_region(ioaddr, HP_IO_EXTENT, "hp-plus"))
- return -ENODEV;
+ if (!request_region(ioaddr, HP_IO_EXTENT, dev->name))
+ return -EBUSY;
/* Check for the HP+ signature, 50 48 0x 53. */
if (inw(ioaddr + HP_ID) != 0x4850
@@ -249,9 +249,10 @@ hpp_open(struct net_device *dev)
{
int ioaddr = dev->base_addr - NIC_OFFSET;
int option_reg;
+ int retval;
- if (request_irq(dev->irq, ei_interrupt, 0, "hp-plus", dev)) {
- return -EAGAIN;
+ if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+ return retval;
}
/* Reset the 8390 and HP chip. */
@@ -423,9 +424,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("hp-plus.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
struct net_device *dev = &dev_hpp[this_dev];
dev->irq = irq[this_dev];
@@ -440,7 +438,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -464,7 +461,6 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index f36c341d2..26b92b8c6 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -101,9 +101,9 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
{
int i, retval, board_id, wordmode;
const char *name;
- static unsigned version_printed = 0;
+ static unsigned version_printed;
- if (!request_region(ioaddr, HP_IO_EXTENT, "hp"))
+ if (!request_region(ioaddr, HP_IO_EXTENT, dev->name))
return -ENODEV;
/* Check for the HP physical address, 08 00 09 xx xx xx. */
@@ -150,12 +150,12 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
do {
int irq = *irqp;
if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
- autoirq_setup(0);
+ unsigned long cookie = probe_irq_on();
/* Twinkle the interrupt, and check if it's seen. */
outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
- if (irq == autoirq_report(0) /* It's a good IRQ line! */
- && request_irq (irq, ei_interrupt, 0, "hp", dev) == 0) {
+ if (irq == probe_irq_off(cookie) /* It's a good IRQ line! */
+ && request_irq (irq, ei_interrupt, 0, dev->name, dev) == 0) {
printk(" selecting IRQ %d.\n", irq);
dev->irq = *irqp;
break;
@@ -170,9 +170,8 @@ int __init hp_probe1(struct net_device *dev, int ioaddr)
} else {
if (dev->irq == 2)
dev->irq = 9;
- if (request_irq(dev->irq, ei_interrupt, 0, "hp", dev)) {
+ if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
printk (" unable to get IRQ %d.\n", dev->irq);
- retval = -EBUSY;
goto out1;
}
}
@@ -396,9 +395,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("hp.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
struct net_device *dev = &dev_hp[this_dev];
dev->irq = irq[this_dev];
@@ -413,7 +409,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -437,7 +432,6 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 776169ae9..8f05bb5a0 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -857,7 +857,7 @@ static int ibmlana_open(struct IBMLANA_NETDEV *dev)
result =
request_irq(priv->realirq, irq_handler,
- SA_SHIRQ | SA_SAMPLE_RANDOM, "ibm_lana", dev);
+ SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
if (result != 0) {
printk("%s: failed to register irq %d\n", dev->name,
dev->irq);
@@ -1046,7 +1046,7 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
/* can't work without an MCA bus ;-) */
if (MCA_bus == 0)
- return ENODEV;
+ return -ENODEV;
/* start address of 1 --> forced detection */
@@ -1101,19 +1101,18 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
/* nothing found ? */
if (slot == -1)
- return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
+ return ((base != 0) || (irq != 0)) ? -ENXIO : -ENODEV;
/* announce success */
printk("%s: IBM LAN Adapter/A found in slot %d\n", dev->name,
slot + 1);
/* try to obtain I/O range */
- if (check_region(iobase, IBM_LANA_IORANGE) < 0) {
- printk("cannot allocate I/O range at %#x!\n", iobase);
+ if (!request_region(iobase, IBM_LANA_IORANGE, dev->name)) {
+ printk("%s: cannot allocate I/O range at %#x!\n", dev->name, iobase);
startslot = slot + 1;
- return 0;
+ return -EBUSY;
}
- request_region(iobase, IBM_LANA_IORANGE, "ibm_lana");
/* make procfs entries */
@@ -1128,6 +1127,10 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
priv = dev->priv =
(ibmlana_priv *) kmalloc(sizeof(ibmlana_priv), GFP_KERNEL);
+ if (!priv) {
+ release_region(iobase, IBM_LANA_IORANGE);
+ return -ENOMEM;
+ }
priv->slot = slot;
priv->realirq = irq;
priv->medium = medium;
@@ -1189,24 +1192,11 @@ int ibmlana_probe(struct IBMLANA_NETDEV *dev)
#define DEVMAX 5
-#if (LINUX_VERSION_CODE >= 0x020363)
-static struct IBMLANA_NETDEV moddevs[DEVMAX] =
- { {" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{" ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}
+static struct IBMLANA_NETDEV moddevs[DEVMAX] = {
+ { init: ibmlana_probe }, { init: ibmlana_probe },
+ { init: ibmlana_probe }, { init: ibmlana_probe },
+ { init: ibmlana_probe }
};
-#else
-static char NameSpace[8 * DEVMAX];
-static struct IBMLANA_NETDEV moddevs[DEVMAX] =
- { {NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe},
-{NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, ibmlana_probe}
-};
-#endif
int irq = 0;
int io = 0;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 03944f066..d9c2edbc0 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -230,7 +230,7 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
dev->init = irport_net_init;
dev->hard_start_xmit = irport_hard_xmit;
dev->tx_timeout = irport_timeout;
- dev->watchdog_timeo = HZ/20;
+ dev->watchdog_timeo = HZ; /* Allow time enough for speed change */
dev->open = irport_net_open;
dev->stop = irport_net_close;
dev->get_stats = irport_net_get_stats;
@@ -496,7 +496,6 @@ static void irport_write_wakeup(struct irport_cb *self)
self->tx_buff.data += actual;
self->tx_buff.len -= actual;
} else {
-
/*
* Now serial buffer is almost free & we can start
* transmission of another packet. But first we must check
@@ -629,8 +628,16 @@ int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ irda_task_execute(self, __irport_change_speed,
+ irport_change_speed_complete,
+ NULL, (void *) speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
spin_lock_irqsave(&self->lock, flags);
@@ -999,7 +1006,9 @@ static struct net_device_stats *irport_net_get_stats(struct net_device *dev)
#ifdef MODULE
MODULE_PARM(io, "1-4i");
+MODULE_PARM_DESC(io, "Base I/O adresses");
MODULE_PARM(irq, "1-4i");
+MODULE_PARM_DESC(irq, "IRQ lines");
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
index 1fd3acda9..614c5e200 100644
--- a/drivers/net/irda/irtty.c
+++ b/drivers/net/irda/irtty.c
@@ -176,7 +176,7 @@ static int irtty_open(struct tty_struct *tty)
MINOR(tty->device) - tty->driver.minor_start +
tty->driver.name_base);
- hashbin_insert(irtty, (queue_t *) self, (int) self, NULL);
+ hashbin_insert(irtty, (irda_queue_t *) self, (int) self, NULL);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -233,8 +233,6 @@ static int irtty_open(struct tty_struct *tty)
ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
return -ENOMEM;
}
- /* dev_alloc doesn't clear the struct */
- memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
dev->priv = (void *) self;
self->netdev = dev;
@@ -640,8 +638,16 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ irda_task_execute(self, irtty_change_speed,
+ irtty_change_speed_complete,
+ NULL, (void *) speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
/* Init tx buffer*/
self->tx_buff.data = self->tx_buff.head;
@@ -1029,6 +1035,7 @@ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("IrDA TTY device driver");
MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
/*
* Function init_module (void)
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 834300c28..245442ff2 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1076,9 +1076,15 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
-
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ nsc_ircc_change_speed(self, speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
+
spin_lock_irqsave(&self->lock, flags);
/* Save current bank */
@@ -1120,8 +1126,14 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ nsc_ircc_change_speed(self, speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
spin_lock_irqsave(&self->lock, flags);
@@ -2029,10 +2041,15 @@ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("NSC IrDA Device Driver");
MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
MODULE_PARM(io, "1-4i");
+MODULE_PARM_DESC(io, "Base I/O addresses");
MODULE_PARM(irq, "1-4i");
+MODULE_PARM_DESC(irq, "IRQ lines");
MODULE_PARM(dma, "1-4i");
+MODULE_PARM_DESC(dma, "DMA channels");
MODULE_PARM(dongle_id, "i");
+MODULE_PARM_DESC(dongle_id, "Type-id of used dongle");
int init_module(void)
{
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
index 470d6dd4d..480796f75 100644
--- a/drivers/net/irda/smc-ircc.c
+++ b/drivers/net/irda/smc-ircc.c
@@ -7,7 +7,7 @@
* Author: Thomas Davis (tadavis@jps.net)
* Created at:
* Modified at: Tue Feb 22 10:05:06 2000
- * Modified by: Dag Brattli <dagb@cs.uit.no>
+ * Modified by: Dag Brattli <dag@brattli.net>
*
* Copyright (c) 1999-2000 Dag Brattli
* Copyright (c) 1998-1999 Thomas Davis,
@@ -252,6 +252,7 @@ static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
irport->qos.min_turn_time.bits = 0x07;
+ irport->qos.window_size.bits = 0x01;
irda_qos_bits_to_value(&irport->qos);
irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
@@ -508,6 +509,10 @@ static void ircc_change_speed(void *priv, __u32 speed)
outb(0x00, iobase+IRCC_MASTER);
switch (speed) {
+ default:
+ IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n",
+ speed);
+ /* FALLTHROUGH */
case 9600:
case 19200:
case 38400:
@@ -535,10 +540,6 @@ static void ircc_change_speed(void *priv, __u32 speed)
fast = IRCC_LCR_A_FAST;
IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
break;
- default:
- IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n",
- speed);
- return;
}
register_bank(iobase, 0);
@@ -589,6 +590,8 @@ static void ircc_change_speed(void *priv, __u32 speed)
register_bank(iobase, 0);
outb(fast, iobase+IRCC_LCR_A);
+
+ netif_start_queue(dev);
}
/*
@@ -612,13 +615,19 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
iobase = self->io.fir_base;
- spin_lock_irqsave(&self->lock, flags);
+ netif_stop_queue(dev);
/* Check if we need to change the speed after this frame */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ ircc_change_speed(self, speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
- netif_stop_queue(dev);
+ spin_lock_irqsave(&self->lock, flags);
memcpy(self->tx_buff.head, skb->data, skb->len);
@@ -630,7 +639,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
int bofs;
/*
- * Compute who many BOFS (STA or PA's) we need to waste the
+ * Compute how many BOFs (STA or PA's) we need to waste the
* min turn time given the speed of the link.
*/
bofs = mtt * (self->io.speed / 1000) / 8000;
@@ -642,7 +651,6 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Transmit frame */
ircc_dma_xmit(self, iobase, 0);
}
-
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
@@ -759,6 +767,7 @@ static int ircc_dma_receive(struct ircc_cb *self, int iobase)
setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize,
DMA_RX_MODE);
+
/* Set max Rx frame size */
register_bank(iobase, 4);
outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
@@ -787,7 +796,6 @@ static int ircc_dma_receive(struct ircc_cb *self, int iobase)
*
* Finished with receiving frames
*
- *
*/
static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
{
@@ -814,7 +822,7 @@ static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
else
len -= 4;
- if ((len < 2) && (len > 2050)) {
+ if ((len < 2) || (len > 2050)) {
WARNING(__FUNCTION__ "(), bogus len=%d\n", len);
return;
}
@@ -1039,7 +1047,9 @@ static int ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
MODULE_DESCRIPTION("SMC IrCC controller driver");
MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM_DESC(ircc_dma, "DMA channel");
MODULE_PARM(ircc_irq, "1i");
+MODULE_PARM_DESC(ircc_irq, "IRQ line");
int init_module(void)
{
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 65ccfee2b..04d91c232 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -272,8 +272,14 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ toshoboe_setbaud(self, speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
netif_stop_queue(dev);
@@ -628,7 +634,10 @@ static int toshoboe_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#ifdef MODULE
+MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver");
+MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>");
MODULE_PARM (max_baud, "i");
+MODULE_PARM_DESC(max_baus, "Maximum baud rate");
static int
toshoboe_close (struct toshoboe_cb *self)
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 2456e012d..91e81df66 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -255,13 +255,12 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
dev->get_stats = w83977af_net_get_stats;
rtnl_lock();
- err = register_netdev(dev);
+ err = register_netdevice(dev);
rtnl_unlock();
if (err) {
- ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+ ERROR(__FUNCTION__ "(), register_netdevice() failed!\n");
return -1;
}
-
MESSAGE("IrDA: Registered device %s\n", dev->name);
return 0;
@@ -514,8 +513,14 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
/* Check if we need to change the speed */
- if ((speed = irda_get_speed(skb)) != self->io.speed)
- self->new_speed = speed;
+ if ((speed = irda_get_speed(skb)) != self->io.speed) {
+ /* Check for empty frame */
+ if (!skb->len) {
+ w83977af_change_speed(self, speed);
+ return 0;
+ } else
+ self->new_speed = speed;
+ }
/* Save current set */
set = inb(iobase+SSR);
@@ -1366,9 +1371,11 @@ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");
MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time");
MODULE_PARM(io, "1-4i");
-MODULE_PARM(io2, "1-4i");
+MODULE_PARM_DESC(io, "Base I/O addresses");
MODULE_PARM(irq, "1-4i");
+MODULE_PARM_DESC(irq, "IRQ lines");
/*
* Function init_module (void)
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index c6b11ecf5..6a6745704 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -224,7 +224,6 @@ struct lance_private {
int dma;
struct net_device_stats stats;
unsigned char chip_version; /* See lance_chip_type. */
- char tx_full;
spinlock_t devlock;
};
@@ -268,8 +267,6 @@ static struct lance_chip_type {
enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6};
-/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
-static unsigned int pci_irq_line = 0;
/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers.
Assume yes until we know the memory size. */
@@ -360,29 +357,6 @@ int lance_probe(struct net_device *dev)
if (high_memory <= phys_to_virt(16*1024*1024))
lance_need_isa_bounce_buffers = 0;
-#if defined(CONFIG_PCI)
- {
- struct pci_dev *pdev = NULL;
- if (lance_debug > 1)
- printk("lance.c: PCI bios is present, checking for devices...\n");
-
- while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
- unsigned int pci_ioaddr;
-
- if (pci_enable_device(pdev))
- continue;
- pci_set_master(pdev);
- pci_irq_line = pdev->irq;
- pci_ioaddr = pci_resource_start (pdev, 0);
- printk("Found PCnet/PCI at %#x, irq %d.\n",
- pci_ioaddr, pci_irq_line);
- result = lance_probe1(dev, pci_ioaddr, pci_irq_line, 0);
- pci_irq_line = 0;
- if (!result) return 0;
- }
- }
-#endif /* defined(CONFIG_PCI) */
-
for (port = lance_portlist; *port; port++) {
int ioaddr = *port;
@@ -671,7 +645,7 @@ lance_open_fail(struct net_device *dev)
static int
lance_open(struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
int ioaddr = dev->base_addr;
int i;
@@ -761,7 +735,7 @@ lance_open(struct net_device *dev)
static void
lance_purge_ring(struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
int i;
/* Free all the skbuffs in the Rx and Tx queues. */
@@ -770,11 +744,11 @@ lance_purge_ring(struct net_device *dev)
lp->rx_skbuff[i] = 0;
lp->rx_ring[i].base = 0; /* Not owned by LANCE chip. */
if (skb)
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (lp->tx_skbuff[i]) {
- dev_kfree_skb(lp->tx_skbuff[i]);
+ dev_kfree_skb_any(lp->tx_skbuff[i]);
lp->tx_skbuff[i] = NULL;
}
}
@@ -785,10 +759,9 @@ lance_purge_ring(struct net_device *dev)
static void
lance_init_ring(struct net_device *dev, int gfp)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
int i;
- lp->tx_full = 0;
lp->cur_rx = lp->cur_tx = 0;
lp->dirty_rx = lp->dirty_tx = 0;
@@ -828,7 +801,7 @@ lance_init_ring(struct net_device *dev, int gfp)
static void
lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
if (must_reinit ||
(chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
@@ -854,7 +827,7 @@ static void lance_tx_timeout (struct net_device *dev)
if (lance_debug > 3) {
int i;
printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
- lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+ lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (full)" : "",
lp->cur_rx);
for (i = 0; i < RX_RING_SIZE; i++)
printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
@@ -876,10 +849,13 @@ static void lance_tx_timeout (struct net_device *dev)
static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
int ioaddr = dev->base_addr;
int entry;
unsigned long flags;
+
+ spin_lock_irqsave(&lp->devlock, flags);
+
if (lance_debug > 3) {
outw(0x0000, ioaddr+LANCE_ADDR);
printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
@@ -887,8 +863,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw(0x0000, ioaddr+LANCE_DATA);
}
- netif_stop_queue (dev);
-
/* Fill in a Tx ring entry */
/* Mask to ring buffer boundary. */
@@ -929,13 +903,10 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- spin_lock_irqsave (&lp->devlock, flags);
- if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
- netif_start_queue (dev);
- else
- lp->tx_full = 1;
- spin_unlock_irqrestore (&lp->devlock, flags);
+ if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE)
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&lp->devlock, flags);
return 0;
}
@@ -954,7 +925,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
ioaddr = dev->base_addr;
- lp = (struct lance_private *)dev->priv;
+ lp = dev->priv;
spin_lock (&lp->devlock);
@@ -1018,19 +989,17 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifndef final_version
if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
- printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dirty_tx, lp->cur_tx, lp->tx_full);
+ printk("out-of-sync dirty pointer, %d vs. %d, full=%s.\n",
+ dirty_tx, lp->cur_tx,
+ netif_queue_stopped(dev) ? "yes" : "no");
dirty_tx += TX_RING_SIZE;
}
#endif
- if (lp->tx_full &&
- (netif_queue_stopped(dev)) &&
- dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
- /* The ring is no longer full, clear tbusy. */
- lp->tx_full = 0;
+ /* if the ring is no longer full, accept more packets */
+ if (netif_queue_stopped(dev) &&
+ dirty_tx > lp->cur_tx - TX_RING_SIZE + 2)
netif_wake_queue (dev);
- }
lp->dirty_tx = dirty_tx;
}
@@ -1068,7 +1037,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
static int
lance_rx(struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
int entry = lp->cur_rx & RX_RING_MOD_MASK;
int i;
@@ -1147,7 +1116,7 @@ static int
lance_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
- struct lance_private *lp = (struct lance_private *)dev->priv;
+ struct lance_private *lp = dev->priv;
netif_stop_queue (dev);
@@ -1181,19 +1150,19 @@ lance_close(struct net_device *dev)
static struct net_device_stats *lance_get_stats(struct net_device *dev)
{
- struct lance_private *lp = (struct lance_private *)dev->priv;
- short ioaddr = dev->base_addr;
- short saved_addr;
- unsigned long flags;
+ struct lance_private *lp = dev->priv;
if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
- save_flags(flags);
- cli();
+ short ioaddr = dev->base_addr;
+ short saved_addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->devlock, flags);
saved_addr = inw(ioaddr+LANCE_ADDR);
outw(112, ioaddr+LANCE_ADDR);
lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
outw(saved_addr, ioaddr+LANCE_ADDR);
- restore_flags(flags);
+ spin_unlock_irqrestore(&lp->devlock, flags);
}
return &lp->stats;
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index c1674c550..d524b5ef6 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -394,9 +394,6 @@ int init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("lne390.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) {
struct net_device *dev = &dev_lne[this_dev];
dev->irq = irq[this_dev];
@@ -410,7 +407,6 @@ int init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -434,7 +430,6 @@ void cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 806f1e114..133e8d1a1 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -29,21 +29,22 @@
occur after memory is allocated for dev->priv. Deallocated memory
last in cleanup_modue()
Richard Guenther : Added support for ISAPnP cards
-
+ Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead.
+
*/
/* Routines for the NatSemi-based designs (NE[12]000). */
-static const char *version =
- "ne.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+static const char version1[] =
+"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
+static const char version2[] =
+"Last modified Nov 1, 2000 by Paul Gortmaker\n";
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/pci.h>
#include <linux/isapnp.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -70,28 +71,11 @@ static const char *version =
/* A zero-terminated list of I/O addresses to be probed at boot. */
#ifndef MODULE
-static unsigned int netcard_portlist[] __initdata = {
+static unsigned int netcard_portlist[] __initdata = {
0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
};
#endif
-#ifdef CONFIG_PCI
-/* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */
-static struct { unsigned short vendor, dev_id; char *name; }
-pci_clone_list[] __initdata = {
- {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, "Realtek 8029" },
- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, "Winbond 89C940" },
- {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, "Compex ReadyLink 2000" },
- {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, "KTI ET32P2" },
- {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, "NetVin NV5000" },
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926, "VIA 82C926 Amazon" },
- {PCI_VENDOR_ID_SURECOM, PCI_DEVICE_ID_SURECOM_NE34, "SureCom NE34"},
- {0,}
-};
-
-static int probe_pci = 1;
-#endif
-
static struct { unsigned short vendor, function; char *name; }
isapnp_clone_list[] __initdata = {
{ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), "NN NE2000" },
@@ -114,7 +98,9 @@ bad_clone_list[] __initdata = {
{"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
{"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
{"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
- {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
+ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
+ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
+ {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
{0,}
};
#endif
@@ -132,15 +118,9 @@ bad_clone_list[] __initdata = {
#define NESM_START_PG 0x40 /* First page of TX buffer */
#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
-/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
-static unsigned int pci_irq_line = 0;
-
int ne_probe(struct net_device *dev);
static int ne_probe1(struct net_device *dev, int ioaddr);
static int ne_probe_isapnp(struct net_device *dev);
-#ifdef CONFIG_PCI
-static int ne_probe_pci(struct net_device *dev);
-#endif
static int ne_open(struct net_device *dev);
static int ne_close(struct net_device *dev);
@@ -175,16 +155,9 @@ static void ne_block_output(struct net_device *dev, const int count,
E2010 starts at 0x100 and ends at 0x4000.
E2010-x starts at 0x100 and ends at 0xffff. */
-/*
- * Note that at boot, this probe only picks up one card at a time, even for
- * multiple PCI ne2k cards. Use "ether=0,0,eth1" if you have a second PCI
- * ne2k card. This keeps things consistent regardless of the bus type of
- * the card.
- */
-
int __init ne_probe(struct net_device *dev)
{
- int base_addr = dev ? dev->base_addr : 0;
+ unsigned int base_addr = dev ? dev->base_addr : 0;
/* First check any supplied i/o locations. User knows best. <cough> */
if (base_addr > 0x1ff) /* Check a single specified location. */
@@ -192,12 +165,6 @@ int __init ne_probe(struct net_device *dev)
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
-#ifdef CONFIG_PCI
- /* Then look for any installed PCI clones */
- if (probe_pci && pci_present() && (ne_probe_pci(dev) == 0))
- return 0;
-#endif
-
/* Then look for any installed ISAPnP clones */
if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
return 0;
@@ -206,8 +173,6 @@ int __init ne_probe(struct net_device *dev)
/* Last resort. The semi-risky ISA auto-probe. */
for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
int ioaddr = netcard_portlist[base_addr];
- if (check_region(ioaddr, NE_IO_EXTENT))
- continue;
if (ne_probe1(dev, ioaddr) == 0)
return 0;
}
@@ -216,47 +181,10 @@ int __init ne_probe(struct net_device *dev)
return -ENODEV;
}
-#ifdef CONFIG_PCI
-static int __init ne_probe_pci(struct net_device *dev)
-{
- int i;
-
- for (i = 0; pci_clone_list[i].vendor != 0; i++) {
- struct pci_dev *pdev = NULL;
- unsigned int pci_ioaddr = 0;
-
- while ((pdev = pci_find_device(pci_clone_list[i].vendor, pci_clone_list[i].dev_id, pdev))) {
- if (pci_enable_device(pdev))
- continue;
- pci_ioaddr = pci_resource_start (pdev, 0);
- /* Avoid already found cards from previous calls */
- if (check_region(pci_ioaddr, NE_IO_EXTENT))
- continue;
- pci_irq_line = pdev->irq;
- if (pci_irq_line) break; /* Found it */
- }
- if (!pdev)
- continue;
- printk(KERN_INFO "ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n",
- pci_clone_list[i].name,
- pci_ioaddr, pci_irq_line);
- printk("*\n* Use of the PCI-NE2000 driver with this card is recommended!\n*\n");
- if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */
- printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr);
- pci_irq_line = 0;
- return -ENXIO;
- }
- pci_irq_line = 0;
- return 0;
- }
- return -ENODEV;
-}
-#endif /* CONFIG_PCI */
-
static int __init ne_probe_isapnp(struct net_device *dev)
{
int i;
-
+
for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
struct pci_dev *idev = NULL;
@@ -269,14 +197,18 @@ static int __init ne_probe_isapnp(struct net_device *dev)
continue;
if (idev->activate(idev))
continue;
- pci_irq_line = idev->irq_resource[0].start;
/* if no irq, search for next */
- if (!pci_irq_line)
+ if (idev->irq_resource[0].start == 0)
continue;
/* found it */
- if (ne_probe1(dev, idev->resource[0].start) != 0) { /* Shouldn't happen. */
- printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n",
- idev->resource[0].start);
+ dev->base_addr = idev->resource[0].start;
+ dev->irq = idev->irq_resource[0].start;
+ printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
+ isapnp_clone_list[i].name,
+
+ dev->base_addr, dev->irq);
+ if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */
+ printk(KERN_ERR "ne.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr);
return -ENXIO;
}
ei_status.priv = (unsigned long)idev;
@@ -284,9 +216,6 @@ static int __init ne_probe_isapnp(struct net_device *dev)
}
if (!idev)
continue;
- printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
- isapnp_clone_list[i].name,
- dev->base_addr, dev->irq);
return 0;
}
@@ -301,11 +230,17 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
const char *name = NULL;
int start_page, stop_page;
int neX000, ctron, copam, bad_card;
- int reg0 = inb_p(ioaddr);
+ int reg0, ret;
static unsigned version_printed = 0;
- if (reg0 == 0xFF)
- return -ENODEV;
+ if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
+ return -EBUSY;
+
+ reg0 = inb_p(ioaddr);
+ if (reg0 == 0xFF) {
+ ret = -ENODEV;
+ goto err_out;
+ }
/* Do a preliminary verification that we have a 8390. */
{
@@ -318,12 +253,13 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
outb_p(reg0, ioaddr);
outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_out;
}
}
if (ei_debug && version_printed++ == 0)
- printk(version);
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
@@ -350,10 +286,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
break;
} else {
printk(" not found (no reset ack).\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_out;
}
}
-
+
outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
}
@@ -362,7 +299,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
We can't reliably read the SAPROM address without this.
(I learned the hard way!). */
{
- struct {unsigned char value, offset; } program_seq[] =
+ struct {unsigned char value, offset; } program_seq[] =
{
{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
{0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
@@ -390,20 +327,10 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
wordlength = 1;
}
- /* At this point, wordlength *only* tells us if the SA_prom is doubled
- up or not because some broken PCI cards don't respect the byte-wide
- request in program_seq above, and hence don't have doubled up values.
- These broken cards would otherwise be detected as an ne1000. */
-
if (wordlength == 2)
+ {
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
-
- if (pci_irq_line || ioaddr >= 0x400)
- wordlength = 2; /* Catch broken PCI cards mentioned above. */
-
- if (wordlength == 2)
- {
/* We must set the 8390 for word mode. */
outb_p(0x49, ioaddr + EN0_DCFG);
start_page = NESM_START_PG;
@@ -416,13 +343,12 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57);
ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
-
/* Set up the rest of the parameters. */
if (neX000 || bad_card || copam) {
name = (wordlength == 2) ? "NE2000" : "NE1000";
}
- else if (ctron)
+ else if (ctron)
{
name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
start_page = 0x01;
@@ -433,13 +359,13 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
#ifdef SUPPORT_NE_BAD_CLONES
/* Ack! Well, there might be a *bad* NE*000 clone there.
Check for total bogus addresses. */
- for (i = 0; bad_clone_list[i].name8; i++)
+ for (i = 0; bad_clone_list[i].name8; i++)
{
if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
- SA_prom[2] == bad_clone_list[i].SAprefix[2])
+ SA_prom[2] == bad_clone_list[i].SAprefix[2])
{
- if (wordlength == 2)
+ if (wordlength == 2)
{
name = bad_clone_list[i].name16;
} else {
@@ -448,31 +374,30 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
break;
}
}
- if (bad_clone_list[i].name8 == NULL)
+ if (bad_clone_list[i].name8 == NULL)
{
printk(" not found (invalid signature %2.2x %2.2x).\n",
SA_prom[14], SA_prom[15]);
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_out;
}
#else
printk(" not found.\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_out;
#endif
}
- if (pci_irq_line)
- dev->irq = pci_irq_line;
-
- if (dev->irq < 2)
+ if (dev->irq < 2)
{
- autoirq_setup(0);
+ unsigned long cookie = probe_irq_on();
outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */
outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
mdelay(10); /* wait 10ms for interrupt to propagate */
outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
- dev->irq = autoirq_report(0);
+ dev->irq = probe_irq_off(cookie);
if (ei_debug > 2)
printk(" autoirq is %d\n", dev->irq);
} else if (dev->irq == 2)
@@ -482,31 +407,27 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
if (! dev->irq) {
printk(" failed to detect IRQ line.\n");
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto err_out;
}
/* Allocate dev->priv and fill in 8390 specific dev fields. */
- if (ethdev_init(dev))
+ if (ethdev_init(dev))
{
printk (" unable to get memory for dev->priv.\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_out;
}
-
+
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
-
- {
- int irqval = request_irq(dev->irq, ei_interrupt,
- pci_irq_line ? SA_SHIRQ : 0, name, dev);
- if (irqval) {
- printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
- kfree(dev->priv);
- dev->priv = NULL;
- return -EAGAIN;
- }
+ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+ if (ret) {
+ printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+ goto err_out_kfree;
}
+
dev->base_addr = ioaddr;
- request_region(ioaddr, NE_IO_EXTENT, name);
for(i = 0; i < ETHER_ADDR_LEN; i++) {
printk(" %2.2x", SA_prom[i]);
@@ -536,6 +457,13 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
dev->stop = &ne_close;
NS8390_init(dev, 0);
return 0;
+
+err_out_kfree:
+ kfree(dev->priv);
+ dev->priv = NULL;
+err_out:
+ release_region(ioaddr, NE_IO_EXTENT);
+ return ret;
}
static int ne_open(struct net_device *dev)
@@ -589,7 +517,7 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, i
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing)
+ if (ei_status.dmaing)
{
printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
"[DMAstat:%d][irqlock:%d].\n",
@@ -628,7 +556,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
char *buf = skb->data;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing)
+ if (ei_status.dmaing)
{
printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
"[DMAstat:%d][irqlock:%d].\n",
@@ -642,10 +570,10 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
- if (ei_status.word16)
+ if (ei_status.word16)
{
insw(NE_BASE + NE_DATAPORT,buf,count>>1);
- if (count & 0x01)
+ if (count & 0x01)
{
buf[count-1] = inb(NE_BASE + NE_DATAPORT);
#ifdef NE_SANITY_CHECK
@@ -662,7 +590,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
this message you either 1) have a slightly incompatible clone
or 2) have noise/speed problems with your bus. */
- if (ei_debug > 1)
+ if (ei_debug > 1)
{
/* DMA termination address check... */
int addr, tries = 20;
@@ -697,12 +625,12 @@ static void ne_block_output(struct net_device *dev, int count,
/* Round the count up for word writes. Do we need to do this?
What effect will an odd byte count have on the 8390?
I should check someday. */
-
+
if (ei_status.word16 && (count & 0x01))
count++;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
- if (ei_status.dmaing)
+ if (ei_status.dmaing)
{
printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
"[DMAstat:%d][irqlock:%d]\n",
@@ -722,7 +650,7 @@ retry:
Crynwr packet driver -- the NatSemi method doesn't work.
Actually this doesn't always work either, but if you have
problems with your NEx000 this is better than nothing! */
-
+
outb_p(0x42, nic_base + EN0_RCNTLO);
outb_p(0x00, nic_base + EN0_RCNTHI);
outb_p(0x42, nic_base + EN0_RSARLO);
@@ -752,8 +680,8 @@ retry:
#ifdef NE_SANITY_CHECK
/* This was for the ALPHA version only, but enough people have
been encountering problems so it is still here. */
-
- if (ei_debug > 1)
+
+ if (ei_debug > 1)
{
/* DMA termination address check... */
int addr, tries = 20;
@@ -765,7 +693,7 @@ retry:
break;
} while (--tries > 0);
- if (tries <= 0)
+ if (tries <= 0)
{
printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
"%#4.4x (expected) vs. %#4.4x (actual).\n",
@@ -801,10 +729,6 @@ MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
-#ifdef CONFIG_PCI
-MODULE_PARM(probe_pci, "i");
-#endif
-
/* This is set up so that no ISA autoprobe takes place. We can't guarantee
that the ne2k probe is the last 8390 based probe to take place (as it
is at boot) and so the probe will get confused by any other 8390 cards.
@@ -814,9 +738,6 @@ int init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("ne.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
struct net_device *dev = &dev_ne[this_dev];
dev->irq = irq[this_dev];
@@ -833,8 +754,7 @@ int init_module(void)
if (io[this_dev] != 0)
printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
else
- printk(KERN_NOTICE "ne.c: No PCI cards found. Use \"io=0xNNN\" value(s) for ISA cards.\n");
- unload_8390_module();
+ printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
return -ENXIO;
}
return 0;
@@ -857,7 +777,6 @@ void cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 2a558e20e..3ff0ef141 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -200,12 +200,12 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
static int __init ne2_probe1(struct net_device *dev, int slot)
{
- int i, base_addr, irq;
+ int i, base_addr, irq, retval;
unsigned char POS;
unsigned char SA_prom[32];
const char *name = "NE/2";
int start_page, stop_page;
- static unsigned version_printed = 0;
+ static unsigned version_printed;
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -226,6 +226,9 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
base_addr = addresses[i - 1];
irq = irqs[(POS & 0x60)>>5];
+ if (!request_region(base_addr, NE_IO_EXTENT, dev->name))
+ return -EBUSY;
+
#ifdef DEBUG
printk("POS info : pos 2 = %#x ; base = %#x ; irq = %ld\n", POS,
base_addr, irq);
@@ -239,7 +242,8 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
outb(0x21, base_addr + NE_CMD);
if (inb(base_addr + NE_CMD) != 0x21) {
printk("NE/2 adapter not responding\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
/* In the crynwr sources they do a RAM-test here. I skip it. I suppose
@@ -260,7 +264,8 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
while ((inb_p(base_addr + EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2*HZ/100) {
printk(" not found (no reset ack).\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
outb_p(0xff, base_addr + EN0_ISR); /* Ack all intr. */
@@ -309,14 +314,11 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
/* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */
- {
- int irqval = request_irq(dev->irq, ei_interrupt,
- 0, name, dev);
- if (irqval) {
- printk (" unable to get IRQ %d (irqval=%d).\n",
- dev->irq, +irqval);
- return -EAGAIN;
- }
+ retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+ if (retval) {
+ printk (" unable to get IRQ %d (irqval=%d).\n",
+ dev->irq, retval);
+ goto out;
}
dev->base_addr = base_addr;
@@ -325,11 +327,10 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
if (ethdev_init(dev)) {
printk (" unable to get memory for dev->priv.\n");
free_irq(dev->irq, dev);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto out;
}
- request_region(base_addr, NE_IO_EXTENT, name);
-
for(i = 0; i < ETHER_ADDR_LEN; i++) {
printk(" %2.2x", SA_prom[i]);
dev->dev_addr[i] = SA_prom[i];
@@ -362,6 +363,9 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
dev->stop = &ne_close;
NS8390_init(dev, 0);
return 0;
+out:
+ release_region(base_addr, NE_IO_EXTENT);
+ return retval;
}
static int ne_open(struct net_device *dev)
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index f43082c7f..3ba20f197 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -2,29 +2,48 @@
/*
A Linux device driver for PCI NE2000 clones.
- Authorship and other copyrights:
- 1992-1998 by Donald Becker, NE2000 core and various modifications.
+ Authors and other copyright holders:
+ 1992-2000 by Donald Becker, NE2000 core and various modifications.
1995-1998 by Paul Gortmaker, core modifications and PCI support.
-
Copyright 1993 assigned to the United States Government as represented
by the Director, National Security Agency.
- This software may be used and distributed according to the terms
- of the GNU Public License, incorporated herein by reference.
-
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
- Center of Excellence in Space Data and Information Sciences
- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
- People are making PCI ne2000 clones! Oh the horror, the horror...
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
Issues remaining:
- No full-duplex support.
+ People are making PCI ne2000 clones! Oh the horror, the horror...
+ Limited full-duplex support.
*/
-/* Our copyright info must remain in the binary. */
-static const char *version =
-"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n";
+static const char version2[] =
+" http://www.scyld.com/network/ne2k-pci.html\n";
+
+/* The user-configurable values.
+ These may be modified when a driver module is loaded.*/
+
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+#define MAX_UNITS 8 /* More are supported, limit only on options */
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS];
+static int options[MAX_UNITS];
+
+/* Force a non std. amount of memory. Units are 256 byte pages. */
+/* #define PACKETBUF_MEMSIZE 0x40 */
+
#include <linux/module.h>
#include <linux/kernel.h>
@@ -48,8 +67,11 @@ static const char *version =
#define outsl outsl_ns
#endif
-/* Set statically or when loading the driver module. */
-static int debug = 1;
+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
+MODULE_DESCRIPTION("PCI NE2000 clone driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
/* Some defines that people can play with if so inclined. */
@@ -59,19 +81,16 @@ static int debug = 1;
/* Do we implement the read before write bugfix ? */
/* #define NE_RW_BUGFIX */
-/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
-/* #define PACKETBUF_MEMSIZE 0x40 */
-
-#define ne2k_flags reg0 /* Rename an existing field to store flags! */
-
-/* Only the low 8 bits are usable for non-init-time flags! */
+/* Flags. We rename an existing ei_status field to store flags! */
+/* Thus only the low 8 bits are usable for non-init-time flags. */
+#define ne2k_flags reg0
enum {
- HOLTEK_FDX=1, /* Full duplex -> set 0x80 at offset 0x20. */
- ONLY_16BIT_IO=2, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ FORCE_FDX=0x20, /* User override. */
+ REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
STOP_PG_0x60=0x100,
};
-
enum ne2k_pci_chipsets {
CH_RealTek_RTL_8029 = 0,
CH_Winbond_89C940,
@@ -90,7 +109,7 @@ static struct {
char *name;
int flags;
} pci_clone_list[] __devinitdata = {
- {"RealTek RTL-8029", 0},
+ {"RealTek RTL-8029", REALTEK_FDX},
{"Winbond 89C940", 0},
{"Compex RL2000", 0},
{"KTI ET32P2", 0},
@@ -145,7 +164,8 @@ static void ne2k_pci_block_output(struct net_device *dev, const int count,
-/* No room in the standard 8390 structure for extra info we need. */
+/* There is no room in the standard 8390 structure for extra info we need,
+ so we build a meta/outer-wrapper structure.. */
struct ne2k_pci_card {
struct net_device *dev;
struct pci_dev *pci_dev;
@@ -171,33 +191,35 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *dev;
- int i, irq, reg0, start_page, stop_page;
+ int i;
unsigned char SA_prom[32];
- int chip_idx = ent->driver_data;
- static unsigned version_printed = 0;
+ int start_page, stop_page;
+ int irq, reg0, chip_idx = ent->driver_data;
+ static unsigned int fnd_cnt;
long ioaddr;
-
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ int flags = pci_clone_list[chip_idx].flags;
+
+ if (fnd_cnt++ == 0)
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
ioaddr = pci_resource_start (pdev, 0);
irq = pdev->irq;
-
+
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
printk (KERN_ERR "ne2k-pci: no I/O resource at PCI BAR #0\n");
return -ENODEV;
}
-
+
i = pci_enable_device (pdev);
if (i)
return i;
-
+
if (request_region (ioaddr, NE_IO_EXTENT, "ne2k-pci") == NULL) {
printk (KERN_ERR "ne2k-pci: I/O resource 0x%x @ 0x%lx busy\n",
NE_IO_EXTENT, ioaddr);
return -EBUSY;
}
-
+
reg0 = inb(ioaddr);
if (reg0 == 0xFF)
goto err_out_free_res;
@@ -222,7 +244,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
printk (KERN_ERR "ne2k-pci: cannot allocate ethernet device\n");
goto err_out_free_res;
}
-
+
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
unsigned long reset_start_time = jiffies;
@@ -238,7 +260,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
printk("ne2k-pci: Card failure (no reset ack).\n");
goto err_out_free_netdev;
}
-
+
outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
}
@@ -269,7 +291,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
/* Note: all PCI cards have at least 16 bit access, so we don't have
to check for 8 bit cards. Most cards permit 32 bit access. */
- if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
+ if (flags & ONLY_32BIT_IO) {
for (i = 0; i < 4 ; i++)
((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
} else
@@ -280,8 +302,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
outb(0x49, ioaddr + EN0_DCFG);
start_page = NESM_START_PG;
- stop_page =
- pci_clone_list[chip_idx].flags&STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
+ stop_page = flags & STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
/* Set up the rest of the parameters. */
dev->irq = irq;
@@ -305,7 +326,11 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
ei_status.tx_start_page = start_page;
ei_status.stop_page = stop_page;
ei_status.word16 = 1;
- ei_status.ne2k_flags = pci_clone_list[chip_idx].flags;
+ ei_status.ne2k_flags = flags;
+ if (fnd_cnt < MAX_UNITS) {
+ if (full_duplex[fnd_cnt] > 0 || (options[fnd_cnt] & FORCE_FDX))
+ ei_status.ne2k_flags |= FORCE_FDX;
+ }
ei_status.rx_start_page = start_page + TX_PAGES;
#ifdef PACKETBUF_MEMSIZE
@@ -331,20 +356,27 @@ err_out_free_res:
}
-static int
-ne2k_pci_open(struct net_device *dev)
+static int ne2k_pci_open(struct net_device *dev)
{
MOD_INC_USE_COUNT;
if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev)) {
MOD_DEC_USE_COUNT;
return -EAGAIN;
}
+ /* Set full duplex for the chips that we know about. */
+ if (ei_status.ne2k_flags & FORCE_FDX) {
+ long ioaddr = dev->base_addr;
+ if (ei_status.ne2k_flags & REALTEK_FDX) {
+ outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ } else if (ei_status.ne2k_flags & HOLTEK_FDX)
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ }
ei_open(dev);
return 0;
}
-static int
-ne2k_pci_close(struct net_device *dev)
+static int ne2k_pci_close(struct net_device *dev)
{
ei_close(dev);
free_irq(dev->irq, dev);
@@ -354,8 +386,7 @@ ne2k_pci_close(struct net_device *dev)
/* Hard reset the card. This used to pause for the same period that a
8390 reset command required, but that shouldn't be necessary. */
-static void
-ne2k_pci_reset_8390(struct net_device *dev)
+static void ne2k_pci_reset_8390(struct net_device *dev)
{
unsigned long reset_start_time = jiffies;
@@ -380,8 +411,7 @@ ne2k_pci_reset_8390(struct net_device *dev)
we don't need to be concerned with ring wrap as the header will be at
the start of a page, so we optimize accordingly. */
-static void
-ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
long nic_base = dev->base_addr;
@@ -418,8 +448,8 @@ ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int rin
The NEx000 doesn't share the on-board packet memory -- you have to put
the packet out through the "remote DMA" dataport using outb. */
-static void
-ne2k_pci_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+static void ne2k_pci_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
{
long nic_base = dev->base_addr;
char *buf = skb->data;
@@ -461,9 +491,8 @@ ne2k_pci_block_input(struct net_device *dev, int count, struct sk_buff *skb, int
ei_status.dmaing &= ~0x01;
}
-static void
-ne2k_pci_block_output(struct net_device *dev, int count,
- const unsigned char *buf, const int start_page)
+static void ne2k_pci_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, const int start_page)
{
long nic_base = NE_BASE;
unsigned long dma_start;
@@ -520,8 +549,8 @@ ne2k_pci_block_output(struct net_device *dev, int count,
dma_start = jiffies;
while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
- if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+ if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
+ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
ne2k_pci_reset_8390(dev);
NS8390_init(dev,1);
break;
@@ -536,12 +565,10 @@ ne2k_pci_block_output(struct net_device *dev, int count,
static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
-
- if (!dev) {
- printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n");
- return;
- }
-
+
+ if (!dev)
+ BUG();
+
unregister_netdev(dev);
release_region(dev->base_addr, NE_IO_EXTENT);
kfree(dev);
@@ -559,43 +586,14 @@ static struct pci_driver ne2k_driver = {
static int __init ne2k_pci_init(void)
{
- int rc;
-
- if (load_8390_module("ne2k-pci.c"))
- return -ENOSYS;
-
- rc = pci_module_init (&ne2k_driver);
-
- /* XXX should this test CONFIG_HOTPLUG like pci_module_init? */
-
- /* YYY No. If we're returning non-zero, we're being unloaded
- * immediately. dwmw2
- */
- if (rc <= 0)
- unload_8390_module();
-
- return rc;
+ return pci_module_init (&ne2k_driver);
}
static void __exit ne2k_pci_cleanup(void)
{
pci_unregister_driver (&ne2k_driver);
- unload_8390_module();
}
module_init(ne2k_pci_init);
module_exit(ne2k_pci_cleanup);
-
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/ -c ne2k-pci.c"
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * version-control: t
- * kept-new-versions: 5
- * End:
- */
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 02b70351b..e57551271 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -44,7 +44,7 @@ static const char *version =
#include "8390.h"
int ne3210_probe(struct net_device *dev);
-int ne3210_probe1(struct net_device *dev, int ioaddr);
+static int ne3210_probe1(struct net_device *dev, int ioaddr);
static int ne3210_open(struct net_device *dev);
static int ne3210_close(struct net_device *dev);
@@ -112,23 +112,26 @@ int __init ne3210_probe(struct net_device *dev)
}
/* EISA spec allows for up to 16 slots, but 8 is typical. */
- for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- if (check_region(ioaddr , NE3210_IO_EXTENT))
- continue;
+ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
if (ne3210_probe1(dev, ioaddr) == 0)
return 0;
- }
return -ENODEV;
}
-int __init ne3210_probe1(struct net_device *dev, int ioaddr)
+static int __init ne3210_probe1(struct net_device *dev, int ioaddr)
{
- int i;
+ int i, retval;
unsigned long eisa_id;
const char *ifmap[] = {"UTP", "?", "BNC", "AUI"};
- if (inb_p(ioaddr + NE3210_ID_PORT) == 0xff) return -ENODEV;
+ if (!request_region(dev->base_addr, NE3210_IO_EXTENT, dev->name))
+ return -EBUSY;
+
+ if (inb_p(ioaddr + NE3210_ID_PORT) == 0xff) {
+ retval = -ENODEV;
+ goto out;
+ }
#if NE3210_DEBUG & NE3210_D_PROBE
printk("ne3210-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + NE3210_ID_PORT));
@@ -140,7 +143,8 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
/* Check the EISA ID of the card. */
eisa_id = inl(ioaddr + NE3210_ID_PORT);
if (eisa_id != NE3210_ID) {
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
@@ -153,14 +157,16 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
for(i = 0; i < ETHER_ADDR_LEN; i++)
printk(" %02x", inb(ioaddr + NE3210_SA_PROM + i));
printk(" (invalid prefix).\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
#endif
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
printk ("ne3210.c: unable to allocate memory for dev->priv!\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto out;
}
printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
@@ -181,11 +187,10 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
}
printk(" IRQ %d,", dev->irq);
- if (request_irq(dev->irq, ei_interrupt, 0, "ne3210", dev)) {
+ retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+ if (retval) {
printk (" unable to get IRQ %d.\n", dev->irq);
- kfree(dev->priv);
- dev->priv = NULL;
- return -EAGAIN;
+ goto out1;
}
if (dev->mem_start == 0) {
@@ -211,20 +216,16 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
printk(KERN_CRIT "ne3210.c: or to an address above 0x%lx.\n", virt_to_bus(high_memory));
printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
- free_irq(dev->irq, dev);
- kfree(dev->priv);
- dev->priv = NULL;
- return -EINVAL;
+ retval = -EINVAL;
+ goto out2;
}
dev->mem_start = (unsigned long)ioremap(dev->mem_start, NE3210_STOP_PG*0x100);
if (dev->mem_start == 0) {
printk(KERN_ERR "ne3210.c: Unable to remap card memory above 1MB !!\n");
printk(KERN_ERR "ne3210.c: Try using EISA SCU to set memory below 1MB.\n");
printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
- free_irq(dev->irq, dev);
- kfree(dev->priv);
- dev->priv = NULL;
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto out2;
}
ei_status.reg0 = 1; /* Use as remap flag */
printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n",
@@ -237,7 +238,6 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
/* The 8390 offset is zero for the NE3210 */
dev->base_addr = ioaddr;
- request_region(dev->base_addr, NE3210_IO_EXTENT, "ne3210");
ei_status.name = "NE3210";
ei_status.tx_start_page = NE3210_START_PG;
@@ -257,6 +257,14 @@ int __init ne3210_probe1(struct net_device *dev, int ioaddr)
dev->stop = &ne3210_close;
NS8390_init(dev, 0);
return 0;
+out2:
+ free_irq(dev->irq, dev);
+out1:
+ kfree(dev->priv);
+ dev->priv = NULL;
+out:
+ release_region(ioaddr, NE3210_IO_EXTENT);
+ return retval;
}
/*
@@ -367,9 +375,6 @@ int init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("ne3210.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
struct net_device *dev = &dev_ne3210[this_dev];
dev->irq = irq[this_dev];
@@ -383,7 +388,6 @@ int init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -398,16 +402,15 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
struct net_device *dev = &dev_ne3210[this_dev];
if (dev->priv != NULL) {
- void *priv = dev->priv;
free_irq(dev->irq, dev);
release_region(dev->base_addr, NE3210_IO_EXTENT);
if (ei_status.reg0)
iounmap((void *)dev->mem_start);
unregister_netdev(dev);
- kfree(priv);
+ kfree(dev->priv);
+ dev->priv = NULL;
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
index e24e0e4f0..f3d2c5426 100644
--- a/drivers/net/oaknet.c
+++ b/drivers/net/oaknet.c
@@ -664,25 +664,10 @@ oaknet_dma_error(struct net_device *dev, const char *name)
*/
static int __init oaknet_init_module (void)
{
- int status;
-
- /*
- * We're dependent on the 8390 generic driver module, make
- * sure its symbols are loaded.
- */
-
- if (load_8390_module("oaknet.c"))
- return (-ENOSYS);
-
if (oaknet_devs != NULL)
return (-EBUSY);
- status = oaknet_init()
-
- if (status != 0)
- unload_8390_module();
-
- return (status);
+ return (oaknet_init());
}
/*
@@ -704,7 +689,6 @@ static void __exit oaknet_cleanup_module (void)
oaknet_devs = NULL;
- unload_8390_module();
}
module_init(oaknet_init_module);
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 4ad968390..0f116b23d 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -36,7 +36,8 @@ if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \
"$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \
"$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \
"$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \
- "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then
+ "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" -o \
+ "$CONFIG_PCMCIA_XIRTULIP" = "y" ]; then
define_bool CONFIG_PCMCIA_NETCARD y
fi
diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c
index c5f5d34de..1b9d83417 100644
--- a/drivers/net/pcmcia/xircom_tulip_cb.c
+++ b/drivers/net/pcmcia/xircom_tulip_cb.c
@@ -466,7 +466,7 @@ static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
restore_flags(flags);
return;
}
- newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+ newcsr6 &= 0x726cfecb; /* mask out the reserved CSR6 bits that always */
/* read 0 on the Xircom cards */
newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
currcsr6 = inl(ioaddr + CSR6);
@@ -1350,7 +1350,7 @@ tulip_up(struct net_device *dev)
tp->tx_ring[0].length = 0x08000000 | 192;
/* Lie about the address of our setup frame to make the */
/* chip happy */
- tp->tx_ring[0].buffer1 = (virt_to_bus(tp->setup_frame) + 4);
+ tp->tx_ring[0].buffer1 = virt_to_bus(tp->setup_frame);
tp->tx_ring[0].status = DescOwned;
tp->cur_tx++;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 05d0c06d1..feb723651 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -5,7 +5,7 @@
* PPPoE --- PPP over Ethernet (RFC 2516)
*
*
- * Version: 0.6.3
+ * Version: 0.6.4
*
* 030700 : Fixed connect logic to allow for disconnect.
* 270700 : Fixed potential SMP problems; we must protect against
@@ -13,12 +13,11 @@
* and ppp_unregister_channel.
* 040800 : Respect reference count mechanisms on net-devices.
* 200800 : fix kfree(skb) in pppoe_rcv (acme)
- *
* Module reference count is decremented in the right spot now,
* guards against sock_put not actually freeing the sk
* in pppoe_release.
- *
- * 051000 : Initialization cleanup
+ * 051000 : Initialization cleanup.
+ * 111100 : Fix recvmsg.
*
* Author: Michal Ostrowski <mostrows@styx.uwaterloo.ca>
* Contributors:
@@ -292,9 +291,7 @@ static int pppoe_device_event(struct notifier_block *this,
static struct notifier_block pppoe_notifier = {
- pppoe_device_event,
- NULL,
- 0
+ notifier_call: pppoe_device_event,
};
@@ -535,13 +532,10 @@ int pppoe_release(struct socket *sock)
if (po->pppoe_dev)
dev_put(po->pppoe_dev);
- /* Should also do a queue purge here */
-
sock_orphan(sk);
sock->sk = NULL;
skb_queue_purge(&sk->receive_queue);
-
sock_put(sk);
return error;
@@ -568,7 +562,7 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
if ((sk->state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid)
goto end;
- /* Check for already disconnected sockets,
+ /* Check for already disconnected sockets,
on attempts to disconnect */
error = -EALREADY;
if((sk->state & PPPOX_DEAD) && !sp->sa_addr.pppoe.sid )
@@ -592,7 +586,7 @@ int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Don't re-bind if sid==0 */
if (sp->sa_addr.pppoe.sid != 0) {
dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
-
+
error = -ENODEV;
if (!dev)
goto end;
@@ -728,6 +722,7 @@ int pppoe_ioctl(struct socket *sock, unsigned int cmd,
if (!relay_po)
break;
+ sock_put(relay_po->sk);
sk->state |= PPPOX_RELAY;
err = 0;
break;
@@ -759,7 +754,6 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
struct pppoe_hdr *ph;
struct net_device *dev;
char *start;
- int copied = 0;
if (sk->dead || !(sk->state & PPPOX_CONNECTED)) {
error = -ENOTCONN;
@@ -775,6 +769,11 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
dev = sk->protinfo.pppox->pppoe_dev;
+ error = -EMSGSIZE;
+ if(total_len > dev->mtu+dev->hard_header_len)
+ goto end;
+
+
skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
0, GFP_KERNEL);
if (!skb) {
@@ -795,21 +794,25 @@ int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr));
start = (char *) &ph->tag[0];
- error = copied = memcpy_fromiovec( start, m->msg_iov, m->msg_iovlen);
- if( error <= 0 )
- goto end;
+ error = memcpy_fromiovec( start, m->msg_iov, total_len);
+
+ if (error < 0) {
+ kfree_skb(skb);
+ goto end;
+ }
+ error = total_len;
dev->hard_header(skb, dev, ETH_P_PPP_SES,
sk->protinfo.pppox->pppoe_pa.remote,
- NULL, copied);
+ NULL, total_len);
memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
- ph->length = htons(copied);
+ ph->length = htons(total_len);
dev_queue_xmit(skb);
-end:
+ end:
release_sock(sk);
return error;
}
@@ -1027,7 +1030,7 @@ int __init pppoe_init(void)
int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
if (err == 0) {
- printk(KERN_INFO "Registered PPPoE v0.6.3\n");
+ printk(KERN_INFO "Registered PPPoE v0.6.4\n");
dev_add_pack(&pppoes_ptype);
register_netdevice_notifier(&pppoe_notifier);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index d12a9e150..0305b4574 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1548,74 +1548,76 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
unsigned int i;
int error = -EOPNOTSUPP;
- rrpriv = (struct rr_private *)dev->priv;
-
- spin_lock(&rrpriv->lock);
+ rrpriv = dev->priv;
switch(cmd){
case SIOCRRGFW:
if (!capable(CAP_SYS_RAWIO)){
- error = -EPERM;
- goto out;
- }
-
- if (rrpriv->fw_running){
- printk("%s: Firmware already running\n", dev->name);
- error = -EPERM;
- goto out;
+ return -EPERM;
}
image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!image){
printk(KERN_ERR "%s: Unable to allocate memory "
"for EEPROM image\n", dev->name);
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
+
+ spin_lock(&rrpriv->lock);
+
+ if (rrpriv->fw_running){
+ printk("%s: Firmware already running\n", dev->name);
+ error = -EPERM;
+ goto out_spin;
+ }
+
i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
if (i != EEPROM_BYTES){
- kfree(image);
- printk(KERN_ERR "%s: Error reading EEPROM\n",
- dev->name);
+ printk(KERN_ERR "%s: Error reading EEPROM\n", dev->name);
error = -EFAULT;
- goto out;
+ goto out_spin;
}
+ spin_unlock(&rrpriv->lock);
error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES);
if (error)
error = -EFAULT;
kfree(image);
- break;
+ return error;
+
case SIOCRRPFW:
if (!capable(CAP_SYS_RAWIO)){
- error = -EPERM;
- goto out;
- }
-
- if (rrpriv->fw_running){
- printk("%s: Firmware already running\n", dev->name);
- error = -EPERM;
- goto out;
+ return -EPERM;
}
image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!image){
printk(KERN_ERR "%s: Unable to allocate memory "
"for EEPROM image\n", dev->name);
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
if (!oldimage){
+ kfree(image);
printk(KERN_ERR "%s: Unable to allocate memory "
"for old EEPROM image\n", dev->name);
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES);
- if (error)
- error = -EFAULT;
+ if (error) {
+ kfree(image);
+ kfree(oldimage);
+ return -EFAULT;
+ }
+
+ spin_lock(&rrpriv->lock);
+ if (rrpriv->fw_running){
+ kfree(oldimage);
+ printk("%s: Firmware already running\n", dev->name);
+ error = -EPERM;
+ goto out_spin;
+ }
printk("%s: Updating EEPROM firmware\n", dev->name);
@@ -1629,6 +1631,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
printk(KERN_ERR "%s: Error reading back EEPROM "
"image\n", dev->name);
+ spin_unlock(&rrpriv->lock);
error = memcmp(image, oldimage, EEPROM_BYTES);
if (error){
printk(KERN_ERR "%s: Error verifying EEPROM image\n",
@@ -1637,16 +1640,16 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
kfree(image);
kfree(oldimage);
- break;
+ return error;
+
case SIOCRRID:
- error = put_user(0x52523032, (int *)(&rq->ifr_data[0]));
- if (error)
- error = -EFAULT;
- break;
+ return put_user(0x52523032, (int *)(&rq->ifr_data[0]));
default:
+ return error;
}
- out:
+ out_spin:
+ kfree(image);
spin_unlock(&rrpriv->lock);
return error;
}
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 532a0f9e7..26ba670b5 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -116,13 +116,9 @@ seeq8005_probe(struct net_device *dev)
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
- for (i = 0; seeq8005_portlist[i]; i++) {
- int ioaddr = seeq8005_portlist[i];
- if (check_region(ioaddr, SEEQ8005_IO_EXTENT))
- continue;
- if (seeq8005_probe1(dev, ioaddr) == 0)
+ for (i = 0; seeq8005_portlist[i]; i++)
+ if (seeq8005_probe1(dev, seeq8005_portlist[i]) == 0)
return 0;
- }
return -ENODEV;
}
@@ -133,7 +129,7 @@ seeq8005_probe(struct net_device *dev)
static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
{
- static unsigned version_printed = 0;
+ static unsigned version_printed;
int i,j;
unsigned char SA_prom[32];
int old_cfg1;
@@ -141,33 +137,42 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
int old_stat;
int old_dmaar;
int old_rear;
+ int retval;
+
+ if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
+ return -ENODEV;
if (net_debug>1)
printk("seeq8005: probing at 0x%x\n",ioaddr);
old_stat = inw(SEEQ_STATUS); /* read status register */
- if (old_stat == 0xffff)
- return -ENODEV; /* assume that 0xffff == no device */
+ if (old_stat == 0xffff) {
+ retval = -ENODEV;
+ goto out; /* assume that 0xffff == no device */
+ }
if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
if (net_debug>1) {
printk("seeq8005: reserved stat bits != 0x1800\n");
printk(" == 0x%04x\n",old_stat);
}
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
old_rear = inw(SEEQ_REA);
if (old_rear == 0xffff) {
outw(0,SEEQ_REA);
if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
} else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
if (net_debug>1) {
printk("seeq8005: unused rear bits != 0xff00\n");
printk(" == 0x%04x\n",old_rear);
}
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
@@ -185,8 +190,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
outw( 0, SEEQ_DMAAR); /* set starting PROM address */
outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
-
-
+
+
j=0;
for(i=0; i <32; i++) {
j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
@@ -201,7 +206,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
outw( old_stat, SEEQ_STATUS);
outw( old_dmaar, SEEQ_DMAAR);
outw( old_cfg1, SEEQ_CFG1);
- return -ENODEV;
+ retval = -ENODEV;
+ goto out;
}
#endif
@@ -279,11 +285,11 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
if (dev->irq == 0xff)
; /* Do nothing: a user-level program will set it. */
else if (dev->irq < 2) { /* "Auto-IRQ" */
- autoirq_setup(0);
+ unsigned long cookie = probe_irq_on();
outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
- dev->irq = autoirq_report(0);
+ dev->irq = probe_irq_off(cookie);
if (net_debug >= 2)
printk(" autoirq is %d\n", dev->irq);
@@ -299,14 +305,12 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
if (irqval) {
printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
dev->irq, irqval);
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto out;
}
}
#endif
- /* Grab the region so we can find another board if autoIRQ fails. */
- request_region(ioaddr, SEEQ8005_IO_EXTENT,"seeq8005");
-
/* Initialize the device structure. */
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
if (dev->priv == NULL)
@@ -327,6 +331,9 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
dev->flags &= ~IFF_MULTICAST;
return 0;
+out:
+ release_region(ioaddr, SEEQ8005_IO_EXTENT);
+ return retval;
}
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 9185f428f..cc0eae214 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1,6 +1,6 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.07.04 Sep. 6 2000
+ Revision: 1.07.06 Nov. 7 2000
Modified from the driver which is originally written by Donald Becker.
@@ -18,6 +18,8 @@
preliminary Rev. 1.0 Jan. 18, 1998
http://www.sis.com.tw/support/databook.htm
+ Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning
+ Rev 1.07.05 Nov. 6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support
Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaroung rule
Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
@@ -56,21 +58,19 @@
#include "sis900.h"
static const char *version =
-"sis900.c: v1.07.04 09/06/2000\n";
+"sis900.c: v1.07.06 11/07/2000\n";
static int max_interrupt_work = 20;
static int multicast_filter_limit = 128;
#define sis900_debug debug
-static int sis900_debug = 0;
+static int sis900_debug;
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*HZ)
/* SiS 900 is capable of 32 bits BM DMA */
#define SIS900_DMA_MASK 0xffffffff
-static struct net_device * sis900_mac_probe (struct pci_dev * pci_dev,
- char *card_name);
enum {
SIS_900 = 0,
SIS_7016
@@ -140,7 +140,6 @@ struct sis900_private {
BufferDesc rx_ring[NUM_RX_DESC];
unsigned int tx_full; /* The Tx queue is full. */
- int LinkOn;
};
MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
@@ -171,39 +170,10 @@ static u16 sis900_compute_hashtable_index(u8 *addr);
static void set_rx_mode(struct net_device *net_dev);
static void sis900_reset(struct net_device *net_dev);
static void sis630e_set_eq(struct net_device *net_dev);
-
-/* walk through every ethernet PCI devices to see if some of them are matched with our card list*/
-static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- u32 pci_io_base;
-
- if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
- printk(KERN_ERR "sis900.c: architecture does not support "
- "32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- pci_io_base = pci_resource_start(pci_dev, 0);
- if (check_region(pci_io_base, SIS900_TOTAL_SIZE)) {
- printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%08x\n",
- pci_io_base);
- return -ENODEV;
- }
-
- /* setup various bits in PCI command register */
- if (pci_enable_device (pci_dev))
- return -ENODEV;
- pci_set_master(pci_dev);
-
- /* do the real low level jobs */
- if (sis900_mac_probe(pci_dev, card_names[pci_id->driver_data]) == NULL)
- return -ENODEV;
-
- return 0;
-}
+static int sis900_set_config(struct net_device *dev, struct ifmap *map);
/* older SiS900 and friends, use EEPROM to store MAC address */
-static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
{
long ioaddr = pci_resource_start(pci_dev, 0);
u16 signature;
@@ -225,7 +195,7 @@ static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_
}
/* SiS630E model, use APC CMOS RAM to store MAC address */
-static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
{
struct pci_dev *isa_bridge = NULL;
u8 reg;
@@ -247,17 +217,36 @@ static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net
return 1;
}
-static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name)
+static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
struct sis900_private *sis_priv;
long ioaddr = pci_resource_start(pci_dev, 0);
- struct net_device *net_dev = NULL;
+ struct net_device *net_dev;
int irq = pci_dev->irq;
int i, ret = 0;
u8 revision;
+ char *card_name = card_names[pci_id->driver_data];
- if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
- return NULL;
+ if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
+ printk(KERN_ERR "sis900.c: architecture does not support "
+ "32bit PCI busmaster DMA\n");
+ return -ENODEV;
+ }
+
+ /* setup various bits in PCI command register */
+ if (pci_enable_device (pci_dev))
+ return -ENODEV;
+ pci_set_master(pci_dev);
+
+ net_dev = init_etherdev(NULL, sizeof(struct sis900_private));
+ if (!net_dev)
+ return -ENOMEM;
+
+ if (!request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name)) {
+ printk(KERN_ERR "sis900.c: can't allocate I/O space at 0x%lX\n", ioaddr);
+ ret = -EBUSY;
+ goto err_out;
+ }
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
if (revision == SIS630E_REV || revision == SIS630EA1_REV)
@@ -268,8 +257,8 @@ static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, ch
ret = sis900_get_mac_addr(pci_dev, net_dev);
if (ret == 0) {
- unregister_netdevice(net_dev);
- return NULL;
+ ret = -ENODEV;
+ goto err_out_region;
}
/* print some information about our NIC */
@@ -279,16 +268,9 @@ static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, ch
printk("%2.2x:", (u8)net_dev->dev_addr[i]);
printk("%2.2x.\n", net_dev->dev_addr[i]);
- if ((net_dev->priv = kmalloc(sizeof(struct sis900_private), GFP_KERNEL)) == NULL) {
- unregister_netdevice(net_dev);
- return NULL;
- }
-
sis_priv = net_dev->priv;
- memset(sis_priv, 0, sizeof(struct sis900_private));
/* We do a request_region() to register /proc/ioports info. */
- request_region(ioaddr, SIS900_TOTAL_SIZE, net_dev->name);
net_dev->base_addr = ioaddr;
net_dev->irq = irq;
sis_priv->pci_dev = pci_dev;
@@ -296,10 +278,8 @@ static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, ch
/* probe for mii transciver */
if (sis900_mii_probe(net_dev) == 0) {
- unregister_netdev(net_dev);
- kfree(sis_priv);
- release_region(ioaddr, SIS900_TOTAL_SIZE);
- return NULL;
+ ret = -ENODEV;
+ goto err_out_region;
}
pci_dev->driver_data = net_dev;
@@ -310,12 +290,20 @@ static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, ch
net_dev->hard_start_xmit = &sis900_start_xmit;
net_dev->stop = &sis900_close;
net_dev->get_stats = &sis900_get_stats;
+ net_dev->set_config = &sis900_set_config;
net_dev->set_multicast_list = &set_rx_mode;
net_dev->do_ioctl = &mii_ioctl;
net_dev->tx_timeout = sis900_tx_timeout;
net_dev->watchdog_timeo = TX_TIMEOUT;
- return net_dev;
+ return 0;
+
+err_out_region:
+ release_region(ioaddr, SIS900_TOTAL_SIZE);
+err_out:
+ unregister_netdev(net_dev);
+ kfree(net_dev);
+ return ret;
}
static int __init sis900_mii_probe (struct net_device * net_dev)
@@ -385,9 +373,9 @@ static int __init sis900_mii_probe (struct net_device * net_dev)
}
if (sis_priv->mii->status & MII_STAT_LINK)
- sis_priv->LinkOn = TRUE;
+ netif_carrier_on(net_dev);
else
- sis_priv->LinkOn = FALSE;
+ netif_carrier_off(net_dev);
return 1;
}
@@ -720,7 +708,7 @@ static void sis630e_set_eq(struct net_device *net_dev)
u16 reg14h, eq_value, max_value=0, min_value=0;
int i, maxcount=10;
- if (sis_priv->LinkOn == TRUE) {
+ if (netif_carrier_ok(net_dev)) {
reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
for (i=0; i < maxcount; i++) {
@@ -764,10 +752,10 @@ static void sis900_timer(unsigned long data)
/* current mii phy is failed to link, try another one */
while (!(status & MII_STAT_LINK)) {
if (mii_phy->next == NULL) {
- if (sis_priv->LinkOn) {
+ if (netif_carrier_ok(net_dev)) {
/* link stat change from ON to OFF */
next_tick = HZ;
- sis_priv->LinkOn = FALSE;
+ netif_carrier_off(net_dev);
/* Equalizer workaroung Rule */
pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
@@ -785,9 +773,9 @@ static void sis900_timer(unsigned long data)
status = mdio_read(net_dev, mii_phy->phy_addr, MII_STATUS);
}
- if (!sis_priv->LinkOn) {
+ if (!netif_carrier_ok(net_dev)) {
/* link stat change forn OFF to ON, read and report link mode */
- sis_priv->LinkOn = TRUE;
+ netif_carrier_on(net_dev);
next_tick = 5*HZ;
/* Equalizer workaroung Rule */
@@ -1326,6 +1314,96 @@ sis900_get_stats(struct net_device *net_dev)
return &sis_priv->stats;
}
+/* Support for media type changes via net_device->set_config */
+static int sis900_set_config(struct net_device *dev, struct ifmap *map)
+{
+ struct sis900_private *sis_priv = (struct sis900_private *)dev->priv;
+ struct mii_phy *mii_phy = sis_priv->mii;
+
+ u16 status;
+
+ /* we support only port changes. All other runtime configuration
+ changes will be ignored (io base and interrupt changes for example)*/
+ if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+ /* we switch on the ifmap->port field. I couldn't find anything
+ like a definition or standard for the values of that field.
+ I think the meaning of those values is device specific. But
+ since I would like to change the media type via the ifconfig
+ command I use the definition from linux/netdevice.h
+ (which seems to be different from the ifport(pcmcia) definition)
+ */
+ switch(map->port){
+ case IF_PORT_UNKNOWN: /* use auto here */
+ dev->if_port = map->port;
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ netif_carrier_off(dev);
+
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+
+ /* enable auto negotiation and reset the negotioation
+ (I dont really know what the auto negatiotiation reset
+ really means, but it sounds for me right to do one here)*/
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
+
+ break;
+
+ case IF_PORT_10BASET: /* 10BaseT */
+ dev->if_port = map->port;
+
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ netif_carrier_off(dev);
+
+ /* set Speed to 10Mbps */
+ /* read current state */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+
+ /* disable auto negotiation and force 10MBit mode*/
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, status & ~(MII_CNTL_SPEED | MII_CNTL_AUTO));
+ break;
+
+ case IF_PORT_100BASET: /* 100BaseT */
+ case IF_PORT_100BASETX: /* 100BaseTx */
+ dev->if_port = map->port;
+
+ /* we are going to change the media type, so the Link will
+ be temporary down and we need to reflect that here. When
+ the Link comes up again, it will be sensed by the sis_timer
+ procedure, which also does all the rest for us */
+ netif_carrier_off(dev);
+
+ /* set Speed to 100Mbps */
+ /* disable auto negotiation and enable 100MBit Mode */
+ status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
+ mdio_write(dev, mii_phy->phy_addr,
+ MII_CONTROL, (status & ~MII_CNTL_SPEED) | MII_CNTL_SPEED);
+
+ break;
+
+ case IF_PORT_10BASE2: /* 10Base2 */
+ case IF_PORT_AUI: /* AUI */
+ case IF_PORT_100BASEFX: /* 100BaseFx */
+ /* These Modes are not supported (are they?)*/
+ printk(KERN_INFO "Not supported");
+ return -EOPNOTSUPP;
+ break;
+
+ default:
+ printk(KERN_INFO "Invalid");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
/* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes
this function a little bit different from other drivers */
static u16 sis900_compute_hashtable_index(u8 *addr)
@@ -1431,15 +1509,12 @@ static void sis900_reset(struct net_device *net_dev)
outl(PESEL, ioaddr + cfg);
}
-static void __exit sis900_remove(struct pci_dev *pci_dev)
+static void __devexit sis900_remove(struct pci_dev *pci_dev)
{
struct net_device *net_dev = pci_dev->driver_data;
- struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
unregister_netdev(net_dev);
release_region(net_dev->base_addr, SIS900_TOTAL_SIZE);
-
- kfree(sis_priv);
kfree(net_dev);
}
@@ -1454,16 +1529,9 @@ static struct pci_driver sis900_pci_driver = {
static int __init sis900_init_module(void)
{
- if (!pci_present()) /* No PCI bus in this machine! */
- return -ENODEV;
-
printk(KERN_INFO "%s", version);
- if (!pci_register_driver(&sis900_pci_driver)) {
- pci_unregister_driver(&sis900_pci_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&sis900_pci_driver);
}
static void __exit sis900_cleanup_module(void)
@@ -1473,3 +1541,4 @@ static void __exit sis900_cleanup_module(void)
module_init(sis900_init_module);
module_exit(sis900_cleanup_module);
+
diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
index e905f09a6..561a40444 100644
--- a/drivers/net/sis900.h
+++ b/drivers/net/sis900.h
@@ -10,7 +10,10 @@
* http://www.sis.com.tw/support/databook.htm
*/
-/* MAC operation registers of SiS 7016 and SiS 900 ethernet controller */
+/*
+ * SiS 7016 and SiS 900 ethernet controller registers
+ */
+
/* The I/O extent, SiS 900 needs 256 bytes of io address */
#define SIS900_TOTAL_SIZE 0x100
@@ -252,14 +255,11 @@ enum sis630_revision_id {
#define NUM_TX_DESC 16 /* Number of Tx descriptor registers. */
#define NUM_RX_DESC 16 /* Number of Rx descriptor registers. */
-#define TRUE 1
-#define FALSE 0
-
/* PCI stuff, should be move to pic.h */
#define PCI_DEVICE_ID_SI_900 0x900
#define PCI_DEVICE_ID_SI_7016 0x7016
-/* ioctl for accessing MII transveiver */
+/* ioctl for accessing MII transceiver */
#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */
#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */
#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register */
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 0f41a233d..af2050833 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -194,7 +194,7 @@ int __init ultramca_probe(struct net_device *dev)
}
if(!adapter_found) {
- return ((base_addr || irq) ? ENXIO : ENODEV);
+ return ((base_addr || irq) ? -ENXIO : -ENODEV);
}
/* Adapter found. */
@@ -249,6 +249,9 @@ int __init ultramca_probe(struct net_device *dev)
if (dev->mem_start == 0) /* sanity check, shouldn't happen */
return -ENODEV;
+ if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name))
+ return -EBUSY;
+
reg4 = inb(ioaddr + 4) & 0x7f;
outb(reg4, ioaddr + 4);
@@ -279,14 +282,10 @@ int __init ultramca_probe(struct net_device *dev)
if (ethdev_init(dev)) {
printk (KERN_INFO ", no memory for dev->priv.\n");
+ release_region(ioaddr, ULTRA_IO_EXTENT);
return -ENOMEM;
}
- /* OK, we are certain this is going to work. Setup the device.
- */
-
- request_region(ioaddr, ULTRA_IO_EXTENT, "smc-mca");
-
/* The 8390 isn't at the base address, so fake the offset
*/
@@ -322,9 +321,10 @@ int __init ultramca_probe(struct net_device *dev)
static int ultramca_open(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+ int retval;
- if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev))
- return -EAGAIN;
+ if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)))
+ return retval;
outb(ULTRA_MEMENB, ioaddr); /* Enable memory */
outb(0x80, ioaddr + 5); /* ??? */
@@ -455,9 +455,6 @@ int init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("wd.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_ULTRAMCA_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
dev->irq = irq[this_dev];
@@ -468,7 +465,6 @@ int init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
printk(KERN_NOTICE "smc-mca.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
return -ENXIO;
}
@@ -493,7 +489,6 @@ void cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index f106732a7..5e7c7aeae 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -112,41 +112,44 @@ int __init ultra_probe(struct net_device *dev)
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
- for (i = 0; ultra_portlist[i]; i++) {
- int ioaddr = ultra_portlist[i];
- if (check_region(ioaddr, ULTRA_IO_EXTENT))
- continue;
- if (ultra_probe1(dev, ioaddr) == 0)
+ for (i = 0; ultra_portlist[i]; i++)
+ if (ultra_probe1(dev, ultra_portlist[i]) == 0)
return 0;
- }
return -ENODEV;
}
static int __init ultra_probe1(struct net_device *dev, int ioaddr)
{
- int i;
+ int i, retval;
int checksum = 0;
const char *model_name;
unsigned char eeprom_irq = 0;
- static unsigned version_printed = 0;
+ static unsigned version_printed;
/* Values from various config regs. */
unsigned char num_pages, irqreg, addr, piomode;
unsigned char idreg = inb(ioaddr + 7);
unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
+ if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name))
+ return -EBUSY;
+
/* Check the ID nibble. */
if ((idreg & 0xF0) != 0x20 /* SMC Ultra */
- && (idreg & 0xF0) != 0x40) /* SMC EtherEZ */
- return -ENODEV;
+ && (idreg & 0xF0) != 0x40) { /* SMC EtherEZ */
+ retval = -ENODEV;
+ goto out;
+ }
/* Select the station address register set. */
outb(reg4, ioaddr + 4);
for (i = 0; i < 8; i++)
checksum += inb(ioaddr + 8 + i);
- if ((checksum & 0xff) != 0xFF)
- return -ENODEV;
+ if ((checksum & 0xff) != 0xFF) {
+ retval = -ENODEV;
+ goto out;
+ }
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -181,7 +184,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
if (irq == 0) {
printk(", failed to detect IRQ line.\n");
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto out;
}
dev->irq = irq;
eeprom_irq = 1;
@@ -190,12 +194,10 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (ethdev_init(dev)) {
printk (", no memory for dev->priv.\n");
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto out;
}
- /* OK, we are certain this is going to work. Setup the device. */
- request_region(ioaddr, ULTRA_IO_EXTENT, model_name);
-
/* The 8390 isn't at the base address, so fake the offset */
dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
@@ -236,17 +238,22 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
NS8390_init(dev, 0);
return 0;
+out:
+ release_region(ioaddr, ULTRA_IO_EXTENT);
+ return retval;
}
static int
ultra_open(struct net_device *dev)
{
+ int retval;
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40,
- 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, };
+ 0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, };
- if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev))
- return -EAGAIN;
+ retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+ if (retval)
+ return retval;
outb(0x00, ioaddr); /* Disable shared memory for safety. */
outb(0x80, ioaddr + 5);
@@ -429,9 +436,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("smc-ultra.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
dev->irq = irq[this_dev];
@@ -444,7 +448,6 @@ init_module(void)
if (register_netdev(dev) != 0) {
printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
if (found != 0) return 0; /* Got at least one. */
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -468,7 +471,6 @@ cleanup_module(void)
kfree(dev->priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 9d54e2d05..ba387049c 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -365,9 +365,6 @@ int init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("smc-ultra32.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) {
struct net_device *dev = &dev_ultra[this_dev];
dev->init = ultra32_probe;
@@ -375,7 +372,6 @@ int init_module(void)
if (found > 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n");
return -ENXIO;
}
@@ -399,6 +395,5 @@ void cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index fba1949a8..201b259f7 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -200,13 +200,6 @@ static int smc_open(struct net_device *dev);
static void smc_timeout(struct net_device *dev);
/*
- . This is called by the kernel to send a packet out into the net. it's
- . responsible for doing a best-effort send, but if it's simply not possible
- . to send it, the packet gets dropped.
-*/
-static int smc_send_packet(struct sk_buff *skb, struct net_device *dev);
-
-/*
. This is called by the kernel in response to 'ifconfig ethX down'. It
. is responsible for cleaning up everything that the open routine
. does, and maybe putting the card into a powerdown state.
@@ -512,6 +505,10 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
unsigned short numPages;
word time_out;
+ netif_stop_queue(dev);
+ /* Well, I want to send the packet.. but I don't know
+ if I can send it right now... */
+
if ( lp->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
lp->stats.tx_aborted_errors++;
@@ -626,7 +623,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
if ( packet_no & 0x80 ) {
/* or isn't there? BAD CHIP! */
printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
- kfree_skb(skb);
+ dev_kfree_skb(skb);
lp->saved_skb = NULL;
netif_wake_queue(dev);
return;
@@ -761,6 +758,7 @@ int __init smc_init(struct net_device *dev)
int __init smc_findirq( int ioaddr )
{
int timeout = 20;
+ unsigned long cookie;
/* I have to do a STI() here, because this is called from
@@ -768,7 +766,7 @@ int __init smc_findirq( int ioaddr )
rather difficult to get interrupts for auto detection */
sti();
- autoirq_setup( 0 );
+ cookie = probe_irq_on();
/*
* What I try to do here is trigger an ALLOC_INT. This is done
@@ -821,7 +819,7 @@ int __init smc_findirq( int ioaddr )
cli();
/* and return what I found */
- return autoirq_report( 0 );
+ return probe_irq_off(cookie);
}
/*----------------------------------------------------------------------
@@ -922,13 +920,6 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
int irqval;
- /* see if I need to initialize the ethernet card structure */
- if (dev == NULL) {
- dev = init_etherdev(0, 0);
- if (dev == NULL)
- return -ENOMEM;
- }
-
if (version_printed++ == 0)
printk("%s", version);
@@ -1060,7 +1051,7 @@ static int __init smc_initcard(struct net_device *dev, int ioaddr)
dev->open = smc_open;
dev->stop = smc_close;
- dev->hard_start_xmit = smc_send_packet;
+ dev->hard_start_xmit = smc_wait_to_send_packet;
dev->tx_timeout = smc_timeout;
dev->watchdog_timeo = HZ/20;
dev->get_stats = smc_query_statistics;
@@ -1181,14 +1172,6 @@ static void smc_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-static int smc_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- netif_stop_queue(dev);
- /* Well, I want to send the packet.. but I don't know
- if I can send it right now... */
- return smc_wait_to_send_packet( skb, dev );
-}
-
/*--------------------------------------------------------------------
.
. This is the main routine of the driver, to handle the device when
@@ -1594,15 +1577,11 @@ static void smc_set_multicast_list(struct net_device *dev)
#ifdef MODULE
-static struct net_device devSMC9194 = {
- "", /* device name is inserted by linux/drivers/net/net_init.c */
- 0, 0, 0, 0,
- 0, 0, /* I/O address, IRQ */
- 0, 0, 0, NULL, smc_init };
+static struct net_device devSMC9194 = { init: smc_init };
-int io = 0;
-int irq = 0;
-int ifport = 0;
+static int io;
+static int irq;
+static int ifport;
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index e65271119..12c8b2b55 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -105,9 +105,6 @@ int __init stnic_probe(void)
if (! MACH_SE)
return -ENODEV;
- if (load_8390_module ("stnic.c"))
- return -ENOSYS;
-
/* New style probing API */
dev = init_etherdev (0, 0);
stnic_dev = dev;
@@ -313,6 +310,4 @@ do_stnic_intr (int irq, void *dev_id, struct pt_regs *regs)
}
module_init(stnic_probe);
-/* No cleanup routine - if there were one, it should do a:
- unload_8390_module()
-*/
+/* No cleanup routine. */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 2f0f46d95..bfb0f57df 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,9 +1,16 @@
-/* $Id: sunhme.c,v 1.98 2000/10/22 16:08:38 davem Exp $
+/* $Id: sunhme.c,v 1.104 2000/11/17 01:40:00 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.
*
* Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ *
+ * Changes :
+ * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
+ * - port to non-sparc architectures. Tested only on x86 and
+ * only currently works with QFE PCI cards.
+ * - ability to specify the MAC address at module load time by passing this
+ * argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
*/
static char *version =
@@ -24,6 +31,7 @@ static char *version =
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/ethtool.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
@@ -31,33 +39,46 @@ static char *version =
#include <linux/errno.h>
#include <asm/byteorder.h>
+#ifdef __sparc__
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/auxio.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
#ifndef __sparc_v9__
#include <asm/io-unit.h>
#endif
-#include <asm/ethtool.h>
+#endif
#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
+#ifdef __sparc__
#include <asm/pbm.h>
#endif
+#endif
#include "sunhme.h"
+
+static int macaddr[6];
+
+/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
+MODULE_PARM(macaddr, "6i");
+
static struct happy_meal *root_happy_dev = NULL;
+#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list = NULL;
+#endif
+
#ifdef CONFIG_PCI
static struct quattro *qfe_pci_list = NULL;
#endif
@@ -150,6 +171,25 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
+#ifdef CONFIG_PCI
+/* This happy_pci_ids is declared __initdata because it is only used
+ as an advisory to depmod. If this is ported to the new PCI interface
+ where it could be referenced at any time due to hot plugging,
+ it should be changed to __devinitdata. */
+
+struct pci_device_id happymeal_pci_ids[] __initdata = {
+ {
+ vendor: PCI_VENDOR_ID_SUN,
+ device: PCI_DEVICE_ID_SUN_HAPPYMEAL,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
+#endif
+
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
@@ -282,9 +322,25 @@ do { (__txd)->tx_addr = cpu_to_le32(__addr); \
#endif
#endif
-#define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
-#define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE
-#define DMA_TODEVICE SBUS_DMA_TODEVICE
+
+#ifdef SBUS_DMA_BIDIRECTIONAL
+# define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL
+#else
+# define DMA_BIDIRECTIONAL 0
+#endif
+
+#ifdef SBUS_DMA_FROMDEVICE
+# define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE
+#else
+# define DMA_TODEVICE 1
+#endif
+
+#ifdef SBUS_DMA_TODEVICE
+# define DMA_TODEVICE SBUS_DMA_TODEVICE
+#else
+# define DMA_FROMDEVICE 2
+#endif
+
/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */
static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit)
@@ -1563,6 +1619,10 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
+#ifndef __sparc__
+ /* It is always PCI and can handle 64byte bursts. */
+ hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
+#else
if ((hp->happy_bursts & DMA_BURST64) &&
((hp->happy_flags & HFLAG_PCI) != 0
#ifdef CONFIG_SBUS
@@ -1596,6 +1656,7 @@ static int happy_meal_init(struct happy_meal *hp, int from_irq)
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
+#endif /* __sparc__ */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
@@ -2071,6 +2132,7 @@ static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
HMD(("done\n"));
}
+#ifdef CONFIG_SBUS
static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs)
{
struct quattro *qp = (struct quattro *) cookie;
@@ -2112,6 +2174,7 @@ static void quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs
}
HMD(("done\n"));
}
+#endif
static int happy_meal_open(struct net_device *dev)
{
@@ -2127,8 +2190,14 @@ static int happy_meal_open(struct net_device *dev)
if (request_irq(dev->irq, &happy_meal_interrupt,
SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
HMD(("EAGAIN\n"));
+#ifdef __sparc__
printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
__irq_itoa(dev->irq));
+#else
+ printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n",
+ dev->irq);
+#endif
+
return -EAGAIN;
}
}
@@ -2168,6 +2237,7 @@ static int happy_meal_close(struct net_device *dev)
#define SXD(x)
#endif
+#ifdef CONFIG_SBUS
static void happy_meal_tx_timeout(struct net_device *dev)
{
struct happy_meal *hp = (struct happy_meal *) dev->priv;
@@ -2181,6 +2251,7 @@ static void happy_meal_tx_timeout(struct net_device *dev)
happy_meal_init(hp, 0);
netif_wake_queue(dev);
}
+#endif
static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -2541,11 +2612,25 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
dev->name);
- /* Quattro local-mac-address... */
- if (qfe_slot != -1 && prom_getproplen(sdev->prom_node,"local-mac-address")==6)
- prom_getproperty(sdev->prom_node,"local-mac-address",dev->dev_addr,6);
- else
- memcpy(dev->dev_addr,idprom->id_ethaddr,6);
+ /* If user did not specify a MAC address specifically, use
+ * the Quattro local-mac-address property...
+ */
+ for (i = 0; i < 6; i++) {
+ if (macaddr[i] != 0)
+ break;
+ }
+ if (i < 6) { /* a mac address was given */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = macaddr[i];
+ } else if (qfe_slot != -1 &&
+ prom_getproplen(sdev->prom_node,
+ "local-mac-address") == 6) {
+ prom_getproperty(sdev->prom_node, "local-mac-address",
+ dev->dev_addr, 6);
+ } else {
+ memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ }
+
for (i = 0; i < 6; i++)
printk("%2.2x%c",
dev->dev_addr[i], i == 5 ? ' ' : ':');
@@ -2683,13 +2768,17 @@ static int __init happy_meal_sbus_init(struct net_device *dev,
static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pdev)
{
struct quattro *qp = NULL;
+#ifdef __sparc__
struct pcidev_cookie *pcp;
+ int node;
+#endif
struct happy_meal *hp;
unsigned long hpreg_base;
- int i, node, qfe_slot = -1;
+ int i, qfe_slot = -1;
char prom_name[64];
/* Now make sure pci_dev cookie is there. */
+#ifdef __sparc__
pcp = pdev->sysdata;
if (pcp == NULL || pcp->prom_node == -1) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
@@ -2698,6 +2787,11 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
node = pcp->prom_node;
prom_getstring(node, "name", prom_name, sizeof(prom_name));
+#else
+#warning This needs to be corrected... -DaveM
+ strcpy(prom_name, "qfe");
+#endif
+
if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
qp = quattro_pci_find(pdev);
if (qp == NULL)
@@ -2763,10 +2857,27 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
}
hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000);
- if (qfe_slot != -1 && prom_getproplen(node, "local-mac-address") == 6)
- prom_getproperty(node, "local-mac-address", dev->dev_addr, 6);
- else
- memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ for (i = 0; i < 6; i++) {
+ if (macaddr[i] != 0)
+ break;
+ }
+ if (i < 6) { /* a mac address was given */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = macaddr[i];
+ } else {
+#ifdef __sparc__
+ if (qfe_slot != -1 &&
+ prom_getproplen(node, "local-mac-address") == 6) {
+ prom_getproperty(node, "local-mac-address",
+ dev->dev_addr, 6);
+ } else {
+ memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ }
+#else
+ memset(dev->dev_addr, 0, 6);
+#endif
+ }
+
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
@@ -2779,9 +2890,14 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
+#ifdef __sparc__
hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
+#else
+ /* works with this on non-sparc hosts */
+ hp->hm_revision = 0x20;
+#endif
/* Now enable the feature flags we can. */
if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21)
@@ -2795,8 +2911,10 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
+#ifdef __sparc__
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
+#endif
hp->happy_block = (struct hmeal_init_block *)
pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 57b5d7f5e..846a3744d 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -1,4 +1,4 @@
-/* $Id: sunhme.h,v 1.30 2000/02/18 13:49:26 davem Exp $
+/* $Id: sunhme.h,v 1.31 2000/11/12 10:23:30 davem Exp $
* sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
* Also known as the "Happy Meal".
*
@@ -9,6 +9,7 @@
#define _SUNHME_H
#include <linux/config.h>
+#include <linux/pci.h>
/* Happy Meal global registers. */
#define GREG_SWRESET 0x000UL /* Software Reset */
@@ -589,7 +590,9 @@ struct quattro {
struct quattro *next;
/* PROM ranges, if any. */
+#ifdef CONFIG_SBUS
struct linux_prom_ranges ranges[8];
+#endif
int nranges;
};
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 8398e1bea..60cc79b75 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -115,7 +115,7 @@ void t21142_start_nway(struct net_device *dev)
outl(csr14, ioaddr + CSR14);
if (tp->chip_id == PNIC2)
tp->csr6 = 0x01a80000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
- else
+ else
tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
tulip_outl_csr(tp, tp->csr6, CSR6);
if (tp->mtable && tp->mtable->csr15dir) {
diff --git a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog
new file mode 100644
index 000000000..6c37fb683
--- /dev/null
+++ b/drivers/net/tulip/ChangeLog
@@ -0,0 +1,29 @@
+2000-11-02 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+ * tulip_core.c (set_rx_mode): This is synchronized via
+ dev->xmit_lock, so only the queueing of the setup frame needs to
+ be locked, against tulip_interrupt.
+
+2000-11-02 Alexey Kuznetov <kuznet@ms2.inr.ac.ru>
+
+ * timer.c (tulip_timer): Call netif_carrier_{on,off} to report
+ link state to the rest of the kernel, and userspace.
+ * interrupt.c (tulip_interrupt): Remove tx_full.
+ * tulip.h: Likewise.
+ * tulip_core.c (tulip_init_ring, tulip_start_xmit, set_rx_mode):
+ Likewise.
+
+2000-10-18 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+ * tulip_core.c: (tulip_init_one) Print out ethernet interface
+ on error. Print out a message when pci_enable_device fails.
+ Handle DMA alloc failure.
+
+2000-10-18 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+ * Makefile: New file.
+ * tulip_core.c (tulip_init_one): Correct error messages
+ on PIO/MMIO region reserve failure.
+ (tulip_init_one) Add new check to ensure that PIO region is
+ sufficient for our needs.
+
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 2a4a7c201..5014726c3 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -19,7 +19,7 @@
int tulip_rx_copybreak;
-int tulip_max_interrupt_work;
+unsigned int tulip_max_interrupt_work;
@@ -177,12 +177,17 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
int maxrx = RX_RING_SIZE;
int maxtx = TX_RING_SIZE;
int maxoi = TX_RING_SIZE;
- int work_count = tulip_max_interrupt_work;
-
+ unsigned int work_count = tulip_max_interrupt_work;
+
+ /* Let's see whether the interrupt really is for us */
+ csr5 = inl(ioaddr + CSR5);
+
+ if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+ return;
+
tp->nir++;
do {
- csr5 = inl(ioaddr + CSR5);
/* Acknowledge all of the current interrupt sources ASAP. */
outl(csr5 & 0x0001ffff, ioaddr + CSR5);
@@ -190,9 +195,6 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
dev->name, csr5, inl(dev->base_addr + CSR5));
- if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
- break;
-
if (csr5 & (RxIntr | RxNoBuf)) {
rx += tulip_rx(dev);
tulip_refill_rx(dev);
@@ -221,7 +223,7 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
PCI_DMA_TODEVICE);
continue;
}
-
+
if (status & 0x8000) {
/* There was an major error, log it. */
#ifndef final_version
@@ -256,17 +258,14 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
#ifndef final_version
if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
- printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
+ dev->name, dirty_tx, tp->cur_tx);
dirty_tx += TX_RING_SIZE;
}
#endif
- if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
- /* The ring is no longer full, clear tbusy. */
- tp->tx_full = 0;
+ if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
netif_wake_queue(dev);
- }
tp->dirty_tx = dirty_tx;
if (csr5 & TxDied) {
@@ -330,22 +329,28 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
/* Acknowledge all interrupt sources. */
outl(0x8001ffff, ioaddr + CSR5);
if (tp->flags & HAS_INTR_MITIGATION) {
- /* Josip Loncaric at ICASE did extensive experimentation
+ /* Josip Loncaric at ICASE did extensive experimentation
to develop a good interrupt mitigation setting.*/
outl(0x8b240000, ioaddr + CSR11);
} else {
- /* Mask all interrupting sources, set timer to
+ /* Mask all interrupting sources, set timer to
re-enable. */
outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
outl(0x0012, ioaddr + CSR11);
}
break;
}
- } while (work_count-- > 0);
+
+ work_count--;
+ if (work_count == 0)
+ break;
+
+ csr5 = inl(ioaddr + CSR5);
+ } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
tulip_refill_rx(dev);
- /* check if we card is in suspend mode */
+ /* check if the card is in suspend mode */
entry = tp->dirty_rx % RX_RING_SIZE;
if (tp->rx_buffers[entry].skb == NULL) {
if (tulip_debug > 1)
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index f8b06c58f..357454359 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -130,13 +130,15 @@ void tulip_timer(unsigned long data)
/* Check that the specified bit has the proper value. */
if ((bitnum < 0) !=
((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
- if (tulip_debug > 1)
+ if (tulip_debug > 2)
printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
medianame[mleaf->media]);
if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
goto actually_mii;
+ netif_carrier_on(dev);
break;
}
+ netif_carrier_off(dev);
if (tp->medialock)
break;
select_next_media:
@@ -160,7 +162,10 @@ void tulip_timer(unsigned long data)
}
case 1: case 3: /* 21140, 21142 MII */
actually_mii:
- tulip_check_duplex(dev);
+ if (tulip_check_duplex(dev) < 0)
+ netif_carrier_off(dev);
+ else
+ netif_carrier_on(dev);
next_tick = 60*HZ;
break;
case 2: /* 21142 serial block has no link beat. */
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 4e21319ba..d0668cf42 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -208,7 +208,7 @@ enum t21143_csr6_bits {
csr6_ho = (1<<2), /* Hash-only filtering mode: can't be set */
csr6_sr = (1<<1), /* Start(1)/Stop(0) Receive */
csr6_hp = (1<<0), /* Hash/Perfect Receive Filtering Mode: can't be set */
-
+
csr6_mask_capture = (csr6_sc | csr6_ca),
csr6_mask_defstate = (csr6_mask_capture | csr6_mbo),
csr6_mask_hdcap = (csr6_mask_defstate | csr6_hbd | csr6_ps),
@@ -340,7 +340,6 @@ struct tulip_private {
spinlock_t lock;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int full_duplex_lock:1;
unsigned int fake_addr:1; /* Multiport board faked address. */
@@ -389,7 +388,7 @@ void tulip_parse_eeprom(struct net_device *dev);
int tulip_read_eeprom(long ioaddr, int location, int addr_len);
/* interrupt.c */
-extern int tulip_max_interrupt_work;
+extern unsigned int tulip_max_interrupt_work;
extern int tulip_rx_copybreak;
void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -436,5 +435,4 @@ static inline void tulip_restart_rxtx(struct tulip_private *tp, u32 csr6mask)
tulip_outl_csr(tp, csr6mask | csr6_st | csr6_sr, CSR6);
}
-
#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 19d4f8f5e..de4af6890 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -7,11 +7,11 @@
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
-
+
Please read Documentation/networking/tulip.txt for more
information.
- For this specific driver variant please use linux-kernel for
+ For this specific driver variant please use linux-kernel for
bug reports.
Additional information available at
@@ -28,13 +28,13 @@
#include <asm/unaligned.h>
static char version[] __devinitdata =
- "Linux Tulip driver version 0.9.10 (September 6, 2000)\n";
+ "Linux Tulip driver version 0.9.11 (November 3, 2000)\n";
/* A few user-configurable values. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 25;
+static unsigned int max_interrupt_work = 25;
#define MAX_UNITS 8
/* Used to pass the full-duplex flag, etc. */
@@ -415,11 +415,11 @@ tulip_open(struct net_device *dev)
}
tulip_init_ring (dev);
-
+
tulip_up (dev);
-
+
netif_start_queue (dev);
-
+
return 0;
}
@@ -429,7 +429,7 @@ static void tulip_tx_timeout(struct net_device *dev)
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
unsigned long flags;
-
+
DPRINTK("ENTER\n");
spin_lock_irqsave (&tp->lock, flags);
@@ -541,7 +541,6 @@ static void tulip_init_ring(struct net_device *dev)
DPRINTK("ENTER\n");
- tp->tx_full = 0;
tp->cur_rx = tp->cur_tx = 0;
tp->dirty_rx = tp->dirty_tx = 0;
tp->susp_rx = 0;
@@ -597,9 +596,6 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 flag;
dma_addr_t mapping;
- /* Caution: the write order is important here, set the field
- with the ownership bits last. */
-
spin_lock_irq(&tp->lock);
/* Calculate the next Tx descriptor entry. */
@@ -618,7 +614,6 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
flag = 0x60000000; /* No Tx-done intr. */
} else { /* Leave room for set_rx_mode() to fill entries. */
- tp->tx_full = 1;
flag = 0xe0000000; /* Tx-done intr. */
netif_stop_queue(dev);
}
@@ -626,7 +621,11 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
flag = 0xe0000000 | DESC_RING_WRAP;
tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
+ /* if we were using Transmit Automatic Polling, we would need a
+ * wmb() here. */
tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+ wmb();
+
tp->cur_tx++;
/* Trigger an immediate transmit demand. */
@@ -670,14 +669,14 @@ static void tulip_down (struct net_device *dev)
if (tp->flags & HAS_ACPI)
pci_write_config_dword (tp->pdev, 0x40, 0x40000000);
}
-
-
+
+
static int tulip_close (struct net_device *dev)
{
long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *) dev->priv;
int i;
-
+
netif_stop_queue (dev);
tulip_down (dev);
@@ -846,18 +845,77 @@ static inline u32 ether_crc(int length, unsigned char *data)
return crc;
}
+#undef set_bit_le
+#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
+
+static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ u16 hash_table[32];
+ struct dev_mc_list *mclist;
+ int i;
+ u16 *eaddrs;
+
+ memset(hash_table, 0, sizeof(hash_table));
+ set_bit_le(255, hash_table); /* Broadcast entry */
+ /* This should work on big-endian machines as well. */
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
+
+ set_bit_le(index, hash_table);
+
+ for (i = 0; i < 32; i++) {
+ *setup_frm++ = hash_table[i];
+ *setup_frm++ = hash_table[i];
+ }
+ setup_frm = &tp->setup_frame[13*6];
+ }
+
+ /* Fill the final entry with our physical address. */
+ eaddrs = (u16 *)dev->dev_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+}
+
+static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ struct dev_mc_list *mclist;
+ int i;
+ u16 *eaddrs;
+
+ /* We have <= 14 addresses so we can use the wonderful
+ 16 address perfect filtering of the Tulip. */
+ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+ }
+ /* Fill the unused entries with the broadcast address. */
+ memset(setup_frm, 0xff, (15-i)*12);
+ setup_frm = &tp->setup_frame[15*6];
+
+ /* Fill the final entry with our physical address. */
+ eaddrs = (u16 *)dev->dev_addr;
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+}
+
+
static void set_rx_mode(struct net_device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
long ioaddr = dev->base_addr;
- int csr6, need_lock = 0;
- unsigned long flags;
+ int csr6;
DPRINTK("ENTER\n");
- spin_lock_irqsave(&tp->lock, flags);
csr6 = inl(ioaddr + CSR6) & ~0x00D5;
- spin_unlock_irqrestore(&tp->lock, flags);
tp->csr6 &= ~0x00D5;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
@@ -865,14 +923,10 @@ static void set_rx_mode(struct net_device *dev)
csr6 |= 0x00C0;
/* Unconditionally log net taps. */
printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
-
- need_lock = 1;
} else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well -- accept all multicasts. */
tp->csr6 |= 0x0080;
csr6 |= 0x0080;
-
- need_lock = 1;
} else if (tp->flags & MC_HASH_ONLY) {
/* Some work-alikes have only a 64-entry hash filter table. */
/* Should verify correctness on big-endian/__powerpc__ */
@@ -882,7 +936,6 @@ static void set_rx_mode(struct net_device *dev)
if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
tp->csr6 |= 0x0080;
csr6 |= 0x0080;
- need_lock = 1;
} else {
mc_filter[1] = mc_filter[0] = 0;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -890,71 +943,32 @@ static void set_rx_mode(struct net_device *dev)
set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
if (tp->chip_id == AX88140) {
- spin_lock_irqsave(&tp->lock, flags);
outl(2, ioaddr + CSR13);
outl(mc_filter[0], ioaddr + CSR14);
outl(3, ioaddr + CSR13);
outl(mc_filter[1], ioaddr + CSR14);
- /* need_lock = 0; */
} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
- spin_lock_irqsave(&tp->lock, flags);
outl(mc_filter[0], ioaddr + 0xAC);
outl(mc_filter[1], ioaddr + 0xB0);
- /* need_lock = 0; */
- } else {
- need_lock = 1;
}
}
-
} else {
- u16 *eaddrs, *setup_frm = tp->setup_frame;
- struct dev_mc_list *mclist;
- u32 tx_flags = 0x08000000 | 192;
- int i;
+ unsigned long flags;
/* Note that only the low-address shortword of setup_frame is valid!
The values are doubled for big-endian architectures. */
if (dev->mc_count > 14) { /* Must use a multicast hash table. */
- u16 hash_table[32];
- tx_flags = 0x08400000 | 192; /* Use hash filter. */
- memset(hash_table, 0, sizeof(hash_table));
- set_bit(255, hash_table); /* Broadcast entry */
- /* This should work on big-endian machines as well. */
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
- hash_table);
- for (i = 0; i < 32; i++) {
- *setup_frm++ = hash_table[i];
- *setup_frm++ = hash_table[i];
- }
- setup_frm = &tp->setup_frame[13*6];
+ build_setup_frame_hash(tp->setup_frame, dev);
} else {
- /* We have <= 14 addresses so we can use the wonderful
- 16 address perfect filtering of the Tulip. */
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
- i++, mclist = mclist->next) {
- u16 *eaddrs = (u16 *)mclist->dmi_addr;
- *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
- }
- /* Fill the unused entries with the broadcast address. */
- memset(setup_frm, 0xff, (15-i)*12);
- setup_frm = &tp->setup_frame[15*6];
+ build_setup_frame_perfect(tp->setup_frame, dev);
}
- /* Fill the final entry with our physical address. */
- eaddrs = (u16 *)dev->dev_addr;
- *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-
spin_lock_irqsave(&tp->lock, flags);
if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
/* Same setup recently queued, we need not add it. */
} else {
+ u32 tx_flags = 0x08000000 | 192;
unsigned int entry;
int dummy = -1;
@@ -988,24 +1002,18 @@ static void set_rx_mode(struct net_device *dev)
tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
if (dummy >= 0)
tp->tx_ring[dummy].status = cpu_to_le32(DescOwned);
- if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+ if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2)
netif_stop_queue(dev);
- tp->tx_full = 1;
- }
/* Trigger an immediate transmit demand. */
outl(0, ioaddr + CSR1);
-
}
+
+ spin_unlock_irqrestore(&tp->lock, flags);
}
-
- if (need_lock)
- spin_lock_irqsave(&tp->lock, flags);
/* Can someone explain to me what the OR here is supposed to accomplish???? */
tulip_outl_csr(tp, csr6 | 0x0000, CSR6);
-
- spin_unlock_irqrestore(&tp->lock, flags);
}
@@ -1026,7 +1034,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
long ioaddr;
static int board_idx = -1;
int chip_idx = ent->driver_data;
-
+
board_idx++;
if (tulip_debug > 0 && did_version++ == 0)
@@ -1036,7 +1044,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
printk (KERN_ERR PFX "skipping LMC card.\n");
return -ENODEV;
}
-
+
ioaddr = pci_resource_start (pdev, 0);
irq = pdev->irq;
@@ -1047,25 +1055,37 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
return -ENOMEM;
}
+ if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
+ printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
+ "aborting\n", dev->name, pci_resource_len (pdev, 0),
+ pci_resource_start (pdev, 0));
+ goto err_out_free_netdev;
+ }
+
/* grab all resources from both PIO and MMIO regions, as we
* don't want anyone else messing around with our hardware */
if (!request_region (pci_resource_start (pdev, 0),
pci_resource_len (pdev, 0),
dev->name)) {
- printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, "
- "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr);
+ printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) unavailable, "
+ "aborting\n", dev->name, pci_resource_len (pdev, 0),
+ pci_resource_start (pdev, 0));
goto err_out_free_netdev;
}
if (!request_mem_region (pci_resource_start (pdev, 1),
pci_resource_len (pdev, 1),
dev->name)) {
- printk (KERN_ERR PFX "MMIO resource (0x%x@0x%lx) unavailable, "
- "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr);
+ printk (KERN_ERR PFX "%s: MMIO region (0x%lx@0x%lx) unavailable, "
+ "aborting\n", dev->name, pci_resource_len (pdev, 1),
+ pci_resource_start (pdev, 1));
goto err_out_free_pio_res;
}
- if (pci_enable_device(pdev))
+ if (pci_enable_device(pdev)) {
+ printk (KERN_ERR PFX "%s: Cannot enable PCI device, aborting\n",
+ dev->name);
goto err_out_free_mmio_res;
+ }
pci_set_master(pdev);
@@ -1081,6 +1101,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
sizeof(struct tulip_rx_desc) * RX_RING_SIZE +
sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
&tp->rx_ring_dma);
+ if (!tp->rx_ring)
+ goto err_out_free_mmio_res;
tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE);
tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE;
@@ -1122,7 +1144,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tulip_stop_rxtx(tp, inl(ioaddr + CSR6));
/* Clear the missed-packet counter. */
- (volatile int)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
if (chip_idx == DC21041) {
if (inl(ioaddr + CSR9) & 0x8000) {
@@ -1240,7 +1262,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->to_advertise = media2advert[tp->default_port - 9];
} else if (tp->flags & HAS_8023X)
tp->to_advertise = 0x05e1;
- else
+ else
tp->to_advertise = 0x01e1;
/* This is logically part of _init_one(), but too complex to write inline. */
@@ -1455,7 +1477,7 @@ static int __init tulip_init (void)
/* copy module parms into globals */
tulip_rx_copybreak = rx_copybreak;
tulip_max_interrupt_work = max_interrupt_work;
-
+
/* probe for and init boards */
return pci_module_init (&tulip_driver);
}
diff --git a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c
index 0e2737ac3..acbb7f112 100644
--- a/drivers/net/wan/comx-proto-lapb.c
+++ b/drivers/net/wan/comx-proto-lapb.c
@@ -15,6 +15,9 @@
* Version 0.80 (99/06/14):
* - cleaned up the source code a bit
* - ported back to kernel, now works as non-module
+ *
+ * Changed (00/10/29, Henner Eisen):
+ * - comx_rx() / comxlapb_data_indication() return status.
*
*/
@@ -359,7 +362,7 @@ static void comxlapb_disconnected(void *token, int reason)
comx_status(ch->dev, ch->line_status);
}
-static void comxlapb_data_indication(void *token, struct sk_buff *skb)
+static int comxlapb_data_indication(void *token, struct sk_buff *skb)
{
struct comx_channel *ch = token;
@@ -373,7 +376,7 @@ static void comxlapb_data_indication(void *token, struct sk_buff *skb)
skb->dev = ch->dev;
skb->mac.raw = skb->data;
- comx_rx(ch->dev, skb);
+ return comx_rx(ch->dev, skb);
}
static void comxlapb_data_transmit(void *token, struct sk_buff *skb)
diff --git a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c
index f1e1ffdcb..47ba5cc74 100644
--- a/drivers/net/wan/comx.c
+++ b/drivers/net/wan/comx.c
@@ -46,6 +46,9 @@
* Version 0.85 (00/08/15):
* - resource release on failure in comx_mkdir
* - fix return value on failure at comx_write_proc
+ *
+ * Changed (00/10/29, Henner Eisen):
+ * - comx_rx() / comxlapb_data_indication() return status.
*/
#define VERSION "0.85"
@@ -852,7 +855,7 @@ cleanup_filename_protocol:
cleanup_filename_hardware:
remove_proc_entry(FILENAME_HARDWARE, new_dir);
cleanup_new_dir:
- remove_proc_entry(dentry->d_name.name, &comx_root_dir);
+ remove_proc_entry(dentry->d_name.name, comx_root_dir);
cleanup_dev:
kfree(dev);
return ret;
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 826fb02c6..eaba0cd34 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -16,6 +16,8 @@
*
* History
* LAPBETH 001 Jonathan Naylor Cloned from bpqether.c
+ * 2000-10-29 Henner Eisen lapb_data_indication() return status.
+ * 2000-11-14 Henner Eisen dev_hold/put, NETDEV_GOING_DOWN support
*/
#include <linux/errno.h>
@@ -79,6 +81,7 @@ static struct lapbethdev {
/*
* Get the ethernet device for a LAPB device
*/
+#if 0
static __inline__ struct net_device *lapbeth_get_ether_dev(struct net_device *dev)
{
struct lapbethdev *lapbeth;
@@ -87,7 +90,7 @@ static __inline__ struct net_device *lapbeth_get_ether_dev(struct net_device *de
return (lapbeth != NULL) ? lapbeth->ethdev : NULL;
}
-
+#endif
/*
* Get the LAPB device for the ethernet device
*/
@@ -136,6 +139,7 @@ static int lapbeth_check_devices(struct net_device *dev)
result = 1;
unregister_netdev(&lapbeth->axdev);
+ dev_put(lapbeth->ethdev);
kfree(lapbeth);
}
@@ -185,7 +189,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
return 0;
}
-static void lapbeth_data_indication(void *token, struct sk_buff *skb)
+static int lapbeth_data_indication(void *token, struct sk_buff *skb)
{
struct lapbethdev *lapbeth = (struct lapbethdev *)token;
unsigned char *ptr;
@@ -198,7 +202,7 @@ static void lapbeth_data_indication(void *token, struct sk_buff *skb)
skb->mac.raw = skb->data;
skb->pkt_type = PACKET_HOST;
- netif_rx(skb);
+ return netif_rx(skb);
}
/*
@@ -418,6 +422,7 @@ static int lapbeth_new_device(struct net_device *dev)
memset(lapbeth, 0, sizeof(struct lapbethdev));
+ dev_hold(dev);
lapbeth->ethdev = dev;
lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0';
@@ -436,6 +441,7 @@ static int lapbeth_new_device(struct net_device *dev)
}
if (k == MAXLAPBDEV) {
+ dev_put(dev);
kfree(lapbeth);
return -ENODEV;
}
@@ -445,6 +451,7 @@ static int lapbeth_new_device(struct net_device *dev)
dev->init = lapbeth_dev_init;
if (register_netdev(dev) != 0) {
+ dev_put(dev);
kfree(lapbeth);
return -EIO;
}
@@ -498,6 +505,7 @@ static int lapbeth_device_event(struct notifier_block *this,unsigned long event,
lapbeth_new_device(dev);
break;
+ case NETDEV_GOING_DOWN:
case NETDEV_DOWN: /* ethernet device closed -> close LAPB interface */
if ((dev = lapbeth_get_x25_dev(dev)) != NULL)
dev_close(dev);
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 5651ddeb2..1d8b6b1d8 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -9,6 +9,9 @@
* recommendations. Its primarily for testing purposes. If you wanted
* to do CCITT then in theory all you need is to nick the HDLC async
* checksum routines from ppp.c
+ * Changes:
+ *
+ * 2000-10-29 Henner Eisen lapb_data_indication() return status.
*/
#include <linux/module.h>
@@ -390,9 +393,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* at the net layer.
*/
-static void x25_asy_data_indication(void *token, struct sk_buff *skb)
+static int x25_asy_data_indication(void *token, struct sk_buff *skb)
{
- netif_rx(skb);
+ return netif_rx(skb);
}
/*
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index e4d53f88f..e46844b59 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -34,6 +34,7 @@ static const char *version =
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -84,19 +85,33 @@ static int wd_close(struct net_device *dev);
int __init wd_probe(struct net_device *dev)
{
int i;
+ struct resource *r;
int base_addr = dev ? dev->base_addr : 0;
- if (base_addr > 0x1ff) /* Check a single specified location. */
- return wd_probe1(dev, base_addr);
+ if (base_addr > 0x1ff) { /* Check a user specified location. */
+ r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
+ if ( r == NULL)
+ return -EBUSY;
+ i = wd_probe1(dev, base_addr);
+ if (i != 0)
+ release_resource(r);
+ else
+ r->name = ei_status.name;
+ return i;
+ }
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
for (i = 0; wd_portlist[i]; i++) {
int ioaddr = wd_portlist[i];
- if (check_region(ioaddr, WD_IO_EXTENT))
+ r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe");
+ if (r == NULL)
continue;
- if (wd_probe1(dev, ioaddr) == 0)
+ if (wd_probe1(dev, ioaddr) == 0) {
+ r->name = ei_status.name;
return 0;
+ }
+ release_resource(r);
}
return -ENODEV;
@@ -256,8 +271,6 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
}
/* OK, were are certain this is going to work. Setup the device. */
- request_region(ioaddr, WD_IO_EXTENT, model_name);
-
ei_status.name = model_name;
ei_status.word16 = word16;
ei_status.tx_start_page = WD_START_PG;
@@ -444,9 +457,6 @@ init_module(void)
{
int this_dev, found = 0;
- if (load_8390_module("wd.c"))
- return -ENOSYS;
-
for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
struct net_device *dev = &dev_wd[this_dev];
dev->irq = irq[this_dev];
@@ -463,7 +473,6 @@ init_module(void)
if (found != 0) { /* Got at least one. */
return 0;
}
- unload_8390_module();
return -ENXIO;
}
found++;
@@ -487,7 +496,6 @@ cleanup_module(void)
kfree(priv);
}
}
- unload_8390_module();
}
#endif /* MODULE */
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index f41daa570..40ca15bb0 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -148,7 +148,7 @@ int nubus_proc_detach_device(struct nubus_dev *dev)
struct proc_dir_entry *e;
if ((e = dev->procdir)) {
- if (e->count)
+ if (atomic_read(&e->count))
return -EBUSY;
remove_proc_entry(e->name, proc_bus_nubus_dir);
dev->procdir = NULL;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ea13f254d..f90c23520 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -20,6 +20,8 @@
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/kmod.h> /* for hotplug_path */
#include <asm/page.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
@@ -343,6 +345,49 @@ pci_unregister_driver(struct pci_driver *drv)
#ifdef CONFIG_HOTPLUG
+#ifndef FALSE
+#define FALSE (0)
+#define TRUE (!FALSE)
+#endif
+
+static void
+run_sbin_hotplug(struct pci_dev *pdev, int insert)
+{
+ int i;
+ char *argv[3], *envp[7];
+ char id[20], sub_id[24], bus_id[64], class_id[20];
+
+ if (!hotplug_path[0])
+ return;
+
+ sprintf(class_id, "PCI_CLASS=%X", pdev->class >> 8);
+ sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
+ sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
+ sprintf(bus_id, "PCI_BUS_ID=%s", pdev->slot_name);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "pci";
+ argv[i] = 0;
+
+ i = 0;
+ /* minimal command environment */
+ envp[i++] = "HOME=/";
+ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ /* other stuff we want to pass to /sbin/hotplug */
+ envp[i++] = id;
+ envp[i++] = sub_id;
+ envp[i++] = bus_id;
+ if (insert)
+ envp[i++] = "ACTION=add";
+ else
+ envp[i++] = "ACTION=remove";
+ envp[i] = 0;
+
+ call_usermodehelper (argv [0], argv, envp);
+}
+
void
pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
{
@@ -358,9 +403,13 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
if (drv->remove && pci_announce_device(drv, dev))
break;
}
+
+ /* notify userspace of new hotplug device */
+ run_sbin_hotplug(dev, TRUE);
}
-static void pci_free_resources(struct pci_dev *dev)
+static void
+pci_free_resources(struct pci_dev *dev)
{
int i;
@@ -385,6 +434,9 @@ pci_remove_device(struct pci_dev *dev)
#ifdef CONFIG_PROC_FS
pci_proc_detach_device(dev);
#endif
+
+ /* notify userspace of hotplug device removal */
+ run_sbin_hotplug(dev, FALSE);
}
#endif
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index bfb9de0be..df9937fd2 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -1472,7 +1472,8 @@
10b7 3590 TokenLink Velocity XL Adapter
4500 3c450 Cyclone/unknown
5055 3c555 Laptop Hurricane
- 6055 3c556 Laptop Hurricane
+ 6055 3c556 Laptop Tornado
+ 6056 3c556B Laptop Hurricane
5057 3c575 [Megahertz] 10/100 LAN CardBus
10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card
5157 3CCFE575BT Cyclone CardBus
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 81902c572..049cdcf35 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -279,7 +279,7 @@ int pci_proc_detach_device(struct pci_dev *dev)
struct proc_dir_entry *e;
if ((e = dev->procent)) {
- if (e->count)
+ if (atomic_read(&e->count))
return -EBUSY;
remove_proc_entry(e->name, dev->bus->procdir);
dev->procent = NULL;
diff --git a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
index 52f9a325b..a90be801f 100644
--- a/drivers/pcmcia/Config.in
+++ b/drivers/pcmcia/Config.in
@@ -7,18 +7,18 @@
mainmenu_option next_comment
comment 'PCMCIA/CardBus support'
-dep_tristate 'CardBus support' CONFIG_PCMCIA $CONFIG_PCI
-if [ "$CONFIG_PCMCIA" != "n" ]; then
- define_bool CONFIG_CARDBUS y
-fi
-
-#tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+#dep_tristate 'CardBus support' CONFIG_PCMCIA $CONFIG_PCI
#if [ "$CONFIG_PCMCIA" != "n" ]; then
-# if [ "$CONFIG_PCI" != "n" ]; then
-# bool ' CardBus support' CONFIG_CARDBUS
-# fi
-# bool ' i82365 compatible bridge support' CONFIG_I82365
-# bool ' Databook TCIC host bridge support' CONFIG_TCIC
+# define_bool CONFIG_CARDBUS y
#fi
+tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ bool ' CardBus support' CONFIG_CARDBUS
+ fi
+ bool ' i82365 compatible bridge support' CONFIG_I82365
+ bool ' Databook TCIC host bridge support' CONFIG_TCIC
+fi
+
endmenu
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 3383f3e73..3a83b10c8 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -383,7 +383,7 @@ void cb_enable(socket_info_t * s)
dev = &s->cb_config[i].dev;
pci_writeb(dev, PCI_COMMAND, PCI_COMMAND_MASTER |
PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
- pci_writeb(dev, PCI_CACHE_LINE_SIZE, 8);
+ pci_writeb(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
}
if (s->irq.AssignedIRQ) {
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 21482915a..b6e99d212 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -319,6 +319,8 @@ socket_info_t *pcmcia_register_socket (int slot,
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", ss_entry);
s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+ if (!s)
+ return NULL;
memset(s, 0, sizeof(socket_info_t));
s->ss_entry = ss_entry;
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 578cbfcd0..b09e1182f 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -859,6 +859,28 @@ static void __init isa_probe(void)
/*====================================================================*/
+static u_int pending_events[8];
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static void pcic_bh(void *dummy)
+{
+ u_int events;
+ int i;
+
+ for (i=0; i < sockets; i++) {
+ spin_lock_irq(&pending_event_lock);
+ events = pending_events[i];
+ pending_events[i] = 0;
+ spin_unlock_irq(&pending_event_lock);
+ if (socket[i].handler)
+ socket[i].handler(socket[i].info, events);
+ }
+}
+
+static struct tq_struct pcic_task = {
+ routine: pcic_bh
+};
+
static void pcic_interrupt(int irq, void *dev,
struct pt_regs *regs)
{
@@ -893,8 +915,13 @@ static void pcic_interrupt(int irq, void *dev,
}
ISA_UNLOCK(i, flags);
DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
- if (events)
- socket[i].handler(socket[i].info, events);
+
+ if (events) {
+ spin_lock(&pending_event_lock);
+ pending_events[i] |= events;
+ spin_unlock(&pending_event_lock);
+ schedule_task(&pcic_task);
+ }
active |= events;
}
if (!active) break;
diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
index 7f21f827e..03a026f17 100644
--- a/drivers/pcmcia/pci_socket.c
+++ b/drivers/pcmcia/pci_socket.c
@@ -177,7 +177,7 @@ static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_sock
socket->dev = dev;
socket->op = ops;
dev->driver_data = socket;
- init_waitqueue_head(&socket->wait);
+ spin_lock_init(&socket->event_lock);
return socket->op->open(socket);
}
diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h
index 6893fb1c2..50bc5702f 100644
--- a/drivers/pcmcia/pci_socket.h
+++ b/drivers/pcmcia/pci_socket.h
@@ -18,9 +18,11 @@ typedef struct pci_socket {
void *info;
struct pci_socket_ops *op;
socket_cap_t cap;
- wait_queue_head_t wait;
+ spinlock_t event_lock;
unsigned int events;
struct socket_info_t *pcmcia_socket;
+ struct tq_struct tq_task;
+ struct timer_list poll_timer;
/* A few words of private data for the low-level driver.. */
unsigned int private[8];
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 67abc32e6..a4d43e168 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -530,6 +530,28 @@ static void __exit exit_tcic(void)
/*====================================================================*/
+static u_int pending_events[2];
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static void tcic_bh(void *dummy)
+{
+ u_int events;
+ int i;
+
+ for (i=0; i < sockets; i++) {
+ spin_lock_irq(&pending_event_lock);
+ events = pending_events[i];
+ pending_events[i] = 0;
+ spin_unlock_irq(&pending_event_lock);
+ if (socket_table[i].handler)
+ socket_table[i].handler(socket_table[i].info, events);
+ }
+}
+
+static struct tq_struct tcic_task = {
+ routine: tcic_bh
+};
+
static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
{
int i, quick = 0;
@@ -568,8 +590,12 @@ static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
}
- if (events)
- socket_table[i].handler(socket_table[i].info, events);
+ if (events) {
+ spin_lock(&pending_event_lock);
+ pending_events[i] |= events;
+ spin_unlock(&pending_event_lock);
+ schedule_task(&tcic_task);
+ }
}
/* Schedule next poll, if needed */
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index c9a3ddab3..1bbf2c376 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -10,7 +10,10 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
#include <asm/io.h>
@@ -464,6 +467,20 @@ static unsigned int yenta_events(pci_socket_t *socket)
return events;
}
+
+static void yenta_bh(void *data)
+{
+ pci_socket_t *socket = data;
+ unsigned int events;
+
+ spin_lock_irq(&socket->event_lock);
+ events = socket->events;
+ socket->events = 0;
+ spin_unlock_irq(&socket->event_lock);
+ if (socket->handler)
+ socket->handler(socket->info, events);
+}
+
static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int events;
@@ -471,11 +488,22 @@ static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
events = yenta_events(socket);
if (events) {
+ spin_lock(&socket->event_lock);
socket->events |= events;
- wake_up_interruptible(&socket->wait);
+ spin_unlock(&socket->event_lock);
+ schedule_task(&socket->tq_task);
}
}
+static void yenta_interrupt_wrapper(unsigned long data)
+{
+ pci_socket_t *socket = (pci_socket_t *) data;
+
+ yenta_interrupt(0, (void *)socket, NULL);
+ socket->poll_timer.expires = jiffies + HZ;
+ add_timer(&socket->poll_timer);
+}
+
/*
* Only probe "regular" interrupts, don't
* touch dangerous spots like the mouse irq,
@@ -546,23 +574,23 @@ static void yenta_get_socket_capabilities(pci_socket_t *socket, u32 isa_irq_mask
extern void cardbus_register(pci_socket_t *socket);
/*
- * Watch a socket every second (and possibly in a
- * more timely manner if the state change interrupt
- * works..)
+ * 'Bottom half' for the yenta_open routine. Allocate the interrupt line
+ * and register the socket with the upper layers.
*/
-static int yenta_socket_thread(void * data)
+static void yenta_open_bh(void * data)
{
pci_socket_t * socket = (pci_socket_t *) data;
- DECLARE_WAITQUEUE(wait, current);
- MOD_INC_USE_COUNT;
- daemonize();
- strcpy(current->comm, "CardBus Watcher");
+ /* It's OK to overwrite this now */
+ socket->tq_task.routine = yenta_bh;
- if (request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) {
- printk ("Yenta: unable to register irq %d\n", socket->cb_irq);
- MOD_DEC_USE_COUNT;
- return (1);
+ if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->name, socket)) {
+ /* No IRQ or request_irq failed. Poll */
+ socket->cb_irq = 0; /* But zero is a valid IRQ number. */
+ socket->poll_timer.function = yenta_interrupt_wrapper;
+ socket->poll_timer.data = (unsigned long)socket;
+ socket->poll_timer.expires = jiffies + HZ;
+ add_timer(&socket->poll_timer);
}
/* Figure out what the dang thing can do for the PCMCIA layer... */
@@ -572,23 +600,7 @@ static int yenta_socket_thread(void * data)
/* Register it with the pcmcia layer.. */
cardbus_register(socket);
- do {
- unsigned int events = socket->events | yenta_events(socket);
-
- if (events) {
- socket->events = 0;
- if (socket->handler)
- socket->handler(socket->info, events);
- }
-
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&socket->wait, &wait);
- if (!socket->events)
- schedule_timeout(HZ);
- remove_wait_queue(&socket->wait, &wait);
- } while (!signal_pending(current));
MOD_DEC_USE_COUNT;
- return 0;
}
static void yenta_clear_maps(pci_socket_t *socket)
@@ -745,6 +757,9 @@ static void yenta_close(pci_socket_t *sock)
{
if (sock->cb_irq)
free_irq(sock->cb_irq, sock);
+ else
+ del_timer_sync(&sock->poll_timer);
+
if (sock->base)
iounmap(sock->base);
}
@@ -836,7 +851,16 @@ static int yenta_open(pci_socket_t *socket)
}
}
- kernel_thread(yenta_socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ /* Get the PCMCIA kernel thread to complete the
+ initialisation later. We can't do this here,
+ because, er, because Linus says so :)
+ */
+ socket->tq_task.routine = yenta_open_bh;
+ socket->tq_task.data = socket;
+
+ MOD_INC_USE_COUNT;
+ schedule_task(&socket->tq_task);
+
return 0;
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 624d7dfd7..10a43856c 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -696,6 +696,7 @@ static void raw3215_shutdown(raw3215_info *raw)
s390irq_spin_unlock_irqrestore(raw->irq, flags);
schedule();
s390irq_spin_lock_irqsave(raw->irq, flags);
+ remove_wait_queue(&raw->empty_wait, &wait);
current->state = TASK_RUNNING;
raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
}
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 44566c0a9..f2ee5ccc3 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -1,4 +1,4 @@
-/* $Id: aurora.c,v 1.7 1999/09/21 14:37:46 davem Exp $
+/* $Id: aurora.c,v 1.9 2000/11/08 05:33:03 davem Exp $
* linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
*
* Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
@@ -2387,7 +2387,6 @@ static void aurora_release_drivers(void)
#endif
}
-#ifndef MODULE
/*
* Called at boot time.
*
@@ -2406,10 +2405,7 @@ void __init aurora_setup(char *str, int *ints)
}
}
-int __init aurora_init(void)
-#else
-int aurora_init(void)
-#endif
+static int __init aurora_real_init(void)
{
int found;
int i;
@@ -2439,7 +2435,6 @@ int aurora_init(void)
return 0;
}
-#ifdef MODULE
int irq = 0;
int irq1 = 0;
int irq2 = 0;
@@ -2449,16 +2444,16 @@ MODULE_PARM(irq1, "i");
MODULE_PARM(irq2, "i");
MODULE_PARM(irq3, "i");
-int init_module(void)
+static int __init aurora_init(void)
{
if (irq ) irqs[0]=irq ;
if (irq1) irqs[1]=irq1;
if (irq2) irqs[2]=irq2;
if (irq3) irqs[3]=irq3;
- return aurora_init();
+ return aurora_real_init();
}
-void cleanup_module(void)
+static void __exit aurora_cleanup(void)
{
int i;
@@ -2473,4 +2468,6 @@ printk("cleanup_module: aurora_release_drivers\n");
aurora_release_io_range(&aurora_board[i]);
}
}
-#endif /* MODULE */
+
+module_init(aurora_init);
+module_exit(aurora_cleanup);
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 4579404e3..c96a141a5 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -1017,11 +1017,7 @@ static inline void freeLptPort(int idx)
static devfs_handle_t devfs_handle;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init bpp_init(void)
-#endif
+static int __init bpp_init(void)
{
int rc;
unsigned idx;
@@ -1046,8 +1042,7 @@ int __init bpp_init(void)
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit bpp_cleanup(void)
{
unsigned idx;
@@ -1059,4 +1054,6 @@ void cleanup_module(void)
freeLptPort(idx);
}
}
-#endif
+
+module_init(bpp_init);
+module_exit(bpp_cleanup);
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 2ee0aee37..091152a1c 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -1,4 +1,4 @@
-/* $Id: display7seg.c,v 1.3 2000/08/29 07:01:55 davem Exp $
+/* $Id: display7seg.c,v 1.4 2000/11/08 05:08:23 davem Exp $
*
* display7seg - Driver implementation for the 7-segment display
* present on Sun Microsystems CP1400 and CP1500
@@ -172,11 +172,7 @@ static struct file_operations d7s_fops = {
static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
-#ifdef MODULE
-int init_module(void)
-#else
-int __init d7s_init(void)
-#endif
+static int __init d7s_init(void)
{
struct linux_ebus *ebus = NULL;
struct linux_ebus_device *edev = NULL;
@@ -222,8 +218,7 @@ ebus_done:
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit d7s_cleanup(void)
{
int regs = readb(d7s_regs);
@@ -237,4 +232,6 @@ void cleanup_module(void)
misc_deregister(&d7s_miscdev);
d7s_free();
}
-#endif
+
+module_init(d7s_init);
+module_exit(d7s_cleanup);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 31c9de932..e1de7a680 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.18 2000/10/17 16:20:35 davem Exp $
+/* $Id: envctrl.c,v 1.19 2000/11/03 00:37:40 davem Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
@@ -11,7 +11,9 @@
* http://www-eu2.semiconductors.com/pip/PCF8584P
* http://www-eu2.semiconductors.com/pip/PCF8574AP
* http://www-eu2.semiconductors.com/pip/PCF8591P
- *
+ *
+ * EB - Added support for CP1500 Global Address and PS/Voltage monitoring.
+ * Eric Brower <ebrower@usa.net>
*/
#include <linux/config.h>
@@ -72,15 +74,16 @@
* Firmware definitions.
*/
#define PCF8584_MAX_CHANNELS 8
+#define PCF8584_GLOBALADDR_TYPE 6 /* global address monitor */
#define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */
#define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */
-#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
+#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
/* Monitor type of i2c child device.
* Driver definitions.
*/
-#define ENVCTRL_NOMON 0
-#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
+#define ENVCTRL_NOMON 0
+#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
#define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */
#define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */
#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */
@@ -88,6 +91,7 @@
#define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */
#define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */
#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */
+#define ENVCTRL_GLOBALADDR_MON 8 /* global address */
/* Child device type.
* Driver definitions.
@@ -109,6 +113,15 @@
#define ENVCTRL_MAX_CPU 4
#define CHANNEL_DESC_SZ 256
+/* Mask values for combined GlobalAddress/PowerStatus node */
+#define ENVCTRL_GLOBALADDR_ADDR_MASK 0x1F
+#define ENVCTRL_GLOBALADDR_PSTAT_MASK 0x60
+
+/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms
+ * (see envctrl_init_i2c_child)
+ */
+#define ENVCTRL_CPCI_IGNORED_NODE 0x70
+
struct pcf8584_reg {
unsigned char data;
unsigned char csr;
@@ -317,7 +330,6 @@ static unsigned char envctrl_i2c_read_8574(unsigned char addr)
/* Do a single byte read and send stop. */
rd = envctrl_i2c_read_data();
envctrl_i2c_stop();
-
return rd;
}
@@ -462,7 +474,32 @@ static int envctrl_i2c_fan_status(struct i2c_child_t *pchild,
return 1;
}
-/* Function Description: Read voltage and power supply status.
+/* Function Description: Read global addressing line.
+ * Return : Always 1 byte. Status stored in bufdata.
+ */
+static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild,
+ unsigned char data,
+ char *bufdata)
+{
+ /* Translatation table is not necessary, as global
+ * addr is the integer value of the GA# bits.
+ *
+ * NOTE: MSB is documented as zero, but I see it as '1' always....
+ *
+ * -----------------------------------------------
+ * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 |
+ * -----------------------------------------------
+ * GA0 - GA4 integer value of Global Address (backplane slot#)
+ * DEG 0 = cPCI Power supply output is starting to degrade
+ * 1 = cPCI Power supply output is OK
+ * FAL 0 = cPCI Power supply has failed
+ * 1 = cPCI Power supply output is OK
+ */
+ bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK);
+ return 1;
+}
+
+/* Function Description: Read standard voltage and power supply status.
* Return : Always 1 byte. Status stored in bufdata.
*/
static unsigned char envctrl_i2c_voltage_status(struct i2c_child_t *pchild,
@@ -587,10 +624,20 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos)
ret = envctrl_i2c_fan_status(pchild,data[0], data);
copy_to_user((unsigned char *)buf, data, ret);
break;
+
+ case ENVCTRL_RD_GLOBALADDRESS:
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
+ data[0] = envctrl_i2c_read_8574(pchild->addr);
+ ret = envctrl_i2c_globaladdr(pchild, data[0], data);
+ copy_to_user((unsigned char *)buf, data, ret);
+ break;
case ENVCTRL_RD_VOLTAGE_STATUS:
if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON)))
- return 0;
+ /* If voltage monitor not present, check for CPCI equivalent */
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
data[0] = envctrl_i2c_read_8574(pchild->addr);
ret = envctrl_i2c_voltage_status(pchild, data[0], data);
copy_to_user((unsigned char *)buf, data, ret);
@@ -621,6 +668,7 @@ envctrl_ioctl(struct inode *inode, struct file *file,
case ENVCTRL_RD_VOLTAGE_STATUS:
case ENVCTRL_RD_ETHERNET_TEMPERATURE:
case ENVCTRL_RD_SCSI_TEMPERATURE:
+ case ENVCTRL_RD_GLOBALADDRESS:
file->private_data = (void *)(long)cmd;
break;
@@ -714,9 +762,6 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
if (!(strcmp(chnl_desc,"temp,ethernet")))
pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
-
- if (!(strcmp(chnl_desc,"temp,ethernet")))
- pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
}
/* Function Description: Initialize monitor channel with channel desc,
@@ -770,6 +815,39 @@ static void envctrl_init_fanstat(struct i2c_child_t *pchild)
pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;
}
+/* Function Description: Initialize child device for global addressing line.
+ * Return: None.
+ */
+static void envctrl_init_globaladdr(struct i2c_child_t *pchild)
+{
+ int i;
+
+ /* Voltage/PowerSupply monitoring is piggybacked
+ * with Global Address on CompactPCI. See comments
+ * within envctrl_i2c_globaladdr for bit assignments.
+ *
+ * The mask is created here by assigning mask bits to each
+ * bit position that represents PCF8584_VOLTAGE_TYPE data.
+ * Channel numbers are not consecutive within the globaladdr
+ * node (why?), so we use the actual counter value as chnls_mask
+ * index instead of the chnl_array[x].chnl_no value.
+ *
+ * NOTE: This loop could be replaced with a constant representing
+ * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).
+ */
+ for (i = 0; i < pchild->total_chnls; i++) {
+ if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {
+ pchild->voltage_mask |= chnls_mask[i];
+ }
+ }
+
+ /* We only need to know if this child has global addressing
+ * line monitored. We dont care which channels since we know
+ * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).
+ */
+ pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;
+}
+
/* Initialize child device monitoring voltage status. */
static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
{
@@ -822,6 +900,27 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
}
}
+ /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
+ * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is
+ * "For Factory Use Only."
+ *
+ * We ignore the node on these platforms by assigning the
+ * 'NULL' monitor type.
+ */
+ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+ int len;
+ char prop[56];
+
+ len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+ if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
+ {
+ for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
+ pchild->mon_type[len] = ENVCTRL_NOMON;
+ }
+ return;
+ }
+ }
+
/* Get the monitor channels. */
len = prom_getproperty(node, "channels-in-use",
(char *) pchild->chnl_array,
@@ -835,6 +934,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
envctrl_init_adc(pchild, node);
break;
+ case PCF8584_GLOBALADDR_TYPE:
+ envctrl_init_globaladdr(pchild);
+ i = pchild->total_chnls;
+ break;
+
case PCF8584_FANSTAT_TYPE:
envctrl_init_fanstat(pchild);
i = pchild->total_chnls;
@@ -865,7 +969,7 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type)
for (i = 0; i < ENVCTRL_MAX_CPU*2; i++) {
for (j = 0; j < PCF8584_MAX_CHANNELS; j++) {
if (i2c_childlist[i].mon_type[j] == mon_type) {
- return (struct i2c_child_t*)(&(i2c_childlist[i]));
+ return (struct i2c_child_t *)(&(i2c_childlist[i]));
}
}
}
@@ -932,8 +1036,7 @@ done:
* child devices.
*/
printk("envctrl: initialized ");
- for(--i; i >= 0; --i)
- {
+ for (--i; i >= 0; --i) {
printk("[%s 0x%lx]%s",
(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") :
((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")),
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 8690638b3..71809b59d 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.19 2000/07/13 08:06:40 davem Exp $
+/* $Id: flash.c,v 1.20 2000/11/08 04:57:49 davem Exp $
* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -149,11 +149,7 @@ static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
EXPORT_NO_SYMBOLS;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init flash_init(void)
-#endif
+static int __init flash_init(void)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = 0;
@@ -236,9 +232,10 @@ int __init flash_init(void)
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit flash_cleanup(void)
{
misc_deregister(&flash_dev);
}
-#endif
+
+module_init(flash_init);
+module_exit(flash_cleanup);
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 26e5ae8d9..f565ef6d2 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -626,11 +626,7 @@ static struct miscdevice openprom_dev = {
EXPORT_NO_SYMBOLS;
-#ifdef MODULE
-int init_module(void)
-#else
-int __init openprom_init(void)
-#endif
+static int __init openprom_init(void)
{
unsigned long flags;
int error;
@@ -655,9 +651,10 @@ int __init openprom_init(void)
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit openprom_cleanup(void)
{
misc_deregister(&openprom_dev);
}
-#endif
+
+module_init(openprom_init);
+module_exit(openprom_cleanup);
diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c
index ae7ba7ac1..fa5f383c3 100644
--- a/drivers/sbus/char/sab82532.c
+++ b/drivers/sbus/char/sab82532.c
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.52 2000/10/14 10:09:04 davem Exp $
+/* $Id: sab82532.c,v 1.53 2000/11/15 07:28:09 davem Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -1833,6 +1833,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
schedule();
}
+ current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp))
info->count++;
@@ -2133,7 +2134,7 @@ static void __init sab82532_kgdb_hook(int line)
static inline void __init show_serial_version(void)
{
- char *revision = "$Revision: 1.52 $";
+ char *revision = "$Revision: 1.53 $";
char *version, *p;
version = strchr(revision, ' ');
diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c
index 1fd2d6fbf..bb256e46e 100644
--- a/drivers/sbus/char/su.c
+++ b/drivers/sbus/char/su.c
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.42 2000/10/14 10:09:04 davem Exp $
+/* $Id: su.c,v 1.43 2000/11/15 07:28:09 davem Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -2001,6 +2001,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
schedule();
}
+ current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
if (extra_count)
info->count++;
@@ -2219,7 +2220,7 @@ done:
*/
static __inline__ void __init show_su_version(void)
{
- char *revision = "$Revision: 1.42 $";
+ char *revision = "$Revision: 1.43 $";
char *version, *p;
version = strchr(revision, ' ');
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 6294d0e37..2740c62f3 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -1,4 +1,4 @@
-/* $Id: uctrl.c,v 1.8 2000/06/19 06:24:47 davem Exp $
+/* $Id: uctrl.c,v 1.9 2000/11/08 05:04:06 davem Exp $
* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
*
* Copyright 1999 Derrick J Brashear (shadow@dementia.org)
@@ -363,11 +363,7 @@ void uctrl_get_external_status()
}
-#ifdef MODULE
-int init_module(void)
-#else
-int __init ts102_uctrl_init(void)
-#endif
+static int __init ts102_uctrl_init(void)
{
struct uctrl_driver *driver = &drv;
int len, i;
@@ -419,9 +415,7 @@ int __init ts102_uctrl_init(void)
return 0;
}
-
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit ts102_uctrl_cleanup(void)
{
struct uctrl_driver *driver = &drv;
@@ -433,4 +427,6 @@ void cleanup_module(void)
if (driver->regs)
driver->regs = 0;
}
-#endif
+
+module_init(ts102_uctrl_init);
+module_exit(ts102_uctrl_cleanup);
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 35865dd70..942a6c59b 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.86 2000/03/16 09:23:57 jj Exp $
+/* $Id: sbus.c,v 1.91 2000/11/08 05:04:06 davem Exp $
* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -165,21 +165,9 @@ no_ranges:
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
void sun4_init(void);
-#ifdef CONFIG_SUN_OPENPROMIO
-extern int openprom_init(void);
-#endif
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
-#ifdef CONFIG_OBP_FLASH
-extern int flash_init(void);
-#endif
-#ifdef CONFIG_SUN_AURORA
-extern int aurora_init(void);
-#endif
-#ifdef CONFIG_TADPOLE_TS102_UCTRL
-extern int ts102_uctrl_init(void);
-#endif
static void __init sbus_do_child_siblings(int start_node,
struct sbus_dev *child,
@@ -520,25 +508,10 @@ void __init sbus_init(void)
firetruck_init();
}
#endif
-#ifdef CONFIG_SUN_OPENPROMIO
- openprom_init();
-#endif
-#ifdef CONFIG_SUN_BPP
- bpp_init();
-#endif
#ifdef CONFIG_SUN_AUXIO
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
-#ifdef CONFIG_OBP_FLASH
- flash_init();
-#endif
-#ifdef CONFIG_SUN_AURORA
- aurora_init();
-#endif
-#ifdef CONFIG_TADPOLE_TS102_UCTRL
- ts102_uctrl_init();
-#endif
#ifdef __sparc_v9__
if (sparc_cpu_model == sun4u) {
extern void clock_probe(void);
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index cb70168a3..0a3db13f8 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -696,8 +696,13 @@ int tw_findcards(Scsi_Host_Template *tw_host)
/* Register the card with the kernel SCSI layer */
host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-
- /* FIXME - check for NULL */
+ if( host == NULL)
+ {
+ release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+ tw_free_device_extension(tw_dev);
+ kfree(tw_dev);
+ continue;
+ }
status_reg_value = inl(tw_dev->registers.status_reg_addr);
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 7caa27312..2ee80ae09 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -1125,6 +1125,7 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
schedule_size = 0, ok = 0;
void *tmp;
+ unsigned long page;
switch (chip) {
case 710:
@@ -1191,6 +1192,12 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
*/
(sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
+ page = __get_free_pages(GFP_ATOMIC,1);
+ if(page==0)
+ {
+ printk(KERN_ERR "53c7xx: out of memory.\n");
+ return -ENOMEM;
+ }
#ifdef FORCE_DSA_ALIGNMENT
/*
* 53c710 rev.0 doesn't have an add-with-carry instruction.
@@ -1203,10 +1210,11 @@ ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
panic("53c7xx: hostdata > 8K");
instance = scsi_register (tpnt, 4);
if (!instance)
+ {
+ free_page(page);
return -1;
- instance->hostdata[0] = __get_free_pages(GFP_ATOMIC, 1);
- if (instance->hostdata[0] == 0)
- panic ("53c7xx: Couldn't get hostdata memory");
+ }
+ instance->hostdata[0] = page;
memset((void *)instance->hostdata[0], 0, 8192);
cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
@@ -3087,7 +3095,7 @@ allocate_cmd (Scsi_Cmnd *cmd) {
panic ("53c7xx: allocate_cmd size > 4K");
real = get_free_page(GFP_ATOMIC);
if (real == 0)
- panic ("53c7xx: Couldn't get memory for allocate_cmd");
+ return NULL;
memset((void *)real, 0, 4096);
cache_push(virt_to_phys((void *)real), 4096);
cache_clear(virt_to_phys((void *)real), 4096);
diff --git a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c
index 8d92082aa..1b0e2161e 100644
--- a/drivers/scsi/AM53C974.c
+++ b/drivers/scsi/AM53C974.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
@@ -381,11 +380,11 @@ static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastat
unsigned char statreg);
static void AM53C974_intr_bus_reset(struct Scsi_Host *instance);
-static struct Scsi_Host *first_instance = NULL;
-static Scsi_Host_Template *the_template = NULL;
-static struct Scsi_Host *first_host = NULL; /* Head of list of AMD boards */
-static volatile int main_running = 0;
-static int commandline_current = 0;
+static struct Scsi_Host *first_instance;
+static Scsi_Host_Template *the_template;
+static struct Scsi_Host *first_host; /* Head of list of AMD boards */
+static volatile int main_running;
+static int commandline_current;
override_t overrides[7] =
{
{-1, 0, 0, 0},}; /* LILO overrides */
@@ -571,19 +570,25 @@ static void AM53C974_keywait(void)
restore_flags(flags);
}
+#ifndef MODULE
/**************************************************************************
-* Function : AM53C974_setup(char *str, int *ints)
+* Function : AM53C974_setup(char *str)
*
* Purpose : LILO command line initialization of the overrides array,
*
-* Inputs : str - unused, ints - array of integer parameters with ints[0]
-* equal to the number of ints.
+* Input : str - parameter string.
+*
+* Returns : 1.
*
* NOTE : this function needs to be declared as an external function
* in init/main.c and included there in the bootsetups list
***************************************************************************/
-void AM53C974_setup(char *str, int *ints)
+static int AM53C974_setup(char *str)
{
+ int ints[5];
+
+ get_options(str, ARRAY_SIZE(ints), ints);
+
if (ints[0] < 4)
printk("AM53C974_setup: wrong number of parameters;\n correct syntax is: AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset\n");
else {
@@ -604,9 +609,13 @@ void AM53C974_setup(char *str, int *ints)
} else
printk("AM53C974_setup: too many overrides\n");
}
+
+ return 1;
}
+__setup("AM53C974=", AM53C974_setup);
+
+#endif /* !MODULE */
-#if defined (CONFIG_PCI)
/**************************************************************************
* Function : int AM53C974_pci_detect(Scsi_Host_Template *tpnt)
*
@@ -616,7 +625,7 @@ void AM53C974_setup(char *str, int *ints)
*
* Returns : number of host adapters detected
**************************************************************************/
-static inline int AM53C974_pci_detect(Scsi_Host_Template * tpnt)
+static int __init AM53C974_pci_detect(Scsi_Host_Template * tpnt)
{
int count = 0; /* number of boards detected */
struct pci_dev *pdev = NULL;
@@ -639,29 +648,6 @@ static inline int AM53C974_pci_detect(Scsi_Host_Template * tpnt)
}
return (count);
}
-#endif
-
-/**************************************************************************
-* Function : int AM53C974_detect(Scsi_Host_Template *tpnt)
-*
-* Purpose : detects and initializes AM53C974 SCSI chips
-*
-* Inputs : tpnt - host template
-*
-* Returns : number of host adapters detected
-**************************************************************************/
-int __init AM53C974_detect(Scsi_Host_Template * tpnt)
-{
- int count = 0; /* number of boards detected */
-
- tpnt->proc_name = "am53c974";
-
-#if defined (CONFIG_PCI)
- if (pci_present())
- count = AM53C974_pci_detect(tpnt);
-#endif
- return (count);
-}
/**************************************************************************
* Function : int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev)
@@ -810,7 +796,7 @@ static void AM53C974_config_after_reset(struct Scsi_Host *instance)
* *
* Returns : info string *
************************************************************************/
-const char *AM53C974_info(struct Scsi_Host *instance)
+static const char *AM53C974_info(struct Scsi_Host *instance)
{
static char info[100];
@@ -830,7 +816,7 @@ const char *AM53C974_info(struct Scsi_Host *instance)
* *
* Returns :status, see hosts.h for details *
***************************************************************************/
-int AM53C974_command(Scsi_Cmnd * SCpnt)
+static int AM53C974_command(Scsi_Cmnd * SCpnt)
{
DEB(printk("AM53C974_command called\n"));
return 0;
@@ -903,7 +889,7 @@ static __inline__ void run_main(void)
* twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
**************************************************************************/
-int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
unsigned long flags;
struct Scsi_Host *instance = cmd->host;
@@ -2283,7 +2269,7 @@ static void AM53C974_intr_bus_reset(struct Scsi_Host *instance)
*
* Returns : 0 - success, -1 on failure.
**************************************************************************/
-int AM53C974_abort(Scsi_Cmnd * cmd)
+static int AM53C974_abort(Scsi_Cmnd * cmd)
{
AM53C974_local_declare();
unsigned long flags;
@@ -2391,7 +2377,7 @@ int AM53C974_abort(Scsi_Cmnd * cmd)
*
* FIXME(eric) the reset_flags are ignored.
**************************************************************************/
-int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int reset_flags)
+static int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int reset_flags)
{
AM53C974_local_declare();
unsigned long flags;
@@ -2447,7 +2433,7 @@ int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int reset_flags)
*
* Release resources allocated for a single AM53C974 adapter.
*/
-int AM53C974_release(struct Scsi_Host *shp)
+static int AM53C974_release(struct Scsi_Host *shp)
{
free_irq(shp->irq, shp);
scsi_unregister(shp);
@@ -2455,11 +2441,9 @@ int AM53C974_release(struct Scsi_Host *shp)
}
-#ifdef MODULE
/* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d
on boot up */
MODULE_PARM(overrides, "1-32i");
-#endif
static Scsi_Host_Template driver_template = AM53C974;
#include "scsi_module.c"
diff --git a/drivers/scsi/AM53C974.h b/drivers/scsi/AM53C974.h
index 78c6d21f8..e7a494b5c 100644
--- a/drivers/scsi/AM53C974.h
+++ b/drivers/scsi/AM53C974.h
@@ -53,7 +53,7 @@ struct AM53C974_hostdata {
#define AM53C974 { \
proc_name: "am53c974", \
name: "AM53C974", \
- detect: AM53C974_detect, \
+ detect: AM53C974_pci_detect, \
release: AM53C974_release, \
info: AM53C974_info, \
command: AM53C974_command, \
@@ -68,14 +68,12 @@ struct AM53C974_hostdata {
use_clustering: DISABLE_CLUSTERING \
}
-void AM53C974_setup(char *str, int *ints);
-int AM53C974_detect(Scsi_Host_Template * tpnt);
-int AM53C974_release(struct Scsi_Host *shp);
-int AM53C974_biosparm(Disk * disk, int dev, int *info_array);
-const char *AM53C974_info(struct Scsi_Host *);
-int AM53C974_command(Scsi_Cmnd * SCpnt);
-int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
-int AM53C974_abort(Scsi_Cmnd * cmd);
-int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int);
+static int AM53C974_pci_detect(Scsi_Host_Template * tpnt);
+static int AM53C974_release(struct Scsi_Host *shp);
+static const char *AM53C974_info(struct Scsi_Host *);
+static int AM53C974_command(Scsi_Cmnd * SCpnt);
+static int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+static int AM53C974_abort(Scsi_Cmnd * cmd);
+static int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int);
#endif /* AM53C974_H */
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 1abc1a8c7..83512a854 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2793,6 +2793,11 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
Register the SCSI Host structure.
*/
Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T));
+ if(Host==NULL)
+ {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
+ continue;
+ }
HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata;
memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
HostAdapter->SCSI_Host = Host;
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 83f2c789f..e450016a8 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -57,7 +57,7 @@ if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
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
+dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI $CONFIG_PCI
dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI
dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 98ceaf3e9..5c657b2e5 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -207,6 +207,10 @@ int __init a2091_detect(Scsi_Host_Template *tpnt)
continue;
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
+ if (instance == NULL) {
+ release_mem_region(address, 256);
+ continue;
+ }
instance->base = ZTWO_VADDR(address);
instance->irq = IRQ_AMIGA_PORTS;
instance->unique_id = z->slotaddr;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 422536d77..c9a4253f0 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -175,6 +175,8 @@ int __init a3000_detect(Scsi_Host_Template *tpnt)
tpnt->proc_info = &wd33c93_proc_info;
a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
+ if(a3000_host == NULL)
+ return 0;
a3000_host->base = ZTWO_VADDR(0xDD0000);
a3000_host->irq = IRQ_AMIGA_PORTS;
DMA(a3000_host)->DAWR = DAWR_A3000;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index bf89438ee..69fec6b14 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -4774,6 +4774,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
*/
ASC_DBG(2, "advansys_detect: scsi_register()\n");
shp = scsi_register(tpnt, sizeof(asc_board_t));
+
+ if(shp==NULL)
+ continue;
/* Save a pointer to the Scsi_host of each board found. */
asc_host[asc_board_count++] = shp;
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 667eedd3c..25636b008 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -13,9 +13,16 @@
* General Public License for more details.
*
*
- * $Id: aha152x.c,v 2.1 2000/05/17 16:23:17 fischer Exp fischer $
+ * $Id: aha152x.c,v 2.3 2000/11/04 16:40:26 fischer Exp $
*
* $Log: aha152x.c,v $
+ * Revision 2.3 2000/11/04 16:40:26 fischer
+ * - handle data overruns
+ * - extend timeout for data phases
+ *
+ * Revision 2.2 2000/08/08 19:54:53 fischer
+ * - minor changes
+ *
* Revision 2.1 2000/05/17 16:23:17 fischer
* - signature update
* - fix for data out w/o scatter gather
@@ -256,7 +263,7 @@
#define DO_LOCK(flags) \
do { \
- if(QLOCK.lock) { \
+ if(spin_is_locked(&QLOCK)) { \
DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
} \
DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
@@ -293,7 +300,6 @@
(cmd) ? ((cmd)->lun & 0x07) : -1
#define DELAY_DEFAULT 100
-#define DEBUG_DEFAULT 0
/* possible irq range */
#if defined(PCMCIA)
@@ -357,11 +363,11 @@ static int exttrans[] = {0, 0};
#if !defined(AHA152X_DEBUG)
MODULE_PARM(aha152x, "1-8i");
MODULE_PARM_DESC(aha152x, "parameters for first controller");
-static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
MODULE_PARM(aha152x1, "1-8i");
MODULE_PARM_DESC(aha152x1, "parameters for second controller");
-static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
#else
MODULE_PARM(debug, "1-2i");
MODULE_PARM_DESC(debug, "flags for driver debugging");
@@ -369,11 +375,11 @@ static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
MODULE_PARM(aha152x, "1-9i");
MODULE_PARM_DESC(aha152x, "parameters for first controller");
-static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
MODULE_PARM(aha152x1, "1-9i");
MODULE_PARM_DESC(aha152x1, "parameters for second controller");
-static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
#endif /* !defined(AHA152X_DEBUG) */
#endif /* MODULE */
@@ -954,7 +960,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
if (setup_count < 2) {
struct aha152x_setup override = SETUP0;
- if (setup_count == 0 || (override.io_port != setup[0].io_port))
+ if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
if (!checksetup(&override)) {
printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
@@ -967,6 +973,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
override.ext_trans);
} else
setup[setup_count++] = override;
+ }
}
#endif
@@ -974,7 +981,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
if (setup_count < 2) {
struct aha152x_setup override = SETUP1;
- if (setup_count == 0 || (override.io_port != setup[0].io_port))
+ if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
if (!checksetup(&override)) {
printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
override.io_port,
@@ -987,6 +994,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
override.ext_trans);
} else
setup[setup_count++] = override;
+ }
}
#endif
@@ -2436,8 +2444,13 @@ static void msgo_run(struct Scsi_Host *shpnt)
static void msgo_end(struct Scsi_Host *shpnt)
{
- if(MSGO_I<MSGOLEN)
+ if(MSGO_I<MSGOLEN) {
printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+ if(SYNCNEG==1) {
+ printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+ SYNCNEG=2;
+ }
+ }
MSGO_I = 0;
MSGOLEN = 0;
@@ -2553,7 +2566,7 @@ static void datai_run(struct Scsi_Host *shpnt)
* STCNT to trigger ENSWRAP interrupt, instead of
* polling for DFIFOFULL
*/
- the_time=jiffies + 100;
+ the_time=jiffies + 10*HZ;
while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
barrier();
@@ -2579,42 +2592,50 @@ static void datai_run(struct Scsi_Host *shpnt)
fifodata = GETPORT(FIFOSTAT);
}
- while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
- data_count = fifodata>CURRENT_SC->SCp.this_residual ?
- CURRENT_SC->SCp.this_residual :
- fifodata;
- fifodata -= data_count;
-
- if(data_count & 1) {
- DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
- SETPORT(DMACNTRL0, ENDMA|_8BIT);
- *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
- CURRENT_SC->SCp.this_residual--;
- DATA_LEN++;
- SETPORT(DMACNTRL0, ENDMA);
- }
-
- if(data_count > 1) {
- DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
- data_count >>= 1;
- insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
- CURRENT_SC->SCp.ptr += 2 * data_count;
- CURRENT_SC->SCp.this_residual -= 2 * data_count;
- DATA_LEN += 2 * data_count;
- }
-
- if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
- /* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
- CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
- }
- }
-
- if(fifodata>0 && CURRENT_SC->SCp.this_residual==0) {
+ if(CURRENT_SC->SCp.this_residual>0) {
+ while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
+ data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+ CURRENT_SC->SCp.this_residual :
+ fifodata;
+ fifodata -= data_count;
+
+ if(data_count & 1) {
+ DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+ CURRENT_SC->SCp.this_residual--;
+ DATA_LEN++;
+ SETPORT(DMACNTRL0, ENDMA);
+ }
+
+ if(data_count > 1) {
+ DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+ data_count >>= 1;
+ insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
+ DATA_LEN += 2 * data_count;
+ }
+
+ if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+ /* advance to next buffer */
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address;
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+ }
+ }
+ } else if(fifodata>0) {
printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
- break;
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ while(fifodata>0) {
+ int data;
+ data=GETPORT(DATAPORT);
+ DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data);
+ fifodata--;
+ DATA_LEN++;
+ }
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
}
}
@@ -2714,7 +2735,7 @@ static void datao_run(struct Scsi_Host *shpnt)
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
}
- the_time=jiffies+100;
+ the_time=jiffies+10*HZ;
while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
barrier();
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index 910f1668b..86f84cbe2 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -2,7 +2,7 @@
#define _AHA152X_H
/*
- * $Id: aha152x.h,v 2.0 1999/12/25 15:08:35 fischer Exp fischer $
+ * $Id: aha152x.h,v 2.3 2000/11/04 16:41:37 fischer Exp $
*/
#if defined(__KERNEL__)
@@ -27,7 +27,7 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
(unless we support more than 1 cmd_per_lun this should do) */
#define AHA152X_MAXQUEUE 7
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.0 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.3 $"
/* Initial value of Scsi_Host entry */
#define AHA152X { proc_name: "aha152x", \
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 7ed3170c9..9d3584a25 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -1154,6 +1154,8 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
shpnt = scsi_register(tpnt,
sizeof(struct aha1542_hostdata));
+ if(shpnt==NULL)
+ continue;
/* For now we do this - until kmalloc is more intelligent
we are resigned to stupid hacks like this */
if (SCSI_PA(shpnt) >= ISA_DMA_THRESHOLD) {
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index c3a25c121..8e8c901bb 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -541,6 +541,11 @@ int aha1740_detect(Scsi_Host_Template * tpnt)
continue;
}
shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata));
+ if(shpnt == NULL)
+ {
+ free_irq(irq_level, NULL);
+ continue;
+ }
request_region(slotbase, SLOTSIZE, "aha1740");
shpnt->base = 0;
shpnt->io_port = slotbase;
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 118f09f05..77feb1cbc 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -667,6 +667,12 @@ int atari_scsi_detect (Scsi_Host_Template *host)
}
#endif
instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
+ if(instance == NULL)
+ {
+ atari_stram_free(atari_dma_buffer);
+ atari_dma_buffer = 0;
+ return 0;
+ }
atari_scsi_host = instance;
/* Set irq to 0, to avoid that the mid-level code disables our interrupt
* during queue_command calls. This is completely unnecessary, and even
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index b0722e20f..890d44426 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -1734,6 +1734,8 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
dev->ultra_map = 0xffff;
}
shpnt = scsi_register(tpnt, 4);
+ if(shpnt==NULL)
+ return count;
save_flags(flags);
cli();
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
index b51b515a6..dac695423 100644
--- a/drivers/scsi/cpqfcTSinit.c
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -290,6 +290,9 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
(ULONG)sizeof(CPQFCHBA));
HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
+
+ if(HostAdapter == NULL)
+ continue;
DEBUG_PCI( printk(" HBA found!\n"));
DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[0]));
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 327743bf8..b369c0618 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -82,6 +82,11 @@ int __init dmx3191d_detect(Scsi_Host_Template *tmpl) {
request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME);
instance = scsi_register(tmpl, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ {
+ release_region(port, DMX3191D_REGION);
+ continue;
+ }
instance->io_port = port;
instance->irq = pdev->irq;
NCR5380_init(instance, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 5e2635cba..845174d27 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -241,6 +241,9 @@ int __init dtc_detect(Scsi_Host_Template * tpnt){
break;
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ break;
+
instance->base = base;
NCR5380_init(instance, 0);
diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c
index 09b6929b2..9559c716c 100644
--- a/drivers/scsi/eata_dma.c
+++ b/drivers/scsi/eata_dma.c
@@ -554,7 +554,17 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
GFP_ATOMIC | GFP_DMA);
}
if (ccb->sg_list == NULL)
- panic("eata_dma: Run out of DMA memory for SG lists !\n");
+ {
+ /*
+ * Claim the bus was busy. Actually we are the problem but this
+ * will do a deferred retry for us ;)
+ */
+ printk(KERN_ERR "eata_dma: Run out of DMA memory for SG lists !\n");
+ cmd->result = DID_BUS_BUSY << 16;
+ ccb->status = FREE;
+ done(cmd);
+ return(0);
+ }
ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list));
ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
@@ -909,8 +919,17 @@ char * get_board_data(u32 base, u32 irq, u32 id)
cp = (struct eata_ccb *) kmalloc(sizeof(struct eata_ccb),
GFP_ATOMIC | GFP_DMA);
+
+ if(cp==NULL)
+ return NULL;
+
sp = (struct eata_sp *) kmalloc(sizeof(struct eata_sp),
GFP_ATOMIC | GFP_DMA);
+ if(sp==NULL)
+ {
+ kfree(cp);
+ return NULL;
+ }
buff = dma_scratch;
@@ -1463,6 +1482,10 @@ int eata_detect(Scsi_Host_Template * tpnt)
if(status == NULL || dma_scratch == NULL) {
printk("eata_dma: can't allocate enough memory to probe for hosts !\n");
+ if(status)
+ kfree(status);
+ if(dma_scratch)
+ kfree(dma_scratch);
return(0);
}
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index 7961483e1..3ee72657c 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -153,7 +153,18 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
} else {
SDev = scsi_get_host_dev(HBA_ptr);
+
+ if(SDev == NULL)
+ return -ENOMEM;
+
scmd = scsi_allocate_request(SDev);
+
+ if(scmd == NULL)
+ {
+ scsi_free_host_dev(SDev);
+ return -ENOMEM;
+ }
+
cmnd[0] = LOG_SENSE;
cmnd[1] = 0;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index ef4561fdc..0d890817c 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -728,6 +728,12 @@ int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
sh = scsi_register(tpnt, size);
+ if(sh == NULL)
+ {
+ release_region(base, 8);
+ return FALSE;
+ }
+
hd = SD(sh);
memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 8dce8b2cf..828c9e290 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.97 2000/09/19 01:29:27 davem Exp $
+/* $Id: esp.c,v 1.98 2000/11/02 22:34:16 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
@@ -400,7 +400,7 @@ extern inline void esp_cmd(struct esp *esp, u8 cmd)
*
* struct scsi_cmnd:
*
- * We keep track of the syncronous capabilities of a target
+ * We keep track of the synchronous capabilities of a target
* in the device member, using sync_min_period and
* sync_max_offset. These are the values we directly write
* into the ESP registers while running a command. If offset
@@ -2661,7 +2661,7 @@ static int esp_do_data_finale(struct esp *esp)
* on HME broken adapters because we skip the HME fifo
* workaround code in esp_handle() if we are doing data
* phase things. We don't want to fuck directly with
- * the fifo like that, especially if doing syncronous
+ * the fifo like that, especially if doing synchronous
* transfers! Also, will need to double the count on
* HME if we are doing wide transfers, as the HME fifo
* will move and count 16-bit quantities during wide data.
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
index 05ff2f7d9..4ffef8561 100644
--- a/drivers/scsi/fcal.c
+++ b/drivers/scsi/fcal.c
@@ -128,7 +128,11 @@ int __init fcal_detect(Scsi_Host_Template *tpnt)
if (!ages) continue;
host = scsi_register (tpnt, sizeof (struct fcal));
- if (!host) panic ("Cannot register FCAL host\n");
+ if (!host)
+ {
+ kfree(ages);
+ continue;
+ }
nfcals++;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index d6ac51931..884a2ea25 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -965,6 +965,8 @@ int fdomain_16x0_detect( Scsi_Host_Template *tpnt )
get resources. */
shpnt = scsi_register( tpnt, 0 );
+ if(shpnt == NULL)
+ return 0;
shpnt->irq = interrupt_level;
shpnt->io_port = port_base;
shpnt->n_io_port = 0x10;
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index c582c8e72..492de3866 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -390,6 +390,17 @@ int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
NCR5380_region_size, "ncr5380");
#endif
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ {
+#ifdef CONFIG_SCSI_G_NCR5380_PORT
+ release_region(overrides[current_override].NCR5380_map_name,
+ NCR5380_region_size);
+#else
+ release_mem_region(overrides[current_override].NCR5380_map_name,
+ NCR5380_region_size);
+#endif
+ }
+
instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
NCR5380_init(instance, flags);
@@ -902,3 +913,4 @@ MODULE_PARM(ncr_53c400a, "i");
MODULE_PARM(dtc_3181e, "i");
#endif
+
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index dd26cda1e..ec5814c7f 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -3125,6 +3125,8 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
break;
if (gdth_search_isa(isa_bios)) { /* controller found */
shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ if(shp == NULL)
+ continue;
ha = HADATA(shp);
if (!gdth_init_isa(isa_bios,ha)) {
scsi_unregister(shp);
@@ -3197,6 +3199,8 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
break;
if (gdth_search_eisa(eisa_slot)) { /* controller found */
shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ if(shp == NULL)
+ continue;
ha = HADATA(shp);
if (!gdth_init_eisa(eisa_slot,ha)) {
scsi_unregister(shp);
@@ -3268,6 +3272,8 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
if (gdth_ctr_count >= MAXHA)
break;
shp = scsi_register(shtp,sizeof(gdth_ext_str));
+ if(shp == NULL)
+ continue;
ha = HADATA(shp);
if (!gdth_init_pci(&pcistr[ctr],ha)) {
scsi_unregister(shp);
@@ -3571,24 +3577,29 @@ static void gdth_flush(int hanum)
ha = HADATA(gdth_ctr_tab[hanum]);
sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+ if (!sdev)
+ return;
+
scp = scsi_allocate_device(sdev, 1, FALSE);
- scp->cmd_len = 12;
- scp->use_sg = 0;
+ if (scp) {
+ scp->cmd_len = 12;
+ scp->use_sg = 0;
- for (i = 0; i < MAX_HDRIVES; ++i) {
- if (ha->hdr[i].present) {
- gdtcmd.BoardNode = LOCALBOARD;
- gdtcmd.Service = CACHESERVICE;
- gdtcmd.OpCode = GDT_FLUSH;
- gdtcmd.u.cache.DeviceNo = i;
- gdtcmd.u.cache.BlockNo = 1;
- gdtcmd.u.cache.sg_canz = 0;
- TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
- gdth_do_cmd(scp, &gdtcmd, 30);
+ for (i = 0; i < MAX_HDRIVES; ++i) {
+ if (ha->hdr[i].present) {
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_FLUSH;
+ gdtcmd.u.cache.DeviceNo = i;
+ gdtcmd.u.cache.BlockNo = 1;
+ gdtcmd.u.cache.sg_canz = 0;
+ TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+ gdth_do_cmd(scp, &gdtcmd, 30);
+ }
}
+ scsi_release_command(scp);
}
- scsi_release_command(scp);
scsi_free_host_dev(sdev);
}
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 13d7dc398..e37175af2 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -39,7 +39,17 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
piowr = (gdth_iowr_str *)buffer;
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+
+ if(sdev==NULL)
+ return -ENOMEM;
+
scp = scsi_allocate_device(sdev, 1, FALSE);
+
+ if(scp==NULL)
+ {
+ scsi_free_host_dev(sdev);
+ return -ENOMEM;
+ }
scp->cmd_len = 12;
scp->use_sg = 0;
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index cd64662ee..e6d5b2942 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -304,6 +304,8 @@ int __init gvp11_detect(Scsi_Host_Template *tpnt)
#endif
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
+ if(instance == NULL)
+ goto release;
instance->base = ZTWO_VADDR(address);
instance->irq = IRQ_AMIGA_PORTS;
instance->unique_id = z->slotaddr;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 3e425043a..46591840e 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -1796,8 +1796,6 @@ static int device_exists (int host_index, int ldn, int *block_length,
/*--------------------------------------------------------------------*/
-#ifdef CONFIG_SCSI_IBMMCA
-
void internal_ibmmca_scsi_setup (char *str, int *ints)
{
int i, j, io_base, id_base;
@@ -1852,8 +1850,6 @@ void internal_ibmmca_scsi_setup (char *str, int *ints)
return;
}
-#endif
-
/*--------------------------------------------------------------------*/
static int ibmmca_getinfo (char *buf, int slot, void *dev)
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 6d312168c..61298e9c0 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -198,6 +198,8 @@ int imm_detect(Scsi_Host_Template * host)
host->can_queue = IMM_CAN_QUEUE;
host->sg_tablesize = imm_sg;
hreg = scsi_register(host, 0);
+ if(hreg == NULL)
+ continue;
hreg->io_port = pb->base;
hreg->n_io_port = ports;
hreg->dma_channel = -1;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 4453fdab7..b47b7a0e1 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2024,8 +2024,10 @@ char buf[32];
*/
tpnt->proc_name = "in2000";
- detect_count++;
instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata));
+ if(instance == NULL)
+ continue;
+ detect_count++;
if (!instance_list)
instance_list = instance;
hostdata = (struct IN2000_hostdata *)instance->hostdata;
diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
index fa03acae8..4dc0717c7 100644
--- a/drivers/scsi/ini9100u.c
+++ b/drivers/scsi/ini9100u.c
@@ -389,6 +389,11 @@ int i91u_detect(Scsi_Host_Template * tpnt)
pHCB->HCS_Index = i; /* 7/29/98 */
hreg = scsi_register(tpnt, sizeof(HCS));
+ if(hreg == NULL)
+ {
+ release_region(pHCB->HCS_Base, 256);
+ return 0;
+ }
hreg->io_port = pHCB->HCS_Base;
hreg->n_io_port = 0xff;
hreg->can_queue = tul_num_scb; /* 03/05/98 */
diff --git a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c
index 5d0efa845..3adcc43ce 100644
--- a/drivers/scsi/inia100.c
+++ b/drivers/scsi/inia100.c
@@ -363,6 +363,7 @@ int inia100_detect(Scsi_Host_Template * tpnt)
sz = orc_num_scb * sizeof(ESCB);
if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
printk("inia100: ESCB memory allocation error\n");
+ /* ?? does pHCB->HCS_virtScbArray leak ??*/
return (0);
}
memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz);
@@ -383,7 +384,8 @@ int inia100_detect(Scsi_Host_Template * tpnt)
hreg = scsi_register(tpnt, sizeof(ORC_HCS));
if (hreg == NULL) {
- printk("Invalid scsi_register pointer.\n");
+ release_region(pHCB->HCS_Base, 256); /* Register */
+ return 0;
}
hreg->io_port = pHCB->HCS_Base;
hreg->n_io_port = 0xff;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 8630e8ddf..d98c57686 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -4552,6 +4552,8 @@ ips_allocatescbs(ips_ha_t *ha) {
/* Allocate memory for the CCBs */
ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
+ if(ha->scbs == NULL)
+ return 0;
memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 87b46476b..ba29e33d8 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -78,8 +78,8 @@ mac53c94_detect(Scsi_Host_Template *tp)
panic("53c94: expected 2 addrs and intrs (got %d/%d)",
node->n_addrs, node->n_intrs);
host = scsi_register(tp, sizeof(struct fsc_state));
- if (host == 0)
- panic("couldn't register 53c94 host");
+ if (host == NULL)
+ break;
host->unique_id = nfscs;
#ifndef MODULE
note_scsi_host(node, host);
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 54f3f7c39..cbc805e4d 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -258,6 +258,8 @@ int macscsi_detect(Scsi_Host_Template * tpnt)
for (count = 0; count < mac_num_scsi; count++) {
#endif
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ continue;
default_instance = instance;
if (macintosh_config->ident == MAC_MODEL_IIFX) {
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index fea2a9b4f..0e1dec169 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1491,21 +1491,6 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
pciDev,
pdev->slot_name);
- /*
- * Dont crash on boot with AMI cards configured for I2O.
- * (our I2O code will find them then they will fail oddly until
- * we figure why they upset our I2O code). This driver will die
- * if it tries to boot an I2O mode board and we dont stop it now.
- * - Alan Cox , Red Hat Software, Jan 2000
- */
-
- if((pdev->class >> 8) == PCI_CLASS_INTELLIGENT_I2O)
- {
- printk( KERN_INFO "megaraid: Board configured for I2O, ignoring this card. Reconfigure the card\n"
- KERN_INFO "megaraid: in the BIOS for \"mass storage\" to use it with this driver.\n");
- continue;
- }
-
/* Read the base port and IRQ from PCI */
megaBase = pci_resource_start (pdev, 0);
megaIrq = pdev->irq;
@@ -1517,6 +1502,8 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
/* Initialize SCSI Host structure */
host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+ if(host == NULL)
+ continue;
megaCfg = (mega_host_config *) host->hostdata;
memset (megaCfg, 0, sizeof (mega_host_config));
@@ -1543,12 +1530,11 @@ int mega_findCard (Scsi_Host_Template * pHostTmpl,
megaCtlrs[numCtlrs++] = megaCfg;
if (flag != BOARD_QUARTZ) {
/* Request our IO Range */
- if (check_region (megaBase, 16)) {
+ if (request_region (megaBase, 16, "megaraid")) {
printk (KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR);
scsi_unregister (host);
continue;
}
- request_region (megaBase, 16, "megaraid");
}
/* Request our IRQ */
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index d44ce6a18..03e941fd9 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -440,6 +440,9 @@ int __init pas16_detect(Scsi_Host_Template * tpnt)
break;
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ break;
+
instance->io_port = io_port;
NCR5380_init(instance, 0);
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 425932efc..3b9b0e227 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -682,6 +682,8 @@ int Pci2000_Detect (Scsi_Host_Template *tpnt)
if (pci_enable_device(pdev))
continue;
pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
+ if(pshost == NULL)
+ continue;
padapter = HOSTDATA(pshost);
padapter->basePort = pci_resource_start (pdev, 1);
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index 1869be7c0..6b767a1c8 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -2545,6 +2545,9 @@ int Pci2220i_Detect (Scsi_Host_Template *tpnt)
if (pci_enable_device(pcidev))
continue;
pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+ if(pshost==NULL)
+ continue;
+
padapter = HOSTDATA(pshost);
if ( GetRegs (pshost, FALSE, pcidev) )
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 73dfaf299..a0ca91c60 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -221,7 +221,11 @@ int __init pluto_detect(Scsi_Host_Template *tpnt)
if (!ages) continue;
host = scsi_register (tpnt, sizeof (struct pluto));
- if (!host) panic ("Cannot register PLUTO host\n");
+ if(!host)
+ {
+ kfree(ages);
+ continue;
+ }
nplutos++;
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 96b3c8400..661316cac 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -194,6 +194,8 @@ int ppa_detect(Scsi_Host_Template * host)
host->can_queue = PPA_CAN_QUEUE;
host->sg_tablesize = ppa_sg;
hreg = scsi_register(host, 0);
+ if(hreg == NULL)
+ continue;
hreg->io_port = pb->base;
hreg->n_io_port = ports;
hreg->dma_channel = -1;
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index ccd233120..d3987e52a 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -597,6 +597,8 @@ int Psi240i_Detect (Scsi_Host_Template *tpnt)
continue;
pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
+ if(pshost == NULL)
+ continue;
save_flags (flags);
cli ();
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index c52465a8c..8a9a6d92e 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -554,9 +554,21 @@ static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
printk("Allocating host dev\n");
sdev = scsi_get_host_dev(shpnt);
+ if(sdev==NULL)
+ {
+ printk("Out of memory.\n");
+ return;
+ }
+
printk("Got %p. Allocating command block\n", sdev);
scp = scsi_allocate_request(sdev);
printk("Got %p\n", scp);
+
+ if(scp==NULL)
+ {
+ printk("Out of memory.\n");
+ goto bail;
+ }
scp->sr_cmd_len = 6;
scp->sr_use_sg = 0;
@@ -567,7 +579,8 @@ static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
printk("Releasing command\n");
scsi_release_request(scp);
- printk("Freeing device\n");
+bail:
+ printk("Freeing device\n");
scsi_free_host_dev(sdev);
}
@@ -762,6 +775,8 @@ void *scsi_debug_get_handle(void)
static Scsi_Host_Template driver_copy = SCSI_DEBUG;
void *rtn;
rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
+ if(rtn==NULL)
+ return NULL;
memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
return rtn;
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e7b8bbe19..3d6e45fcd 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1861,9 +1861,6 @@ void scsi_error_handler(void *data)
* Flush resources
*/
- exit_files(current);
- current->files = init_task.files;
- atomic_inc(&current->files->count);
daemonize();
/*
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 4bb3981d5..8b25ca5b3 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -1,3 +1,9 @@
+/*
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000
+ * - get rid of some verify_areas and use __copy*user and __get/put_user
+ * for the ones that remain
+ */
#define __NO_VERSION__
#include <linux/module.h>
@@ -39,16 +45,14 @@
static int ioctl_probe(struct Scsi_Host *host, void *buffer)
{
- int temp, result;
unsigned int len, slen;
const char *string;
+ int temp = host->hostt->present;
- if ((temp = host->hostt->present) && buffer) {
- result = verify_area(VERIFY_READ, buffer, sizeof(long));
- if (result)
- return result;
+ if (temp && buffer) {
+ if (get_user(len, (unsigned int *) buffer))
+ return -EFAULT;
- get_user(len, (unsigned int *) buffer);
if (host->hostt->info)
string = host->hostt->info(host);
else
@@ -57,11 +61,8 @@ static int ioctl_probe(struct Scsi_Host *host, void *buffer)
slen = strlen(string);
if (len > slen)
len = slen + 1;
- result = verify_area(VERIFY_WRITE, buffer, len);
- if (result)
- return result;
-
- copy_to_user(buffer, string, len);
+ if (copy_to_user(buffer, string, len))
+ return -EFAULT;
}
}
return temp;
@@ -202,12 +203,11 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
/*
* Verify that we can read at least this much.
*/
- result = verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command));
- if (result)
- return result;
+ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
+ return -EFAULT;
- get_user(inlen, &sic->inlen);
- get_user(outlen, &sic->outlen);
+ __get_user(inlen, &sic->inlen);
+ __get_user(outlen, &sic->outlen);
/*
* We do not transfer more than MAX_BUF with this interface.
@@ -220,7 +220,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
return -EINVAL;
cmd_in = sic->data;
- get_user(opcode, cmd_in);
+ __get_user(opcode, cmd_in);
needed = buf_needed = (inlen > outlen ? inlen : outlen);
if (buf_needed) {
@@ -252,16 +252,15 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
*/
cmdlen = COMMAND_SIZE(opcode);
- result = verify_area(VERIFY_READ, cmd_in, cmdlen + inlen);
- if (result)
- return result;
+ if (verify_area(VERIFY_READ, cmd_in, cmdlen + inlen))
+ return -EFAULT;
- copy_from_user(cmd, cmd_in, cmdlen);
+ __copy_from_user(cmd, cmd_in, cmdlen);
/*
* Obtain the data to be sent to the device (if any).
*/
- copy_from_user(buf, cmd_in + cmdlen, inlen);
+ __copy_from_user(buf, cmd_in + cmdlen, inlen);
/*
* Set the lun field to the correct value.
@@ -314,18 +313,13 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
int sb_len = sizeof(SRpnt->sr_sense_buffer);
sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
- result = verify_area(VERIFY_WRITE, cmd_in, sb_len);
- if (result)
- return result;
- copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len);
- } else {
- result = verify_area(VERIFY_WRITE, cmd_in, outlen);
- if (result)
- return result;
- copy_to_user(cmd_in, buf, outlen);
- }
- result = SRpnt->sr_result;
+ if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len))
+ return -EFAULT;
+ } else
+ if (copy_to_user(cmd_in, buf, outlen))
+ return -EFAULT;
+ result = SRpnt->sr_result;
SDpnt = SRpnt->sr_device;
scsi_release_request(SRpnt);
@@ -361,7 +355,6 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
*/
int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
{
- int result;
char scsi_cmd[MAX_COMMAND_SIZE];
/* No idea how this happens.... */
@@ -379,23 +372,18 @@ int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
}
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
- result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun));
- if (result)
- return result;
+ if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun)))
+ return -EFAULT;
- put_user(dev->id
+ __put_user(dev->id
+ (dev->lun << 8)
+ (dev->channel << 16)
+ ((dev->host->host_no & 0xff) << 24),
&((Scsi_Idlun *) arg)->dev_id);
- put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
+ __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
return 0;
case SCSI_IOCTL_GET_BUS_NUMBER:
- result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- if (result)
- return result;
- put_user(dev->host->host_no, (int *) arg);
- return 0;
+ return put_user(dev->host->host_no, (int *) arg);
case SCSI_IOCTL_TAGGED_ENABLE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
index 0b25bd4e2..55adb72af 100644
--- a/drivers/scsi/scsi_obsolete.c
+++ b/drivers/scsi/scsi_obsolete.c
@@ -370,7 +370,7 @@ void scsi_old_done(Scsi_Cmnd * SCpnt)
* crashing, all scsi_done() calls during sync resets are ignored.
*/
printk("scsi%d: device driver called scsi_done() "
- "for a syncronous reset.\n", SCpnt->host->host_no);
+ "for a synchronous reset.\n", SCpnt->host->host_no);
return;
}
if (SCpnt->flags & WAS_SENSE) {
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 1ee407d14..ebd5eff75 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -488,6 +488,9 @@ int __init seagate_st0x_detect (Scsi_Host_Template * tpnt)
* loose our first interrupt.
*/
instance = scsi_register (tpnt, 0);
+ if(instance == NULL)
+ return 0;
+
hostno = instance->host_no;
if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT,
(controller_type == SEAGATE) ? "seagate" : "tmc-8xx", NULL)) {
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index cd92b715e..50a7bb34d 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -275,6 +275,8 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
SGIblows->proc_name = "SGIWD93";
sgiwd93_host = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata));
+ if(sgiwd93_host == NULL)
+ return 0;
sgiwd93_host->base = (unsigned long) hregs;
sgiwd93_host->irq = SGI_WD93_0_IRQ;
@@ -294,22 +296,25 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
/* set up second controller on the Indigo2 */
if(!sgi_guiness) {
sgiwd93_host1 = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata));
- sgiwd93_host1->base = (unsigned long) hregs1;
- sgiwd93_host1->irq = SGI_WD93_1_IRQ;
-
- buf = (uchar *) get_free_page(GFP_KERNEL);
- init_hpc_chain(buf);
- dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
- /* HPC_SCSI_REG1 | 0x03 | KSEG1 */
- wd33c93_init(sgiwd93_host1, (wd33c93_regs *) 0xbfbc8003,
- dma_setup, dma_stop, WD33C93_FS_16_20);
-
- hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
- hdata1->no_sync = 0;
- hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
- dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
-
- request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1);
+ if(sgiwd93_host1 != NULL)
+ {
+ sgiwd93_host1->base = (unsigned long) hregs1;
+ sgiwd93_host1->irq = SGI_WD93_1_IRQ;
+
+ buf = (uchar *) get_free_page(GFP_KERNEL);
+ init_hpc_chain(buf);
+ dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
+ /* HPC_SCSI_REG1 | 0x03 | KSEG1 */
+ wd33c93_init(sgiwd93_host1, (wd33c93_regs *) 0xbfbc8003,
+ dma_setup, dma_stop, WD33C93_FS_16_20);
+
+ hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
+ hdata1->no_sync = 0;
+ hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
+ dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
+
+ request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1);
+ }
}
called = 1;
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 82869fb81..444802652 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -274,7 +274,7 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
/* ----------------------------------------------------------------------- */
/* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */
-/* becauce the generic cdrom driver does the user access stuff for us. */
+/* because the generic cdrom driver does the user access stuff for us. */
/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */
/* sr_disk_status interface for the generic cdrom driver. */
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b0e5026fc..88608c5f5 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -12,7 +12,7 @@
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Tue Aug 15 16:56:35 2000 by makisara@kai.makisara.local
+ Last modified: Mon Nov 13 21:01:09 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -976,7 +976,7 @@ static int st_flush(struct file *filp)
((SRpnt->sr_sense_buffer[0] & 0x80) != 0 &&
(SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] |
SRpnt->sr_sense_buffer[5] |
- SRpnt->sr_sense_buffer[6]) == 0))) {
+ SRpnt->sr_sense_buffer[6]) != 0))) {
/* Filter out successful write at EOM */
scsi_release_request(SRpnt);
SRpnt = NULL;
@@ -2495,10 +2495,8 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
- if (fileno >= 0)
+ if (STps->drv_file >= 0)
STps->drv_file = fileno + undone;
- else
- STps->drv_file = fileno;
STps->drv_block = 0;
STps->eof = ST_NOEOF;
} else if (cmd_in == MTFSR) {
@@ -2519,10 +2517,8 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
STps->drv_file--;
STps->drv_block = (-1);
} else {
- if (blkno >= 0)
+ if (STps->drv_block >= 0)
STps->drv_block = blkno + undone;
- else
- STps->drv_block = (-1);
}
STps->eof = ST_NOEOF;
} else if (cmd_in == MTEOM) {
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 29084c39d..6769009d5 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -250,6 +250,9 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt)
#endif
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ return 0;
+
default_instance = instance;
instance->io_port = (unsigned long) ioaddr;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 3ea1adac1..733abc939 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -677,6 +677,8 @@ int sym53c416_detect(Scsi_Host_Template *tpnt)
if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
{
shpnt = scsi_register(tpnt, 0);
+ if(shpnt==NULL)
+ continue;
save_flags(flags);
cli();
/* Request for specified IRQ */
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index f152035b9..3abd78cd2 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -234,6 +234,9 @@ int __init t128_detect(Scsi_Host_Template * tpnt){
break;
instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+ if(instance == NULL)
+ break;
+
instance->base = base;
NCR5380_init(instance, 0);
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 5d943c645..e7af1328b 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1626,6 +1626,8 @@ int wd7000_detect (Scsi_Host_Template *tpnt)
* array hostdata.
*/
sh = scsi_register (tpnt, sizeof (Adapter));
+ if(sh==NULL)
+ continue;
host = (Adapter *) sh->hostdata;
#ifdef WD7000_DEBUG
diff --git a/drivers/sound/724hwmcode.h b/drivers/sound/724hwmcode.h
index 756583529..6f44377f1 100644
--- a/drivers/sound/724hwmcode.h
+++ b/drivers/sound/724hwmcode.h
@@ -9,7 +9,7 @@
#ifndef _HWMCODE_
#define _HWMCODE_
-static unsigned long int DspInst[] = {
+static unsigned long int DspInst[] __initdata = {
0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
@@ -20,7 +20,7 @@ static unsigned long int DspInst[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
-static unsigned long int CntrlInst[] = {
+static unsigned long int CntrlInst[] __initdata = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
@@ -799,7 +799,7 @@ static unsigned long int CntrlInst[] = {
// 04/09?@creat
// 04/12 stop nise fix
// 06/21?@WorkingOff timming
-static unsigned long int CntrlInst1E[] = {
+static unsigned long int CntrlInst1E[] __initdata = {
0x000007, 0x240007, 0x0C0007, 0x1C0007,
0x060007, 0x700002, 0x000020, 0x030040,
0x007104, 0x004286, 0x030040, 0x000F0D,
diff --git a/drivers/sound/aci.c b/drivers/sound/aci.c
index 5c3045f2a..73361978a 100644
--- a/drivers/sound/aci.c
+++ b/drivers/sound/aci.c
@@ -441,7 +441,7 @@ aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
}
if (((cmd >> 8) & 0xff) == 'M') {
- if (cmd & IOC_IN)
+ if (cmd & SIOC_IN)
/* read and write */
switch (cmd & 0xff) {
case SOUND_MIXER_VOLUME:
diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c
index 311cdab9b..be1aec5a5 100644
--- a/drivers/sound/ad1816.c
+++ b/drivers/sound/ad1816.c
@@ -916,7 +916,7 @@ ad1816_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
if (((cmd >> 8) & 0xff) == 'M') {
/* set ioctl */
- if (_IOC_DIR (cmd) & _IOC_WRITE) {
+ if (_SIOC_DIR (cmd) & _SIOC_WRITE) {
switch (cmd & 0xff){
case SOUND_MIXER_RECSRC:
diff --git a/drivers/sound/awe_wave.c b/drivers/sound/awe_wave.c
index a87c10ce3..0b0720881 100644
--- a/drivers/sound/awe_wave.c
+++ b/drivers/sound/awe_wave.c
@@ -4321,7 +4321,7 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
level = ((level & 0xff) + (level >> 8)) / 2;
DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
- if (_SIOC_DIR(cmd) & _IOC_WRITE) {
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
switch (cmd & 0xff) {
case SOUND_MIXER_BASS:
value = level * 12 / 100;
diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c
index 78c19298e..38ac2abf4 100644
--- a/drivers/sound/cmpci.c
+++ b/drivers/sound/cmpci.c
@@ -983,9 +983,9 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
}
if (cmd == OSS_GETVERSION)
return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
return put_user(mixer_recmask(s), (int *)arg);
@@ -1033,7 +1033,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
}
- if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
return -EINVAL;
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
@@ -1197,9 +1197,9 @@ static int drain_dac(struct cm_state *s, int nonblock)
if (s->dma_dac.mapped || !s->dma_dac.ready)
return 0;
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1839,6 +1839,7 @@ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_
ret = 0;
add_wait_queue(&s->midi.iwait, &wait);
while (count > 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
ptr = s->midi.ird;
cnt = MIDIINBUF - ptr;
@@ -1854,7 +1855,6 @@ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current))
{
@@ -1903,6 +1903,7 @@ static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count
ret = 0;
add_wait_queue(&s->midi.owait, &wait);
while (count > 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
ptr = s->midi.owr;
cnt = MIDIOUTBUF - ptr;
@@ -1919,7 +1920,6 @@ static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count
ret = -EAGAIN;
break;
}
- __set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (signal_pending(current)) {
if (!ret)
@@ -2041,9 +2041,9 @@ static int cm_midi_release(struct inode *inode, struct file *file)
lock_kernel();
if (file->f_mode & FMODE_WRITE) {
- __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c
index 8891124cb..f32f295c3 100644
--- a/drivers/sound/cs4232.c
+++ b/drivers/sound/cs4232.c
@@ -40,6 +40,8 @@
* Christoph Hellwig Adapted to module_init/module_exit,
* simple cleanups
* Arnaldo C. de Melo got rid of attach_uart401
+ * Bartlomiej Zolnierkiewicz
+ * Added some __init/__initdata/__exit
*/
#include <linux/config.h>
@@ -67,7 +69,7 @@ static int mpu_base = 0, mpu_irq = 0;
static int synth_base = 0, synth_irq = 0;
static int mpu_detected = 0;
-int probe_cs4232_mpu(struct address_info *hw_config)
+int __init probe_cs4232_mpu(struct address_info *hw_config)
{
/*
* Just write down the config values.
@@ -79,7 +81,7 @@ int probe_cs4232_mpu(struct address_info *hw_config)
return 1;
}
-static unsigned char crystal_key[] = /* A 32 byte magic key sequence */
+static unsigned char crystal_key[] __initdata = /* A 32 byte magic key sequence */
{
0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
@@ -93,7 +95,7 @@ static void sleep(unsigned howlong)
schedule_timeout(howlong);
}
-int probe_cs4232(struct address_info *hw_config)
+int __init probe_cs4232(struct address_info *hw_config)
{
int i, n;
int base = hw_config->io_base, irq = hw_config->irq;
@@ -209,7 +211,7 @@ int probe_cs4232(struct address_info *hw_config)
return 0;
}
-void attach_cs4232(struct address_info *hw_config)
+void __init attach_cs4232(struct address_info *hw_config)
{
int base = hw_config->io_base,
irq = hw_config->irq,
@@ -268,7 +270,7 @@ void attach_cs4232(struct address_info *hw_config)
}
}
-void unload_cs4232(struct address_info *hw_config)
+void __exit unload_cs4232(struct address_info *hw_config)
{
int base = hw_config->io_base, irq = hw_config->irq;
int dma1 = hw_config->dma, dma2 = hw_config->dma2;
diff --git a/drivers/sound/cs4281.c b/drivers/sound/cs4281.c
index 913cf55c1..3fcb068d1 100644
--- a/drivers/sound/cs4281.c
+++ b/drivers/sound/cs4281.c
@@ -30,11 +30,22 @@
// /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
// /dev/midi simple MIDI UART interface, no ioctl
//
+// Modification History
+// 08/20/00 trw - silence and no stopping DAC until release
+// 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.
+// 09/18/00 trw - added 16bit only record with conversion
+// 09/24/00 trw - added Enhanced Full duplex (separate simultaneous
+// capture/playback rates)
+// 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin
+// libOSSm.so)
+// 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)
+// 11/03/00 trw - fixed interrupt loss/stutter, added debug.
+// 11/10/00 bkz - added __devinit to cs4281_hw_init()
//
-//
-
// *****************************************************************************
+#include <linux/config.h>
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/ioport.h>
@@ -50,9 +61,11 @@
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <linux/wrapper.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
-#include <linux/vmalloc.h>
+//#include <linux/vmalloc.h>
#include "dm.h"
#include "cs4281_hwdefs.h"
@@ -71,10 +84,10 @@ EXPORT_NO_SYMBOLS;
#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
-#define CSDEBUG 1
-//
// Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
//
+#define CSDEBUG_INTERFACE 1
+#define CSDEBUG 1
//
// CSDEBUG is usual mode is set to 1, then use the
// cs_debuglevel and cs_debugmask to turn on or off debugging.
@@ -82,36 +95,39 @@ EXPORT_NO_SYMBOLS;
// that should be printed on any released driver.
//
#if CSDEBUG
-extern unsigned cs_debugmask;
-extern unsigned cs_debuglevel;
-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
+extern unsigned long cs_debugmask;
+extern unsigned long cs_debuglevel;
+#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}
#else
-#define CS_DBGOUT(mask,level,x)
+#define CS_DBGOUT(mask,level,x)
#endif
//
// cs_debugmask areas
//
-#define CS_INIT 0x00000001 // initialization and probe functions
-#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
-#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
-#define CS_FUNCTION 0x00000008 // enter/leave functions
-#define CS_WAVE_WRITE 0x00000010 // write information for wave
-#define CS_WAVE_READ 0x00000020 // read information for wave
-#define CS_MIDI_WRITE 0x00000040 // write information for midi
-#define CS_MIDI_READ 0x00000080 // read information for midi
-#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
-#define CS_MPU401_READ 0x00000200 // read information for mpu401
-#define CS_OPEN 0x00000400 // all open functions in the driver
-#define CS_RELEASE 0x00000800 // all release functions in the driver
-#define CS_PARMS 0x00001000 // functional and operational parameters
-#define CS_TMP 0x10000000 // tmp debug mask bit
-
-unsigned cs_debuglevel=1; // levels range from 1-9
-unsigned cs_debugmask=CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
+#define CS_INIT 0x00000001 // initialization and probe functions
+#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
+#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
+#define CS_FUNCTION 0x00000008 // enter/leave functions
+#define CS_WAVE_WRITE 0x00000010 // write information for wave
+#define CS_WAVE_READ 0x00000020 // read information for wave
+#define CS_MIDI_WRITE 0x00000040 // write information for midi
+#define CS_MIDI_READ 0x00000080 // read information for midi
+#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
+#define CS_MPU401_READ 0x00000200 // read information for mpu401
+#define CS_OPEN 0x00000400 // all open functions in the driver
+#define CS_RELEASE 0x00000800 // all release functions in the driver
+#define CS_PARMS 0x00001000 // functional and operational parameters
+#define CS_IOCTL 0x00002000 // ioctl (non-mixer)
+#define CS_TMP 0x10000000 // tmp debug mask bit
+
+#if CSDEBUG
+static unsigned long cs_debuglevel = 1; // levels range from 1-9
+static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
#if MODULE
MODULE_PARM(cs_debuglevel, "i");
MODULE_PARM(cs_debugmask, "i");
#endif
+#endif
// MIDI buffer sizes
#define MIDIINBUF 500
@@ -127,14 +143,17 @@ MODULE_PARM(cs_debugmask, "i");
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-#define CS4281_MAJOR_VERSION 0
-#define CS4281_MINOR_VERSION 4
+#define CS4281_MAJOR_VERSION 1
+#define CS4281_MINOR_VERSION 1
#ifdef __ia64__
-#define CS4281_ARCH 64 //architecture key
+#define CS4281_ARCH 64 //architecture key
#else
-#define CS4281_ARCH 32 //architecture key
+#define CS4281_ARCH 32 //architecture key
#endif
+#define CS_TYPE_ADC 0
+#define CS_TYPE_DAC 1
+
struct cs4281_state {
// magic
unsigned int magic;
@@ -152,9 +171,8 @@ struct cs4281_state {
// hardware resources
unsigned int pBA0phys, pBA1phys;
- char *pBA0, *pBA1;
+ char *pBA0, *pBA1;
unsigned int irq;
- int endofbuffer;
// mixer registers
struct {
@@ -164,38 +182,50 @@ struct cs4281_state {
unsigned short micpreamp;
} mix;
- // wave stuff // Note that play & record formats must be the same *wb.
- unsigned fmt;
- unsigned channels;
- unsigned rate;
- unsigned char clkdiv;
+ // wave stuff
+ struct properties {
+ unsigned fmt;
+ unsigned fmt_original; // original requested format
+ unsigned channels;
+ unsigned rate;
+ unsigned char clkdiv;
+ } prop_dac, prop_adc;
+ unsigned conversion:1; // conversion from 16 to 8 bit in progress
+ void *tmpbuff; // tmp buffer for sample conversions
unsigned ena;
-
spinlock_t lock;
struct semaphore open_sem;
+ struct semaphore open_sem_adc;
+ struct semaphore open_sem_dac;
mode_t open_mode;
wait_queue_head_t open_wait;
+ wait_queue_head_t open_wait_adc;
+ wait_queue_head_t open_wait_dac;
+ dma_addr_t dmaaddr_tmpbuff;
+ unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes..
struct dmabuf {
- void *rawbuf; // Physical address of
- dma_addr_t dmaaddr;
- unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
- unsigned numfrag; // # of 'fragments' in the buffer.
- unsigned fragshift; // Log base 2 of fragment size.
+ void *rawbuf; // Physical address of
+ dma_addr_t dmaaddr;
+ unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
+ unsigned numfrag; // # of 'fragments' in the buffer.
+ unsigned fragshift; // Log base 2 of fragment size.
unsigned hwptr, swptr;
- unsigned total_bytes; // # bytes process since open.
- unsigned blocks; // last returned blocks value GETOPTR
+ unsigned total_bytes; // # bytes process since open.
+ unsigned blocks; // last returned blocks value GETOPTR
+ unsigned wakeup; // interrupt occurred on block
int count;
- unsigned error; // over/underrun
+ unsigned error; // over/underrun
wait_queue_head_t wait;
// redundant, but makes calculations easier
- unsigned fragsize; // 2**fragshift..
- unsigned dmasize; // 2**buforder.
+ unsigned fragsize; // 2**fragshift..
+ unsigned dmasize; // 2**buforder.
unsigned fragsamples;
// OSS stuff
- unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
- unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
+ unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
+ unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
unsigned endcleared:1;
+ unsigned type:1; // adc or dac buffer (CS_TYPE_XXX)
unsigned ossfragshift;
int ossmaxfrags;
unsigned subdivision;
@@ -214,11 +244,250 @@ struct cs4281_state {
};
+#if CSDEBUG
+
+// DEBUG ROUTINES
+
+#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
+#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
+#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
+#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
+
+#define SNDCTL_DSP_CS_GETDBGLEVEL _SIOWR('P', 50, int)
+#define SNDCTL_DSP_CS_SETDBGLEVEL _SIOWR('P', 51, int)
+#define SNDCTL_DSP_CS_GETDBGMASK _SIOWR('P', 52, int)
+#define SNDCTL_DSP_CS_SETDBGMASK _SIOWR('P', 53, int)
+
+void printioctl(unsigned int x)
+{
+ unsigned int i;
+ unsigned char vidx;
+ // Index of mixtable1[] member is Device ID
+ // and must be <= SOUND_MIXER_NRDEVICES.
+ // Value of array member is index into s->mix.vol[]
+ static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
+ [SOUND_MIXER_PCM] = 1, // voice
+ [SOUND_MIXER_LINE1] = 2, // AUX
+ [SOUND_MIXER_CD] = 3, // CD
+ [SOUND_MIXER_LINE] = 4, // Line
+ [SOUND_MIXER_SYNTH] = 5, // FM
+ [SOUND_MIXER_MIC] = 6, // Mic
+ [SOUND_MIXER_SPEAKER] = 7, // Speaker
+ [SOUND_MIXER_RECLEV] = 8, // Recording level
+ [SOUND_MIXER_VOLUME] = 9 // Master Volume
+ };
+
+ switch (x) {
+ case SOUND_MIXER_CS_GETDBGMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_CS_GETDBGMASK:\n"));
+ break;
+ case SOUND_MIXER_CS_GETDBGLEVEL:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));
+ break;
+ case SOUND_MIXER_CS_SETDBGMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_CS_SETDBGMASK:\n"));
+ break;
+ case SOUND_MIXER_CS_SETDBGLEVEL:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));
+ break;
+ case OSS_GETVERSION:
+ CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));
+ break;
+ case SNDCTL_DSP_SYNC:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));
+ break;
+ case SNDCTL_DSP_SETDUPLEX:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));
+ break;
+ case SNDCTL_DSP_GETCAPS:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));
+ break;
+ case SNDCTL_DSP_RESET:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));
+ break;
+ case SNDCTL_DSP_SPEED:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));
+ break;
+ case SNDCTL_DSP_STEREO:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));
+ break;
+ case SNDCTL_DSP_CHANNELS:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));
+ break;
+ case SNDCTL_DSP_GETFMTS:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));
+ break;
+ case SNDCTL_DSP_SETFMT:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));
+ break;
+ case SNDCTL_DSP_POST:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));
+ break;
+ case SNDCTL_DSP_GETTRIGGER:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));
+ break;
+ case SNDCTL_DSP_SETTRIGGER:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));
+ break;
+ case SNDCTL_DSP_GETOSPACE:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));
+ break;
+ case SNDCTL_DSP_GETISPACE:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));
+ break;
+ case SNDCTL_DSP_NONBLOCK:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));
+ break;
+ case SNDCTL_DSP_GETODELAY:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));
+ break;
+ case SNDCTL_DSP_GETIPTR:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));
+ break;
+ case SNDCTL_DSP_GETOPTR:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));
+ break;
+ case SNDCTL_DSP_GETBLKSIZE:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));
+ break;
+ case SNDCTL_DSP_SETFRAGMENT:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SNDCTL_DSP_SETFRAGMENT:\n"));
+ break;
+ case SNDCTL_DSP_SUBDIVIDE:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));
+ break;
+ case SOUND_PCM_READ_RATE:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));
+ break;
+ case SOUND_PCM_READ_CHANNELS:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_PCM_READ_CHANNELS:\n"));
+ break;
+ case SOUND_PCM_READ_BITS:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));
+ break;
+ case SOUND_PCM_WRITE_FILTER:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_PCM_WRITE_FILTER:\n"));
+ break;
+ case SNDCTL_DSP_SETSYNCRO:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));
+ break;
+ case SOUND_PCM_READ_FILTER:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));
+ break;
+ case SNDCTL_DSP_CS_GETDBGMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SNDCTL_DSP_CS_GETDBGMASK:\n"));
+ break;
+ case SNDCTL_DSP_CS_GETDBGLEVEL:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SNDCTL_DSP_CS_GETDBGLEVEL:\n"));
+ break;
+ case SNDCTL_DSP_CS_SETDBGMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SNDCTL_DSP_CS_SETDBGMASK:\n"));
+ break;
+ case SNDCTL_DSP_CS_SETDBGLEVEL:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SNDCTL_DSP_CS_SETDBGLEVEL:\n"));
+ break;
+
+ case SOUND_MIXER_PRIVATE1:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));
+ break;
+ case SOUND_MIXER_PRIVATE2:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));
+ break;
+ case SOUND_MIXER_PRIVATE3:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));
+ break;
+ case SOUND_MIXER_PRIVATE4:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));
+ break;
+ case SOUND_MIXER_PRIVATE5:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));
+ break;
+ case SOUND_MIXER_INFO:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));
+ break;
+ case SOUND_OLD_MIXER_INFO:
+ CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));
+ break;
+
+ default:
+ switch (_IOC_NR(x)) {
+ case SOUND_MIXER_VOLUME:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_VOLUME:\n"));
+ break;
+ case SOUND_MIXER_SPEAKER:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_SPEAKER:\n"));
+ break;
+ case SOUND_MIXER_RECLEV:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_RECLEV:\n"));
+ break;
+ case SOUND_MIXER_MIC:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_MIC:\n"));
+ break;
+ case SOUND_MIXER_SYNTH:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_SYNTH:\n"));
+ break;
+ case SOUND_MIXER_RECSRC:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_RECSRC:\n"));
+ break;
+ case SOUND_MIXER_DEVMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_DEVMASK:\n"));
+ break;
+ case SOUND_MIXER_RECMASK:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_RECMASK:\n"));
+ break;
+ case SOUND_MIXER_STEREODEVS:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_STEREODEVS:\n"));
+ break;
+ case SOUND_MIXER_CAPS:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk("SOUND_MIXER_CAPS:\n"));
+ break;
+ default:
+ i = _IOC_NR(x);
+ if (i >= SOUND_MIXER_NRDEVICES
+ || !(vidx = mixtable1[i])) {
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk
+ ("UNKNOWN IOCTL: 0x%.8x NR=%d\n",
+ x, i));
+ } else {
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk
+ ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",
+ x, i));
+ }
+ break;
+ }
+ }
+}
+#endif
+static int prog_dmabuf_adc(struct cs4281_state *s);
+static void prog_codec(struct cs4281_state *s, unsigned type);
-struct cs4281_state *devs = NULL;
+static struct cs4281_state *devs = NULL;
// ---------------------------------------------------------------------
//
-// Hardware Interfaces For the CS4281
+// Hardware Interfaces For the CS4281
//
@@ -227,18 +496,16 @@ struct cs4281_state *devs = NULL;
//******************************************************************************
static void delayus(u32 delay)
{
- u32 j;
- if(delay > 9999)
- {
- j = (delay * HZ)/1000000; /* calculate delay in jiffies */
- if(j<1)
- j=1; /* minimum one jiffy. */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(j);
- }
- else
+ u32 j;
+ if (delay > 9999) {
+ j = (delay * HZ) / 1000000; /* calculate delay in jiffies */
+ if (j < 1)
+ j = 1; /* minimum one jiffy. */
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(j);
+ } else
udelay(delay);
- return;
+ return;
}
@@ -254,14 +521,15 @@ static void delayus(u32 delay)
// 5. if DCV not cleared, break and return error
// 6. Read ACSTS = Status Register = 464h, check VSTS bit
//****************************************************************************
-static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, u32 *value)
+static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,
+ u32 * value)
{
u32 count, status;
// Make sure that there is not data sitting
// around from a previous uncompleted access.
// ACSDA = Status Data Register = 47Ch
- status = readl(card->pBA0+BA0_ACSDA);
+ status = readl(card->pBA0 + BA0_ACSDA);
// Setup the AC97 control registers on the CS4281 to send the
// appropriate command to the AC97 to perform the read.
@@ -274,51 +542,50 @@ static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, u32 *value)
// bit ESYN - ASYNC generation enabled
// Get the actual AC97 register from the offset
- writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD);
- writel(0, card->pBA0+BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL);
+ writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
+ writel(0, card->pBA0 + BA0_ACCDA);
+ writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,
+ card->pBA0 + BA0_ACCTL);
- // Wait for the read to occur.
- for(count = 0; count < 10; count++)
- {
+ // Wait for the read to occur.
+ for (count = 0; count < 10; count++) {
// First, we want to wait for a short time.
udelay(25);
// Now, check to see if the read has completed.
// ACCTL = 460h, DCV should be reset by now and 460h = 17h
- if( !(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV))
+ if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))
break;
}
- // Make sure the read completed.
- if(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV)
- return 1;
+ // Make sure the read completed.
+ if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)
+ return 1;
- // Wait for the valid status bit to go active.
- for(count = 0; count < 10; count++)
- {
+ // Wait for the valid status bit to go active.
+ for (count = 0; count < 10; count++) {
// Read the AC97 status register.
// ACSTS = Status Register = 464h
- status = readl(card->pBA0+BA0_ACSTS);
+ status = readl(card->pBA0 + BA0_ACSTS);
// See if we have valid status.
// VSTS - Valid Status
- if(status & ACSTS_VSTS)
+ if (status & ACSTS_VSTS)
break;
// Wait for a short while.
udelay(25);
}
- // Make sure we got valid status.
- if(!(status & ACSTS_VSTS))
+ // Make sure we got valid status.
+ if (!(status & ACSTS_VSTS))
return 1;
// Read the data returned from the AC97 register.
// ACSDA = Status Data Register = 474h
- *value = readl(card->pBA0+BA0_ACSDA);
+ *value = readl(card->pBA0 + BA0_ACSDA);
// Success.
- return(0);
+ return (0);
}
@@ -334,49 +601,51 @@ static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, u32 *value)
// 5. if DCV not cleared, break and return error
//
//****************************************************************************
-static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, u32 value)
+static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
+ u32 value)
{
u32 count, status;
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));
- // Setup the AC97 control registers on the CS4281 to send the
- // appropriate command to the AC97 to perform the read.
- // ACCAD = Command Address Register = 46Ch
- // ACCDA = Command Data Register = 470h
- // ACCTL = Control Register = 460h
- // set DCV - will clear when process completed
- // reset CRW - Write command
- // set VFRM - valid frame enabled
- // set ESYN - ASYNC generation enabled
- // set RSTN - ARST# inactive, AC97 codec not reset
+ // Setup the AC97 control registers on the CS4281 to send the
+ // appropriate command to the AC97 to perform the read.
+ // ACCAD = Command Address Register = 46Ch
+ // ACCDA = Command Data Register = 470h
+ // ACCTL = Control Register = 460h
+ // set DCV - will clear when process completed
+ // reset CRW - Write command
+ // set VFRM - valid frame enabled
+ // set ESYN - ASYNC generation enabled
+ // set RSTN - ARST# inactive, AC97 codec not reset
- // Get the actual AC97 register from the offset
+ // Get the actual AC97 register from the offset
- writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD);
- writel(value, card->pBA0+BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL);
+ writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
+ writel(value, card->pBA0 + BA0_ACCDA);
+ writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,
+ card->pBA0 + BA0_ACCTL);
- // Wait for the write to occur.
- for(count = 0; count < 10; count++)
- {
+ // Wait for the write to occur.
+ for (count = 0; count < 10; count++) {
// First, we want to wait for a short time.
udelay(25);
// Now, check to see if the write has completed.
// ACCTL = 460h, DCV should be reset by now and 460h = 07h
- status = readl(card->pBA0+BA0_ACCTL);
- if(!(status & ACCTL_DCV))
+ status = readl(card->pBA0 + BA0_ACCTL);
+ if (!(status & ACCTL_DCV))
break;
}
// Make sure the write completed.
- if(status & ACCTL_DCV)
- {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n") );
+ if (status & ACCTL_DCV) {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+ "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));
return 1;
}
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));
// Success.
return 0;
}
@@ -385,72 +654,71 @@ static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, u32 value)
//******************************************************************************
// "Init4281()" -- Bring up the part.
//******************************************************************************
-static int cs4281_hw_init(struct cs4281_state *card)
+static int __devinit cs4281_hw_init(struct cs4281_state *card)
{
u32 ac97_slotid;
u32 temp1, temp2;
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));
//***************************************7
// Set up the Sound System Configuration
//***************************************
- // Set the 'Configuration Write Protect' register
- // to 4281h. Allows vendor-defined configuration
- // space between 0e4h and 0ffh to be written.
+ // Set the 'Configuration Write Protect' register
+ // to 4281h. Allows vendor-defined configuration
+ // space between 0e4h and 0ffh to be written.
- writel(0x4281, card->pBA0+BA0_CWPR); // (3e0h)
+ writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h)
- // (0), Blast the clock control register to zero so that the
- // PLL starts out in a known state, and blast the master serial
- // port control register to zero so that the serial ports also
- // start out in a known state.
+ // (0), Blast the clock control register to zero so that the
+ // PLL starts out in a known state, and blast the master serial
+ // port control register to zero so that the serial ports also
+ // start out in a known state.
- writel(0, card->pBA0+BA0_CLKCR1); // (400h)
- writel(0, card->pBA0+BA0_SERMC); // (420h)
+ writel(0, card->pBA0 + BA0_CLKCR1); // (400h)
+ writel(0, card->pBA0 + BA0_SERMC); // (420h)
- // (1), Make ESYN go to zero to turn off
- // the Sync pulse on the AC97 link.
+ // (1), Make ESYN go to zero to turn off
+ // the Sync pulse on the AC97 link.
- writel(0, card->pBA0+BA0_ACCTL);
+ writel(0, card->pBA0 + BA0_ACCTL);
udelay(50);
- // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
- // the AC97 spec) and then drive it high. This is done for non
- // AC97 modes since there might be logic external to the CS461x
- // that uses the ARST# line for a reset.
+ // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
+ // the AC97 spec) and then drive it high. This is done for non
+ // AC97 modes since there might be logic external to the CS461x
+ // that uses the ARST# line for a reset.
- writel(0, card->pBA0+BA0_SPMC); // (3ech)
+ writel(0, card->pBA0 + BA0_SPMC); // (3ech)
udelay(100);
- writel(SPMC_RSTN, card->pBA0+BA0_SPMC);
- delayus(50000); // Wait 50 ms for ABITCLK to become stable.
+ writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);
+ delayus(50000); // Wait 50 ms for ABITCLK to become stable.
// (3) Turn on the Sound System Clocks.
- writel(CLKCR1_PLLP, card->pBA0+BA0_CLKCR1); // (400h)
- delayus(50000); // Wait for the PLL to stabilize.
+ writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h)
+ delayus(50000); // Wait for the PLL to stabilize.
// Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
- writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0+BA0_CLKCR1);
+ writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);
// (4) Power on everything for now..
- writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
+ writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
// (5) Wait for clock stabilization.
- for(temp1=0; temp1<1000; temp1++)
- {
+ for (temp1 = 0; temp1 < 1000; temp1++) {
udelay(1000);
- if(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY)
+ if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)
break;
}
- if(!(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY))
- {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: DLLRDY failed!\n") );
+ if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {
+ CS_DBGOUT(CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: DLLRDY failed!\n"));
return -EIO;
}
-
// (6) Enable ASYNC generation.
- writel(ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h)
+ writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
// Now wait 'for a short while' to allow the AC97
// part to start generating bit clock. (so we don't
@@ -459,99 +727,95 @@ static int cs4281_hw_init(struct cs4281_state *card)
// Set the serial port timing configuration, so that the
// clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2.
+ writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
// (7) Wait for the codec ready signal from the AC97 codec.
- for(temp1=0; temp1<1000; temp1++)
- {
+ for (temp1 = 0; temp1 < 1000; temp1++) {
// Delay a mil to let things settle out and
// to prevent retrying the read too quickly.
udelay(1000);
- if( readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY ) // If ready, (464h)
- break; // exit the 'for' loop.
+ if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h)
+ break; // exit the 'for' loop.
}
- if( !(readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY) ) // If never came ready,
- {
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_ERR "cs4281: ACSTS never came ready!\n") );
- return -EIO; // exit initialization.
- }
-
- // (8) Assert the 'valid frame' signal so we can
- // begin sending commands to the AC97 codec.
- writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h)
-
- // (9), Wait until CODEC calibration is finished.
- // Print an error message if it doesn't.
- for(temp1 = 0; temp1 < 1000; temp1++)
+ if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready,
{
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_ERR
+ "cs4281: ACSTS never came ready!\n"));
+ return -EIO; // exit initialization.
+ }
+ // (8) Assert the 'valid frame' signal so we can
+ // begin sending commands to the AC97 codec.
+ writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
+
+ // (9), Wait until CODEC calibration is finished.
+ // Print an error message if it doesn't.
+ for (temp1 = 0; temp1 < 1000; temp1++) {
delayus(10000);
// Read the AC97 Powerdown Control/Status Register.
cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
- if( (temp2 & 0x0000000F) == 0x0000000F )
+ if ((temp2 & 0x0000000F) == 0x0000000F)
break;
}
- if ( (temp2 & 0x0000000F) != 0x0000000F )
- {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs4281: Codec failed to calibrate. Status = %.8x.\n", temp2) );
+ if ((temp2 & 0x0000000F) != 0x0000000F) {
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
+ "cs4281: Codec failed to calibrate. Status = %.8x.\n",
+ temp2));
return -EIO;
}
-
- // (10), Set the serial port timing configuration, so that the
- // clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2.
+ // (10), Set the serial port timing configuration, so that the
+ // clock control circuit gets its clock from the right place.
+ writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
- // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
- // that the codec is pumping ADC data across the AC link.
- for(temp1=0; temp1<1000; temp1++)
- {
+ // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
+ // that the codec is pumping ADC data across the AC link.
+ for (temp1 = 0; temp1 < 1000; temp1++) {
// Delay a mil to let things settle out and
// to prevent retrying the read too quickly.
- delayus(1000); //(test)
+ delayus(1000); //(test)
// Read the input slot valid register; See
// if input slots 3 and 4 are valid yet.
- if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) )
- == (ACISV_ISV3 | ACISV_ISV4))
- break; // Exit the 'for' if slots are valid.
- }
- // If we never got valid data, exit initialization.
- if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) )
- != (ACISV_ISV3 | ACISV_ISV4))
- {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR "cs4281: Never got valid data!\n"));
- return -EIO; // If no valid data, exit initialization.
+ if (
+ (readl(card->pBA0 + BA0_ACISV) &
+ (ACISV_ISV3 | ACISV_ISV4)) ==
+ (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid.
+ }
+ // If we never got valid data, exit initialization.
+ if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))
+ != (ACISV_ISV3 | ACISV_ISV4)) {
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_ERR
+ "cs4281: Never got valid data!\n"));
+ return -EIO; // If no valid data, exit initialization.
}
-
// (12), Start digital data transfer of audio data to the codec.
- writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0+BA0_ACOSV); // (468h)
+ writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h)
//**************************************
// Unmute the Master and Alternate
// (headphone) volumes. Set to max.
//**************************************
- cs4281_write_ac97(card,BA0_AC97_HEADPHONE_VOLUME, 0);
- cs4281_write_ac97(card,BA0_AC97_MASTER_VOLUME, 0);
+ cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);
+ cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);
//******************************************
// Power on the DAC(AddDACUser()from main())
//******************************************
- cs4281_read_ac97(card,BA0_AC97_POWERDOWN, &temp1);
- cs4281_write_ac97(card,BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
+ cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
+ cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
// Wait until we sample a DAC ready state.
- for(temp2=0; temp2<32; temp2++)
- {
+ for (temp2 = 0; temp2 < 32; temp2++) {
// Let's wait a mil to let things settle.
delayus(1000);
// Read the current state of the power control reg.
cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
// If the DAC ready state bit is set, stop waiting.
- if(temp1 & 0x2)
+ if (temp1 & 0x2)
break;
}
@@ -562,14 +826,13 @@ static int cs4281_hw_init(struct cs4281_state *card)
cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
// Wait until we sample ADC ready state.
- for(temp2=0; temp2<32; temp2++)
- {
+ for (temp2 = 0; temp2 < 32; temp2++) {
// Let's wait a mil to let things settle.
delayus(1000);
// Read the current state of the power control reg.
cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
// If the ADC ready state bit is set, stop waiting.
- if(temp1 & 0x1)
+ if (temp1 & 0x1)
break;
}
// Set up 4281 Register contents that
@@ -580,19 +843,19 @@ static int cs4281_hw_init(struct cs4281_state *card)
// Set the fifo to be 15 bytes at offset zero.
ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback).
- // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
- // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
- writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
+ // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
+ // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
+ writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
+ writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
// For capture, we map AC97 slot 10 and 11(Left
// and Right PCM Record) to DMA Channel 1.
// Set the fifo to be 15 bytes at offset sixteen.
ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record).
- // FCR1.LS[4:0]=10(=>slot10, left PCM record).
- // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
- writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
+ // FCR1.LS[4:0]=10(=>slot10, left PCM record).
+ // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
+ writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
+ writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
// Map the Playback SRC to the same AC97 slots(3 & 4--
// --Playback left & right)as DMA channel 0.
@@ -600,33 +863,34 @@ static int cs4281_hw_init(struct cs4281_state *card)
// -- Record left & right) as DMA channel 1.
ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
- // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
- // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
- // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
- writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
+ // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
+ // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
+ // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
+ writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
// Set 'Half Terminal Count Interrupt Enable' and 'Terminal
// Count Interrupt Enable' in DMA Control Registers 0 & 1.
// Set 'MSK' flag to 1 to keep the DMA engines paused.
- temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
- writel(temp1, card->pBA0 + BA0_DCR0); // (154h
- writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
+ temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
+ writel(temp1, card->pBA0 + BA0_DCR0); // (154h
+ writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
// Set 'Auto-Initialize Control' to 'enabled'; For playback,
// set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
// for record, set Transfer Type Control to 'write transfer'.
// All other bits set to zero; Some will be changed @ transfer start.
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
- writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
- writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
+ temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
+ writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
+ temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
+ writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
// Enable DMA interrupts generally, and
// DMA0 & DMA1 interrupts specifically.
- temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
- writel(temp1, card->pBA0+BA0_HIMR);
+ temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
+ writel(temp1, card->pBA0 + BA0_HIMR);
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));
return 0;
}
@@ -638,29 +902,30 @@ static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
{
u32 DACSRvalue = 1;
- // Based on the sample rate, program the DACSR register.
- if(playrate == 8000)
+ // Based on the sample rate, program the DACSR register.
+ if (playrate == 8000)
DACSRvalue = 5;
- if(playrate == 11025)
+ if (playrate == 11025)
DACSRvalue = 4;
- else if(playrate == 22050)
+ else if (playrate == 22050)
DACSRvalue = 2;
- else if(playrate == 44100)
+ else if (playrate == 44100)
DACSRvalue = 1;
- else if((playrate <= 48000) && (playrate >= 6023))
- DACSRvalue = 24576000/(playrate*16);
- else if(playrate < 6023)
+ else if ((playrate <= 48000) && (playrate >= 6023))
+ DACSRvalue = 24576000 / (playrate * 16);
+ else if (playrate < 6023)
// Not allowed by open.
return;
- else if(playrate > 48000)
+ else if (playrate > 48000)
// Not allowed by open.
return;
- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
- DACSRvalue,playrate));
- // Write the 'sample rate select code'
- // to the 'DAC Sample Rate' register.
- writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
+ CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
+ DACSRvalue,
+ playrate));
+ // Write the 'sample rate select code'
+ // to the 'DAC Sample Rate' register.
+ writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
}
//******************************************************************************
@@ -670,35 +935,32 @@ static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
{
u32 ADCSRvalue = 1;
- //
- // Based on the sample rate, program the ADCSR register
- //
- if(outrate == 8000)
+ //
+ // Based on the sample rate, program the ADCSR register
+ //
+ if (outrate == 8000)
ADCSRvalue = 5;
- if(outrate == 11025)
+ if (outrate == 11025)
ADCSRvalue = 4;
- else if(outrate == 22050)
+ else if (outrate == 22050)
ADCSRvalue = 2;
- else if(outrate == 44100)
+ else if (outrate == 44100)
ADCSRvalue = 1;
- else if((outrate <= 48000) && (outrate >= 6023))
- ADCSRvalue = 24576000/(outrate*16);
- else if(outrate < 6023)
- {
+ else if ((outrate <= 48000) && (outrate >= 6023))
+ ADCSRvalue = 24576000 / (outrate * 16);
+ else if (outrate < 6023) {
// Not allowed by open.
return;
- }
- else if(outrate > 48000)
- {
+ } else if (outrate > 48000) {
// Not allowed by open.
return;
}
- CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
- ADCSRvalue,outrate) );
+ CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
+ ADCSRvalue, outrate));
// Write the 'sample rate select code
// to the 'ADC Sample Rate' register.
- writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
+ writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
}
@@ -708,11 +970,12 @@ static void stop_dac(struct cs4281_state *s)
unsigned long flags;
unsigned temp1;
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n") );
+ CS_DBGOUT(CS_WAVE_WRITE, 3,
+ printk(KERN_INFO "cs4281: stop_dac():\n"));
spin_lock_irqsave(&s->lock, flags);
s->ena &= ~FMODE_WRITE;
- temp1 = readl(s->pBA0+ BA0_DCR0) | DCRn_MSK;
- writel(temp1, s->pBA0+BA0_DCR0);
+ temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;
+ writel(temp1, s->pBA0 + BA0_DCR0);
spin_unlock_irqrestore(&s->lock, flags);
}
@@ -723,20 +986,27 @@ static void start_dac(struct cs4281_state *s)
unsigned long flags;
unsigned temp1;
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_dac():\n") );
+ CS_DBGOUT(CS_FUNCTION, 3,
+ printk(KERN_INFO "cs4281: start_dac()+\n"));
spin_lock_irqsave(&s->lock, flags);
if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
- s->dma_dac.count > 0) && s->dma_dac.ready) {
+ s->dma_dac.count > 0)
+ && s->dma_dac.ready) {
s->ena |= FMODE_WRITE;
- temp1 = readl(s->pBA0+BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
- writel(temp1, s->pBA0+BA0_DCR0); // Start DMA'ing.
- writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts.
-
- writel(7, s->pBA0+BA0_PPRVC);
- writel(7, s->pBA0+BA0_PPLVC);
-
+ temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
+ writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing.
+ writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
+
+ writel(7, s->pBA0 + BA0_PPRVC);
+ writel(7, s->pBA0 + BA0_PPLVC);
+ CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO
+ "cs4281: start_dac(): writel 0x%x start dma\n",
+ temp1));
+
}
spin_unlock_irqrestore(&s->lock, flags);
+ CS_DBGOUT(CS_FUNCTION, 3,
+ printk(KERN_INFO "cs4281: start_dac()-\n"));
}
@@ -745,13 +1015,21 @@ static void stop_adc(struct cs4281_state *s)
unsigned long flags;
unsigned temp1;
- CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO "cs4281: stop_adc():\n") );
+ CS_DBGOUT(CS_FUNCTION, 3,
+ printk(KERN_INFO "cs4281: stop_adc()+\n"));
spin_lock_irqsave(&s->lock, flags);
s->ena &= ~FMODE_READ;
- temp1 = readl(s->pBA0+ BA0_DCR1) | DCRn_MSK;
- writel(temp1, s->pBA0+BA0_DCR1);
+
+ if (s->conversion == 1) {
+ s->conversion = 0;
+ s->prop_adc.fmt = s->prop_adc.fmt_original;
+ }
+ temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;
+ writel(temp1, s->pBA0 + BA0_DCR1);
spin_unlock_irqrestore(&s->lock, flags);
+ CS_DBGOUT(CS_FUNCTION, 3,
+ printk(KERN_INFO "cs4281: stop_adc()-\n"));
}
@@ -760,41 +1038,92 @@ static void start_adc(struct cs4281_state *s)
unsigned long flags;
unsigned temp1;
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_adc():\n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: start_adc()+\n"));
spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped
- || s->dma_adc.count <=
- (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready)
- {
+ if (!(s->ena & FMODE_READ) &&
+ (s->dma_adc.mapped || s->dma_adc.count <=
+ (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))
+ && s->dma_adc.ready) {
+ if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {
+ //
+ // now only use 16 bit capture, due to truncation issue
+ // in the chip, noticable distortion occurs.
+ // allocate buffer and then convert from 16 bit to
+ // 8 bit for the user buffer.
+ //
+ s->prop_adc.fmt_original = s->prop_adc.fmt;
+ if (s->prop_adc.fmt & AFMT_S8) {
+ s->prop_adc.fmt &= ~AFMT_S8;
+ s->prop_adc.fmt |= AFMT_S16_LE;
+ }
+ if (s->prop_adc.fmt & AFMT_U8) {
+ s->prop_adc.fmt &= ~AFMT_U8;
+ s->prop_adc.fmt |= AFMT_U16_LE;
+ }
+ //
+ // prog_dmabuf_adc performs a stop_adc() but that is
+ // ok since we really haven't started the DMA yet.
+ //
+ prog_codec(s, CS_TYPE_ADC);
+
+ if (prog_dmabuf_adc(s) != 0) {
+ CS_DBGOUT(CS_ERROR, 3,
+ printk(KERN_INFO
+ "cs4281: start_adc(): error in prog_dmabuf_adc\n"));
+ }
+ s->conversion = 1;
+ }
s->ena |= FMODE_READ;
- temp1 = readl(s->pBA0+BA0_DCR1) & ~ DCRn_MSK; // Clear DMA1 channel mask bit.
- writel(temp1, s->pBA0+BA0_DCR1); // Start recording
- writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts.
+ temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit.
+ writel(temp1, s->pBA0 + BA0_DCR1); // Start recording
+ writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
+ CS_DBGOUT(CS_PARMS, 6,
+ printk(KERN_INFO
+ "cs4281: start_adc(): writel 0x%x \n",
+ temp1));
}
spin_unlock_irqrestore(&s->lock, flags);
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: start_adc()-\n"));
}
// ---------------------------------------------------------------------
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) // == 3(for PC), = log base 2( buff sz = 32k).
-#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
+// use 64k (+1) rather than 32k as some of the higher frequencies need a larger buffer.
+// comments reflect 32k.
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT+1) // == 3(for PC), = log base 2( buff sz = 32k).
+#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
-extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
+extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
{
struct page *map, *mapend;
if (db->rawbuf) {
// Undo prog_dmabuf()'s marking the pages as reserved
- mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+ mapend =
+ virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
+ 1);
for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- clear_bit(PG_reserved, &map->flags);
- pci_free_consistent(s->pcidev,PAGE_SIZE<<db->buforder,
- db->rawbuf,db->dmaaddr);
+ mem_map_unreserve(map);
+ pci_free_consistent(s->pcidev, PAGE_SIZE << db->buforder,
+ db->rawbuf, db->dmaaddr);
}
+ if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {
+ // Undo prog_dmabuf()'s marking the pages as reserved
+ mapend =
+ virt_to_page(s->tmpbuff +
+ (PAGE_SIZE << s->buforder_tmpbuff) - 1);
+ for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
+ mem_map_unreserve(map);
+ pci_free_consistent(s->pcidev,
+ PAGE_SIZE << s->buforder_tmpbuff,
+ s->tmpbuff, s->dmaaddr_tmpbuff);
+ }
+ s->tmpbuff = NULL;
db->rawbuf = NULL;
db->mapped = db->ready = 0;
}
@@ -806,91 +1135,165 @@ static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
unsigned bufs, sample_shift = 0;
struct page *map, *mapend;
- db->hwptr = db->swptr = db->total_bytes = db->count =
- db->error = db->endcleared = db->blocks = 0;
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));
+ db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
+ db->endcleared = db->blocks = db->wakeup = 0;
+
if (!db->rawbuf) {
db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = (void *)pci_alloc_consistent(
- s->pcidev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: prog_dmabuf(): unable to allocate rawbuf\n") );
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER;
+ order--)
+ if (
+ (db->rawbuf =
+ (void *) pci_alloc_consistent(s->pcidev,
+ PAGE_SIZE <<
+ order,
+ &db->
+ dmaaddr)))
+ break;
+ if (!db->rawbuf) {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));
return -ENOMEM;
}
db->buforder = order;
// Now mark the pages as reserved; otherwise the
// remap_page_range() in cs4281_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
+ // 1. get index to last page in mem_map array for rawbuf.
+ mapend =
+ virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
+ 1);
+
+ // 2. mark each physical page in range as 'reserved'.
for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- set_bit(PG_reserved, &map->flags);
+ mem_map_reserve(map);
+ }
+ if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER;
+ order--)
+ if (
+ (s->tmpbuff =
+ (void *) pci_alloc_consistent(s->pcidev,
+ PAGE_SIZE <<
+ order,
+ &s->
+ dmaaddr_tmpbuff)))
+ break;
+ if (!s->tmpbuff) {
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));
+ return -ENOMEM;
+ }
+ s->buforder_tmpbuff = order;
+ // Now mark the pages as reserved; otherwise the
+ // remap_page_range() in cs4281_mmap doesn't work.
+ // 1. get index to last page in mem_map array for rawbuf.
+ mapend =
+ virt_to_page(s->tmpbuff +
+ (PAGE_SIZE << s->buforder_tmpbuff) - 1);
+
+ // 2. mark each physical page in range as 'reserved'.
+ for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
+ mem_map_reserve(map);
+ }
+ if (db->type == CS_TYPE_DAC) {
+ if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ sample_shift++;
+ if (s->prop_dac.channels > 1)
+ sample_shift++;
+ bytespersec = s->prop_dac.rate << sample_shift;
+ } else // CS_TYPE_ADC
+ {
+ if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ sample_shift++;
+ if (s->prop_adc.channels > 1)
+ sample_shift++;
+ bytespersec = s->prop_adc.rate << sample_shift;
}
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->channels > 1)
- sample_shift++;
- bytespersec = s->rate << sample_shift;
bufs = PAGE_SIZE << db->buforder;
-#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
+#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
db->numfrag = 2;
- temp1 = bytespersec/(1000/INTERRUPT_RATE_MS); // Nominal frag size(bytes/interrupt)
- db->fragshift = 8; // Min 256 bytes.
- while( 1 << db->fragshift < temp1) // Calc power of 2 frag size.
- db->fragshift +=1;
- db->fragsize = 1 << db->fragshift;
+ temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS); // Nominal frag size(bytes/interrupt)
+ db->fragshift = 8; // Min 256 bytes.
+ while (1 << db->fragshift < temp1) // Calc power of 2 frag size.
+ db->fragshift += 1;
+ db->fragsize = 1 << db->fragshift;
db->dmasize = db->fragsize * 2;
-
- // If the calculated size is larger than the allocated
- // buffer, divide the allocated buffer into 2 fragments.
- if(db->dmasize > bufs) {
- db->numfrag = 2; // Two fragments.
- db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
- db->dmasize = bufs; // Use all the alloc'ed buffer.
-
- db->fragshift = 0; // Calculate 'fragshift'.
- temp1 = db->fragsize; // update_ptr() uses it
- while( (temp1 >>=1) > 1) // to calc 'total-bytes'
- db->fragshift +=1; // returned in DSP_GETI/OPTR.
- }
- CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d\n",
- db->numfrag,db->fragsize,db->fragsamples,db->fragshift) );
+ db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
+
+// If the calculated size is larger than the allocated
+// buffer, divide the allocated buffer into 2 fragments.
+ if (db->dmasize > bufs) {
+
+ db->numfrag = 2; // Two fragments.
+ db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
+ db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
+ db->dmasize = bufs; // Use all the alloc'ed buffer.
+
+ db->fragshift = 0; // Calculate 'fragshift'.
+ temp1 = db->fragsize; // update_ptr() uses it
+ while ((temp1 >>= 1) > 1) // to calc 'total-bytes'
+ db->fragshift += 1; // returned in DSP_GETI/OPTR.
+ }
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));
+ CS_DBGOUT(CS_PARMS, 8,
+ printk(KERN_INFO
+ "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",
+ db->numfrag, db->fragsize, db->fragsamples,
+ db->fragshift, bufs,
+ (db->type ==
+ CS_TYPE_DAC) ? s->prop_dac.fmt : s->prop_adc.fmt,
+ (db->type ==
+ CS_TYPE_DAC) ? s->prop_dac.channels : s->
+ prop_adc.channels));
return 0;
-}
+}
static int prog_dmabuf_adc(struct cs4281_state *s)
{
unsigned long va;
- unsigned count;
+ unsigned count;
int c;
stop_adc(s);
+ s->dma_adc.type = CS_TYPE_ADC;
if ((c = prog_dmabuf(s, &s->dma_adc)))
return c;
-
+
+ if (s->dma_adc.rawbuf) {
+ memset(s->dma_adc.rawbuf,
+ (s->prop_adc.
+ fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+ s->dma_adc.dmasize);
+ }
+ if (s->tmpbuff) {
+ memset(s->tmpbuff,
+ (s->prop_adc.
+ fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+ PAGE_SIZE << s->buforder_tmpbuff);
+ }
+
va = virt_to_bus(s->dma_adc.rawbuf);
-
- count = s->dma_adc.dmasize;
-
- if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if(s->channels > 1)
- count /= 2; // Assume stereo.
-
- CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n", count,(unsigned)va) );
-
- writel(va, s->pBA0+BA0_DBA1); // Set buffer start address.
- writel(count-1, s->pBA0+BA0_DBC1); // Set count.
+
+ count = s->dma_adc.dmasize;
+
+ if (s->prop_adc.
+ fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+ count /= 2; // 16-bit.
+
+ if (s->prop_adc.channels > 1)
+ count /= 2; // Assume stereo.
+
+ CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
+ "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",
+ count, (unsigned) va));
+
+ writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address.
+ writel(count - 1, s->pBA0 + BA0_DBC1); // Set count.
s->dma_adc.ready = 1;
return 0;
}
@@ -902,43 +1305,50 @@ static int prog_dmabuf_dac(struct cs4281_state *s)
unsigned count;
int c;
stop_dac(s);
+ s->dma_dac.type = CS_TYPE_DAC;
if ((c = prog_dmabuf(s, &s->dma_dac)))
return c;
- memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE))
- ? 0x80 : 0, s->dma_dac.dmasize);
+ memset(s->dma_dac.rawbuf,
+ (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
+ s->dma_dac.dmasize);
va = virt_to_bus(s->dma_dac.rawbuf);
- count = s->dma_dac.dmasize;
- if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if(s->channels > 1)
- count /= 2; // Assume stereo.
-
- writel(va, s->pBA0+BA0_DBA0); // Set buffer start address.
- writel(count-1, s->pBA0+BA0_DBC0); // Set count.
+ count = s->dma_dac.dmasize;
+ if (s->prop_dac.
+ fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
+ count /= 2; // 16-bit.
+
+ if (s->prop_dac.channels > 1)
+ count /= 2; // Assume stereo.
+
+ writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address.
+ writel(count - 1, s->pBA0 + BA0_DBC0); // Set count.
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n", count,(unsigned)va) );
+ CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
+ "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",
+ count, (unsigned) va));
s->dma_dac.ready = 1;
return 0;
}
-static void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
+static void clear_advance(void *buf, unsigned bsize, unsigned bptr,
+ unsigned len, unsigned char c)
{
if (bptr + len > bsize) {
unsigned x = bsize - bptr;
- memset(((char *)buf) + bptr, c, x);
+ memset(((char *) buf) + bptr, c, x);
bptr = 0;
len -= x;
}
- CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
- "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n",
- (unsigned)c,(unsigned)((char *)buf) + bptr, len) );
- memset(((char *)buf) + bptr, c, len);
+ CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
+ "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n",
+ (unsigned) c,
+ (unsigned) ((char *) buf) +
+ bptr, len));
+ memset(((char *) buf) + bptr, c, len);
}
@@ -947,156 +1357,219 @@ static void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len
static void cs4281_update_ptr(struct cs4281_state *s)
{
int diff;
- unsigned hwptr, va, temp1;
+ unsigned hwptr, va;
// update ADC pointer
if (s->ena & FMODE_READ) {
- hwptr = readl(s->pBA0+BA0_DCA1); // Read capture DMA address.
+ hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address.
va = virt_to_bus(s->dma_adc.rawbuf);
- hwptr -= (unsigned)va;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+ hwptr -= (unsigned) va;
+ diff =
+ (s->dma_adc.dmasize + hwptr -
+ s->dma_adc.hwptr) % s->dma_adc.dmasize;
s->dma_adc.hwptr = hwptr;
s->dma_adc.total_bytes += diff;
s->dma_adc.count += diff;
+ if (s->dma_adc.count > s->dma_adc.dmasize)
+ s->dma_adc.count = s->dma_adc.dmasize;
if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
+ if (s->dma_adc.count >=
+ (signed) s->dma_adc.fragsize) wake_up(&s->
+ dma_adc.
+ wait);
} else {
if (s->dma_adc.count > 0)
wake_up(&s->dma_adc.wait);
}
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
- (unsigned)s,s->dma_adc.hwptr,s->dma_adc.total_bytes,s->dma_adc.count) );
+ CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
+ (unsigned) s,
+ s->dma_adc.hwptr,
+ s->dma_adc.total_bytes,
+ s->dma_adc.count));
}
// update DAC pointer
//
// check for end of buffer, means that we are going to wait for another interrupt
// to allow silence to fill the fifos on the part, to keep pops down to a minimum.
//
- if ( (s->ena & FMODE_WRITE) && (!s->endofbuffer) )
- {
- hwptr = readl(s->pBA0+BA0_DCA0); // Read play DMA address.
+ if (s->ena & FMODE_WRITE) {
+ hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address.
va = virt_to_bus(s->dma_dac.rawbuf);
- hwptr -= (unsigned)va;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+ hwptr -= (unsigned) va;
+ diff =
+ (s->dma_dac.dmasize + hwptr -
+ s->dma_dac.hwptr) % s->dma_dac.dmasize;
s->dma_dac.hwptr = hwptr;
s->dma_dac.total_bytes += diff;
if (s->dma_dac.mapped) {
s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
+ if (s->dma_dac.count >= s->dma_dac.fragsize) {
+ s->dma_dac.wakeup = 1;
wake_up(&s->dma_dac.wait);
+ if (s->dma_dac.count > s->dma_dac.dmasize)
+ s->dma_dac.count &=
+ s->dma_dac.dmasize - 1;
+ }
} else {
+
s->dma_dac.count -= diff;
if (s->dma_dac.count <= 0) {
- s->ena &= ~FMODE_WRITE;
- temp1 = readl(s->pBA0+BA0_DCR0);
- //
- // fill with silence, and wait on turning off the DAC until interrupt routine.
- // wait on "Poke(pBA0+BA0_DCR0, temp1 | DCRn_MSK); // Stop Play DMA"
- //
- CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n",
- (unsigned)(s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- (unsigned)s->dma_dac.rawbuf, s->dma_dac.dmasize) );
- memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_dac.dmasize);
- s->endofbuffer = 1;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize
- && !s->dma_dac.endcleared) {
- clear_advance(s->dma_dac.rawbuf,
- s->dma_dac.dmasize, s->dma_dac.swptr,
+ //
+ // fill with silence, and do not shut down the DAC.
+ // Continue to play silence until the _release.
+ //
+ CS_DBGOUT(CS_WAVE_WRITE, 6,
+ printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n",
+ (unsigned) (s->prop_dac.
+ fmt & (AFMT_U8
+ |
+ AFMT_U16_LE))
+ ? 0x80 : 0,
+ (unsigned) s->dma_dac.
+ rawbuf,
+ s->dma_dac.dmasize));
+ memset(s->dma_dac.rawbuf,
+ (s->prop_dac.
+ fmt & (AFMT_U8 | AFMT_U16_LE)) ?
+ 0x80 : 0, s->dma_dac.dmasize);
+ } else if (s->dma_dac.count <=
+ (signed) s->dma_dac.fragsize
+ && !s->dma_dac.endcleared) {
+ clear_advance(s->dma_dac.rawbuf,
+ s->dma_dac.dmasize,
+ s->dma_dac.swptr,
s->dma_dac.fragsize,
- (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0);
+ (s->prop_dac.
+ fmt & (AFMT_U8 |
+ AFMT_U16_LE)) ? 0x80
+ : 0);
s->dma_dac.endcleared = 1;
}
- if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+ if (s->dma_dac.count < (signed) s->dma_dac.dmasize)
wake_up(&s->dma_dac.wait);
}
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
- (unsigned)s,s->dma_dac.hwptr,s->dma_dac.total_bytes,s->dma_dac.count) );
+ CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
+ "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
+ (unsigned) s,
+ s->dma_dac.hwptr,
+ s->dma_dac.total_bytes,
+ s->dma_dac.count));
}
}
// ---------------------------------------------------------------------
-static void prog_codec(struct cs4281_state *s)
+static void prog_codec(struct cs4281_state *s, unsigned type)
{
unsigned long flags;
unsigned temp1, format;
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_codec()+ \n") );
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: prog_codec()+ \n"));
spin_lock_irqsave(&s->lock, flags);
- temp1 = readl(s->pBA0+BA0_DCR0);
- writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR0); // Stop play DMA, if active.
- temp1 = readl(s->pBA0+BA0_DCR1);
- writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR1); // Stop capture DMA, if active.
-
- // program sampling rates
- // Note, for CS4281, capture & play rates can be set independently.
- cs4281_record_rate(s, s->rate);
-
- // program ADC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
- if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
- format |= DMRn_BEND;
- if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- }
- else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
- if(s->channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0+BA0_DMR1);
-
-
- // program DAC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
- if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE))
- format |= DMRn_BEND; // Big Endian.
- if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- }
- else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
-
- if(s->channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0+BA0_DMR0);
+ if (type == CS_TYPE_ADC) {
+ temp1 = readl(s->pBA0 + BA0_DCR1);
+ writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active.
+
+ // program sampling rates
+ // Note, for CS4281, capture & play rates can be set independently.
+ cs4281_record_rate(s, s->prop_adc.rate);
+
+ // program ADC parameters
+ format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
+ if (s->prop_adc.
+ fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+ if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
+ format |= DMRn_BEND;
+ if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))
+ format |= DMRn_USIGN; // Unsigned.
+ } else
+ format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+ if (s->prop_adc.channels < 2)
+ format |= DMRn_MONO;
+
+ writel(format, s->pBA0 + BA0_DMR1);
+
+ CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",
+ (format & DMRn_SIZE8) ? "8" :
+ "16",
+ (format & DMRn_USIGN) ?
+ "Unsigned" : "Signed",
+ (format & DMRn_MONO) ? "Mono"
+ : "Stereo", s->prop_adc.rate,
+ format));
+
+ s->ena &= ~FMODE_READ; // not capturing data yet
+ }
+
+
+ if (type == CS_TYPE_DAC) {
+ temp1 = readl(s->pBA0 + BA0_DCR0);
+ writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active.
+
+ // program sampling rates
+ // Note, for CS4281, capture & play rates can be set independently.
+ cs4281_play_rate(s, s->prop_dac.rate);
+
+ // program DAC parameters
+ format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
+ if (s->prop_dac.
+ fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
+ if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))
+ format |= DMRn_BEND; // Big Endian.
+ if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))
+ format |= DMRn_USIGN; // Unsigned.
+ } else
+ format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
+
+ if (s->prop_dac.channels < 2)
+ format |= DMRn_MONO;
+
+ writel(format, s->pBA0 + BA0_DMR0);
+
+
+ CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
+ "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",
+ (format & DMRn_SIZE8) ? "8" :
+ "16",
+ (format & DMRn_USIGN) ?
+ "Unsigned" : "Signed",
+ (format & DMRn_MONO) ? "Mono"
+ : "Stereo", s->prop_dac.rate,
+ format));
+
+ s->ena &= ~FMODE_WRITE; // not capturing data yet
- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
- "cs4281: prog_codec(): format=0x%.8x rate=%d\n", format,s->rate) );
-
- cs4281_play_rate(s, s->rate);
-
- s->ena = 0; // Neither writing or reading.
+ }
spin_unlock_irqrestore(&s->lock, flags);
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: prog_codec()- \n"));
}
// ---------------------------------------------------------------------
-static const char invalid_magic[] = KERN_CRIT "cs4281: invalid magic value\n";
+static const char invalid_magic[] =
+ KERN_CRIT "cs4281: invalid magic value\n";
#define VALIDATE_STATE(s) \
({ \
- if (!(s) || (s)->magic != CS4281_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
+ if (!(s) || (s)->magic != CS4281_MAGIC) { \
+ printk(invalid_magic); \
+ return -ENXIO; \
+ } \
})
// ---------------------------------------------------------------------
-static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long arg)
+static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
+ unsigned long arg)
{
// Index to mixer_src[] is value of AC97 Input Mux Select Reg.
// Value of array member is recording source Device ID Mask.
@@ -1104,39 +1577,81 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
};
-
+
// Index of mixtable1[] member is Device ID
// and must be <= SOUND_MIXER_NRDEVICES.
// Value of array member is index into s->mix.vol[]
static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, // voice
- [SOUND_MIXER_LINE1] = 2, // AUX
- [SOUND_MIXER_CD] = 3, // CD
- [SOUND_MIXER_LINE] = 4, // Line
- [SOUND_MIXER_SYNTH] = 5, // FM
- [SOUND_MIXER_MIC] = 6, // Mic
- [SOUND_MIXER_SPEAKER] = 7, // Speaker
- [SOUND_MIXER_RECLEV] = 8, // Recording level
- [SOUND_MIXER_VOLUME] = 9 // Master Volume
+ [SOUND_MIXER_PCM] = 1, // voice
+ [SOUND_MIXER_LINE1] = 2, // AUX
+ [SOUND_MIXER_CD] = 3, // CD
+ [SOUND_MIXER_LINE] = 4, // Line
+ [SOUND_MIXER_SYNTH] = 5, // FM
+ [SOUND_MIXER_MIC] = 6, // Mic
+ [SOUND_MIXER_SPEAKER] = 7, // Speaker
+ [SOUND_MIXER_RECLEV] = 8, // Recording level
+ [SOUND_MIXER_VOLUME] = 9 // Master Volume
};
-
-
+
+
static const unsigned mixreg[] = {
BA0_AC97_PCM_OUT_VOLUME,
- BA0_AC97_AUX_VOLUME,
- BA0_AC97_CD_VOLUME,
+ BA0_AC97_AUX_VOLUME,
+ BA0_AC97_CD_VOLUME,
BA0_AC97_LINE_IN_VOLUME
};
unsigned char l, r, rl, rr, vidx;
- unsigned char attentbl[11] = {63,42,26,17,14,11,8,6,4,2,0};
+ unsigned char attentbl[11] =
+ { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };
unsigned temp1;
int i, val;
VALIDATE_STATE(s);
-
+ CS_DBGOUT(CS_FUNCTION, 4,
+ printk(KERN_INFO
+ "cs4281: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n",
+ (unsigned) s, cmd));
+#if CSDEBUG
+ printioctl(cmd);
+#endif
+#if CSDEBUG_INTERFACE
+
+ if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||
+ (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
+ (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
+ (cmd == SOUND_MIXER_CS_SETDBGLEVEL)) {
+ switch (cmd) {
+
+ case SOUND_MIXER_CS_GETDBGMASK:
+ return put_user(cs_debugmask,
+ (unsigned long *) arg);
+
+ case SOUND_MIXER_CS_GETDBGLEVEL:
+ return put_user(cs_debuglevel,
+ (unsigned long *) arg);
+
+ case SOUND_MIXER_CS_SETDBGMASK:
+ if (get_user(val, (unsigned long *) arg))
+ return -EFAULT;
+ cs_debugmask = val;
+ return 0;
+
+ case SOUND_MIXER_CS_SETDBGLEVEL:
+ if (get_user(val, (unsigned long *) arg))
+ return -EFAULT;
+ cs_debuglevel = val;
+ return 0;
+ default:
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
+ "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));
+ return 0;
+ }
+ }
+#endif
+
if (cmd == SOUND_MIXER_PRIVATE1) {
// enable/disable/query mixer preamp
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
if (val != -1) {
cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
@@ -1145,27 +1660,29 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
}
cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
val = (temp1 & 0x40) ? 1 : 0;
- return put_user(val, (int *)arg);
+ return put_user(val, (int *) arg);
}
if (cmd == SOUND_MIXER_PRIVATE2) {
// enable/disable/query spatializer
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
if (val != -1) {
temp1 = (val & 0x3f) >> 2;
cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &temp1);
- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,temp1 | 0x2000);
+ cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,
+ &temp1);
+ cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,
+ temp1 | 0x2000);
}
cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
- return put_user((temp1 << 2) | 3, (int *)arg);
+ return put_user((temp1 << 2) | 3, (int *) arg);
}
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
strncpy(info.id, "CS4281", sizeof(info.id));
strncpy(info.name, "Crystal CS4281", sizeof(info.name));
info.modify_counter = s->mix.modcnt;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
+ if (copy_to_user((void *) arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
@@ -1173,138 +1690,142 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
_old_mixer_info info;
strncpy(info.id, "CS4281", sizeof(info.id));
strncpy(info.name, "Crystal CS4281", sizeof(info.name));
- if (copy_to_user((void *)arg, &info, sizeof(info)))
+ if (copy_to_user((void *) arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
-
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- // If ioctl has only the IOC_READ bit(bit 31)
- // on, process the only-read commands.
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
- return put_user(mixer_src[temp1 & 7], (int *)arg);
+ return put_user(SOUND_VERSION, (int *) arg);
- case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_RECLEV |
- SOUND_MASK_SPEAKER, (int *)arg);
-
- case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD
- | SOUND_MASK_VOLUME | SOUND_MASK_LINE1, (int *)arg);
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
- case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, (int *)arg);
+ // If ioctl has only the SIOC_READ bit(bit 31)
+ // on, process the only-read commands.
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+ cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT,
+ &temp1);
+ return put_user(mixer_src[temp1 & 7], (int *) arg);
+
+ case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
+ SOUND_MASK_CD | SOUND_MASK_LINE |
+ SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME |
+ SOUND_MASK_RECLEV |
+ SOUND_MASK_SPEAKER, (int *) arg);
+
+ case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
+ return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |
+ SOUND_MASK_CD | SOUND_MASK_VOLUME |
+ SOUND_MASK_LINE1, (int *) arg);
+
+ case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
+ return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
+ SOUND_MASK_CD | SOUND_MASK_LINE |
+ SOUND_MASK_LINE1 | SOUND_MASK_MIC |
+ SOUND_MASK_VOLUME |
+ SOUND_MASK_RECLEV, (int *) arg);
case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
default:
i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
+ if (i >= SOUND_MIXER_NRDEVICES
+ || !(vidx = mixtable1[i]))
return -EINVAL;
- return put_user(s->mix.vol[vidx-1], (int *)arg);
+ return put_user(s->mix.vol[vidx - 1], (int *) arg);
}
}
-
- // If ioctl doesn't have both the IOC_READ and
- // the IOC_WRITE bit set, return invalid.
- if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ // If ioctl doesn't have both the SIOC_READ and
+ // the SIOC_WRITE bit set, return invalid.
+ if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE))
return -EINVAL;
-
- // Increment the count of volume writes.
+
+ // Increment the count of volume writes.
s->mix.modcnt++;
-
- // Isolate the command; it must be a write.
+
+ // Isolate the command; it must be a write.
switch (_IOC_NR(cmd)) {
-
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- if (get_user(val, (int *)arg))
+
+ case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
+ if (get_user(val, (int *) arg))
return -EFAULT;
- i = hweight32(val); // i = # bits on in val.
- if (i != 1) // One & only 1 bit must be on.
+ i = hweight32(val); // i = # bits on in val.
+ if (i != 1) // One & only 1 bit must be on.
return 0;
- for(i=0; i<sizeof(mixer_src)/sizeof(int); i++) {
- if(val == mixer_src[i]) {
- temp1 = (i << 8) | i;
- cs4281_write_ac97(s, BA0_AC97_RECORD_SELECT, temp1);
+ for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) {
+ if (val == mixer_src[i]) {
+ temp1 = (i << 8) | i;
+ cs4281_write_ac97(s,
+ BA0_AC97_RECORD_SELECT,
+ temp1);
return 0;
}
}
return 0;
case SOUND_MIXER_VOLUME:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
- if(l > 100)
- l = 100; // Max soundcard.h vol is 100.
- if(l < 6) {
+ if (l > 100)
+ l = 100; // Max soundcard.h vol is 100.
+ if (l < 6) {
rl = 63;
- l = 0;
- }
- else
- rl = attentbl[(10*l)/100]; // Convert 0-100 vol to 63-0 atten.
-
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100; // Max right volume is 100, too
- if(r < 6) {
- rr = 63;
- r = 0;
- }
- else
- rr = attentbl[(10*r)/100]; // Convert volume to attenuation.
-
- if ((rl > 60 ) && (rr > 60)) // If both l & r are 'low',
- temp1 = 0x8000; // turn on the mute bit.
+ l = 0;
+ } else
+ rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten.
+
+ r = (val >> 8) & 0xff;
+ if (r > 100)
+ r = 100; // Max right volume is 100, too
+ if (r < 6) {
+ rr = 63;
+ r = 0;
+ } else
+ rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation.
+
+ if ((rl > 60) && (rr > 60)) // If both l & r are 'low',
+ temp1 = 0x8000; // turn on the mute bit.
else
temp1 = 0;
-
+
temp1 |= (rl << 8) | rr;
-
+
cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[8] = ((unsigned int)r << 8) | l;
+ s->mix.vol[8] = ((unsigned int) r << 8) | l;
#else
s->mix.vol[8] = val;
#endif
- return put_user(s->mix.vol[8], (int *)arg);
+ return put_user(s->mix.vol[8], (int *) arg);
case SOUND_MIXER_SPEAKER:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
if (l > 100)
l = 100;
- if(l < 3 ) {
+ if (l < 3) {
rl = 0;
l = 0;
- }
- else {
- rl = (l*2 - 5)/13; // Convert 0-100 range to 0-15.
- l = (rl*13 +5)/2;
+ } else {
+ rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15.
+ l = (rl * 13 + 5) / 2;
}
- if (rl < 3){
- temp1 = 0x8000;
- rl = 0;
- }
- else
- temp1 = 0;
- rl = 15 - rl; // Convert volume to attenuation.
+ if (rl < 3) {
+ temp1 = 0x8000;
+ rl = 0;
+ } else
+ temp1 = 0;
+ rl = 15 - rl; // Convert volume to attenuation.
temp1 |= rl << 1;
cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
@@ -1313,10 +1834,10 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
#else
s->mix.vol[6] = val;
#endif
- return put_user(s->mix.vol[6], (int *)arg);
+ return put_user(s->mix.vol[6], (int *) arg);
case SOUND_MIXER_RECLEV:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
if (l > 100)
@@ -1324,25 +1845,25 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
r = (val >> 8) & 0xff;
if (r > 100)
r = 100;
- rl = (l*2 - 5) / 13; // Convert 0-100 scale to 0-15.
- rr = (r*2 - 5) / 13;
- if (rl <3 && rr <3)
+ rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15.
+ rr = (r * 2 - 5) / 13;
+ if (rl < 3 && rr < 3)
temp1 = 0x8000;
else
temp1 = 0;
temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
+ cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[7] = ((unsigned int)r << 8) | l;
+ s->mix.vol[7] = ((unsigned int) r << 8) | l;
#else
s->mix.vol[7] = val;
#endif
- return put_user(s->mix.vol[7], (int *)arg);
+ return put_user(s->mix.vol[7], (int *) arg);
case SOUND_MIXER_MIC:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
if (l > 100)
@@ -1350,19 +1871,18 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
if (l < 1) {
l = 0;
rl = 0;
- }
- else {
- rl = ((unsigned)l*5 - 4)/16; // Convert 0-100 range to 0-31.
- l = (rl*16 +4)/5;
+ } else {
+ rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31.
+ l = (rl * 16 + 4) / 5;
}
cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- temp1 &= 0x40; // Isolate 20db gain bit.
- if (rl < 3){
- temp1 |= 0x8000;
- rl = 0;
+ temp1 &= 0x40; // Isolate 20db gain bit.
+ if (rl < 3) {
+ temp1 |= 0x8000;
+ rl = 0;
}
- rl = 31 - rl; // Convert volume to attenuation.
- temp1 |= rl;
+ rl = 31 - rl; // Convert volume to attenuation.
+ temp1 |= rl;
cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -1370,49 +1890,52 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
#else
s->mix.vol[5] = val;
#endif
- return put_user(s->mix.vol[5], (int *)arg);
-
-
+ return put_user(s->mix.vol[5], (int *) arg);
+
+
case SOUND_MIXER_SYNTH:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
if (l > 100)
l = 100;
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
r = (val >> 8) & 0xff;
if (r > 100)
r = 100;
- rl = (l * 2 - 11)/3; // Convert 0-100 range to 0-63.
- rr = (r * 2 - 11)/3;
- if (rl < 3) // If l is low, turn on
- temp1 = 0x0080; // the mute bit.
+ rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63.
+ rr = (r * 2 - 11) / 3;
+ if (rl < 3) // If l is low, turn on
+ temp1 = 0x0080; // the mute bit.
else
temp1 = 0;
- rl = 63 - rl; // Convert vol to attenuation.
- writel(temp1|rl, s->pBA0+BA0_FMLVC);
- if (rr < 3) // If rr is low, turn on
- temp1 = 0x0080; // the mute bit.
+ rl = 63 - rl; // Convert vol to attenuation.
+ writel(temp1 | rl, s->pBA0 + BA0_FMLVC);
+ if (rr < 3) // If rr is low, turn on
+ temp1 = 0x0080; // the mute bit.
else
temp1 = 0;
- rr = 63 - rr; // Convert vol to attenuation.
- writel(temp1 | rr, s->pBA0+BA0_FMRVC);
+ rr = 63 - rr; // Convert vol to attenuation.
+ writel(temp1 | rr, s->pBA0 + BA0_FMRVC);
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
s->mix.vol[4] = (r << 8) | l;
#else
s->mix.vol[4] = val;
#endif
- return put_user(s->mix.vol[4], (int *)arg);
+ return put_user(s->mix.vol[4], (int *) arg);
+
-
default:
+ CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
+ "cs4281: mixer_ioctl(): default\n"));
+
i = _IOC_NR(cmd);
if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
return -EINVAL;
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
l = val & 0xff;
if (l > 100)
@@ -1420,32 +1943,30 @@ static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long a
if (l < 1) {
l = 0;
rl = 31;
- }
- else
- rl = (attentbl[(l*10)/100])>>1;
-
+ } else
+ rl = (attentbl[(l * 10) / 100]) >> 1;
+
r = (val >> 8) & 0xff;
if (r > 100)
r = 100;
if (r < 1) {
r = 0;
rr = 31;
- }
- else
- rr = (attentbl[(r*10)/100])>>1;
+ } else
+ rr = (attentbl[(r * 10) / 100]) >> 1;
if ((rl > 30) && (rr > 30))
temp1 = 0x8000;
else
temp1 = 0;
- temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, mixreg[vidx-1], temp1);
-
+ temp1 = temp1 | (rl << 8) | rr;
+ cs4281_write_ac97(s, mixreg[vidx - 1], temp1);
+
#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
+ s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;
#else
- s->mix.vol[vidx-1] = val;
+ s->mix.vol[vidx - 1] = val;
#endif
- return put_user(s->mix.vol[vidx-1], (int *)arg);
+ return put_user(s->mix.vol[vidx - 1], (int *) arg);
}
}
@@ -1478,7 +1999,8 @@ static int cs4281_open_mixdev(struct inode *inode, struct file *file)
static int cs4281_release_mixdev(struct inode *inode, struct file *file)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
VALIDATE_STATE(s);
MOD_DEC_USE_COUNT;
@@ -1489,22 +2011,72 @@ static int cs4281_release_mixdev(struct inode *inode, struct file *file)
static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- return mixer_ioctl((struct cs4281_state *)file->private_data, cmd, arg);
+ return mixer_ioctl((struct cs4281_state *) file->private_data, cmd,
+ arg);
}
// ******************************************************************************************
// Mixer file operations struct.
// ******************************************************************************************
-static /*const*/ struct file_operations cs4281_mixer_fops = {
- llseek: cs4281_llseek,
- ioctl: cs4281_ioctl_mixdev,
- open: cs4281_open_mixdev,
- release: cs4281_release_mixdev,
+static /*const */ struct file_operations cs4281_mixer_fops = {
+ llseek:cs4281_llseek,
+ ioctl:cs4281_ioctl_mixdev,
+ open:cs4281_open_mixdev,
+ release:cs4281_release_mixdev,
};
// ---------------------------------------------------------------------
+
+static int drain_adc(struct cs4281_state *s, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count;
+ unsigned tmo;
+
+ if (s->dma_adc.mapped)
+ return 0;
+ add_wait_queue(&s->dma_adc.wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&s->lock, flags);
+ count = s->dma_adc.count;
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: drain_adc() %d\n",
+ count));
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0) {
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO
+ "cs4281: drain_adc() count<0\n"));
+ break;
+ }
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ current->state = TASK_RUNNING;
+ return -EBUSY;
+ }
+ tmo =
+ 3 * HZ * (count +
+ s->dma_adc.fragsize) / 2 / s->prop_adc.rate;
+ if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ tmo >>= 1;
+ if (s->prop_adc.channels > 1)
+ tmo >>= 1;
+ if (!schedule_timeout(tmo + 1))
+ printk(KERN_DEBUG "cs4281: dma timed out??\n");
+ }
+ remove_wait_queue(&s->dma_adc.wait, &wait);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
static int drain_dac(struct cs4281_state *s, int nonblock)
{
DECLARE_WAITQUEUE(wait, current);
@@ -1514,9 +2086,9 @@ static int drain_dac(struct cs4281_state *s, int nonblock)
if (s->dma_dac.mapped)
return 0;
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->dma_dac.wait, &wait);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
@@ -1529,10 +2101,12 @@ static int drain_dac(struct cs4281_state *s, int nonblock)
current->state = TASK_RUNNING;
return -EBUSY;
}
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
+ tmo =
+ 3 * HZ * (count +
+ s->dma_dac.fragsize) / 2 / s->prop_dac.rate;
+ if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
tmo >>= 1;
- if (s->channels > 1)
+ if (s->prop_dac.channels > 1)
tmo >>= 1;
if (!schedule_timeout(tmo + 1))
printk(KERN_DEBUG "cs4281: dma timed out??\n");
@@ -1544,19 +2118,189 @@ static int drain_dac(struct cs4281_state *s, int nonblock)
return 0;
}
+//****************************************************************************
+//
+// CopySamples copies 16-bit stereo samples from the source to the
+// destination, possibly converting down to either 8-bit or mono or both.
+// count specifies the number of output bytes to write.
+//
+// Arguments:
+//
+// dst - Pointer to a destination buffer.
+// src - Pointer to a source buffer
+// count - The number of bytes to copy into the destination buffer.
+// iChannels - Stereo - 2
+// Mono - 1
+// fmt - AFMT_xxx (soundcard.h formats)
+//
+// NOTES: only call this routine for conversion to 8bit from 16bit
+//
+//****************************************************************************
+static void CopySamples(char *dst, char *src, int count, int iChannels,
+ unsigned fmt)
+{
+
+ unsigned short *psSrc;
+ long lAudioSample;
+
+ CS_DBGOUT(CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: CopySamples()+ "));
+ CS_DBGOUT(CS_WAVE_READ, 8,
+ printk(KERN_INFO
+ " dst=0x%x src=0x%x count=%d iChannels=%d fmt=0x%x\n",
+ (unsigned) dst, (unsigned) src, (unsigned) count,
+ (unsigned) iChannels, (unsigned) fmt));
+
+ // Gershwin does format conversion in hardware so normally
+ // we don't do any host based coversion. The data formatter
+ // truncates 16 bit data to 8 bit and that causes some hiss.
+ // We have already forced the HW to do 16 bit sampling and
+ // 2 channel so that we can use software to round instead
+ // of truncate
+
+ //
+ // See if the data should be output as 8-bit unsigned stereo.
+ //
+ if ((iChannels == 2) && (fmt & AFMT_U8)) {
+ //
+ // Convert each 16-bit unsigned stereo sample to 8-bit unsigned
+ // stereo using rounding.
+ //
+ psSrc = (unsigned short *) src;
+ count = count / 2;
+ while (count--) {
+ lAudioSample = (long) psSrc[count] + (long) 0x80;
+ if (lAudioSample > 0xffff) {
+ lAudioSample = 0xffff;
+ }
+ dst[count] = (char) (lAudioSample >> 8);
+ }
+ }
+ //
+ // check for 8-bit signed stereo.
+ //
+ else if ((iChannels == 2) && (fmt & AFMT_S8)) {
+ //
+ // Convert each 16-bit stereo sample to 8-bit stereo using rounding.
+ //
+ psSrc = (short *) src;
+ while (count--) {
+ lAudioSample =
+ (((long) psSrc[0] + (long) psSrc[1]) / 2);
+ psSrc += 2;
+ *dst++ = (char) ((short) lAudioSample >> 8);
+ }
+ }
+ //
+ // See if the data should be output at 8-bit unsigned mono.
+ //
+ else if ((iChannels == 1) && (fmt & AFMT_U8)) {
+ //
+ // Convert each 16-bit unsigned mono sample to 8-bit unsigned
+ // mono using rounding.
+ //
+
+ psSrc = (short *) src;
+ while (count--) {
+ lAudioSample = (long) *psSrc++ + (long) 0x80;
+ if (lAudioSample > 0x7fff) {
+ lAudioSample = 0x7fff;
+ }
+ //
+ // Convert Signed to Unsigned.
+ //
+
+ *dst++ =
+ (unsigned
+ char) (((short) lAudioSample +
+ (short) 0x8000) >> 8);
+ }
+ }
+ //
+ // Otherwise, the data should be output as 8-bit signed mono.
+ //
+ else if ((iChannels == 1) && (fmt & AFMT_S8)) {
+ //
+ // Convert each 16-bit signed mono sample to 8-bit signed mono
+ // using rounding.
+ //
+ psSrc = (short *) src;
+ while (count--) {
+ lAudioSample =
+ (((long) psSrc[0] + (long) psSrc[1]) / 2);
+ if (lAudioSample > 0x7fff) {
+ lAudioSample = 0x7fff;
+ }
+ psSrc += 2;
+ *dst++ = (char) ((short) lAudioSample >> 8);
+ }
+ }
+}
+
+//
+// cs_copy_to_user()
+// replacement for the standard copy_to_user, to allow for a conversion from
+// 16 bit to 8 bit if the record conversion is active. the cs4281 has some
+// issues with 8 bit capture, so the driver always captures data in 16 bit
+// and then if the user requested 8 bit, converts from 16 to 8 bit.
+//
+static unsigned cs_copy_to_user(struct cs4281_state *s, void *dest,
+ unsigned *hwsrc, unsigned cnt,
+ unsigned *copied)
+{
+ void *src = hwsrc; //default to the standard destination buffer addr
+
+ CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
+ "cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=0x%.8x\n",
+ s->prop_adc.fmt,
+ s->prop_adc.fmt_original,
+ (unsigned) cnt, (unsigned) dest));
+
+ if (cnt > s->dma_adc.dmasize) {
+ cnt = s->dma_adc.dmasize;
+ }
+ if (!cnt) {
+ *copied = 0;
+ return 0;
+ }
+ if (s->conversion) {
+ if (!s->tmpbuff) {
+ *copied = cnt / 2;
+ return 0;
+ }
+ CopySamples(s->tmpbuff, (void *) hwsrc, cnt,
+ (unsigned) s->prop_adc.channels,
+ s->prop_adc.fmt_original);
+ src = s->tmpbuff;
+ cnt = cnt / 2;
+ }
+
+ if (copy_to_user(dest, src, cnt)) {
+ *copied = 0;
+ return -EFAULT;
+ }
+ *copied = cnt;
+ CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
+ "cs4281: cs_copy_to_user()- copied bytes is %d \n",
+ cnt));
+ return 0;
+}
// ---------------------------------------------------------------------
-static ssize_t cs4281_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t cs4281_read(struct file *file, char *buffer, size_t count,
+ loff_t * ppos)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
+ unsigned copied = 0;
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()+ \n") );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+ printk(KERN_INFO "cs4281: cs4281_read()+ %d \n", count));
VALIDATE_STATE(s);
if (ppos != &file->f_pos)
@@ -1568,52 +2312,115 @@ static ssize_t cs4281_read(struct file *file, char *buffer, size_t count, loff_t
if (!access_ok(VERIFY_WRITE, buffer, count))
return -EFAULT;
ret = 0;
+//
+// "count" is the amount of bytes to read (from app), is decremented each loop
+// by the amount of bytes that have been returned to the user buffer.
+// "cnt" is the running total of each read from the buffer (changes each loop)
+// "buffer" points to the app's buffer
+// "ret" keeps a running total of the amount of bytes that have been copied
+// to the user buffer.
+// "copied" is the total bytes copied into the user buffer for each loop.
+//
while (count > 0) {
+ CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
+ "_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n",
+ count, s->dma_adc.count,
+ s->dma_adc.swptr,
+ s->dma_adc.hwptr));
spin_lock_irqsave(&s->lock, flags);
+
+ // get the current copy point of the sw buffer
swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
+
+ // cnt is the amount of unread bytes from the end of the
+ // hw buffer to the current sw pointer
+ cnt = s->dma_adc.dmasize - swptr;
+
+ // dma_adc.count is the current total bytes that have not been read.
+ // if the amount of unread bytes from the current sw pointer to the
+ // end of the buffer is greater than the current total bytes that
+ // have not been read, then set the "cnt" (unread bytes) to the
+ // amount of unread bytes.
+
if (s->dma_adc.count < cnt)
cnt = s->dma_adc.count;
spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
+ //
+ // if we are converting from 8/16 then we need to copy
+ // twice the number of 16 bit bytes then 8 bit bytes.
+ //
+ if (s->conversion) {
+ if (cnt > (count * 2))
+ cnt = (count * 2);
+ } else {
+ if (cnt > count)
+ cnt = count;
+ }
+ //
+ // "cnt" NOW is the smaller of the amount that will be read,
+ // and the amount that is requested in this read (or partial).
+ // if there are no bytes in the buffer to read, then start the
+ // ADC and wait for the interrupt handler to wake us up.
+ //
if (cnt <= 0) {
+
+ // start up the dma engine and then continue back to the top of
+ // the loop when wake up occurs.
start_adc(s);
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
interruptible_sleep_on(&s->dma_adc.wait);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
}
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt))
+ // there are bytes in the buffer to read.
+ // copy from the hw buffer over to the user buffer.
+ // user buffer is designated by "buffer"
+ // virtual address to copy from is rawbuf+swptr
+ // the "cnt" is the number of bytes to read.
+
+ CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
+ "_read() copy_to cnt=%d count=%d ",
+ cnt, count));
+ CS_DBGOUT(CS_WAVE_READ, 8,
+ printk(KERN_INFO
+ " .dmasize=%d .count=%d buffer=0x%.8x ret=%d\n",
+ s->dma_adc.dmasize, s->dma_adc.count,
+ (unsigned) buffer, ret));
+
+ if (cs_copy_to_user
+ (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
return ret ? ret : -EFAULT;
swptr = (swptr + cnt) % s->dma_adc.dmasize;
spin_lock_irqsave(&s->lock, flags);
s->dma_adc.swptr = swptr;
s->dma_adc.count -= cnt;
spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
+ count -= copied;
+ buffer += copied;
+ ret += copied;
start_adc(s);
}
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()- %d\n",ret) );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
+ printk(KERN_INFO "cs4281: cs4281_read()- %d\n", ret));
return ret;
}
-static ssize_t cs4281_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t cs4281_write(struct file *file, const char *buffer,
+ size_t count, loff_t * ppos)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
ssize_t ret;
unsigned long flags;
unsigned swptr;
int cnt;
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()+ \n") );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+ printk(KERN_INFO "cs4281: cs4281_write()+ count=%d\n",
+ count));
VALIDATE_STATE(s);
if (ppos != &file->f_pos)
@@ -1632,13 +2439,14 @@ static ssize_t cs4281_write(struct file *file, const char *buffer, size_t count,
s->dma_dac.swptr = s->dma_dac.hwptr;
}
swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
+ cnt = s->dma_dac.dmasize - swptr;
if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
cnt = s->dma_dac.dmasize - s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
if (cnt > count)
cnt = count;
if (cnt <= 0) {
+
start_dac(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
@@ -1660,61 +2468,79 @@ static ssize_t cs4281_write(struct file *file, const char *buffer, size_t count,
ret += cnt;
start_dac(s);
}
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()- %d\n",ret) );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
+ printk(KERN_INFO "cs4281: cs4281_write()- %d\n", ret));
return ret;
}
-static unsigned int cs4281_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int cs4281_poll(struct file *file,
+ struct poll_table_struct *wait)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
unsigned long flags;
unsigned int mask = 0;
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()+\n") );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO "cs4281: cs4281_poll()+\n"));
VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
+ if (file->f_mode & FMODE_WRITE) {
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
+ }
+ if (file->f_mode & FMODE_READ) {
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_poll() wait on FMODE_READ\n"));
poll_wait(file, &s->dma_adc.wait, wait);
+ }
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- } else {
- if (s->dma_adc.count > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- }
if (file->f_mode & FMODE_WRITE) {
if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
+ if (s->dma_dac.count >=
+ (signed) s->dma_dac.fragsize) {
+ if (s->dma_dac.wakeup)
+ mask |= POLLOUT | POLLWRNORM;
+ else
+ mask = 0;
+ s->dma_dac.wakeup = 0;
+ }
} else {
- if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+ if ((signed) s->dma_dac.dmasize > s->dma_dac.count)
mask |= POLLOUT | POLLWRNORM;
}
+ } else if (file->f_mode & FMODE_READ) {
+ if (s->dma_adc.mapped) {
+ if (s->dma_adc.count >=
+ (signed) s->dma_adc.fragsize) mask |=
+ POLLIN | POLLRDNORM;
+ } else {
+ if (s->dma_adc.count > 0)
+ mask |= POLLIN | POLLRDNORM;
+ }
}
spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",mask) );
+ CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
+ printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",
+ mask));
return mask;
}
static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
struct dmabuf *db;
int ret;
unsigned long size;
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()+\n") );
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+ printk(KERN_INFO "cs4281: cs4281_mmap()+\n"));
VALIDATE_STATE(s);
if (vma->vm_flags & VM_WRITE) {
@@ -1727,131 +2553,253 @@ static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
db = &s->dma_adc;
} else
return -EINVAL;
+//
+// only support PLAYBACK for now
+//
+ db = &s->dma_dac;
+
if (vma->vm_pgoff != 0)
return -EINVAL;
size = vma->vm_end - vma->vm_start;
if (size > (PAGE_SIZE << db->buforder))
return -EINVAL;
- if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
- return -EAGAIN;
+ if (remap_page_range
+ (vma->vm_start, virt_to_phys(db->rawbuf), size,
+ vma->vm_page_prot)) return -EAGAIN;
db->mapped = 1;
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
- (unsigned)size) );
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
+ printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
+ (unsigned) size));
return 0;
}
-static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int cs4281_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
int val, mapped, ret;
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs4281: cs4281_ioctl(): file=0x%.8x cmd=0x%.8x\n",
- (unsigned)file,cmd) );
+
+ CS_DBGOUT(CS_FUNCTION, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): file=0x%.8x cmd=0x%.8x\n",
+ (unsigned) file, cmd));
+#if CSDEBUG
+ printioctl(cmd);
+#endif
VALIDATE_STATE(s);
mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+ ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
switch (cmd) {
case OSS_GETVERSION:
- CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n", SOUND_VERSION) );
- return put_user(SOUND_VERSION, (int *)arg);
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n",
+ SOUND_VERSION));
+ return put_user(SOUND_VERSION, (int *) arg);
case SNDCTL_DSP_SYNC:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_SYNC\n"));
if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
+ return drain_dac(s,
+ 0 /*file->f_flags & O_NONBLOCK */
+ );
return 0;
case SNDCTL_DSP_SETDUPLEX:
return 0;
case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+ DSP_CAP_TRIGGER | DSP_CAP_MMAP,
+ (int *) arg);
case SNDCTL_DSP_RESET:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_RESET\n"));
if (file->f_mode & FMODE_WRITE) {
stop_dac(s);
synchronize_irq();
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count =
- s->dma_dac.total_bytes = s->dma_dac.blocks = 0;
+ s->dma_dac.swptr = s->dma_dac.hwptr =
+ s->dma_dac.count = s->dma_dac.total_bytes =
+ s->dma_dac.blocks = s->dma_dac.wakeup = 0;
+ prog_codec(s, CS_TYPE_DAC);
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
synchronize_irq();
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count =
- s->dma_adc.total_bytes = s->dma_adc.blocks = 0;
+ s->dma_adc.swptr = s->dma_adc.hwptr =
+ s->dma_adc.count = s->dma_adc.total_bytes =
+ s->dma_adc.blocks = s->dma_dac.wakeup = 0;
+ prog_codec(s, CS_TYPE_ADC);
}
- prog_codec(s);
return 0;
case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
- if (val >= 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- // program sampling rates
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- s->rate = val;
- prog_codec(s);
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n",
+ val));
+ //
+ // support independent capture and playback channels
+ // assume that the file mode bit determines the
+ // direction of the data flow.
+ //
+ if (file->f_mode & FMODE_READ) {
+ if (val >= 0) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ // program sampling rates
+ if (val > 48000)
+ val = 48000;
+ if (val < 6300)
+ val = 6300;
+ s->prop_adc.rate = val;
+ prog_codec(s, CS_TYPE_ADC);
+ }
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val >= 0) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ // program sampling rates
+ if (val > 48000)
+ val = 48000;
+ if (val < 6300)
+ val = 6300;
+ s->prop_dac.rate = val;
+ prog_codec(s, CS_TYPE_DAC);
+ }
}
- return put_user(s->rate, (int *)arg);
+
+ if (file->f_mode & FMODE_WRITE)
+ val = s->prop_dac.rate;
+ else if (file->f_mode & FMODE_READ)
+ val = s->prop_adc.rate;
+
+ return put_user(val, (int *) arg);
case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- // program channels
- s->channels = val ? 2 : 1;
- prog_codec(s);
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n",
+ val));
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ s->prop_adc.channels = val ? 2 : 1;
+ prog_codec(s, CS_TYPE_ADC);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ s->prop_dac.channels = val ? 2 : 1;
+ prog_codec(s, CS_TYPE_DAC);
+ }
return 0;
case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n",
+ val));
if (val != 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- // program channels
- s->channels = val ? 2 : 1;
- prog_codec(s);
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val >= 2)
+ s->prop_adc.channels = 2;
+ else
+ s->prop_adc.channels = 1;
+ prog_codec(s, CS_TYPE_ADC);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val >= 2)
+ s->prop_dac.channels = 2;
+ else
+ s->prop_dac.channels = 1;
+ prog_codec(s, CS_TYPE_DAC);
+ }
}
- return put_user(s->channels, (int *)arg);
-
- case SNDCTL_DSP_GETFMTS: // Returns a mask
- return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
- case SNDCTL_DSP_SETFMT: // Selects ONE fmt
- if (get_user(val, (int *)arg))
+ if (file->f_mode & FMODE_WRITE)
+ val = s->prop_dac.channels;
+ else if (file->f_mode & FMODE_READ)
+ val = s->prop_adc.channels;
+
+ return put_user(val, (int *) arg);
+
+ case SNDCTL_DSP_GETFMTS: // Returns a mask
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n",
+ AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
+ AFMT_U8));
+ return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
+ AFMT_U8, (int *) arg);
+
+ case SNDCTL_DSP_SETFMT:
+ if (get_user(val, (int *) arg))
return -EFAULT;
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n",
+ val));
if (val != AFMT_QUERY) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- // program format
- if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
- val != AFMT_S8 && val != AFMT_U8)
- val = AFMT_U8;
- s->fmt = val;
- prog_codec(s);
+ if (file->f_mode & FMODE_READ) {
+ stop_adc(s);
+ s->dma_adc.ready = 0;
+ if (val != AFMT_S16_LE
+ && val != AFMT_U16_LE && val != AFMT_S8
+ && val != AFMT_U8)
+ val = AFMT_U8;
+ s->prop_adc.fmt = val;
+ s->prop_adc.fmt_original = s->prop_adc.fmt;
+ prog_codec(s, CS_TYPE_ADC);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ stop_dac(s);
+ s->dma_dac.ready = 0;
+ if (val != AFMT_S16_LE
+ && val != AFMT_U16_LE && val != AFMT_S8
+ && val != AFMT_U8)
+ val = AFMT_U8;
+ s->prop_dac.fmt = val;
+ s->prop_dac.fmt_original = s->prop_dac.fmt;
+ prog_codec(s, CS_TYPE_DAC);
+ }
+ } else {
+ if (file->f_mode & FMODE_WRITE)
+ val = s->prop_dac.fmt_original;
+ else if (file->f_mode & FMODE_READ)
+ val = s->prop_adc.fmt_original;
}
- return put_user(s->fmt, (int *)arg);
+ CS_DBGOUT(CS_IOCTL | CS_PARMS, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n",
+ val));
+ return put_user(val, (int *) arg);
case SNDCTL_DSP_POST:
+ CS_DBGOUT(CS_IOCTL, 4,
+ printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): DSP_POST\n"));
return 0;
case SNDCTL_DSP_GETTRIGGER:
@@ -1860,14 +2808,15 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
val |= PCM_ENABLE_INPUT;
if (file->f_mode & s->ena & FMODE_WRITE)
val |= PCM_ENABLE_OUTPUT;
- return put_user(val, (int *)arg);
+ return put_user(val, (int *) arg);
case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ if (!s->dma_adc.ready
+ && (ret = prog_dmabuf_adc(s)))
return ret;
start_adc(s);
} else
@@ -1875,7 +2824,8 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
if (file->f_mode & FMODE_WRITE) {
if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ if (!s->dma_dac.ready
+ && (ret = prog_dmabuf_dac(s)))
return ret;
start_dac(s);
} else
@@ -1886,30 +2836,55 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+ if (!(s->ena & FMODE_WRITE)
+ && (val = prog_dmabuf_dac(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ if (s->dma_dac.mapped)
+ abinfo.bytes = s->dma_dac.dmasize;
+ else
+ abinfo.bytes =
+ s->dma_dac.dmasize - s->dma_dac.count;
abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+ CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
+ "cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n",
+ abinfo.
+ fragsize,
+ abinfo.bytes,
+ abinfo.
+ fragstotal,
+ abinfo.
+ fragments));
spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ return copy_to_user((void *) arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
- return val;
+ if (!(s->ena & FMODE_READ)
+ && (val = prog_dmabuf_adc(s)) != 0) return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
+ if (s->conversion) {
+ abinfo.fragsize = s->dma_adc.fragsize / 2;
+ abinfo.bytes = s->dma_adc.count / 2;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments =
+ abinfo.bytes >> (s->dma_adc.fragshift - 1);
+ } else {
+ abinfo.fragsize = s->dma_adc.fragsize;
+ abinfo.bytes = s->dma_adc.count;
+ abinfo.fragstotal = s->dma_adc.numfrag;
+ abinfo.fragments =
+ abinfo.bytes >> s->dma_adc.fragshift;
+ }
spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+ return copy_to_user((void *) arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
case SNDCTL_DSP_NONBLOCK:
file->f_flags |= O_NONBLOCK;
@@ -1922,7 +2897,7 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
cs4281_update_ptr(s);
val = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ return put_user(val, (int *) arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
@@ -1930,12 +2905,30 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
+ if (s->dma_adc.mapped) {
+ cinfo.blocks =
+ (cinfo.bytes >> s->dma_adc.fragshift) -
+ s->dma_adc.blocks;
+ s->dma_adc.blocks =
+ cinfo.bytes >> s->dma_adc.fragshift;
+ } else {
+ if (s->conversion) {
+ cinfo.blocks =
+ s->dma_adc.count /
+ 2 >> (s->dma_adc.fragshift - 1);
+ } else
+ cinfo.blocks =
+ s->dma_adc.count >> s->dma_adc.
+ fragshift;
+ }
+ if (s->conversion)
+ cinfo.ptr = s->dma_adc.hwptr / 2;
+ else
+ cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
+ s->dma_adc.count &= s->dma_adc.fragsize - 1;
spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
@@ -1943,65 +2936,107 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
- if (s->dma_dac.mapped)
- {
- cinfo.blocks = (cinfo.bytes >> s->dma_dac.fragshift)
- - s->dma_adc.blocks;
- s->dma_dac.blocks = cinfo.bytes >> s->dma_dac.fragshift;
- }
- else
- {
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ if (s->dma_dac.mapped) {
+ cinfo.blocks =
+ (cinfo.bytes >> s->dma_dac.fragshift) -
+ s->dma_dac.blocks;
+ s->dma_dac.blocks =
+ cinfo.bytes >> s->dma_dac.fragshift;
+ } else {
+ cinfo.blocks =
+ s->dma_dac.count >> s->dma_dac.fragshift;
}
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
+ s->dma_dac.count &= s->dma_dac.fragsize - 1;
spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+ return copy_to_user((void *) arg, &cinfo, sizeof(cinfo));
case SNDCTL_DSP_GETBLKSIZE:
if (file->f_mode & FMODE_WRITE) {
if ((val = prog_dmabuf_dac(s)))
return val;
- return put_user(s->dma_dac.fragsize, (int *)arg);
+ return put_user(s->dma_dac.fragsize, (int *) arg);
}
if ((val = prog_dmabuf_adc(s)))
return val;
- return put_user(s->dma_adc.fragsize, (int *)arg);
+ if (s->conversion)
+ return put_user(s->dma_adc.fragsize / 2,
+ (int *) arg);
+ else
+ return put_user(s->dma_adc.fragsize, (int *) arg);
case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *)arg))
+ if (get_user(val, (int *) arg))
return -EFAULT;
- return 0; // Say OK, but do nothing.
+ return 0; // Say OK, but do nothing.
case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, (int *)arg))
+ if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision)
+ || (file->f_mode & FMODE_WRITE
+ && s->dma_dac.subdivision)) return -EINVAL;
+ if (get_user(val, (int *) arg))
return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
+ else if (file->f_mode & FMODE_WRITE)
s->dma_dac.subdivision = val;
return 0;
case SOUND_PCM_READ_RATE:
- return put_user(s->rate, (int *)arg);
+ if (file->f_mode & FMODE_READ)
+ return put_user(s->prop_adc.rate, (int *) arg);
+ else if (file->f_mode & FMODE_WRITE)
+ return put_user(s->prop_dac.rate, (int *) arg);
case SOUND_PCM_READ_CHANNELS:
- return put_user(s->channels, (int *)arg);
+ if (file->f_mode & FMODE_READ)
+ return put_user(s->prop_adc.channels, (int *) arg);
+ else if (file->f_mode & FMODE_WRITE)
+ return put_user(s->prop_dac.channels, (int *) arg);
case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg);
+ if (file->f_mode & FMODE_READ)
+ return
+ put_user(
+ (s->prop_adc.
+ fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
+ (int *) arg);
+ else if (file->f_mode & FMODE_WRITE)
+ return
+ put_user(
+ (s->prop_dac.
+ fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
+ (int *) arg);
case SOUND_PCM_WRITE_FILTER:
case SNDCTL_DSP_SETSYNCRO:
case SOUND_PCM_READ_FILTER:
return -EINVAL;
+#if CSDEBUG_INTERFACE
+
+ case SNDCTL_DSP_CS_GETDBGMASK:
+ return put_user(cs_debugmask, (unsigned long *) arg);
+
+ case SNDCTL_DSP_CS_GETDBGLEVEL:
+ return put_user(cs_debuglevel, (unsigned long *) arg);
+
+ case SNDCTL_DSP_CS_SETDBGMASK:
+ if (get_user(val, (unsigned long *) arg))
+ return -EFAULT;
+ cs_debugmask = val;
+ return 0;
+
+ case SNDCTL_DSP_CS_SETDBGLEVEL:
+ if (get_user(val, (unsigned long *) arg))
+ return -EFAULT;
+ cs_debuglevel = val;
+ return 0;
+#endif
+
}
return mixer_ioctl(s, cmd, arg);
}
@@ -2009,29 +3044,36 @@ static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd
static int cs4281_release(struct inode *inode, struct file *file)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
- printk(KERN_INFO "cs4281: cs4281_release(): inode=0x%.8x file=0x%.8x\n",
- (unsigned)inode,(unsigned)file) );
+ CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2,
+ printk(KERN_INFO
+ "cs4281: cs4281_release(): inode=0x%.8x file=0x%.8x f_mode=%d\n",
+ (unsigned) inode, (unsigned) file, file->f_mode));
VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- down(&s->open_sem);
if (file->f_mode & FMODE_WRITE) {
+ drain_dac(s, file->f_flags & O_NONBLOCK);
+ down(&s->open_sem_dac);
stop_dac(s);
- dealloc_dmabuf(s,&s->dma_dac);
+ dealloc_dmabuf(s, &s->dma_dac);
+ s->open_mode &= ~FMODE_WRITE;
+ up(&s->open_sem_dac);
+ wake_up(&s->open_wait_dac);
+ MOD_DEC_USE_COUNT;
}
if (file->f_mode & FMODE_READ) {
+ drain_adc(s, file->f_flags & O_NONBLOCK);
+ down(&s->open_sem_adc);
stop_adc(s);
- dealloc_dmabuf(s,&s->dma_adc);
+ dealloc_dmabuf(s, &s->dma_adc);
+ s->open_mode &= ~FMODE_READ;
+ up(&s->open_sem_adc);
+ wake_up(&s->open_wait_adc);
+ MOD_DEC_USE_COUNT;
}
- s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
- up(&s->open_sem);
- wake_up(&s->open_wait);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -2040,54 +3082,102 @@ static int cs4281_open(struct inode *inode, struct file *file)
int minor = MINOR(inode->i_rdev);
struct cs4281_state *s = devs;
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
- printk(KERN_INFO "cs4281: cs4281_open(): inode=0x%.8x file=0x%.8x\n",
- (unsigned)inode,(unsigned)file) );
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
+ printk(KERN_INFO
+ "cs4281: cs4281_open(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n",
+ (unsigned) inode, (unsigned) file, file->f_mode));
while (s && ((s->dev_audio ^ minor) & ~0xf))
s = s->next;
- if (!s)
- {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): ERROR unable to find audio state struct\n") );
+ if (!s) {
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
+ "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
return -ENODEV;
}
VALIDATE_STATE(s);
file->private_data = s;
-
- // wait for device to become free
- down(&s->open_sem);
- while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
- if (file->f_flags & O_NONBLOCK) {
- up(&s->open_sem);
- return -EBUSY;
+
+ // wait for device to become free
+ if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
+ printk(KERN_INFO
+ "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n"));
+ return -ENODEV;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ down(&s->open_sem_dac);
+ while (s->open_mode & FMODE_WRITE) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem_dac);
+ return -EBUSY;
+ }
+ up(&s->open_sem_dac);
+ interruptible_sleep_on(&s->open_wait_dac);
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem_dac);
}
- up(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- down(&s->open_sem);
}
- s->fmt = AFMT_U8;
- s->channels = 1;
- s->rate = 8000;
- s->clkdiv = 96 | 0x80;
- s->ena = s->endofbuffer = 0;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- up(&s->open_sem);
- MOD_INC_USE_COUNT;
+ if (file->f_mode & FMODE_READ) {
+ down(&s->open_sem_adc);
+ while (s->open_mode & FMODE_READ) {
+ if (file->f_flags & O_NONBLOCK) {
+ up(&s->open_sem_adc);
+ return -EBUSY;
+ }
+ up(&s->open_sem_adc);
+ interruptible_sleep_on(&s->open_wait_adc);
- if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) {
-
- printk(KERN_ERR "cs4281: Program dmabufs failed.\n");
- cs4281_release(inode, file);
-
- return -ENOMEM;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ down(&s->open_sem_adc);
+ }
+ }
+ s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ if (file->f_mode & FMODE_READ) {
+ s->prop_adc.fmt = AFMT_U8;
+ s->prop_adc.fmt_original = s->prop_adc.fmt;
+ s->prop_adc.channels = 1;
+ s->prop_adc.rate = 8000;
+ s->prop_adc.clkdiv = 96 | 0x80;
+ s->conversion = 0;
+ s->ena &= ~FMODE_READ;
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+ s->dma_adc.subdivision = 0;
+ up(&s->open_sem_adc);
+ MOD_INC_USE_COUNT;
+
+ if (prog_dmabuf_adc(s)) {
+ CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
+ "cs4281: adc Program dmabufs failed.\n"));
+ cs4281_release(inode, file);
+ return -ENOMEM;
+ }
+ prog_codec(s, CS_TYPE_ADC);
}
- prog_codec(s);
- CS_DBGOUT(CS_INIT | CS_FUNCTION | CS_OPEN, 2,
- printk(KERN_INFO "cs4281: cs4281_open()- 0\n") );
+ if (file->f_mode & FMODE_WRITE) {
+ s->prop_dac.fmt = AFMT_U8;
+ s->prop_dac.fmt_original = s->prop_dac.fmt;
+ s->prop_dac.channels = 1;
+ s->prop_dac.rate = 8000;
+ s->prop_dac.clkdiv = 96 | 0x80;
+ s->conversion = 0;
+ s->ena &= ~FMODE_WRITE;
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+ s->dma_dac.subdivision = 0;
+ up(&s->open_sem_dac);
+ MOD_INC_USE_COUNT;
+
+ if (prog_dmabuf_dac(s)) {
+ CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
+ "cs4281: dac Program dmabufs failed.\n"));
+ cs4281_release(inode, file);
+ return -ENOMEM;
+ }
+ prog_codec(s, CS_TYPE_DAC);
+ }
+ CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
+ printk(KERN_INFO "cs4281: cs4281_open()- 0\n"));
return 0;
}
@@ -2095,15 +3185,15 @@ static int cs4281_open(struct inode *inode, struct file *file)
// ******************************************************************************************
// Wave (audio) file operations struct.
// ******************************************************************************************
-static /*const*/ struct file_operations cs4281_audio_fops = {
- llseek: cs4281_llseek,
- read: cs4281_read,
- write: cs4281_write,
- poll: cs4281_poll,
- ioctl: cs4281_ioctl,
- mmap: cs4281_mmap,
- open: cs4281_open,
- release: cs4281_release,
+static /*const */ struct file_operations cs4281_audio_fops = {
+ llseek:cs4281_llseek,
+ read:cs4281_read,
+ write:cs4281_write,
+ poll:cs4281_poll,
+ ioctl:cs4281_ioctl,
+ mmap:cs4281_mmap,
+ open:cs4281_open,
+ release:cs4281_release,
};
// ---------------------------------------------------------------------
@@ -2116,8 +3206,8 @@ static void cs4281_handle_midi(struct cs4281_state *s)
unsigned temp1;
wake = 0;
- while (!(readl(s->pBA0+ BA0_MIDSR) & 0x80)) {
- ch = readl(s->pBA0+BA0_MIDRP);
+ while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) {
+ ch = readl(s->pBA0 + BA0_MIDRP);
if (s->midi.icnt < MIDIINBUF) {
s->midi.ibuf[s->midi.iwr] = ch;
s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
@@ -2128,12 +3218,12 @@ static void cs4281_handle_midi(struct cs4281_state *s)
if (wake)
wake_up(&s->midi.iwait);
wake = 0;
- while (!(readl(s->pBA0+ BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
- temp1 = ( s->midi.obuf[s->midi.ord] ) & 0x000000ff;
- writel(temp1, s->pBA0+BA0_MIDWP);
+ while (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
+ temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff;
+ writel(temp1, s->pBA0 + BA0_MIDWP);
s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF-16)
+ if (s->midi.ocnt < MIDIOUTBUF - 16)
wake = 1;
}
if (wake)
@@ -2144,48 +3234,32 @@ static void cs4281_handle_midi(struct cs4281_state *s)
static void cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- struct cs4281_state *s = (struct cs4281_state *)dev_id;
+ struct cs4281_state *s = (struct cs4281_state *) dev_id;
unsigned int temp1;
// fastpath out, to ease interrupt sharing
- temp1 = readl(s->pBA0+BA0_HISR); // Get Int Status reg.
+ temp1 = readl(s->pBA0 + BA0_HISR); // Get Int Status reg.
- CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
- "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n",temp1) );
+ CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
+ "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n",
+ temp1));
- if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) { // If not DMA or MIDI int,
- writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // reenable interrupts
- CS_DBGOUT(CS_INTERRUPT, 4, printk(KERN_INFO
- "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n") );
- return; // and return.
+ if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) { // If not DMA or MIDI int,
+ writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // reenable interrupts
+ CS_DBGOUT(CS_INTERRUPT, 4, printk(KERN_INFO
+ "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n"));
+ return; // and return.
}
-
- if(temp1 & HISR_DMA0) // If play interrupt,
- readl(s->pBA0+BA0_HDSR0); // clear the source.
- if(temp1 & HISR_DMA1) // Same for play.
- readl(s->pBA0+BA0_HDSR1);
- writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // Local EOI
-
+ if (temp1 & HISR_DMA0) // If play interrupt,
+ readl(s->pBA0 + BA0_HDSR0); // clear the source.
+
+ if (temp1 & HISR_DMA1) // Same for play.
+ readl(s->pBA0 + BA0_HDSR1);
+ writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Local EOI
+
spin_lock(&s->lock);
- //
- // ok, at this point we assume that the fifos have been filled
- // with silence and so we now turn off the DMA engine.
- // if FMODE_WRITE is set that means that some thread
- // attempted to start_dac, which probably means that an open
- // occurred, so do not stop the dac in this case.
- //
- if(s->endofbuffer && !(s->ena & FMODE_WRITE))
- {
- CS_DBGOUT(CS_INTERRUPT, 2, printk(KERN_INFO
- "cs4281: cs4281_interrupt() stopping play DMA\n") );
- writel(temp1|DCRn_MSK, s->pBA0+BA0_DCR0); // Stop Play DMA
- s->endofbuffer = 0;
- }
- else
- {
- cs4281_update_ptr(s);
- }
+ cs4281_update_ptr(s);
cs4281_handle_midi(s);
spin_unlock(&s->lock);
}
@@ -2194,22 +3268,24 @@ static void cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void cs4281_midi_timer(unsigned long data)
{
- struct cs4281_state *s = (struct cs4281_state *)data;
+ struct cs4281_state *s = (struct cs4281_state *) data;
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
cs4281_handle_midi(s);
spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies+1;
+ s->midi.timer.expires = jiffies + 1;
add_timer(&s->midi.timer);
}
// ---------------------------------------------------------------------
-static ssize_t cs4281_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+static ssize_t cs4281_midi_read(struct file *file, char *buffer,
+ size_t count, loff_t * ppos)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
ssize_t ret;
unsigned long flags;
unsigned ptr;
@@ -2253,9 +3329,11 @@ static ssize_t cs4281_midi_read(struct file *file, char *buffer, size_t count, l
}
-static ssize_t cs4281_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+static ssize_t cs4281_midi_write(struct file *file, const char *buffer,
+ size_t count, loff_t * ppos)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
ssize_t ret;
unsigned long flags;
unsigned ptr;
@@ -2304,9 +3382,11 @@ static ssize_t cs4281_midi_write(struct file *file, const char *buffer, size_t c
}
-static unsigned int cs4281_midi_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int cs4281_midi_poll(struct file *file,
+ struct poll_table_struct *wait)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
unsigned long flags;
unsigned int mask = 0;
@@ -2333,7 +3413,7 @@ static int cs4281_midi_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
struct cs4281_state *s = devs;
- unsigned long flags,temp1;
+ unsigned long flags, temp1;
while (s && s->dev_midi != minor)
s = s->next;
if (!s)
@@ -2357,16 +3437,16 @@ static int cs4281_midi_open(struct inode *inode, struct file *file)
if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- writel(1, s->pBA0+BA0_MIDCR); // Reset the interface.
- writel(0, s->pBA0+BA0_MIDCR); // Return to normal mode.
+ writel(1, s->pBA0 + BA0_MIDCR); // Reset the interface.
+ writel(0, s->pBA0 + BA0_MIDCR); // Return to normal mode.
s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- writel(0x0000000f, s->pBA0+BA0_MIDCR); // Enable transmit, record, ints.
- temp1 = readl(s->pBA0+BA0_HIMR);
- writel(temp1 & 0xffbfffff, s->pBA0+BA0_HIMR); // Enable midi int. recognition.
- writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts
+ writel(0x0000000f, s->pBA0 + BA0_MIDCR); // Enable transmit, record, ints.
+ temp1 = readl(s->pBA0 + BA0_HIMR);
+ writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR); // Enable midi int. recognition.
+ writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts
init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies+1;
- s->midi.timer.data = (unsigned long)s;
+ s->midi.timer.expires = jiffies + 1;
+ s->midi.timer.data = (unsigned long) s;
s->midi.timer.function = cs4281_midi_timer;
add_timer(&s->midi.timer);
}
@@ -2377,7 +3457,10 @@ static int cs4281_midi_open(struct inode *inode, struct file *file)
s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
}
spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+ s->open_mode |=
+ (file->
+ f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ |
+ FMODE_MIDI_WRITE);
up(&s->open_sem);
MOD_INC_USE_COUNT;
return 0;
@@ -2386,7 +3469,8 @@ static int cs4281_midi_open(struct inode *inode, struct file *file)
static int cs4281_midi_release(struct inode *inode, struct file *file)
{
- struct cs4281_state *s = (struct cs4281_state *)file->private_data;
+ struct cs4281_state *s =
+ (struct cs4281_state *) file->private_data;
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
unsigned count, tmo;
@@ -2394,9 +3478,9 @@ static int cs4281_midi_release(struct inode *inode, struct file *file)
VALIDATE_STATE(s);
if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&s->midi.owait, &wait);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&s->lock, flags);
count = s->midi.ocnt;
spin_unlock_irqrestore(&s->lock, flags);
@@ -2411,16 +3495,19 @@ static int cs4281_midi_release(struct inode *inode, struct file *file)
}
tmo = (count * HZ) / 3100;
if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "cs4281: midi timed out??\n");
+ printk(KERN_DEBUG
+ "cs4281: midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
current->state = TASK_RUNNING;
}
down(&s->open_sem);
- s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+ s->open_mode &=
+ (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ |
+ FMODE_MIDI_WRITE);
spin_lock_irqsave(&s->lock, flags);
if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- writel(0, s->pBA0+BA0_MIDCR); // Disable Midi interrupts.
+ writel(0, s->pBA0 + BA0_MIDCR); // Disable Midi interrupts.
del_timer(&s->midi.timer);
}
spin_unlock_irqrestore(&s->lock, flags);
@@ -2433,20 +3520,20 @@ static int cs4281_midi_release(struct inode *inode, struct file *file)
// ******************************************************************************************
// Midi file operations struct.
// ******************************************************************************************
-static /*const*/ struct file_operations cs4281_midi_fops = {
- llseek: cs4281_llseek,
- read: cs4281_midi_read,
- write: cs4281_midi_write,
- poll: cs4281_midi_poll,
- open: cs4281_midi_open,
- release: cs4281_midi_release,
+static /*const */ struct file_operations cs4281_midi_fops = {
+ llseek:cs4281_llseek,
+ read:cs4281_midi_read,
+ write:cs4281_midi_write,
+ poll:cs4281_midi_poll,
+ open:cs4281_midi_open,
+ release:cs4281_midi_release,
};
// ---------------------------------------------------------------------
// maximum number of devices
-#define NR_DEVICE 8 // Only eight devices supported currently.
+#define NR_DEVICE 8 // Only eight devices supported currently.
// ---------------------------------------------------------------------
@@ -2454,127 +3541,144 @@ static struct initvol {
int mixch;
int vol;
} initvol[] __initdata = {
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_RECLEV, 0x0000 },
- { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x0000 }
+
+ {
+ SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
+ SOUND_MIXER_WRITE_PCM, 0x4040}, {
+ SOUND_MIXER_WRITE_SYNTH, 0x4040}, {
+ SOUND_MIXER_WRITE_CD, 0x4040}, {
+ SOUND_MIXER_WRITE_LINE, 0x4040}, {
+ SOUND_MIXER_WRITE_LINE1, 0x4040}, {
+ SOUND_MIXER_WRITE_RECLEV, 0x0000}, {
+ SOUND_MIXER_WRITE_SPEAKER, 0x4040}, {
+ SOUND_MIXER_WRITE_MIC, 0x0000}
};
-static int __devinit cs4281_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
+static int __devinit cs4281_probe(struct pci_dev *pcidev,
+ const struct pci_device_id *pciid)
{
struct cs4281_state *s;
dma_addr_t dma_mask;
mm_segment_t fs;
int i, val, index = 0;
unsigned int temp1, temp2;
-
- CS_DBGOUT(CS_INIT, 2, printk(KERN_INFO "cs4281: probe()+\n") );
+
+ CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
+ printk(KERN_INFO "cs4281: probe()+\n"));
if (!RSRCISMEMORYREGION(pcidev, 0) ||
- !RSRCISMEMORYREGION(pcidev, 1))
- {
+ !RSRCISMEMORYREGION(pcidev, 1)) {
CS_DBGOUT(CS_ERROR, 1,
- printk(KERN_ERR "cs4281: probe()- Memory region not assigned\n") );
+ printk(KERN_ERR
+ "cs4281: probe()- Memory region not assigned\n"));
return -1;
}
if (pcidev->irq == 0) {
CS_DBGOUT(CS_ERROR, 1,
- printk(KERN_ERR "cs4281: probe() IRQ not assigned\n") );
+ printk(KERN_ERR
+ "cs4281: probe() IRQ not assigned\n"));
return -1;
- }
+ }
if (!pci_dma_supported(pcidev, 0xffffffff)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n") );
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
return -1;
- }
- dma_mask = 0xffffffff; /* this enables playback and recording */
+ }
+ dma_mask = 0xffffffff; /* this enables playback and recording */
if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() no memory for state struct.\n") );
+ CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
+ "cs4281: probe() no memory for state struct.\n"));
return -1;
}
memset(s, 0, sizeof(struct cs4281_state));
init_waitqueue_head(&s->dma_adc.wait);
init_waitqueue_head(&s->dma_dac.wait);
init_waitqueue_head(&s->open_wait);
+ init_waitqueue_head(&s->open_wait_adc);
+ init_waitqueue_head(&s->open_wait_dac);
init_waitqueue_head(&s->midi.iwait);
init_waitqueue_head(&s->midi.owait);
init_MUTEX(&s->open_sem);
+ init_MUTEX(&s->open_sem_adc);
+ init_MUTEX(&s->open_sem_dac);
spin_lock_init(&s->lock);
s->pBA0phys = RSRCADDRESS(pcidev, 0);
s->pBA1phys = RSRCADDRESS(pcidev, 1);
- s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); // Convert phys
- s->pBA1 = ioremap_nocache(s->pBA1phys, 65536); // to linear.
- temp1 = readl(s->pBA0+ BA0_PCICFG00);
- temp2 = readl(s->pBA0+ BA0_PCICFG04);
-
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=0x%.8x pBA1=0x%.8x \n",
- (unsigned)temp1,(unsigned)temp2,(unsigned)s->pBA0,(unsigned)s->pBA1) );
-
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
- (unsigned)s->pBA0phys,(unsigned)s->pBA1phys) );
+ s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); // Convert phys
+ s->pBA1 = ioremap_nocache(s->pBA1phys, 65536); // to linear.
+ temp1 = readl(s->pBA0 + BA0_PCICFG00);
+ temp2 = readl(s->pBA0 + BA0_PCICFG04);
+
+ CS_DBGOUT(CS_INIT, 2,
+ printk(KERN_INFO
+ "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=0x%.8x pBA1=0x%.8x \n",
+ (unsigned) temp1, (unsigned) temp2,
+ (unsigned) s->pBA0, (unsigned) s->pBA1));
+
+ CS_DBGOUT(CS_INIT, 2,
+ printk(KERN_INFO
+ "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
+ (unsigned) s->pBA0phys, (unsigned) s->pBA1phys));
temp1 = cs4281_hw_init(s);
- if(temp1){
- CS_DBGOUT(CS_ERROR | CS_INIT, 1,
- printk(KERN_ERR "cs4281: cs4281_hw_init() failed. Skipping part.\n") );
+ if (temp1) {
+ CS_DBGOUT(CS_ERROR | CS_INIT, 1,
+ printk(KERN_ERR
+ "cs4281: cs4281_hw_init() failed. Skipping part.\n"));
return -1;
- }
+ }
s->magic = CS4281_MAGIC;
s->pcidev = pcidev;
s->irq = pcidev->irq;
- if (pci_enable_device(pcidev))
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: pci_enable_device() failed\n") );
+ if (pci_enable_device(pcidev)) {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR
+ "cs4281: pci_enable_device() failed\n"));
goto err_irq;
}
- if(request_irq(s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)){
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: irq %u in use\n", s->irq) );
+ if (request_irq
+ (s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)) {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR "cs4281: irq %u in use\n",
+ s->irq));
goto err_irq;
}
- if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) < 0)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: probe() register_sound_dsp() failed.\n") );
+ if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) <
+ 0) {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR
+ "cs4281: probe() register_sound_dsp() failed.\n"));
goto err_dev1;
}
- if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) < 0)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: probe() register_sound_mixer() failed.\n") );
+ if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) <
+ 0) {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR
+ "cs4281: probe() register_sound_mixer() failed.\n"));
goto err_dev2;
}
- if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: probe() register_sound_midi() failed.\n") );
+ if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) {
+ CS_DBGOUT(CS_INIT | CS_ERROR, 1,
+ printk(KERN_ERR
+ "cs4281: probe() register_sound_midi() failed.\n"));
goto err_dev3;
}
-
- pci_set_master(pcidev); // enable bus mastering
+
+ pci_set_master(pcidev); // enable bus mastering
fs = get_fs();
set_fs(KERNEL_DS);
val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
+ mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val);
+ for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) {
val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val);
}
- val = 1; // enable mic preamp
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
+ val = 1; // enable mic preamp
+ mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
set_fs(fs);
-
+
// queue it for later freeing
s->next = devs;
pcidev->driver_data = s;
@@ -2583,32 +3687,33 @@ static int __devinit cs4281_probe(struct pci_dev *pcidev, const struct pci_devic
index++;
return 0;
-err_dev3:
+ err_dev3:
unregister_sound_mixer(s->dev_mixer);
-err_dev2:
+ err_dev2:
unregister_sound_dsp(s->dev_audio);
-err_dev1:
+ err_dev1:
free_irq(s->irq, s);
-err_irq:
+ err_irq:
kfree(s);
- if (!devs)
- {
+ if (!devs) {
CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_INFO "cs4281: probe()- no device allocated\n") );
+ printk(KERN_INFO
+ "cs4281: probe()- no device allocated\n"));
return -ENODEV;
}
CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: probe()- device allocated successfully\n") );
+ printk(KERN_INFO
+ "cs4281: probe()- device allocated successfully\n"));
return 0;
-} // probe_cs4281
+} // probe_cs4281
// ---------------------------------------------------------------------
static void __devinit cs4281_remove(struct pci_dev *dev)
{
- struct cs4281_state *s = (struct cs4281_state *)dev->driver_data;
+ struct cs4281_state *s = (struct cs4281_state *) dev->driver_data;
// stop DMA controller
synchronize_irq();
free_irq(s->irq, s);
@@ -2616,44 +3721,51 @@ static void __devinit cs4281_remove(struct pci_dev *dev)
unregister_sound_mixer(s->dev_mixer);
unregister_sound_midi(s->dev_midi);
kfree(s);
- dev->driver_data = NULL;
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_remove(): remove successful\n") );
+ dev->driver_data = NULL;
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO
+ "cs4281: cs4281_remove(): remove successful\n"));
}
static struct pci_device_id id_table[] __devinitdata = {
- { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CRYSTAL_CS4281, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
+
+ {PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CRYSTAL_CS4281,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, id_table);
static struct pci_driver cs4281_driver = {
- name: "cs4281",
- id_table: id_table,
- probe: cs4281_probe,
- remove: cs4281_remove
+ name:"cs4281",
+ id_table:id_table,
+ probe:cs4281_probe,
+ remove:cs4281_remove
};
static int __init init_cs4281(void)
{
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()+ \n") );
- if (!pci_present()) /* No PCI bus in this machine! */
- {
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: init_cs4281()- no pci bus found\n") );
+
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: init_cs4281()+ \n"));
+ if (!pci_present()) { /* No PCI bus in this machine! */
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO
+ "cs4281: init_cs4281()- no pci bus found\n"));
return -ENODEV;
}
- printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " " __DATE__ "\n",
- CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION, CS4281_ARCH);
+ printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
+ __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
+ CS4281_ARCH);
if (!pci_register_driver(&cs4281_driver)) {
pci_unregister_driver(&cs4281_driver);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: init_cs4281()- unable to register pci device \n") );
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO
+ "cs4281: init_cs4281()- unable to register pci device \n"));
return -ENODEV;
}
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()- 0\n") );
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: init_cs4281()- 0\n"));
return 0;
}
@@ -2667,12 +3779,11 @@ MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
static void __exit cleanup_cs4281(void)
{
pci_unregister_driver(&cs4281_driver);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n") );
+ CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
+ printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n"));
}
// ---------------------------------------------------------------------
module_init(init_cs4281);
module_exit(cleanup_cs4281);
-
diff --git a/drivers/sound/cs461x_image.h b/drivers/sound/cs461x_image.h
index 6826aa9a6..36d3ed18f 100644
--- a/drivers/sound/cs461x_image.h
+++ b/drivers/sound/cs461x_image.h
@@ -1,4 +1,4 @@
-struct BA1struct BA1Struct = {
+struct BA1struct BA1Struct __initdata = {
{{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }},
{0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,
diff --git a/drivers/sound/cs46xx.c b/drivers/sound/cs46xx.c
index 765c1a643..a10f9d2c2 100644
--- a/drivers/sound/cs46xx.c
+++ b/drivers/sound/cs46xx.c
@@ -25,7 +25,9 @@
* Changes:
* 20000815 Updated driver to kernel 2.4, some cleanups/fixes
* Nils Faerber <nils@kernelconcepts.de>
- *
+ * 20001110 Added __initdata to BA1Struct in cs461x_image.h
+ * and three more __init here
+ * Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
*/
#include <linux/module.h>
@@ -1999,7 +2001,7 @@ static int __init cs_ac97_init(struct cs_card *card)
/* Boot the card
*/
-static void cs461x_download(struct cs_card *card, u32 *src, unsigned long offset, unsigned long len)
+static void __init cs461x_download(struct cs_card *card, u32 *src, unsigned long offset, unsigned long len)
{
unsigned long counter;
void *dst;
@@ -2024,7 +2026,7 @@ struct BA1struct {
#include "cs461x_image.h"
-static void cs461x_download_image(struct cs_card *card)
+static void __init cs461x_download_image(struct cs_card *card)
{
int idx;
unsigned long offset = 0;
@@ -2240,7 +2242,7 @@ static void cs461x_proc_stop(struct cs_card *card)
-static int cs_hardware_init(struct cs_card *card)
+static int __init cs_hardware_init(struct cs_card *card)
{
unsigned long end_time;
unsigned int tmp;
diff --git a/drivers/sound/dmasound/dmasound.h b/drivers/sound/dmasound/dmasound.h
index 6bce7b4f6..ff7995522 100644
--- a/drivers/sound/dmasound/dmasound.h
+++ b/drivers/sound/dmasound/dmasound.h
@@ -47,7 +47,6 @@
#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))
diff --git a/drivers/sound/dmasound/dmasound_atari.c b/drivers/sound/dmasound/dmasound_atari.c
index fd15eae0a..faf00d798 100644
--- a/drivers/sound/dmasound/dmasound_atari.c
+++ b/drivers/sound/dmasound/dmasound_atari.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/soundcard.h>
#include <linux/mm.h>
@@ -895,7 +896,7 @@ static void TTInit(void)
/* search a frequency that fits into the allowed error range */
idx = -1;
- for (i = 0; i < arraysize(freq); i++)
+ for (i = 0; i < ARRAY_SIZE(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.
*/
@@ -1021,7 +1022,7 @@ static void FalconInit(void)
/* search a frequency that fits into the allowed error range */
idx = -1;
- for (i = 0; i < arraysize(freq); i++)
+ for (i = 0; i < ARRAY_SIZE(freq); i++)
/* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
* be playable without expanding, but that now a kernel runtime
* option
diff --git a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c
index 21f54bdb1..5550ee2c9 100644
--- a/drivers/sound/dmasound/dmasound_core.c
+++ b/drivers/sound/dmasound/dmasound_core.c
@@ -936,6 +936,7 @@ static int sq_release(struct inode *inode, struct file *file)
static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg)
{
+ int val;
u_long fmt;
int data;
int size, nbufs;
@@ -1013,7 +1014,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
} else
size = write_sq.bufSize;
sq_setup(&write_sq, write_sq.numBufs, nbufs, size);
- return 0;
+ return IOCTL_OUT(arg,write_sq.bufSize | write_sq.numBufs << 16);
case SNDCTL_DSP_GETOSPACE:
info.fragments = write_sq.max_active - write_sq.count;
info.fragstotal = write_sq.max_active;
@@ -1022,6 +1023,9 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
+ case SNDCTL_DSP_GETCAPS:
+ val = 1; /* Revision level of this ioctl() */
+ return IOCTL_OUT(arg,val);
default:
return mixer_ioctl(inode, file, cmd, arg);
diff --git a/drivers/sound/emu10k1/emu_wrapper.h b/drivers/sound/emu10k1/emu_wrapper.h
index 3a9862832..16461fd01 100644
--- a/drivers/sound/emu10k1/emu_wrapper.h
+++ b/drivers/sound/emu10k1/emu_wrapper.h
@@ -1,8 +1,8 @@
#ifndef __EMU_WRAPPER_H
#define __EMU_WRAPPER_H
-#include <linux/wrapper.h>
+#define vma_get_pgoff(v) ((v)->vm_pgoff)
-#define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask))
+#define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask))
#endif
diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c
index f7ce193f0..699e79677 100644
--- a/drivers/sound/es1370.c
+++ b/drivers/sound/es1370.c
@@ -898,9 +898,9 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
}
if (cmd == OSS_GETVERSION)
return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
return put_user(s->mix.recsrc, (int *)arg);
@@ -937,7 +937,7 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a
return put_user(s->mix.vol[mixtable[i].volidx], (int *)arg);
}
}
- if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
return -EINVAL;
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c
index 08a892bc3..548ee0949 100644
--- a/drivers/sound/esssolo1.c
+++ b/drivers/sound/esssolo1.c
@@ -725,9 +725,9 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
}
if (cmd == OSS_GETVERSION)
return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
return put_user(mixer_src[read_mixer(s, 0x1c) & 7], (int *)arg);
@@ -756,7 +756,7 @@ static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long ar
return put_user(s->mix.vol[vidx-1], (int *)arg);
}
}
- if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
return -EINVAL;
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c
index 1705d0df2..6fb1ac762 100644
--- a/drivers/sound/gus_midi.c
+++ b/drivers/sound/gus_midi.c
@@ -9,7 +9,13 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added __init to gus_midi_init()
*/
+
+#include "linux/init.h"
#include "sound_config.h"
#include "gus.h"
@@ -199,7 +205,7 @@ static struct midi_operations gus_midi_operations =
buffer_status: gus_midi_buffer_status,
};
-void gus_midi_init(struct address_info *hw_config)
+void __init gus_midi_init(struct address_info *hw_config)
{
int dev = sound_alloc_mididev();
diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c
index 26853486e..30a5357a5 100644
--- a/drivers/sound/gus_wave.c
+++ b/drivers/sound/gus_wave.c
@@ -14,9 +14,10 @@
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
* Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
* usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
+ * Bartlomiej Zolnierkiewicz : added some __init/__exit
*/
-
+#include <linux/init.h>
#include <linux/config.h>
#define GUSPNP_AUTODETECT
@@ -853,7 +854,7 @@ static void gus_initialize(void)
}
-static void pnp_mem_init(void)
+static void __init pnp_mem_init(void)
{
#include "iwmem.h"
#define CHUNK_SIZE (256*1024)
@@ -1022,7 +1023,7 @@ static void pnp_mem_init(void)
gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
}
-int gus_wave_detect(int baseaddr)
+int __init gus_wave_detect(int baseaddr)
{
unsigned long i, max_mem = 1024L;
unsigned long loc;
@@ -2901,7 +2902,7 @@ static struct mixer_operations gus_mixer_operations =
ioctl: gus_default_mixer_ioctl
};
-static int gus_default_mixer_init(void)
+static int __init gus_default_mixer_init(void)
{
int n;
@@ -2926,7 +2927,7 @@ static int gus_default_mixer_init(void)
return n;
}
-void gus_wave_init(struct address_info *hw_config)
+void __init gus_wave_init(struct address_info *hw_config)
{
unsigned long flags;
unsigned char val;
@@ -3167,7 +3168,7 @@ void gus_wave_init(struct address_info *hw_config)
}
}
-void gus_wave_unload(struct address_info *hw_config)
+void __exit gus_wave_unload(struct address_info *hw_config)
{
#ifdef CONFIG_SOUND_GUSMAX
if (have_gus_max)
diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c
index 54b50bb1e..c4d2c50ce 100644
--- a/drivers/sound/i810_audio.c
+++ b/drivers/sound/i810_audio.c
@@ -14,6 +14,11 @@
* Analog Devices (A major AC97 codec maker)
* Intel Corp (you've probably heard of them already)
*
+ * AC97 clues and assistance provided by
+ * Analog Devices
+ * Zach 'Fufu' Brown
+ * Jeff Garzik
+ *
* 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
@@ -96,7 +101,7 @@
#endif
static int ftsodell=0;
-static int clocking=48000;
+static unsigned int clocking=48000;
#define ADC_RUNNING 1
@@ -377,7 +382,7 @@ static void i810_free_pcm_channel(struct i810_card *card, int channel)
static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u16 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
@@ -403,22 +408,18 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int ra
if(rate < 8000)
rate = 8000;
- /* Power down the DAC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
-
-// printk("DAC rate set to %d Returned %d\n",
-// rate, (int)rp);
-
- rate=(rp * 48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE))
+ {
+ /* Power down the DAC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate=(rate * 48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate);
@@ -431,7 +432,7 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int ra
static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u16 dacp, rp;
+ u32 dacp;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
@@ -457,30 +458,23 @@ static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int ra
if(rate < 8000)
rate = 8000;
-
- /* Power down the ADC */
- dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
-
- /* Load the rate and read the effective rate */
- i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
- rp=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
-
-// printk("ADC rate set to %d Returned %d\n",
-// rate, (int)rp);
-
- rate = (rp * 48000) / clocking;
-
- /* Power it back up */
- i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
-
+ if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE))
+ {
+ /* Power down the ADC */
+ dacp=i810_ac97_get(codec, AC97_POWER_CONTROL);
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
+ /* Load the rate and read the effective rate */
+ i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
+ rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
+ /* Power it back up */
+ i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+ }
+ rate = (rate * 48000) / clocking;
dmabuf->rate = rate;
#ifdef DEBUG
printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate);
#endif
-
return rate;
-
}
/* prepare channel attributes for playback */
@@ -1726,10 +1720,37 @@ static int __init i810_ac97_init(struct i810_card *card)
int ready_2nd = 0;
struct ac97_codec *codec;
u16 eid;
+ int i=0;
+ u32 reg;
- outl(0, card->iobase + GLOB_CNT);
- udelay(500);
- outl(1<<1, card->iobase + GLOB_CNT);
+ reg = inl(card->iobase + GLOB_CNT);
+
+ if((reg&2)==0) /* Cold required */
+ reg|=2;
+ else
+ reg|=4; /* Warm */
+
+ reg&=~8; /* ACLink on */
+ outl(reg , card->iobase + GLOB_CNT);
+
+ while(i<10)
+ {
+ if((inl(card->iobase+GLOB_CNT)&4)==0)
+ break;
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/20);
+ i++;
+ }
+ if(i==10)
+ {
+ printk(KERN_ERR "i810_audio: AC'97 reset failed.\n");
+ return 0;
+ }
+
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/5);
+
+ inw(card->ac97base);
for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c
index 84ca968df..8ed87ac38 100644
--- a/drivers/sound/ics2101.c
+++ b/drivers/sound/ics2101.c
@@ -12,7 +12,9 @@
*
*
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
*/
+#include <linux/init.h>
#include "sound_config.h"
#include <linux/ultrasound.h>
@@ -212,8 +214,7 @@ static struct mixer_operations ics2101_mixer_operations =
ioctl: ics2101_mixer_ioctl
};
-int
-ics2101_mixer_init(void)
+int __init ics2101_mixer_init(void)
{
int i;
int n;
diff --git a/drivers/sound/iwmem.h b/drivers/sound/iwmem.h
index b96d5ed1b..84745fbca 100644
--- a/drivers/sound/iwmem.h
+++ b/drivers/sound/iwmem.h
@@ -1,5 +1,5 @@
/*
- * sound/iwmem.c
+ * sound/iwmem.h
*
* DRAM size encoding table for AMD Interwave chip.
*/
@@ -9,12 +9,15 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * Bartlomiej Zolnierkiewicz : added __initdata to mem_decode
*/
#define K 1024
#define M (1024*K)
-static int mem_decode[][4] =
+static int mem_decode[][4] __initdata =
{
/* Bank0 Bank1 Bank2 Bank3 Encoding bits */
{256*K, 0, 0, 0}, /* 0 */
diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c
index c2cb30457..ca96b7f99 100644
--- a/drivers/sound/maestro.c
+++ b/drivers/sound/maestro.c
@@ -115,6 +115,8 @@
* themselves, but we'll see.
*
* History
+ * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * add __init to maestro_ac97_init() and maestro_install()
* (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
* move to 2.3 power management interface, which
* required hacking some suspend/resume/check paths
@@ -812,7 +814,7 @@ ac97_recmask_io(struct ess_card *card, int read, int mask)
* The PT101 setup is untested.
*/
-static u16 maestro_ac97_init(struct ess_card *card)
+static u16 __init maestro_ac97_init(struct ess_card *card)
{
u16 vend1, vend2, caps;
@@ -3290,7 +3292,7 @@ parse_power(struct ess_card *card, struct pci_dev *pcidev)
return card->power_regs ? 1 : 0;
}
-static int
+static int __init
maestro_install(struct pci_dev *pcidev, int card_type)
{
u32 n;
diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c
index d9226d406..54927b719 100644
--- a/drivers/sound/maui.c
+++ b/drivers/sound/maui.c
@@ -14,6 +14,8 @@
* Alan Cox General clean up, use kernel IRQ
* system
* Christoph Hellwig Adapted to module_init/module_exit
+ * Bartlomiej Zolnierkiewicz
+ * Added __init to download_code()
*
* Status:
* Andrew J. Kroll Tested 06/01/1999 with:
@@ -104,7 +106,7 @@ static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
irq_ok = 1;
}
-static int download_code(void)
+static int __init download_code(void)
{
int i, lines = 0;
int eol_seen = 0, done = 0;
diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c
index de587668a..e6bb002e0 100644
--- a/drivers/sound/mpu401.c
+++ b/drivers/sound/mpu401.c
@@ -13,6 +13,7 @@
*
* Thomas Sailer ioctl code reworked (vmalloc/vfree removed)
* Alan Cox modularisation, use normal request_irq, use dev_id
+ * Bartlomiej Zolnierkiewicz removed some __init to allow using many drivers
*/
#include <linux/module.h>
@@ -908,7 +909,7 @@ static struct midi_operations mpu401_midi_proto =
static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV];
-static void __init mpu401_chk_version(int n, struct mpu_config *devc)
+static void mpu401_chk_version(int n, struct mpu_config *devc)
{
int tmp;
unsigned long flags;
@@ -939,7 +940,7 @@ static void __init mpu401_chk_version(int n, struct mpu_config *devc)
restore_flags(flags);
}
-void __init attach_mpu401(struct address_info *hw_config, struct module *owner)
+void attach_mpu401(struct address_info *hw_config, struct module *owner)
{
unsigned long flags;
char revision_char;
@@ -1166,7 +1167,7 @@ static void set_uart_mode(int dev, struct mpu_config *devc, int arg)
}
-int __init probe_mpu401(struct address_info *hw_config)
+int probe_mpu401(struct address_info *hw_config)
{
int ok = 0;
struct mpu_config tmp_devc;
@@ -1662,7 +1663,7 @@ static void timer_ext_event(struct mpu_config *devc, int event, int parm)
}
}
-static int __init mpu_timer_init(int midi_dev)
+static int mpu_timer_init(int midi_dev)
{
struct mpu_config *devc;
int n;
@@ -1724,7 +1725,7 @@ static int __initdata irq = -1;
MODULE_PARM(irq, "i");
MODULE_PARM(io, "i");
-int init_mpu401(void)
+int __init init_mpu401(void)
{
/* Can be loaded either for module use or to provide functions
to others */
@@ -1739,7 +1740,7 @@ int init_mpu401(void)
return 0;
}
-void cleanup_mpu401(void)
+void __exit cleanup_mpu401(void)
{
if (io != -1 && irq != -1) {
/* Check for use by, for example, sscape driver */
diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c
index 43b42d0a5..2fd11df4b 100644
--- a/drivers/sound/msnd.c
+++ b/drivers/sound/msnd.c
@@ -57,7 +57,7 @@
static multisound_dev_t *devs[MSND_MAX_DEVS];
static int num_devs;
-int msnd_register(multisound_dev_t *dev)
+int __init msnd_register(multisound_dev_t *dev)
{
int i;
diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c
index 7b9b1cc29..305969ff0 100644
--- a/drivers/sound/msnd_pinnacle.c
+++ b/drivers/sound/msnd_pinnacle.c
@@ -1404,7 +1404,7 @@ static int __init attach_multisound(void)
}
#ifdef MODULE
-static void unload_multisound(void)
+static void __exit unload_multisound(void)
{
release_region(dev.io, dev.numio);
free_irq(dev.irq, &dev);
diff --git a/drivers/sound/nm256_audio.c b/drivers/sound/nm256_audio.c
index 27f432e17..3aaca0c1b 100644
--- a/drivers/sound/nm256_audio.c
+++ b/drivers/sound/nm256_audio.c
@@ -11,6 +11,10 @@
* This driver was written by someone who wishes to remain anonymous.
* It is in the public domain, so share and enjoy. Try to make a profit
* off of it; go on, I dare you.
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added some __init
*/
#define __NO_VERSION__
@@ -945,7 +949,7 @@ static struct ac97_mixer_value_list mixer_defaults[] = {
/* Installs the AC97 mixer into CARD. */
-static int
+static int __init
nm256_install_mixer (struct nm256_info *card)
{
int mixer;
@@ -989,7 +993,7 @@ nm256_full_reset (struct nm256_info *card)
* RAM.
*/
-static void
+static void __init
nm256_peek_for_sig (struct nm256_info *card)
{
u32 port1offset
@@ -1031,7 +1035,7 @@ nm256_peek_for_sig (struct nm256_info *card)
* VERSTR is a human-readable version string.
*/
-static int
+static int __init
nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
{
struct nm256_info *card;
@@ -1252,7 +1256,7 @@ handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
* the sound cards are.
*/
-int
+int __init
init_nm256(void)
{
struct pci_dev *pcidev = NULL;
diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c
index 979e2a8ec..66e36117e 100644
--- a/drivers/sound/pas2_midi.c
+++ b/drivers/sound/pas2_midi.c
@@ -9,8 +9,11 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Bartlomiej Zolnierkiewicz : Added __init to pas_init_mixer()
*/
+#include <linux/init.h>
#include "sound_config.h"
#include "pas2.h"
@@ -204,7 +207,7 @@ static struct midi_operations pas_midi_operations =
buffer_status: pas_buffer_status,
};
-void pas_midi_init(void)
+void __init pas_midi_init(void)
{
int dev = sound_alloc_mididev();
diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c
index 00cadcc93..fdc8ef1f7 100644
--- a/drivers/sound/pas2_mixer.c
+++ b/drivers/sound/pas2_mixer.c
@@ -14,7 +14,9 @@
*/
/*
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * Bartlomiej Zolnierkiewicz : added __init to pas_init_mixer()
*/
+#include <linux/init.h>
#include "sound_config.h"
#include "pas2.h"
@@ -315,7 +317,7 @@ static struct mixer_operations pas_mixer_operations =
ioctl: pas_mixer_ioctl
};
-int
+int __init
pas_init_mixer(void)
{
int d;
diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c
index 90d461ed0..50b53fa17 100644
--- a/drivers/sound/pas2_pcm.c
+++ b/drivers/sound/pas2_pcm.c
@@ -12,8 +12,10 @@
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
* Alan Cox : Swatted a double allocation of device bug. Made a few
* more things module options.
+ * Bartlomiej Zolnierkiewicz : Added __init to pas_pcm_init()
*/
+#include <linux/init.h>
#include "sound_config.h"
#include "pas2.h"
@@ -385,7 +387,7 @@ static struct audio_driver pas_audio_driver =
trigger: pas_audio_trigger
};
-void pas_pcm_init(struct address_info *hw_config)
+void __init pas_pcm_init(struct address_info *hw_config)
{
DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c
index cf30d7374..728fe8165 100644
--- a/drivers/sound/pss.c
+++ b/drivers/sound/pss.c
@@ -50,6 +50,8 @@
* setting is the previous hardcoded setting "/etc/sound/pss_synth".
* 00-03-03: Christoph Hellwig <chhellwig@gmx.net>
* Adapted to module_init/module_exit
+ * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added __init to probe_pss(), attach_pss() and probe_pss_mpu()
*/
@@ -168,7 +170,7 @@ static void pss_write(pss_confdata *devc, int data)
printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data);
}
-int probe_pss(struct address_info *hw_config)
+int __init probe_pss(struct address_info *hw_config)
{
unsigned short id;
int irq, dma;
@@ -644,7 +646,7 @@ void configure_nonsound_components(void)
}
}
-void attach_pss(struct address_info *hw_config)
+void __init attach_pss(struct address_info *hw_config)
{
unsigned short id;
char tmp[100];
@@ -693,7 +695,7 @@ void attach_pss(struct address_info *hw_config)
conf_printf(tmp, hw_config);
}
-int probe_pss_mpu(struct address_info *hw_config)
+int __init probe_pss_mpu(struct address_info *hw_config)
{
int timeout;
diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c
index ef0e4199c..9d16bbe9f 100644
--- a/drivers/sound/sgalaxy.c
+++ b/drivers/sound/sgalaxy.c
@@ -16,6 +16,10 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added __init to sb_rst() and sb_cmd()
*/
#include <linux/init.h>
@@ -40,7 +44,7 @@ static void sleep( unsigned howlong )
#define SBDSP_STATUS SBDSP_COMMAND
#define SBDSP_DATA_AVAIL 0xE
-static int sb_rst(int base)
+static int __init sb_rst(int base)
{
int i;
@@ -62,7 +66,7 @@ static int sb_rst(int base)
return 1;
}
-static int sb_cmd( int base, unsigned char val )
+static int __init sb_cmd( int base, unsigned char val )
{
int i;
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index 0aef3da29..8727e2a88 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -1073,9 +1073,9 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
return put_user(0, (int *)arg);
return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, (int *)arg);
}
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_SIOC_DIR(cmd) == _SIOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
return put_user(mixer_recmask(s), (int *)arg);
@@ -1114,7 +1114,7 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
}
}
- if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
return -EINVAL;
s->mix.modcnt++;
switch (_IOC_NR(cmd)) {
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 1c399bd5c..85e523cbd 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -14,6 +14,7 @@
* Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
* Sergey Smitienko : ensoniq p'n'p support
* Christoph Hellwig : adapted to module_init/module_exit
+ * Bartlomiej Zolnierkiewicz : added __init to attach_sscape()
*/
#include <linux/init.h>
@@ -609,7 +610,7 @@ static coproc_operations sscape_coproc_operations =
static int sscape_detected = 0;
static int sscape_is_pnp = 0;
-void attach_sscape(struct address_info *hw_config)
+void __init attach_sscape(struct address_info *hw_config)
{
#ifndef SSCAPE_REGS
/*
diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c
index b4db5bb5f..9e32811ac 100644
--- a/drivers/sound/trident.c
+++ b/drivers/sound/trident.c
@@ -31,6 +31,9 @@
*
* History
* v0.14.6
+ * Nov 1 2000 Ching-Ling Lee
+ * Fix the bug of memory leak when swithing 5.1-channels to 2 channels.
+ * Add lock protection into dynamic changing format of data.
* Oct 18 2000 Ching-Ling Lee
* 5.1-channels support for ALi
* June 28 2000 Ching-Ling Lee
@@ -142,7 +145,7 @@
/* minor number of /dev/swmodem (temporary, experimental) */
#define SND_DEV_SWMODEM 7
-static const unsigned ali_multi_channels[] = { ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL/*, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL*/};
+static const unsigned ali_multi_channels_5_1[] = { ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL};
static const unsigned sample_size[] = { 1, 2, 2, 4 };
static const unsigned sample_shift[] = { 0, 1, 1, 2 };
@@ -225,12 +228,14 @@ struct trident_state {
unsigned ossfragshift;
int ossmaxfrags;
unsigned subdivision;
+
} dmabuf;
/* 5.1channels */
struct trident_state *other_states[4];
int multi_channels_adjust_count;
unsigned chans_num;
+ unsigned fmt_flag:1;
};
/* hardware channels */
@@ -341,7 +346,6 @@ static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
static int ali_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data);
static void ali_restore_regs(struct trident_card *card);
static void ali_save_regs(struct trident_card *card);
-static int ali_allocate_multi_channels(struct trident_state *state, int chan_nums);
static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
static unsigned int ali_get_spdif_in_rate(struct trident_card *card);
@@ -349,7 +353,9 @@ static void ali_setup_spdif_in(struct trident_card *card);
static void ali_disable_spdif_in(struct trident_card *card);
static void ali_disable_special_channel(struct trident_card *card, int ch);
static void ali_setup_spdif_out(struct trident_card *card, int flag);
-static unsigned int ali_write_5_1(struct trident_state *state, const char *buffer,int cnt_for_multi_channel);
+static int ali_write_5_1(struct trident_state *state, const char *buffer,int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt);
+static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums);
+static void ali_free_other_states_resources(struct trident_state *state);
/* save registers for ALi Power Management */
@@ -359,9 +365,22 @@ static struct ali_saved_registers {
unsigned mixer_regs[ALI_MIXER_REGS];
} ali_registers;
-#define seek_offset(dma_ptr, buffer, cnt, offset) (dma_ptr) += (offset); \
+#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) (dma_ptr) += (offset); \
(buffer) += (offset); \
- (cnt) -= (offset);
+ (cnt) -= (offset); \
+ (copy_count) += (offset);
+
+#define lock_set_fmt(state) {spin_lock_irqsave(&state->card->lock, flags); \
+ if (state->fmt_flag) { \
+ spin_unlock_irqrestore(&state->card->lock, flags); \
+ return -EFAULT; \
+ } \
+ state->fmt_flag = 1; \
+ spin_unlock_irqrestore(&state->card->lock, flags);}
+
+#define unlock_set_fmt(state) {spin_lock_irqsave(&state->card->lock, flags); \
+ state->fmt_flag = 0; \
+ spin_unlock_irqrestore(&state->card->lock, flags);}
static int trident_enable_loop_interrupts(struct trident_card * card)
{
@@ -993,18 +1012,15 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
struct dmabuf *dmabuf = &state->dmabuf;
unsigned bytepersec;
struct trident_state *s = state;
- unsigned bufsize, dma_nums, default_order;
+ unsigned bufsize, dma_nums;
unsigned long flags;
int ret, i, order;
struct page *page, *pend;
- default_order = DMABUF_DEFAULTORDER;
- if (s->chans_num == 6) {
+ lock_set_fmt(state);
+ if (state->chans_num == 6)
dma_nums = 5;
- }
- else {
- dma_nums = 1;
- }
+ else dma_nums = 1;
for (i = 0; i < dma_nums; i++) {
if (i > 0) {
@@ -1022,8 +1038,10 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
/* allocate DMA buffer if not allocated yet */
if (!dmabuf->rawbuf) {
if (i == 0) {
- if ((ret = alloc_dmabuf(state)))
+ if ((ret = alloc_dmabuf(state))) {
+ unlock_set_fmt(state);
return ret;
+ }
}
else {
if ((order = state->dmabuf.buforder - 1) >= DMABUF_MINORDER)
@@ -1034,6 +1052,7 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
i-=2;
for (; i >= 0; i--)
free_pages((unsigned long)state->other_states[i]->dmabuf.rawbuf, state->other_states[i]->dmabuf.buforder);
+ unlock_set_fmt(state);
return -ENOMEM;
}
dmabuf->ready = dmabuf->mapped = 0;
@@ -1087,6 +1106,7 @@ static int prog_dmabuf(struct trident_state *state, unsigned rec)
dmabuf->fragsize, dmabuf->dmasize);
#endif
}
+ unlock_set_fmt(state);
return 0;
}
@@ -1451,6 +1471,7 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
unsigned swptr;
int cnt;
unsigned int state_cnt;
+ unsigned int copy_count;
#ifdef DEBUG
printk("trident: trident_write called, count = %d\n", count);
@@ -1493,8 +1514,10 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
}
/* No matter how much data left in the buffer, we have to wait untill
CSO == ESO/2 or CSO == ESO when address engine interrupts */
+ lock_set_fmt(state);
tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
tmo >>= sample_shift[dmabuf->fmt];
+ unlock_set_fmt(state);
/* There are two situations when sleep_on_timeout returns, one is when
the interrupt is serviced correctly and the process is waked up by
ISR ON TIME. Another is when timeout is expired, which means that
@@ -1518,17 +1541,34 @@ static ssize_t trident_write(struct file *file, const char *buffer, size_t count
}
continue;
}
-
+ lock_set_fmt(state);
if (state->chans_num == 6) {
- state_cnt = ali_write_5_1(state, buffer, cnt);
+ copy_count = 0;
+ state_cnt = 0;
+ if (ali_write_5_1(state, buffer, cnt, &copy_count, &state_cnt) == -EFAULT) {
+ if (state_cnt){
+ swptr = (swptr + state_cnt) % dmabuf->dmasize;
+ spin_lock_irqsave(&state->card->lock, flags);
+ dmabuf->swptr = swptr;
+ dmabuf->count += state_cnt;
+ dmabuf->endcleared = 0;
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ }
+ ret += copy_count;
+ if (!ret) ret = -EFAULT;
+ unlock_set_fmt(state);
+ return ret;
+ }
}
else {
if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
if (!ret) ret = -EFAULT;
+ unlock_set_fmt(state);
return ret;
}
state_cnt = cnt;
}
+ unlock_set_fmt(state);
swptr = (swptr + state_cnt) % dmabuf->dmasize;
@@ -1684,6 +1724,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
if (get_user(val, (int *)arg))
return -EFAULT;
+ lock_set_fmt(state);
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
dmabuf->ready = 0;
@@ -1700,6 +1741,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
else
dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
}
+ unlock_set_fmt(state);
return 0;
case SNDCTL_DSP_GETBLKSIZE:
@@ -1720,6 +1762,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
case SNDCTL_DSP_SETFMT: /* Select sample format */
if (get_user(val, (int *)arg))
return -EFAULT;
+ lock_set_fmt(state);
if (val != AFMT_QUERY) {
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
@@ -1738,6 +1781,7 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
}
}
+ unlock_set_fmt(state);
return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
AFMT_S16_LE : AFMT_U8, (int *)arg);
@@ -1745,40 +1789,49 @@ static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cm
if (get_user(val, (int *)arg))
return -EFAULT;
if (val != 0) {
+ lock_set_fmt(state);
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
dmabuf->ready = 0;
+
+ //prevent from memory leak
+ if ((state->chans_num > 2) && (state->chans_num != val)) {
+ ali_free_other_states_resources(state);
+ state->chans_num = 1;
+ }
+
if (val >= 2) {
dmabuf->fmt |= TRIDENT_FMT_STEREO;
- if (val == 6) {
- val = ali_setup_multi_channels(state->card, 6);
- if (val < 0)
- return val;
+ if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) {
+ ali_setup_multi_channels(state->card, 6);
down(&state->card->open_sem);
- val = ali_allocate_multi_channels(state, 6);
+ ret = ali_allocate_other_states_resources(state, 6);
up(&state->card->open_sem);
- if (val < 0)
- return val;
- val = 6;
+ if (ret < 0) {
+ unlock_set_fmt(state);
+ return ret;
+ }
}
- else val = 2;
+ else val = 2; /*yield to 2-channels*/
}
else
dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+ state->chans_num = val;
}
if (file->f_mode & FMODE_READ) {
stop_adc(state);
dmabuf->ready = 0;
if (val >= 2) {
- if (val!=6)
+ if (!((file->f_mode & FMODE_WRITE) && (val == 6)))
val = 2;
dmabuf->fmt |= TRIDENT_FMT_STEREO;
}
else
dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+ state->chans_num = val;
}
+ unlock_set_fmt(state);
}
- state->chans_num = val;
return put_user(val, (int *)arg);
case SNDCTL_DSP_POST:
@@ -2059,6 +2112,7 @@ static int trident_release(struct inode *inode, struct file *file)
struct trident_state *state = (struct trident_state *)file->private_data;
struct trident_card *card;
struct dmabuf *dmabuf;
+ unsigned long flags;
lock_kernel();
card = state->card;
@@ -2075,24 +2129,10 @@ static int trident_release(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE) {
stop_dac(state);
- if (state->chans_num == 6) {
- dealloc_dmabuf(state->other_states[0]);
- dealloc_dmabuf(state->other_states[1]);
- dealloc_dmabuf(state->other_states[2]);
- dealloc_dmabuf(state->other_states[3]);
- state->card->free_pcm_channel(state->card, state->other_states[0]->dmabuf.channel->num);
- state->card->free_pcm_channel(state->card, state->other_states[1]->dmabuf.channel->num);
- state->card->free_pcm_channel(state->card, state->other_states[2]->dmabuf.channel->num);
- state->card->free_pcm_channel(state->card, state->other_states[3]->dmabuf.channel->num);
- card->states[state->other_states[0]->virt] = NULL;
- kfree(state->other_states[0]);
- card->states[state->other_states[1]->virt] = NULL;
- kfree(state->other_states[1]);
- card->states[state->other_states[2]->virt] = NULL;
- kfree(state->other_states[2]);
- card->states[state->other_states[3]->virt] = NULL;
- kfree(state->other_states[3]);
- }
+ lock_set_fmt(state);
+ if (state->chans_num > 2)
+ ali_free_other_states_resources(state);
+ unlock_set_fmt(state);
dealloc_dmabuf(state);
state->card->free_pcm_channel(state->card, dmabuf->channel->num);
}
@@ -2495,11 +2535,10 @@ static unsigned int ali_get_spdif_in_rate(struct trident_card *card)
static int ali_setup_multi_channels(struct trident_card *card, int chan_nums)
{
unsigned long dwValue;
+
if (chan_nums == 6) {
dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
outl(dwValue, TRID_REG(card, ALI_SCTRL));
- dwValue = inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) | 0x07800000;
- outl(dwValue, TRID_REG(card, ALI_GLOBAL_CONTROL));
}
return 1;
}
@@ -2517,7 +2556,7 @@ static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel
card->banks[bank].bitmap &= ~(1 << (channel));
}
-static int ali_allocate_multi_channels(struct trident_state *state, int chan_nums)
+static int ali_allocate_other_states_resources(struct trident_state *state, int chan_nums)
{
struct trident_card *card = state->card;
struct trident_state *s;
@@ -2530,26 +2569,26 @@ static int ali_allocate_multi_channels(struct trident_state *state, int chan_num
if (chan_nums == 6) {
for(i = 0;(i < ALI_CHANNELS) && (state_count != 4); i++) {
if (!card->states[i]) {
- if (!(bank->bitmap & (1 << ali_multi_channels[state_count]))) {
- bank->bitmap |= (1 << ali_multi_channels[state_count]);
- channel = &bank->channels[ali_multi_channels[state_count]];
- channel->num = ali_multi_channels[state_count];
+ if (!(bank->bitmap & (1 << ali_multi_channels_5_1[state_count]))) {
+ bank->bitmap |= (1 << ali_multi_channels_5_1[state_count]);
+ channel = &bank->channels[ali_multi_channels_5_1[state_count]];
+ channel->num = ali_multi_channels_5_1[state_count];
}
else {
state_count--;
for (; state_count >= 0; state_count--) {
kfree(state->other_states[state_count]);
- ali_free_pcm_channel(card, ali_multi_channels[state_count]);
+ ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]);
}
return -EBUSY;
}
s = card->states[i] = (struct trident_state *)
kmalloc(sizeof(struct trident_state), GFP_KERNEL);
if (!s) {
- ali_free_pcm_channel(card, ali_multi_channels[state_count]);
+ ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]);
state_count--;
for (; state_count >= 0; state_count--) {
- ali_free_pcm_channel(card, ali_multi_channels[state_count]);
+ ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]);
kfree(state->other_states[state_count]);
}
return -ENOMEM;
@@ -2562,7 +2601,7 @@ static int ali_allocate_multi_channels(struct trident_state *state, int chan_num
s->magic = card->magic;
s->card = card;
s->virt = i;
-
+ ali_enable_special_channel(s);
state->other_states[state_count++] = s;
}
}
@@ -2571,7 +2610,7 @@ static int ali_allocate_multi_channels(struct trident_state *state, int chan_num
state_count--;
for (; state_count >= 0; state_count--) {
kfree(state->other_states[state_count]);
- ali_free_pcm_channel(card, ali_multi_channels[state_count]);
+ ali_free_pcm_channel(card, ali_multi_channels_5_1[state_count]);
}
return -EBUSY;
}
@@ -2791,32 +2830,34 @@ protection is no harm because all DMAs of multi-channels and interrupt
depend on a master state's DMA, and changing the counters of the master
state DMA is protected by a spinlock.
*/
-static unsigned int ali_write_5_1(struct trident_state *state, const char *buf, int cnt_for_multi_channel)
+static int ali_write_5_1(struct trident_state *state, const char *buf, int cnt_for_multi_channel, unsigned int *copy_count, unsigned int *state_cnt)
{
struct dmabuf *dmabuf = &state->dmabuf;
struct dmabuf *dmabuf_temp;
const char *buffer = buf;
unsigned swptr, other_dma_nums, sample_s;
- unsigned int i, loop, state_cnt = 0;
+ unsigned int i, loop;
other_dma_nums = 4;
sample_s = sample_size[dmabuf->fmt] >> 1;
swptr = dmabuf->swptr;
-
+
if ((i = state->multi_channels_adjust_count) > 0) {
if (i == 1) {
- copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s);
- seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
i--;
- state_cnt += sample_s;
+ (*state_cnt) += sample_s;
state->multi_channels_adjust_count++;
}
else i = i - (state->chans_num - other_dma_nums);
for (; (i < other_dma_nums) && (cnt_for_multi_channel > 0); i++) {
dmabuf_temp = &state->other_states[i]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
}
if (cnt_for_multi_channel == 0)
state->multi_channels_adjust_count += i;
@@ -2824,46 +2865,53 @@ static unsigned int ali_write_5_1(struct trident_state *state, const char *buf,
if (cnt_for_multi_channel > 0) {
loop = cnt_for_multi_channel / (state->chans_num * sample_s);
for (i = 0; i < loop; i++) {
- copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s * 2);
- seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s * 2);
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s * 2))
+ return -EFAULT;
+ seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s * 2, *copy_count);
+ (*state_cnt) += (sample_s * 2);
dmabuf_temp = &state->other_states[0]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
dmabuf_temp = &state->other_states[1]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
dmabuf_temp = &state->other_states[2]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
dmabuf_temp = &state->other_states[3]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
}
- state_cnt += (sample_s * 2 * loop);
-
if (cnt_for_multi_channel > 0) {
state->multi_channels_adjust_count = cnt_for_multi_channel / sample_s;
- copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s);
- seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s);
- state_cnt += sample_s;
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
+ (*state_cnt) += sample_s;
if (cnt_for_multi_channel > 0) {
- copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s);
- seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s);
- state_cnt += sample_s;
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
+ (*state_cnt) += sample_s;
if (cnt_for_multi_channel > 0) {
loop = state->multi_channels_adjust_count - (state->chans_num - other_dma_nums);
for (i = 0; i < loop; i++) {
dmabuf_temp = &state->other_states[i]->dmabuf;
- copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s);
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s);
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr, buffer, sample_s))
+ return -EFAULT;
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel, sample_s, *copy_count);
}
}
}
@@ -2875,7 +2923,25 @@ static unsigned int ali_write_5_1(struct trident_state *state, const char *buf,
dmabuf_temp = &state->other_states[i]->dmabuf;
dmabuf_temp->swptr = dmabuf_temp->swptr % dmabuf_temp->dmasize;
}
- return state_cnt;
+ return *state_cnt;
+}
+
+static void ali_free_other_states_resources(struct trident_state *state)
+{
+ int i;
+ struct trident_card *card = state->card;
+ struct trident_state *s;
+ unsigned other_states_count;
+
+ other_states_count = state->chans_num - 2; /* except PCM L/R channels*/
+ for ( i = 0; i < other_states_count; i++) {
+ s = state->other_states[i];
+ dealloc_dmabuf(s);
+ ali_disable_special_channel(s->card, s->dmabuf.channel->num);
+ state->card->free_pcm_channel(s->card, s->dmabuf.channel->num);
+ card->states[s->virt] = NULL;
+ kfree(s);
+ }
}
#ifdef CONFIG_PROC_FS
diff --git a/drivers/sound/vwsnd.c b/drivers/sound/vwsnd.c
index be2cdf678..b79ce2b32 100644
--- a/drivers/sound/vwsnd.c
+++ b/drivers/sound/vwsnd.c
@@ -135,6 +135,10 @@
* For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR
* the 0x80 bit in software to compensate for Lithium's XOR.
* This happens in pcm_copy_{in,out}().
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added some __init/__exit
*/
#include <linux/module.h>
@@ -1330,7 +1334,7 @@ static void ad1843_shutdown_adc(lithium_t *lith)
*
* return 0 on success, -errno on failure. */
-static int ad1843_init(lithium_t *lith)
+static int __init ad1843_init(lithium_t *lith)
{
unsigned long later;
int err;
@@ -1822,8 +1826,8 @@ static void pcm_shutdown_port(vwsnd_dev_t *devc,
aport->swstate = SW_INITIAL;
add_wait_queue(&aport->queue, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irqsave(&aport->lock, flags);
{
hwstate = aport->hwstate;
@@ -2192,8 +2196,8 @@ static void pcm_write_sync(vwsnd_dev_t *devc)
DBGEV("(devc=0x%p)\n", devc);
add_wait_queue(&wport->queue, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irqsave(&wport->lock, flags);
{
hwstate = wport->hwstate;
@@ -2280,9 +2284,9 @@ static ssize_t vwsnd_audio_do_read(struct file *file,
while (count) {
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&rport->queue, &wait);
- current->state = TASK_INTERRUPTIBLE;
while ((nb = swb_inc_u(rport, 0)) == 0) {
DBGPV("blocking\n");
+ set_current_state(TASK_INTERRUPTIBLE);
if (rport->flags & DISABLED ||
file->f_flags & O_NONBLOCK) {
current->state = TASK_RUNNING;
@@ -2356,8 +2360,8 @@ static ssize_t vwsnd_audio_do_write(struct file *file,
while (count) {
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&wport->queue, &wait);
- current->state = TASK_INTERRUPTIBLE;
while ((nb = swb_inc_u(wport, 0)) == 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
if (wport->flags & DISABLED ||
file->f_flags & O_NONBLOCK) {
current->state = TASK_RUNNING;
@@ -3239,7 +3243,7 @@ static struct file_operations vwsnd_mixer_fops = {
/* driver probe routine. Return nonzero if hardware is found. */
-static int probe_vwsnd(struct address_info *hw_config)
+static int __init probe_vwsnd(struct address_info *hw_config)
{
lithium_t lith;
int w;
@@ -3291,7 +3295,7 @@ static int probe_vwsnd(struct address_info *hw_config)
* Return +minor_dev on success, -errno on failure.
*/
-static int attach_vwsnd(struct address_info *hw_config)
+static int __init attach_vwsnd(struct address_info *hw_config)
{
vwsnd_dev_t *devc = NULL;
int err = -ENOMEM;
@@ -3417,7 +3421,7 @@ static int attach_vwsnd(struct address_info *hw_config)
return err;
}
-static int unload_vwsnd(struct address_info *hw_config)
+static int __exit unload_vwsnd(struct address_info *hw_config)
{
vwsnd_dev_t *devc, **devcp;
@@ -3481,10 +3485,3 @@ static void __exit cleanup_vwsnd(void)
module_init(init_vwsnd);
module_exit(cleanup_vwsnd);
-
-/*
- * Local variables:
- * compile-command: "cd ../..; make modules SUBDIRS=drivers/sound"
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c
index 5e4f6c34d..be7b9afbc 100644
--- a/drivers/sound/waveartist.c
+++ b/drivers/sound/waveartist.c
@@ -17,6 +17,10 @@
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added __init to waveartist_init()
*/
/* Debugging */
@@ -1190,8 +1194,7 @@ static struct mixer_operations waveartist_mixer_operations =
ioctl: waveartist_mixer_ioctl
};
-static int
-waveartist_init(wavnc_info *devc)
+static int __init waveartist_init(wavnc_info *devc)
{
wavnc_port_info *portc;
char rev[3], dev_name[64];
diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c
index 5a1a161d9..521f2045a 100644
--- a/drivers/sound/wavfront.c
+++ b/drivers/sound/wavfront.c
@@ -60,7 +60,12 @@
*
* This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info. */
+ * for more info.
+ *
+ * Changes:
+ * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+ * Added some __init and __initdata to entries in yss225.c
+ */
#include <linux/module.h>
@@ -2247,9 +2252,7 @@ wavefront_should_cause_interrupt (int val, int port, int timeout)
restore_flags (flags);
}
-static int
-wavefront_hw_reset (void)
-
+static int __init wavefront_hw_reset (void)
{
int bits;
int hwv[2];
@@ -2703,8 +2706,7 @@ static int __init wavefront_config_midi (void)
return 0;
}
-static int
-wavefront_do_reset (int atboot)
+static int __init wavefront_do_reset (int atboot)
{
char voices[1];
@@ -3076,7 +3078,7 @@ wffx_ioctl (wavefront_fx_info *r)
a somewhat "algorithmic" approach.
*/
-static int wffx_init (void)
+static int __init wffx_init (void)
{
int i;
int j;
diff --git a/drivers/sound/ymf_sb.c b/drivers/sound/ymf_sb.c
index 6020b85b6..26a062a8f 100644
--- a/drivers/sound/ymf_sb.c
+++ b/drivers/sound/ymf_sb.c
@@ -43,6 +43,10 @@
Thu Sep 21 05:32:51 BRT 2000 0.0.5
* got rid of attach_uart401 and attach_sbmpu
Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+
+ Fri Nov 10 21:24:11 CET 2000 0.0.6
+ * added some __init and __initdata to entries in 724hwmcode.h
+ Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
*/
#include <linux/module.h>
@@ -220,7 +224,7 @@
#define PFX "ymf_sb: "
-#define YMFSB_VERSION "0.0.5"
+#define YMFSB_VERSION "0.0.6"
#define YMFSB_CARD_NAME "YMF7xx Legacy Audio driver " YMFSB_VERSION
#ifdef SUPPORT_UART401_MIDI
@@ -338,7 +342,7 @@ static int writeAc97( int adr, unsigned short val )
return 0;
}
-static int checkCodec( struct pci_dev *pcidev )
+static int __init checkCodec( struct pci_dev *pcidev )
{
u8 tmp8;
@@ -357,7 +361,7 @@ static int checkCodec( struct pci_dev *pcidev )
return 0;
}
-static int setupLegacyIO( struct pci_dev *pcidev )
+static int __init setupLegacyIO( struct pci_dev *pcidev )
{
int v;
int sbio=0,mpuio=0,oplio=0,dma=0;
@@ -500,7 +504,7 @@ static void disableDSP( void )
return;
}
-static int setupInstruction( struct pci_dev *pcidev )
+static int __init setupInstruction( struct pci_dev *pcidev )
{
int i;
int val;
diff --git a/drivers/sound/yss225.c b/drivers/sound/yss225.c
index e5d7ec098..e70040057 100644
--- a/drivers/sound/yss225.c
+++ b/drivers/sound/yss225.c
@@ -1,4 +1,6 @@
-unsigned char page_zero[] = {
+#include <linux/init.h>
+
+unsigned char page_zero[] __initdata = {
0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
@@ -25,7 +27,7 @@ unsigned char page_zero[] = {
0x1d, 0x02, 0xdf
};
-unsigned char page_one[] = {
+unsigned char page_one[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
@@ -52,7 +54,7 @@ unsigned char page_one[] = {
0x60, 0x00, 0x1b
};
-unsigned char page_two[] = {
+unsigned char page_two[] __initdata = {
0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -67,7 +69,7 @@ unsigned char page_two[] = {
0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
};
-unsigned char page_three[] = {
+unsigned char page_three[] __initdata = {
0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -82,7 +84,7 @@ unsigned char page_three[] = {
0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
};
-unsigned char page_four[] = {
+unsigned char page_four[] __initdata = {
0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -97,7 +99,7 @@ unsigned char page_four[] = {
0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
};
-unsigned char page_six[] = {
+unsigned char page_six[] __initdata = {
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
@@ -118,7 +120,7 @@ unsigned char page_six[] = {
0x80, 0x00, 0x7e, 0x80, 0x80
};
-unsigned char page_seven[] = {
+unsigned char page_seven[] __initdata = {
0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
@@ -145,7 +147,7 @@ unsigned char page_seven[] = {
0x00, 0x02, 0x00
};
-unsigned char page_zero_v2[] = {
+unsigned char page_zero_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -157,7 +159,7 @@ unsigned char page_zero_v2[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char page_one_v2[] = {
+unsigned char page_one_v2[] __initdata = {
0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -169,21 +171,21 @@ unsigned char page_one_v2[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char page_two_v2[] = {
+unsigned char page_two_v2[] __initdata = {
0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_three_v2[] = {
+unsigned char page_three_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_four_v2[] = {
+unsigned char page_four_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -191,7 +193,7 @@ unsigned char page_four_v2[] = {
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_seven_v2[] = {
+unsigned char page_seven_v2[] __initdata = {
0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -202,7 +204,7 @@ unsigned char page_seven_v2[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char mod_v2[] = {
+unsigned char mod_v2[] __initdata = {
0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
@@ -232,7 +234,7 @@ unsigned char mod_v2[] = {
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
};
-unsigned char coefficients[] = {
+unsigned char coefficients[] __initdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
@@ -268,14 +270,14 @@ unsigned char coefficients[] = {
0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
0xba
};
-unsigned char coefficients2[] = {
+unsigned char coefficients2[] __initdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
};
-unsigned char coefficients3[] = {
+unsigned char coefficients3[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 584b3615c..a3be533e6 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -1812,6 +1812,8 @@ ssize_t ixj_read(struct file * file_p, char *buf, size_t length, loff_t * ppos)
while (!j->read_buffer_ready || (j->dtmf_state && j->flags.dtmf_oob)) {
++j->read_wait;
if(j->tone_state) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&j->read_q, &wait);
j->flags.inread = 0;
return -EAGAIN;
}
@@ -1894,6 +1896,8 @@ ssize_t ixj_write(struct file *file_p, const char *buf, size_t count, loff_t * p
while (!j->write_buffers_empty) {
++j->write_wait;
if(j->tone_state) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&j->write_q, &wait);
j->flags.inwrite = 0;
return -EAGAIN;
}
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 9e510e087..d4feefa21 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -37,6 +37,7 @@ comment 'USB Devices'
if [ "$CONFIG_USB_SERIAL" != "n" ]; then
bool ' USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
dep_tristate ' USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+ dep_tristate ' USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
dep_tristate ' USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
dep_tristate ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL
@@ -49,8 +50,8 @@ comment 'USB Devices'
bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
fi
- dep_tristate ' USB Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
+ dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
fi
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 24ca4858d..1736c503b 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -477,114 +477,113 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines.
*/
-static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
+static void *acm_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct acm *acm;
struct usb_config_descriptor *cfacm;
struct usb_interface_descriptor *ifcom, *ifdata;
struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
- int readsize, ctrlsize, minor, i;
+ int readsize, ctrlsize, minor;
unsigned char *buf;
- if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
+ /* Since 0 is treated as a wildcard by the USB pattern matching,
+ we explicitly check bDeviceSubClass and bDeviceProtocol
+ here. */
+ if (dev->descriptor.bDeviceSubClass != 0
|| dev->descriptor.bDeviceProtocol != 0) return NULL;
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ cfacm = dev->actconfig;
- cfacm = dev->config + i;
+ dbg("probing config %d", cfacm->bConfigurationValue);
- dbg("probing config %d", cfacm->bConfigurationValue);
+ if (cfacm->bNumInterfaces != 2 ||
+ usb_interface_claimed(cfacm->interface + 0) ||
+ usb_interface_claimed(cfacm->interface + 1))
+ return NULL;
- if (cfacm->bNumInterfaces != 2 ||
- usb_interface_claimed(cfacm->interface + 0) ||
- usb_interface_claimed(cfacm->interface + 1))
- continue;
+ ifcom = cfacm->interface[0].altsetting + 0;
+ ifdata = cfacm->interface[1].altsetting + 0;
- ifcom = cfacm->interface[0].altsetting + 0;
- ifdata = cfacm->interface[1].altsetting + 0;
-
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
- ifcom = cfacm->interface[1].altsetting + 0;
- ifdata = cfacm->interface[0].altsetting + 0;
- if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
- continue;
- }
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
+ ifcom = cfacm->interface[1].altsetting + 0;
+ ifdata = cfacm->interface[0].altsetting + 0;
+ if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints !=2)
+ return NULL;
+ }
- if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
- ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
- continue;
+ if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+ ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
+ return NULL;
- epctrl = ifcom->endpoint + 0;
- epread = ifdata->endpoint + 0;
- epwrite = ifdata->endpoint + 1;
+ epctrl = ifcom->endpoint + 0;
+ epread = ifdata->endpoint + 0;
+ epwrite = ifdata->endpoint + 1;
- if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
- (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
- ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
- continue;
+ if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+ (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+ ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
+ return NULL;
- if ((epread->bEndpointAddress & 0x80) != 0x80) {
- epread = ifdata->endpoint + 1;
- epwrite = ifdata->endpoint + 0;
- }
+ if ((epread->bEndpointAddress & 0x80) != 0x80) {
+ epread = ifdata->endpoint + 1;
+ epwrite = ifdata->endpoint + 0;
+ }
- usb_set_configuration(dev, cfacm->bConfigurationValue);
+ usb_set_configuration(dev, cfacm->bConfigurationValue);
- for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
- if (acm_table[minor]) {
- err("no more free acm devices");
- return NULL;
- }
+ for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+ if (acm_table[minor]) {
+ err("no more free acm devices");
+ return NULL;
+ }
- if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
- err("out of memory");
- return NULL;
- }
- memset(acm, 0, sizeof(struct acm));
+ if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+ err("out of memory");
+ return NULL;
+ }
+ memset(acm, 0, sizeof(struct acm));
- ctrlsize = epctrl->wMaxPacketSize;
- readsize = epread->wMaxPacketSize;
- acm->writesize = epwrite->wMaxPacketSize;
- acm->iface = cfacm->interface;
- acm->minor = minor;
- acm->dev = dev;
+ ctrlsize = epctrl->wMaxPacketSize;
+ readsize = epread->wMaxPacketSize;
+ acm->writesize = epwrite->wMaxPacketSize;
+ acm->iface = cfacm->interface;
+ acm->minor = minor;
+ acm->dev = dev;
- acm->tqueue.routine = acm_softint;
- acm->tqueue.data = acm;
+ acm->tqueue.routine = acm_softint;
+ acm->tqueue.data = acm;
- if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
- err("out of memory");
- kfree(acm);
- return NULL;
- }
+ if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+ err("out of memory");
+ kfree(acm);
+ return NULL;
+ }
- FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
- buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+ FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+ buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
- FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
- buf += ctrlsize, readsize, acm_read_bulk, acm);
- acm->readurb.transfer_flags |= USB_NO_FSBR;
+ FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+ buf += ctrlsize, readsize, acm_read_bulk, acm);
+ acm->readurb.transfer_flags |= USB_NO_FSBR;
- FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
- buf += readsize, acm->writesize, acm_write_bulk, acm);
- acm->writeurb.transfer_flags |= USB_NO_FSBR;
-
- printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+ FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+ buf += readsize, acm->writesize, acm_write_bulk, acm);
+ acm->writeurb.transfer_flags |= USB_NO_FSBR;
- acm_set_control(acm, acm->ctrlout);
+ printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
- acm->line.speed = cpu_to_le32(9600);
- acm->line.databits = 8;
- acm_set_line(acm, &acm->line);
+ acm_set_control(acm, acm->ctrlout);
- usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
- usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+ acm->line.speed = cpu_to_le32(9600);
+ acm->line.databits = 8;
+ acm_set_line(acm, &acm->line);
- tty_register_devfs(&acm_tty_driver, 0, minor);
- return acm_table[minor] = acm;
- }
+ usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+ usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
- return NULL;
+ tty_register_devfs(&acm_tty_driver, 0, minor);
+ return acm_table[minor] = acm;
}
static void acm_disconnect(struct usb_device *dev, void *ptr)
@@ -622,10 +621,19 @@ static void acm_disconnect(struct usb_device *dev, void *ptr)
* USB driver structure.
*/
+static struct usb_device_id acm_ids [] = {
+ { bDeviceClass: 2},
+ { bInterfaceClass: 2, bInterfaceSubClass: 2, bInterfaceProtocol: 1},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, acm_ids);
+
static struct usb_driver acm_driver = {
name: "acm",
probe: acm_probe,
- disconnect: acm_disconnect
+ disconnect: acm_disconnect,
+ id_table: acm_ids,
};
/*
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 1db828b24..065d31942 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -2691,16 +2691,23 @@ static /*const*/ struct file_operations usb_audio_fops = {
/* --------------------------------------------------------------------- */
-static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum);
+static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id);
static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_device_id usb_audio_ids [] = {
+ { bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: 1},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_audio_ids);
+
static struct usb_driver usb_audio_driver = {
- "audio",
- usb_audio_probe,
- usb_audio_disconnect,
- LIST_HEAD_INIT(usb_audio_driver.driver_list),
- NULL,
- 0
+ name: "audio",
+ probe: usb_audio_probe,
+ disconnect: usb_audio_disconnect,
+ driver_list: LIST_HEAD_INIT(usb_audio_driver.driver_list),
+ id_table: usb_audio_ids,
};
static void *find_descriptor(void *descstart, unsigned int desclen, void *after,
@@ -3640,7 +3647,8 @@ ret:
/* we only care for the currently active configuration */
-static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_config_descriptor *config = dev->actconfig;
unsigned char *buffer;
@@ -3653,25 +3661,13 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
config->interface[ifnum].altsetting[0].bInterfaceClass,
config->interface[ifnum].altsetting[0].bInterfaceSubClass);
#endif
- if (config->interface[ifnum].altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
- config->interface[ifnum].altsetting[0].bInterfaceSubClass != 1) {
-#if 0
- printk(KERN_DEBUG "usbaudio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n",
- dev->descriptor.idVendor, dev->descriptor.idProduct);
-#endif
- return NULL;
- }
+
/*
* audiocontrol interface found
* find which configuration number is active
*/
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
- if (dev->config+i == config)
- goto configfound;
- printk(KERN_ERR "usbaudio: cannot find active configuration number of device %d\n", dev->devnum);
- return NULL;
+ i = dev->actconfig - config;
- configfound:
if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
printk(KERN_ERR "usbaudio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
return NULL;
diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
index c543b249e..0509f2347 100644
--- a/drivers/usb/bluetooth.c
+++ b/drivers/usb/bluetooth.c
@@ -183,14 +183,27 @@ static void bluetooth_ctrl_callback (struct urb *urb);
static void bluetooth_read_bulk_callback (struct urb *urb);
static void bluetooth_write_bulk_callback (struct urb *urb);
-static void * usb_bluetooth_probe (struct usb_device *dev, unsigned int ifnum);
+static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id);
static void usb_bluetooth_disconnect (struct usb_device *dev, void *ptr);
+static struct usb_device_id usb_bluetooth_ids [] = {
+ {
+ bDeviceClass: WIRELESS_CLASS_CODE,
+ bDeviceSubClass: RF_SUBCLASS_CODE,
+ bDeviceProtocol: BLUETOOTH_PROGRAMMING_PROTOCOL_CODE
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
+
static struct usb_driver usb_bluetooth_driver = {
name: "bluetooth",
probe: usb_bluetooth_probe,
disconnect: usb_bluetooth_disconnect,
+ id_table: usb_bluetooth_ids,
};
static int bluetooth_refcount;
@@ -950,7 +963,8 @@ static void bluetooth_softint(void *private)
}
-static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
+static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_bluetooth *bluetooth = NULL;
struct usb_interface_descriptor *interface;
@@ -967,16 +981,6 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
int num_bulk_in = 0;
int num_bulk_out = 0;
- /* see if this device has the proper class signature */
- if ((dev->descriptor.bDeviceClass != WIRELESS_CLASS_CODE) ||
- (dev->descriptor.bDeviceSubClass != RF_SUBCLASS_CODE) ||
- (dev->descriptor.bDeviceProtocol != BLUETOOTH_PROGRAMMING_PROTOCOL_CODE)) {
- dbg (__FUNCTION__ " - class signature %d, %d, %d did not match",
- dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
- dev->descriptor.bDeviceProtocol);
- return NULL;
- }
-
interface = &dev->actconfig->interface[ifnum].altsetting[0];
control_out_endpoint = interface->bInterfaceNumber;
diff --git a/drivers/usb/dabusb.c b/drivers/usb/dabusb.c
index d14e8e97b..154ed17cb 100644
--- a/drivers/usb/dabusb.c
+++ b/drivers/usb/dabusb.c
@@ -718,7 +718,8 @@ static int dabusb_find_struct (void)
}
/* --------------------------------------------------------------------- */
-static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum)
+static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
int devnum;
pdabusb_t s;
@@ -726,11 +727,6 @@ static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum)
dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
- /* the 1234:5678 is just a self assigned test ID */
- if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) &&
- (usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x9999))
- return NULL;
-
/* We don't handle multiple configurations */
if (usbdev->descriptor.bNumConfigurations != 1)
return NULL;
@@ -790,14 +786,22 @@ static void dabusb_disconnect (struct usb_device *usbdev, void *ptr)
MOD_DEC_USE_COUNT;
}
+static struct usb_device_id dabusb_ids [] = {
+ { idVendor: 0x0547, idProduct: 0x2131 },
+ { idVendor: 0x0547, idProduct: 0x9999 },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dabusb_ids);
+
static struct usb_driver dabusb_driver =
{
- "dabusb",
- dabusb_probe,
- dabusb_disconnect,
- {NULL, NULL},
- &dabusb_fops,
- DABUSB_MINOR
+ name: "dabusb",
+ probe: dabusb_probe,
+ disconnect: dabusb_disconnect,
+ fops: &dabusb_fops,
+ minor: DABUSB_MINOR,
+ id_table: dabusb_ids,
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index 6760e797b..5503e6e66 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -44,11 +44,14 @@
* 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
* 08 Jan, 2000 .. multiple camera support
* 12 Aug, 2000 .. add some real locking, remove an Oops
+ * 10 Oct, 2000 .. usb_device_id table created.
+ * 01 Nov, 2000 .. usb_device_id support added by Adam J. Richter
*
* Thanks to: the folk who've provided USB product IDs, sent in
* patches, and shared their sucesses!
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
@@ -59,7 +62,12 @@
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/module.h>
-#undef DEBUG
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
@@ -82,7 +90,7 @@
/* table of cameras that work through this driver */
-static __devinitdata struct usb_device_id camera_table [] = {
+static struct usb_device_id camera_table [] = {
/* These have the same application level protocol */
{ idVendor: 0x040a, idProduct: 0x0120 }, // Kodak DC-240
@@ -105,7 +113,7 @@ static __devinitdata struct usb_device_id camera_table [] = {
* means, among other things, no iso or interrupt endpoints.
*/
- { } // TERMINATING ENTRY
+ { } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, camera_table);
@@ -346,7 +354,7 @@ static /* const */ struct file_operations usb_camera_fops = {
static void * __devinit
-camera_bind (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info)
+camera_probe (struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *camera_info)
{
int i;
struct usb_interface_descriptor *interface;
@@ -471,7 +479,7 @@ static /* const */ struct usb_driver camera_driver = {
name: "dc2xx",
id_table: camera_table,
- bind: camera_bind,
+ probe: camera_probe,
disconnect: camera_disconnect,
fops: &usb_camera_fops,
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 2a1e12aad..ef46e5b52 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -292,7 +292,8 @@ static void destroy_all_async(struct dev_state *ps)
* interface claiming
*/
-static void *driver_probe(struct usb_device *dev, unsigned int intf)
+static void *driver_probe(struct usb_device *dev, unsigned int intf,
+ const struct usb_device_id *id)
{
return NULL;
}
@@ -541,13 +542,17 @@ static int proc_control(struct dev_state *ps, void *arg)
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
if ((i > 0) && ctrl.length) {
- if (copy_to_user(ctrl.data, tbuf, ctrl.length))
+ if (copy_to_user(ctrl.data, tbuf, ctrl.length)) {
+ free_page((unsigned long)tbuf);
return -EFAULT;
+ }
}
} else {
if (ctrl.length) {
- if (copy_from_user(tbuf, ctrl.data, ctrl.length))
+ if (copy_from_user(tbuf, ctrl.data, ctrl.length)) {
+ free_page((unsigned long)tbuf);
return -EFAULT;
+ }
}
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
@@ -583,7 +588,7 @@ static int proc_bulk(struct dev_state *ps, void *arg)
return -EINVAL;
len1 = bulk.len;
if (len1 > PAGE_SIZE)
- len1 = PAGE_SIZE;
+ return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
return -ENOMEM;
tmo = (bulk.timeout * HZ + 999) / 1000;
@@ -594,13 +599,17 @@ static int proc_bulk(struct dev_state *ps, void *arg)
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
if (!i && len2) {
- if (copy_to_user(bulk.data, tbuf, len2))
+ if (copy_to_user(bulk.data, tbuf, len2)) {
+ free_page((unsigned long)tbuf);
return -EFAULT;
+ }
}
} else {
if (len1) {
- if (copy_from_user(tbuf, bulk.data, len1))
+ if (copy_from_user(tbuf, bulk.data, len1)) {
+ free_page((unsigned long)tbuf);
return -EFAULT;
+ }
}
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
}
@@ -697,9 +706,11 @@ static int proc_resetdevice(struct dev_state *ps)
continue;
if (intf->driver) {
+ const struct usb_device_id *id;
down(&intf->driver->serialize);
intf->driver->disconnect(ps->dev, intf->private_data);
- intf->driver->probe(ps->dev, i);
+ id = usb_match_id(ps->dev,intf,intf->driver->id_table);
+ intf->driver->probe(ps->dev, i, id);
up(&intf->driver->serialize);
}
}
diff --git a/drivers/usb/dsbr100.c b/drivers/usb/dsbr100.c
index aa6372b91..a59759bb9 100644
--- a/drivers/usb/dsbr100.c
+++ b/drivers/usb/dsbr100.c
@@ -70,7 +70,8 @@
#define TB_LEN 16
-static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum);
+static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id);
static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr);
static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
void *arg);
@@ -90,28 +91,30 @@ typedef struct
static struct video_device usb_dsbr100_radio=
{
- "D-Link DSB R-100 USB radio",
- VID_TYPE_TUNER,
- VID_HARDWARE_AZTECH,
- usb_dsbr100_open,
- usb_dsbr100_close,
- NULL, /* Can't read (no capture ability) */
- NULL, /* Can't write */
- NULL, /* No poll */
- usb_dsbr100_ioctl,
- NULL,
- NULL
+ name: "D-Link DSB R-100 USB radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_AZTECH,
+ open: usb_dsbr100_open,
+ close: usb_dsbr100_close,
+ ioctl: usb_dsbr100_ioctl,
};
static int users = 0;
+static struct usb_device_id usb_dsbr100_table [] = {
+ { idVendor: DSB100_VENDOR, idProduct: DSB100_PRODUCT },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
+
static struct usb_driver usb_dsbr100_driver = {
name: "dsbr100",
probe: usb_dsbr100_probe,
disconnect: usb_dsbr100_disconnect,
- driver_list: {NULL,NULL},
- fops: NULL,
- minor: 0
+ fops: NULL,
+ minor: 0,
+ id_table: usb_dsbr100_table,
};
@@ -164,13 +167,11 @@ static void dsbr100_getstat(usb_dsbr100 *radio)
}
-static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
usb_dsbr100 *radio;
- if (dev->descriptor.idVendor!=DSB100_VENDOR ||
- dev->descriptor.idProduct!=DSB100_PRODUCT)
- return NULL;
if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
return NULL;
usb_dsbr100_radio.priv = radio;
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index db4df7931..5acdded23 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -1373,9 +1373,6 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c
if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
- if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID)
- return NULL;
-
if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc)
&& usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) {
dbg("class descriptor not present\n");
@@ -1471,7 +1468,8 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c
return hid;
}
-static void* hid_probe(struct usb_device *dev, unsigned int ifnum)
+static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct hid_device *hid;
char name[128];
@@ -1527,10 +1525,18 @@ static void hid_disconnect(struct usb_device *dev, void *ptr)
hid_free_device(hid);
}
+static struct usb_device_id hid_usb_ids [] = {
+ { bInterfaceClass: USB_INTERFACE_CLASS_HID},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hid_usb_ids);
+
static struct usb_driver hid_driver = {
name: "hid",
probe: hid_probe,
- disconnect: hid_disconnect
+ disconnect: hid_disconnect,
+ id_table: hid_usb_ids,
};
static int __init hid_init(void)
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 8b9b0bfbc..8ecc1221b 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -36,7 +36,7 @@ static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static int khubd_pid = 0; /* PID of khubd */
-static int khubd_running = 0;
+static DECLARE_MUTEX_LOCKED(khubd_exited);
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
@@ -235,7 +235,9 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor
return 0;
}
-static void *hub_probe(struct usb_device *dev, unsigned int i)
+static void *hub_probe(struct usb_device *dev, unsigned int i,
+ const struct usb_device_id *id)
+
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
@@ -244,10 +246,6 @@ static void *hub_probe(struct usb_device *dev, unsigned int i)
interface = &dev->actconfig->interface[i].altsetting[0];
- /* Is it a hub? */
- if (interface->bInterfaceClass != USB_CLASS_HUB)
- return NULL;
-
/* Some hubs have a subclass of 1, which AFAICT according to the */
/* specs is not defined, but it works */
if ((interface->bInterfaceSubClass != 0) &&
@@ -743,17 +741,13 @@ he_unlock:
static int usb_hub_thread(void *__hub)
{
- khubd_running = 1;
-
lock_kernel();
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources
*/
- exit_files(current); /* daemonize doesn't do exit_files */
- current->files = init_task.files;
- atomic_inc(&current->files->count);
+
daemonize();
/* Setup a nice name */
@@ -766,16 +760,23 @@ static int usb_hub_thread(void *__hub)
} while (!signal_pending(current));
dbg("usb_hub_thread exiting");
- khubd_running = 0;
- return 0;
+ up_and_exit(&khubd_exited, 0);
}
+static struct usb_device_id hub_id_table [] = {
+ { bInterfaceClass: USB_CLASS_HUB},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hub_id_table);
+
static struct usb_driver hub_driver = {
name: "hub",
probe: hub_probe,
ioctl: hub_ioctl,
- disconnect: hub_disconnect
+ disconnect: hub_disconnect,
+ id_table: hub_id_table,
};
/*
@@ -811,18 +812,8 @@ void usb_hub_cleanup(void)
/* Kill the thread */
ret = kill_proc(khubd_pid, SIGTERM, 1);
- if (!ret) {
- /* Wait 10 seconds */
- int count = 10 * 100;
- while (khubd_running && --count) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
- }
-
- if (!count)
- err("giving up on killing khubd");
- }
+ down(&khubd_exited);
/*
* Hub resources are freed for us by usb_deregister. It calls
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index 590bcd4bd..a502cbaf1 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -2492,11 +2492,6 @@ static void ibmcam_close(struct video_device *dev)
MOD_DEC_USE_COUNT;
}
-static int ibmcam_init_done(struct video_device *dev)
-{
- return 0;
-}
-
static long ibmcam_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
{
return -EINVAL;
@@ -2855,20 +2850,15 @@ static int ibmcam_mmap(struct video_device *dev, const char *adr, unsigned long
}
static struct video_device ibmcam_template = {
- "CPiA USB Camera",
- VID_TYPE_CAPTURE,
- VID_HARDWARE_CPIA,
- ibmcam_open,
- ibmcam_close,
- ibmcam_read,
- ibmcam_write,
- NULL,
- ibmcam_ioctl,
- ibmcam_mmap,
- ibmcam_init_done,
- NULL,
- 0,
- 0
+ name: "CPiA USB Camera",
+ type: VID_TYPE_CAPTURE,
+ hardware: VID_HARDWARE_CPIA,
+ open: ibmcam_open,
+ close: ibmcam_close,
+ read: ibmcam_read,
+ write: ibmcam_write,
+ ioctl: ibmcam_ioctl,
+ mmap: ibmcam_mmap,
};
static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
@@ -2953,7 +2943,8 @@ static int ibmcam_find_struct(void)
* 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
* 7/3/00 Fixed endianness bug.
*/
-static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_ibmcam *ibmcam = NULL;
const struct usb_interface_descriptor *interface;
@@ -2967,11 +2958,6 @@ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
if (dev->descriptor.bNumConfigurations != 1)
return NULL;
- /* Is it an IBM camera? */
- if ((dev->descriptor.idVendor != 0x0545) ||
- (dev->descriptor.idProduct != 0x8080))
- return NULL;
-
/* Check the version/revision */
switch (dev->descriptor.bcdDevice) {
case 0x0002:
@@ -2988,10 +2974,9 @@ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
dev->descriptor.bcdDevice);
model = IBMCAM_MODEL_2;
break;
- default:
- printk(KERN_ERR "IBM camera with revision 0x%04x is not supported.\n",
- dev->descriptor.bcdDevice);
- return NULL;
+
+ /* ibmcam_table contents prevents any other values from ever
+ being passed to us, so no need for "default" case. */
}
/* Validate found interface: must have one ISO endpoint */
@@ -3124,11 +3109,29 @@ static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
MOD_DEC_USE_COUNT;
}
+static struct usb_device_id ibmcam_table [] = {
+ {
+ idVendor: 0x0545,
+ idProduct: 0x8080,
+ bcdDevice_lo: 0x0002,
+ bcdDevice_hi: 0x0002
+ },
+ {
+ idVendor: 0x0545,
+ idProduct: 0x8080,
+ bcdDevice_lo: 0X030a,
+ bcdDevice_hi: 0x030a
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, ibmcam_table);
+
static struct usb_driver ibmcam_driver = {
- "ibmcam",
- usb_ibmcam_probe,
- usb_ibmcam_disconnect,
- { NULL, NULL }
+ name: "ibmcam",
+ probe: usb_ibmcam_probe,
+ disconnect: usb_ibmcam_disconnect,
+ id_table: ibmcam_table,
};
/*
diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c
index e4fc25d39..131681c8e 100644
--- a/drivers/usb/mdc800.c
+++ b/drivers/usb/mdc800.c
@@ -370,7 +370,8 @@ static struct usb_driver mdc800_usb_driver;
/*
* Callback to search the Mustek MDC800 on the USB Bus
*/
-static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
+static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum,
+ const struct usb_device_id *id)
{
int i,j;
struct usb_interface_descriptor *intf_desc;
@@ -379,11 +380,6 @@ static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
dbg ("(mdc800_usb_probe) called.");
- if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
- return 0;
- if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
- return 0;
-
if (mdc800->dev != 0)
{
warn ("only one Mustek MDC800 is supported.");
@@ -873,17 +869,23 @@ static struct file_operations mdc800_device_ops =
+static struct usb_device_id mdc800_table [] = {
+ { idVendor: MDC800_VENDOR_ID, idProduct: MDC800_PRODUCT_ID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, mdc800_table);
/*
* USB Driver Struct for this device
*/
static struct usb_driver mdc800_usb_driver =
{
- "mdc800",
- mdc800_usb_probe,
- mdc800_usb_disconnect,
- { 0,0 },
- &mdc800_device_ops,
- MDC800_DEVICE_MINOR_BASE
+ name: "mdc800",
+ probe: mdc800_usb_probe,
+ disconnect: mdc800_usb_disconnect,
+ fops: &mdc800_device_ops,
+ minor: MDC800_DEVICE_MINOR_BASE,
+ id_table: mdc800_table
};
diff --git a/drivers/usb/microtek.c b/drivers/usb/microtek.c
index ab37860cd..daa18c88f 100644
--- a/drivers/usb/microtek.c
+++ b/drivers/usb/microtek.c
@@ -140,14 +140,17 @@
/* USB layer driver interface */
-static void *mts_usb_probe(struct usb_device *dev, unsigned int interface);
+static void *mts_usb_probe(struct usb_device *dev, unsigned int interface,
+ const struct usb_device_id *id);
static void mts_usb_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_device_id mts_usb_ids [];
+
static struct usb_driver mts_usb_driver = {
- "microtek",
- mts_usb_probe,
- mts_usb_disconnect,
- { NULL, NULL } /* we need no fops. let gcc fill it */
+ name: "microtek",
+ probe: mts_usb_probe,
+ disconnect: mts_usb_disconnect,
+ id_table: mts_usb_ids,
};
@@ -338,6 +341,7 @@ static inline void mts_wait_abort(struct mts_desc* desc)
while( !atomic_read(&desc->lock.count) ) {
/* Is there a function to check if the semaphore is locked? */
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout( MTS_ABORT_TIMEOUT );
MTS_DEBUG_GOT_HERE();
mts_urb_abort(desc);
@@ -791,8 +795,6 @@ static void mts_usb_disconnect (struct usb_device *dev, void *ptr)
struct vendor_product
{
- u16 idVendor;
- u16 idProduct;
char* name;
enum
{
@@ -807,37 +809,37 @@ struct vendor_product
/* These are taken from the msmUSB.inf file on the Windows driver CD */
const static struct vendor_product mts_supported_products[] =
{
- {
- 0x4ce, 0x300,"Phantom 336CX",mts_sup_unknown
- },
- {
- 0x5da, 0x94,"Phantom 336CX",mts_sup_unknown
- },
- {
- 0x5da, 0x99,"Scanmaker X6",mts_sup_alpha
- },
- {
- 0x5da, 0x9a,"Phantom C6",mts_sup_unknown
- },
- {
- 0x5da, 0xa0,"Phantom 336CX",mts_sup_unknown
- },
- {
- 0x5da, 0xa3,"ScanMaker V6USL",mts_sup_unknown
- },
- {
- 0x5da, 0x80a3,"ScanMaker V6USL",mts_sup_unknown
- },
- {
- 0x5da, 0x80ac,"Scanmaker V6UL",mts_sup_unknown
- }
-}
-;
-const static struct vendor_product* mts_last_product = &mts_supported_products[ sizeof(mts_supported_products) / sizeof(struct vendor_product) ];
- /* Must never be derefed, points to one after last entry */
+ { "Phantom 336CX", mts_sup_unknown},
+ { "Phantom 336CX", mts_sup_unknown},
+ { "Scanmaker X6", mts_sup_alpha},
+ { "Phantom C6", mts_sup_unknown},
+ { "Phantom 336CX", mts_sup_unknown},
+ { "ScanMaker V6USL", mts_sup_unknown},
+ { "ScanMaker V6USL", mts_sup_unknown},
+ { "Scanmaker V6UL", mts_sup_unknown},
+};
+
+/* The entries of microtek_table must correspond, line-by-line to
+ the entries of mts_supported_products[]. */
+
+static struct usb_device_id mts_usb_ids [] =
+{
+ {idVendor: 0x4ce, idProduct: 0x0300},
+ {idVendor: 0x5da, idProduct: 0x0094},
+ {idVendor: 0x5da, idProduct: 0x0099},
+ {idVendor: 0x5da, idProduct: 0x009a},
+ {idVendor: 0x5da, idProduct: 0x00a0},
+ {idVendor: 0x5da, idProduct: 0x00a3},
+ {idVendor: 0x5da, idProduct: 0x80a3},
+ {idVendor: 0x5da, idProduct: 0x80ac},
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, mts_usb_ids);
-static void * mts_usb_probe (struct usb_device *dev, unsigned int interface)
+
+static void * mts_usb_probe (struct usb_device *dev, unsigned int interface,
+ const struct usb_device_id *id)
{
int i;
int result;
@@ -860,20 +862,8 @@ static void * mts_usb_probe (struct usb_device *dev, unsigned int interface)
(int)dev->descriptor.idVendor );
MTS_DEBUG_GOT_HERE();
-
- /* checking IDs */
- for( p = mts_supported_products; p != mts_last_product; p++ )
- if ( dev->descriptor.idVendor == p->idVendor &&
- dev->descriptor.idProduct == p->idProduct )
- goto is_supported;
- else
- MTS_DEBUG( "doesn't appear to be model %s\n", p->name );
-
- MTS_DEBUG( "returning NULL: unsupported\n" );
-
- return NULL;
-
- is_supported:
+
+ p = &mts_supported_products[id - mts_usb_ids];
MTS_DEBUG_GOT_HERE();
diff --git a/drivers/usb/net1080.c b/drivers/usb/net1080.c
index bdfe71eb4..eae365d47 100644
--- a/drivers/usb/net1080.c
+++ b/drivers/usb/net1080.c
@@ -11,7 +11,9 @@
* The IP-over-USB protocol here may be of interest. Embedded devices
* could implement it at the cost of two bulk endpoints, and whatever
* other system resources the desired IP-based applications need.
- * Some Linux palmtops could support that today.
+ * Some Linux palmtops could support that today. (Devices that don't
+ * support the TTL-driven data mangling of the net1080 chip won't need
+ * the header/trailer support though.)
*
* STATUS:
*
@@ -22,6 +24,15 @@
* should handle static and dynamic ("pump") setups.
*
* RX/TX queue sizes currently fixed at one due to URB unlink problems.
+ *
+ * 10-oct-2000
+ * usb_device_id table created.
+ *
+ * 28-oct-2000
+ * misc fixes; mostly, discard more TTL-mangled rx packets.
+ *
+ * 01-nov-2000
+ * usb_device_id table support added by Adam J. Richter <adam@yggdrasil.com>.
*
*-------------------------------------------------------------------------*/
@@ -642,6 +653,7 @@ static int net1080_stop (struct net_device *net)
dbg ("waited for %d urb completions", temp);
}
dev->wait = 0;
+ current->state = TASK_RUNNING;
remove_wait_queue (&unlink_wakeup, &wait);
mutex_unlock (&dev->mutex);
@@ -989,7 +1001,7 @@ static void net1080_disconnect (struct usb_device *udev, void *ptr)
// precondition: never called in_interrupt
static void *
-net1080_bind (struct usb_device *udev, unsigned ifnum, const struct usb_device_id *prod)
+net1080_probe (struct usb_device *udev, unsigned ifnum, const struct usb_device_id *prod)
{
struct net1080 *dev;
struct net_device *net;
@@ -1073,7 +1085,7 @@ net1080_bind (struct usb_device *udev, unsigned ifnum, const struct usb_device_i
static struct usb_driver net1080_driver = {
name: "net1080",
id_table: products,
- bind: net1080_bind,
+ probe: net1080_probe,
disconnect: net1080_disconnect,
};
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index 275ff05b7..2f88242f3 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -30,7 +30,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-static const char version[] = "1.25";
+static const char version[] = "1.28";
#define __NO_VERSION__
@@ -51,8 +51,6 @@ static const char version[] = "1.25";
#include "ov511.h"
-#undef OV511_GBR422 /* Experimental -- sets the 7610 to GBR422 */
-
#define OV511_I2C_RETRIES 3
/* Video Size 640 x 480 x 3 bytes for RGB */
@@ -60,8 +58,6 @@ static const char version[] = "1.25";
#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
-#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : \
- ((p) == VIDEO_PALETTE_YUV422 ? 16 : 24))
/* PARAMETER VARIABLES: */
static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */
@@ -74,7 +70,7 @@ static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */
* 5=highly repetitive mesgs
* NOTE: This should be changed to 0, 1, or 2 for production kernels
*/
-static int debug = 3;
+static int debug = 0;
/* Fix vertical misalignment of red and blue at 640x480 */
static int fix_rgb_offset = 0;
@@ -112,6 +108,13 @@ static int compress = 0;
/* Display test pattern - doesn't work yet either */
static int testpat = 0;
+/* Setting this to 1 will make the sensor output GBR422 instead on YUV420. Only
+ * affects RGB24 mode. */
+static int sensor_gbr = 0;
+
+/* Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details. */
+static int dumppix = 0;
+
MODULE_PARM(autoadjust, "i");
MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure");
MODULE_PARM(debug, "i");
@@ -138,6 +141,10 @@ MODULE_PARM(compress, "i");
MODULE_PARM_DESC(compress, "Turn on compression (not functional yet)");
MODULE_PARM(testpat, "i");
MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)");
+MODULE_PARM(sensor_gbr, "i");
+MODULE_PARM_DESC(sensor_gbr, "Make sensor output GBR422 rather than YUV420");
+MODULE_PARM(dumppix, "i");
+MODULE_PARM_DESC(dumppix, "Dump raw pixel data, in one of 3 formats. See ov511_dumppix() for details");
MODULE_AUTHOR("Mark McClelland <mwm@i.am> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
MODULE_DESCRIPTION("OV511 USB Camera Driver");
@@ -167,6 +174,15 @@ static struct cam_list clist[] = {
{ -1, NULL }
};
+static __devinitdata struct usb_device_id device_table [] = {
+ { idVendor: 0x05a9, idProduct: 0x0511 }, /* OV511 */
+ { idVendor: 0x05a9, idProduct: 0xA511 }, /* OV511+ */
+ { idVendor: 0x0813, idProduct: 0x0002 }, /* Intel Play Me2Cam OV511+ */
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static struct palette_list plist[] = {
{ VIDEO_PALETTE_GREY, "GREY" },
@@ -357,6 +373,7 @@ static int ov511_read_proc(char *page, char **start, off_t off,
ov511->bridge == BRG_OV511PLUS ? "OV511+" :
"unknown");
out += sprintf (out, "sensor : %s\n",
+ ov511->sensor == SEN_OV6620 ? "OV6620" :
ov511->sensor == SEN_OV7610 ? "OV7610" :
ov511->sensor == SEN_OV7620 ? "OV7620" :
ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
@@ -448,7 +465,6 @@ static void proc_ov511_destroy(void)
}
#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
-
/**********************************************************************
*
* Camera interface
@@ -700,7 +716,7 @@ static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
- PDEBUG(3, "Reset: type=0x%X", reset_type);
+ PDEBUG(4, "Reset: type=0x%X", reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
@@ -829,14 +845,21 @@ ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
} else if ((ov511->sensor == SEN_OV7620)
|| (ov511->sensor == SEN_OV7620AE)) {
#if 0
- 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));
+ int cur_sat, new_sat, tmp;
- if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+ cur_sat = ov511_i2c_read(dev, OV7610_REG_BLUE);
+
+ tmp = (p->hue >> 8) - cur_sat;
+ new_sat = (tmp < 0) ? (-tmp) | 0x80 : tmp;
+
+ PDEBUG(1, "cur=%d target=%d diff=%d", cur_sat, p->hue >> 8, tmp);
+
+ if (ov511_i2c_write(dev, OV7610_REG_BLUE, new_sat) < 0)
return -EIO;
+
+ // DEBUG_CODE
+ PDEBUG(1, "hue=%d", ov511_i2c_read(dev, OV7610_REG_BLUE));
+
#endif
}
@@ -882,6 +905,23 @@ ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
return 0;
}
+/* Returns number of bits per pixel (regardless of where they are located; planar or
+ * not), or zero for unsupported format.
+ */
+static int ov511_get_depth(int palette)
+{
+ switch (palette) {
+ case VIDEO_PALETTE_GREY: return 8;
+ case VIDEO_PALETTE_RGB565: return 16;
+ case VIDEO_PALETTE_RGB24: return 24;
+ case VIDEO_PALETTE_YUV422: return 16;
+ case VIDEO_PALETTE_YUYV: return 16;
+ case VIDEO_PALETTE_YUV420: return 24;
+ case VIDEO_PALETTE_YUV422P: return 24; /* Planar */
+ default: return 0; /* Invalid format */
+ }
+}
+
/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
static struct mode_list mlist[] = {
/* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COML */
@@ -917,6 +957,12 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
if (ov511_stop(ov511->dev) < 0)
return -EIO;
+ /* Dumppix only works with RGB24 */
+ if (dumppix && (mode != VIDEO_PALETTE_RGB24)) {
+ err("dumppix only supported with RGB 24");
+ return -EINVAL;
+ }
+
if (mode == VIDEO_PALETTE_GREY) {
ov511_reg_write(dev, 0x16, 0x00);
if (ov511->sensor == SEN_OV7610
@@ -953,9 +999,9 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
break;
case SEN_OV6620:
hwsbase = 0x38;
- hwebase = 0x39;
- vwsbase = 0x03;
- vwebase = 0x04;
+ hwebase = 0x3a;
+ vwsbase = 0x05;
+ vwebase = 0x06;
break;
case SEN_OV7620:
hwsbase = 0x2c;
@@ -1039,13 +1085,16 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
/* Calculate and set the clock divisor */
clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
* (mlist[i].color ? 3 : 2) / 2) / 66000;
+#if 0
+ clock *= cams;
+#endif
ov511_i2c_write(dev, 0x11, clock);
-#ifdef OV511_GBR422
- ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08);
-#else
- ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
-#endif
+ /* We only have code to convert GBR -> RGB24 */
+ if ((mode == VIDEO_PALETTE_RGB24) && sensor_gbr)
+ ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x0a:0x08));
+ else
+ ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
/* 7620/6620 don't have register 0x35, so play it safe */
if (ov511->sensor == SEN_OV7610 ||
@@ -1113,7 +1162,7 @@ ov511_mode_init_regs(struct usb_ov511 *ov511,
static inline void
ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
- int rowPixels, unsigned char * rgb)
+ int rowPixels, unsigned char * rgb, int bits)
{
const int rvScale = 91881;
const int guScale = -22553;
@@ -1134,14 +1183,32 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
yTL *= yScale; yTR *= yScale;
yBL *= yScale; yBR *= yScale;
- /* Write out top two pixels */
- rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
- rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
+ if (bits == 24) {
+ /* Write out top two pixels */
+ rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
+ rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
+
+ /* Skip down to next line to write out bottom two pixels */
+ rgb += 3 * rowPixels;
+ rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
+ rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+ } else if (bits == 16) {
+ /* Write out top two pixels */
+ rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) | ((LIMIT(g+yTL) << 3) & 0xE0);
+ rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07) | (LIMIT(r+yTL) & 0xF8);
+
+ rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) | ((LIMIT(g+yTR) << 3) & 0xE0);
+ rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) | (LIMIT(r+yTR) & 0xF8);
- /* Skip down to next line to write out bottom two pixels */
- rgb += 3 * rowPixels;
- rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
- rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+ /* Skip down to next line to write out bottom two pixels */
+ rgb += 2 * rowPixels;
+
+ rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F) | ((LIMIT(g+yBL) << 3) & 0xE0);
+ rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07) | (LIMIT(r+yBL) & 0xF8);
+
+ rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F) | ((LIMIT(g+yBR) << 3) & 0xE0);
+ rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07) | (LIMIT(r+yBR) & 0xF8);
+ }
}
/*
@@ -1167,7 +1234,7 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
* Note that the U and V data in one segment represents a 16 x 16 pixel
* area, but the Y data represents a 32 x 8 pixel area.
*
- * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
+ * If dumppix module param is set, _parse_data just dumps the incoming segments,
* verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
* this puts the data on the standard output and can be analyzed with the
* parseppm.c utility I wrote. That's a much faster way for figuring out how
@@ -1177,14 +1244,8 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
#define HDIV 8
#define WDIV (256/HDIV)
-#undef OV511_DUMPPIX
-
-/* #define this and OV511_DUMPPIX to disable parsing of UV data */
-#undef OV511_FORCE_MONO
-
-#ifdef OV511_GBR422
static void
-ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
+ov511_parse_gbr422_to_rgb24(unsigned char *pIn0, unsigned char *pOut0,
int iOutY, int iOutUV, int iHalf, int iWidth)
{
int k, l, m;
@@ -1231,14 +1292,12 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
}
}
-#else
-
static void
-ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
- int iOutY, int iOutUV, int iHalf, int iWidth)
+ov511_parse_yuv420_to_rgb(unsigned char *pIn0, unsigned char *pOut0,
+ int iOutY, int iOutUV, int iHalf, int iWidth, int bits)
{
-#ifndef OV511_DUMPPIX
int k, l, m;
+ int bytes = bits >> 3;
unsigned char *pIn;
unsigned char *pOut, *pOut1;
@@ -1251,11 +1310,11 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
for (l = 0; l < 8; l++) {
for (m = 0; m < 8; m++) {
*pOut1 = *pIn++;
- pOut1 += 3;
+ pOut1 += bytes;
}
- pOut1 += (iWidth - 8) * 3;
+ pOut1 += (iWidth - 8) * bytes;
}
- pOut += 8 * 3;
+ pOut += 8 * bytes;
}
}
@@ -1265,16 +1324,16 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
for (l = 0; l < 4; l++) {
for (m=0; m<8; m++) {
int y00 = *(pOut);
- int y01 = *(pOut+3);
- int y10 = *(pOut+iWidth*3);
- int y11 = *(pOut+iWidth*3+3);
+ int y01 = *(pOut+bytes);
+ int y10 = *(pOut+iWidth*bytes);
+ int y11 = *(pOut+iWidth*bytes+bytes);
int v = *(pIn+64) - 128;
int u = *pIn++ - 128;
ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth,
- pOut);
- pOut += 6;
+ pOut, bits);
+ pOut += 2 * bytes;
}
- pOut += (iWidth*2 - 16) * 3;
+ pOut += (iWidth*2 - 16) * bytes;
}
/* Just copy the other UV rows */
@@ -1282,9 +1341,9 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
for (m = 0; m < 8; m++) {
*pOut++ = *(pIn + 64);
*pOut = *pIn++;
- pOut += 5;
+ pOut += 2 * bytes - 1;
}
- pOut += (iWidth*2 - 16) * 3;
+ pOut += (iWidth*2 - 16) * bytes;
}
/* Calculate values if it's the second half */
@@ -1302,72 +1361,65 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
int v = *pOut1 - 128;
int u = *(pOut1+1) - 128;
ov511_move_420_block(y00, y01, y10,
- y11, u, v, iWidth, pOut1);
- pOut1 += 6;
+ y11, u, v, iWidth, pOut1, bits);
+ pOut1 += 2 * bytes;
}
- pOut1 += (iWidth*2 - 8) * 3;
+ pOut1 += (iWidth*2 - 8) * bytes;
pIn += 8;
}
- pOut += 8 * 3;
+ pOut += 8 * bytes;
}
}
-#else
-
-#ifndef OV511_FORCE_MONO
- /* Just dump pix data straight out for debug */
- int i, j;
-
- pOut0 += iOutY;
- for (i = 0; i < HDIV; i++) {
- for (j = 0; j < WDIV; j++) {
- *pOut0++ = *pIn0++;
- *pOut0++ = *pIn0++;
- *pOut0++ = *pIn0++;
- }
- pOut0 += (iWidth - WDIV) * 3;
- }
-#else
+}
-#if 1
- /* This converts the Y data to "black-and-white" RGB data */
- /* Useful for experimenting with compression */
- int k, l, m;
+static void
+ov511_dumppix(unsigned char *pIn0, unsigned char *pOut0,
+ int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+ int i, j, k;
unsigned char *pIn, *pOut, *pOut1;
- pIn = pIn0 + 128;
- pOut = pOut0 + iOutY;
- for (k = 0; k < 4; k++) {
- pOut1 = pOut;
- for (l = 0; l < 8; l++) {
- for (m = 0; m < 8; m++) {
- *pOut1++ = *pIn;
- *pOut1++ = *pIn;
- *pOut1++ = *pIn++;
+ switch (dumppix) {
+ case 1: /* Just dump YUV data straight out for debug */
+ pOut0 += iOutY;
+ for (i = 0; i < HDIV; i++) {
+ for (j = 0; j < WDIV; j++) {
+ *pOut0++ = *pIn0++;
+ *pOut0++ = *pIn0++;
+ *pOut0++ = *pIn0++;
}
- pOut1 += (iWidth - 8) * 3;
+ pOut0 += (iWidth - WDIV) * 3;
}
- pOut += 8 * 3;
- }
-#else
- /* This will dump the Y channel data stream as-is */
- int count;
- unsigned char *pIn, *pOut;
-
- pIn = pIn0 + 128;
- pOut = pOut0 + output_offset;
- for (count = 0; count < 256; count++) {
- *pOut++ = *pIn;
- *pOut++ = *pIn;
- *pOut++ = *pIn++;
- output_offset += 3;
- }
-#endif
-
-#endif
-
-#endif
+ break;
+ case 2: /* This converts the Y data to "black-and-white" RGB data */
+ /* Useful for experimenting with compression */
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for (i = 0; i < 4; i++) {
+ pOut1 = pOut;
+ for (j = 0; j < 8; j++) {
+ for (k = 0; k < 8; k++) {
+ *pOut1++ = *pIn;
+ *pOut1++ = *pIn;
+ *pOut1++ = *pIn++;
+ }
+ pOut1 += (iWidth - 8) * 3;
+ }
+ pOut += 8 * 3;
+ }
+ break;
+ case 3: /* This will dump only the Y channel data stream as-is */
+ pIn = pIn0 + 128;
+ pOut = pOut0 + output_offset;
+ for (i = 0; i < 256; i++) {
+ *pOut++ = *pIn;
+ *pOut++ = *pIn;
+ *pOut++ = *pIn++;
+ output_offset += 3;
+ }
+ break;
+ } /* End switch (dumppix) */
}
-#endif
/* This converts YUV420 segments to YUYV */
static void
@@ -1662,6 +1714,11 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
/* Frame start */
PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
+#if 0
+ /* Make sure no previous data carries over; necessary
+ * for compression experimentation */
+ memset(frame->data, 0, MAX_DATA_SIZE);
+#endif
output_offset = 0;
/* Check to see if it's a snapshot frame */
@@ -1740,8 +1797,19 @@ check_middle:
ov511_parse_data_grey (pData, pOut, iOutY, frame->width);
break;
case VIDEO_PALETTE_RGB24:
- ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
- iY & 1, frame->width);
+ if (dumppix)
+ ov511_dumppix(pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width);
+ else if (sensor_gbr)
+ ov511_parse_gbr422_to_rgb24(pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width);
+ else
+ ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width, 24);
+ break;
+ case VIDEO_PALETTE_RGB565:
+ ov511_parse_yuv420_to_rgb(pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width, 16);
break;
case VIDEO_PALETTE_YUV422:
case VIDEO_PALETTE_YUYV:
@@ -1782,11 +1850,20 @@ check_middle:
static void ov511_isoc_irq(struct urb *urb)
{
int len;
- struct usb_ov511 *ov511 = urb->context;
+ struct usb_ov511 *ov511;
struct ov511_sbuf *sbuf;
- if (!ov511->dev)
+ if (!urb->context) {
+ PDEBUG(4, "no context");
return;
+ }
+
+ ov511 = (struct usb_ov511 *) urb->context;
+
+ if (!ov511->dev || !ov511->user) {
+ PDEBUG(4, "no device, or not open");
+ return;
+ }
if (!ov511->streaming) {
PDEBUG(4, "hmmm... not streaming, but got interrupt");
@@ -1805,6 +1882,8 @@ static void ov511_isoc_irq(struct urb *urb)
/* Move to the next sbuf */
ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
+ urb->dev = ov511->dev;
+
return;
}
@@ -1872,6 +1951,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb;
for (n = 0; n < OV511_NUMSBUF; n++) {
+ ov511->sbuf[n].urb->dev = ov511->dev;
err = usb_submit_urb(ov511->sbuf[n].urb);
if (err)
err("init isoc: usb_submit_urb(%d) ret %d", n, err);
@@ -2079,7 +2159,7 @@ static void ov511_dealloc(struct usb_ov511 *ov511, int now)
static int ov511_open(struct video_device *dev, int flags)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- int err = 0;
+ int err;
MOD_INC_USE_COUNT;
PDEBUG(4, "opening");
@@ -2174,8 +2254,8 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
b.audios = 0;
b.maxwidth = ov511->maxwidth;
b.maxheight = ov511->maxheight;
- b.minwidth = 32;
- b.minheight = 16;
+ b.minwidth = 160;
+ b.minheight = 120;
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
@@ -2237,12 +2317,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
- if (p.palette != VIDEO_PALETTE_GREY &&
- p.palette != VIDEO_PALETTE_RGB24 &&
- p.palette != VIDEO_PALETTE_YUV422 &&
- p.palette != VIDEO_PALETTE_YUYV &&
- p.palette != VIDEO_PALETTE_YUV420 &&
- p.palette != VIDEO_PALETTE_YUV422P)
+ if (!ov511_get_depth(p.palette))
return -EINVAL;
if (ov7610_set_picture(ov511, &p))
@@ -2373,7 +2448,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
- int ret;
+ int ret, depth;
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
@@ -2382,19 +2457,21 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
- if (vm.format != VIDEO_PALETTE_RGB24 &&
- vm.format != VIDEO_PALETTE_YUV422 &&
- vm.format != VIDEO_PALETTE_YUYV &&
- vm.format != VIDEO_PALETTE_YUV420 &&
- vm.format != VIDEO_PALETTE_YUV422P &&
- vm.format != VIDEO_PALETTE_GREY)
+ depth = ov511_get_depth(vm.format);
+ if (!depth) {
+ err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
return -EINVAL;
+ }
- if ((vm.frame != 0) && (vm.frame != 1))
+ if ((vm.frame != 0) && (vm.frame != 1)) {
+ err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
return -EINVAL;
-
- if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight)
+ }
+
+ if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) {
+ err("VIDIOCMCAPTURE: requested dimensions too big");
return -EINVAL;
+ }
if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
return -EBUSY;
@@ -2422,7 +2499,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
ov511->frame[vm.frame].format = vm.format;
ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format);
- ov511->frame[vm.frame].depth = GET_DEPTH(vm.format);
+ ov511->frame[vm.frame].depth = depth;
/* Mark it as ready */
ov511->frame[vm.frame].grabstate = FRAME_READY;
@@ -2481,6 +2558,13 @@ redo:
goto redo;
}
case FRAME_DONE:
+ if (ov511->snap_enabled && !ov511->frame[frame].snapshot) {
+ int ret;
+ if ((ret = ov511_new_frame(ov511, frame)) < 0)
+ return ret;
+ goto redo;
+ }
+
ov511->frame[frame].grabstate = FRAME_UNUSED;
/* Reset the hardware snapshot button */
@@ -2657,7 +2741,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr,
PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
- if (size > (((2 * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+ if (size > (((OV511_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
return -EINVAL;
pos = (unsigned long)ov511->fbuf;
@@ -3057,7 +3141,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
init_waitqueue_head(&ov511->wq);
- if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
+ if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) < 0) {
err("video_register_device failed");
return -EBUSY;
}
@@ -3144,7 +3228,9 @@ error:
*
***************************************************************************/
-static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
+static void * __devinit
+ov511_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_interface_descriptor *interface;
struct usb_ov511 *ov511;
@@ -3158,17 +3244,8 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
interface = &dev->actconfig->interface[ifnum].altsetting[0];
- /* Is it an OV511/OV511+? */
- if (dev->descriptor.idVendor != 0x05a9
- && dev->descriptor.idVendor != 0x0813)
- return NULL;
- if (dev->descriptor.idProduct != 0x0511
- && dev->descriptor.idProduct != 0xA511
- && dev->descriptor.idProduct != 0x0002)
- return NULL;
-
/* Checking vendor/product should be enough, but what the hell */
- if (interface->bInterfaceClass != 0xFF)
+ if (interface->bInterfaceClass != 0xFF)
return NULL;
if (interface->bInterfaceSubClass != 0x00)
return NULL;
@@ -3263,7 +3340,8 @@ error:
}
-static void ov511_disconnect(struct usb_device *dev, void *ptr)
+static void __devexit
+ov511_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
int n;
@@ -3321,10 +3399,10 @@ static void ov511_disconnect(struct usb_device *dev, void *ptr)
}
static struct usb_driver ov511_driver = {
- "ov511",
- ov511_probe,
- ov511_disconnect,
- { NULL, NULL }
+ name: "ov511",
+ id_table: device_table,
+ probe: ov511_probe,
+ disconnect: ov511_disconnect
};
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 02c1eff80..3e6ddee49 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -40,7 +40,6 @@
*/
-#include <linux/module.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <linux/init.h>
@@ -48,162 +47,44 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/usb.h>
-
-
-static const char *version = __FILE__ ": v0.4.13 2000/10/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
+#include <linux/module.h>
+#include "pegasus.h"
#define PEGASUS_USE_INTR
+#define PEGASUS_WRITE_EEPROM
-
-#define PEGASUS_II 0x80000000
-#define HAS_HOME_PNA 0x40000000
-
-#define PEGASUS_MTU 1500
-#define PEGASUS_MAX_MTU 1536
-
-#define EPROM_WRITE 0x01
-#define EPROM_READ 0x02
-#define EPROM_DONE 0x04
-#define EPROM_WR_ENABLE 0x10
-#define EPROM_LOAD 0x20
-
-#define MII_BMCR 0x00
-#define MII_BMSR 0x01
-#define BMSR_MEDIA 0x7808
-#define MII_ANLPA 0x05
-#define ANLPA_100TX_FD 0x0100
-#define ANLPA_100TX_HD 0x0080
-#define ANLPA_10T_FD 0x0040
-#define ANLPA_10T_HD 0x0020
-#define PHY_DONE 0x80
-#define PHY_READ 0x40
-#define PHY_WRITE 0x20
-#define DEFAULT_GPIO_RESET 0x24
-#define LINKSYS_GPIO_RESET 0x24
-#define DEFAULT_GPIO_SET 0x26
-
-#define PEGASUS_PRESENT 0x00000001
-#define PEGASUS_RUNNING 0x00000002
-#define PEGASUS_TX_BUSY 0x00000004
-#define PEGASUS_RX_BUSY 0x00000008
-#define CTRL_URB_RUNNING 0x00000010
-#define CTRL_URB_SLEEP 0x00000020
-#define PEGASUS_UNPLUG 0x00000040
-#define ETH_REGS_CHANGE 0x40000000
-#define ETH_REGS_CHANGED 0x80000000
-
-#define RX_MULTICAST 2
-#define RX_PROMISCUOUS 4
-
-#define REG_TIMEOUT (HZ)
-#define PEGASUS_TX_TIMEOUT (HZ*10)
-
-#define TX_UNDERRUN 0x80
-#define EXCESSIVE_COL 0x40
-#define LATE_COL 0x20
-#define NO_CARRIER 0x10
-#define LOSS_CARRIER 0x08
-#define JABBER_TIMEOUT 0x04
-
-#define PEGASUS_REQT_READ 0xc0
-#define PEGASUS_REQT_WRITE 0x40
-#define PEGASUS_REQ_GET_REGS 0xf0
-#define PEGASUS_REQ_SET_REGS 0xf1
-#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS
-#define NUM_CTRL_URBS 0x10
-#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
-
-enum pegasus_registers {
- EthCtrl0 = 0,
- EthCtrl1 = 1,
- EthCtrl2 = 2,
- EthID = 0x10,
- Reg1d = 0x1d,
- EpromOffset = 0x20,
- EpromData = 0x21, /* 0x21 low, 0x22 high byte */
- EpromCtrl = 0x23,
- PhyAddr = 0x25,
- PhyData = 0x26, /* 0x26 low, 0x27 high byte */
- PhyCtrl = 0x28,
- UsbStst = 0x2a,
- EthTxStat0 = 0x2b,
- EthTxStat1 = 0x2c,
- EthRxStat = 0x2d,
- Reg7b = 0x7b,
- Gpio0 = 0x7e,
- Gpio1 = 0x7f,
- Reg81 = 0x81,
-};
-
-
-typedef struct pegasus {
- struct usb_device *usb;
- struct net_device *net;
- struct net_device_stats stats;
- unsigned flags;
- unsigned features;
- int intr_interval;
- struct urb ctrl_urb, rx_urb, tx_urb, intr_urb;
- devrequest dr;
- wait_queue_head_t ctrl_wait;
- struct semaphore ctrl_sem;
- unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
- unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]);
- unsigned char ALIGN(intr_buff[8]);
- __u8 eth_regs[4];
- __u8 phy;
- __u8 gpio_res;
-} pegasus_t;
-
-struct usb_eth_dev {
- char *name;
- __u16 vendor;
- __u16 device;
- __u32 private; /* LSB is gpio reset value */
-};
+static const char *version = __FILE__ ": v0.4.17 2000/11/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
static int loopback = 0;
static int mii_mode = 0;
static int multicast_filter_limit = 32;
+static struct usb_eth_dev usb_dev_id[] = {
+#define PEGASUS_DEV(pn, vid, pid, flags) \
+ {name:pn, vendor:vid, device:pid, private:flags},
+#include "pegasus.h"
+#undef PEGASUS_DEV
+ {NULL, 0, 0, 0}
+};
+
+static struct usb_device_id pegasus_ids[] = {
+#define PEGASUS_DEV(pn, vid, pid, flags) {idVendor:vid, idProduct:pid},
+#include "pegasus.h"
+#undef PEGASUS_DEV
+ { }
+};
+
MODULE_AUTHOR("Petko Manolov <petkan@dce.bg>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
-MODULE_PARM(mode, "i");
+MODULE_PARM(mii_mode, "i");
MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
-MODULE_PARM_DESC(mode, "Enable HomePNA mode (bit 0) - default = MII mode = 0");
+MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0");
-
-static struct usb_eth_dev usb_dev_id[] = {
- {"Billionton USB-100", 0x08dd, 0x0986, DEFAULT_GPIO_RESET},
- {"Corega FEter USB-TX", 0x7aa, 0x0004, DEFAULT_GPIO_RESET},
- {"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, DEFAULT_GPIO_RESET},
- {"D-Link DSB-650TX", 0x2001, 0x4001, LINKSYS_GPIO_RESET},
- {"D-Link DSB-650TX", 0x2001, 0x4002, LINKSYS_GPIO_RESET},
- {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003,
- HAS_HOME_PNA | DEFAULT_GPIO_RESET},
- {"D-Link DSB-650", 0x2001, 0xabc1, DEFAULT_GPIO_RESET},
- {"D-Link DU-E10", 0x07b8, 0xabc1, DEFAULT_GPIO_RESET},
- {"D-Link DU-E100", 0x07b8, 0x4002, DEFAULT_GPIO_RESET},
- {"Linksys USB10TX", 0x066b, 0x2202, LINKSYS_GPIO_RESET},
- {"Linksys USB100TX", 0x066b, 0x2203, LINKSYS_GPIO_RESET},
- {"Linksys USB100TX", 0x066b, 0x2204, HAS_HOME_PNA | LINKSYS_GPIO_RESET},
- {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, LINKSYS_GPIO_RESET},
- {"SMC 202 USB Ethernet", 0x0707, 0x0200, DEFAULT_GPIO_RESET},
- {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986,
- HAS_HOME_PNA | DEFAULT_GPIO_RESET},
- {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046,
- DEFAULT_GPIO_RESET},
- {"IO DATA USB ET/TX", 0x04bb, 0x0904, DEFAULT_GPIO_RESET},
- {"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, DEFAULT_GPIO_RESET},
- {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, DEFAULT_GPIO_RESET},
- {"ADMtek ADM8511 \"Pegasus II\" USB Ethernet", 0x07a6, 0x8511,
- PEGASUS_II | DEFAULT_GPIO_RESET},
- {NULL, 0, 0, 0}
-};
+MODULE_DEVICE_TABLE (usb, pegasus_ids);
static int update_eth_regs_async( pegasus_t * );
@@ -243,7 +124,7 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
- if ( pegasus->flags & ETH_REGS_CHANGED ) {
+ while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP;
interruptible_sleep_on( &pegasus->ctrl_wait );
}
@@ -274,7 +155,7 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
- if ( pegasus->flags & ETH_REGS_CHANGED ) {
+ while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP ;
interruptible_sleep_on( &pegasus->ctrl_wait );
}
@@ -305,7 +186,7 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
{
int ret;
- if ( pegasus->flags & ETH_REGS_CHANGED ) {
+ while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP;
interruptible_sleep_on( &pegasus->ctrl_wait );
}
@@ -354,7 +235,7 @@ static int update_eth_regs_async( pegasus_t *pegasus )
}
-static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
+static int read_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
@@ -377,7 +258,7 @@ static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd )
}
-static int write_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
+static int write_mii_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd )
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
@@ -505,6 +386,15 @@ static inline int reset_mac( pegasus_t *pegasus )
}
if ( i == REG_TIMEOUT )
return 1;
+
+ if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
+ usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+ __u16 auxmode;
+
+ read_mii_word( pegasus, 0, 0x1b, &auxmode );
+ write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+ }
+
return 0;
}
@@ -516,13 +406,13 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
pegasus_t *pegasus = dev->priv;
- if ( read_phy_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) )
- return 2;
+ if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) )
+ return 1;
if ( !(bmsr & 0x20) && !loopback )
warn( "%s: link NOT established (0x%x) - check the cable.",
dev->name, bmsr );
- if ( read_phy_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
- return 4;
+ if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+ return 2;
if ( !(linkpart & 1) )
warn( "link partner stat %x", linkpart );
@@ -536,7 +426,7 @@ static int enable_net_traffic( struct net_device *dev, struct usb_device *usb )
data[1] = 0;
data[2] = (loopback & 1) ? 0x09 : 0x01;
- *(unsigned *)pegasus->eth_regs = *(unsigned *)data;
+ memcpy( pegasus->eth_regs, data, sizeof(data) );
set_registers( pegasus, EthCtrl0, 3, data );
@@ -562,23 +452,29 @@ static void read_bulk_callback( struct urb *urb )
if ( pegasus->flags & PEGASUS_RX_BUSY ) {
pegasus->stats.rx_errors++;
+ dbg("pegasus Rx busy");
return;
}
pegasus->flags |= PEGASUS_RX_BUSY;
- rx_status = *(int *)(pegasus->rx_buff + count - 4);
-
- if (urb->status) {
- dbg("%s: RX status %d", net->name, urb->status);
- goto goon;
+ switch ( urb->status ) {
+ case USB_ST_NOERROR:
+ break;
+ case USB_ST_NORESPONSE:
+ dbg( "reset MAC" );
+ pegasus->flags &= ~PEGASUS_RX_BUSY;
+ break;
+ default:
+ dbg( "%s: RX status %d", net->name, urb->status );
+ goto goon;
}
if ( !count )
goto goon;
+ rx_status = *(int *)(pegasus->rx_buff + count - 4);
if ( rx_status & 0x000e0000 ) {
-
- dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000);
+ dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
pegasus->stats.rx_errors++;
if ( rx_status & 0x060000 )
pegasus->stats.rx_length_errors++;
@@ -586,7 +482,6 @@ static void read_bulk_callback( struct urb *urb )
pegasus->stats.rx_crc_errors++;
if ( rx_status & 0x100000 )
pegasus->stats.rx_frame_errors++;
-
goto goon;
}
@@ -629,6 +524,7 @@ static void write_bulk_callback( struct urb *urb )
if ( urb->status )
info("%s: TX status %d", pegasus->net->name, urb->status);
+ pegasus->net->trans_start = jiffies;
netif_wake_queue( pegasus->net );
}
@@ -641,6 +537,16 @@ static void intr_callback( struct urb *urb )
if ( !pegasus )
return;
+
+ switch ( urb->status ) {
+ case USB_ST_NOERROR:
+ break;
+ case USB_ST_URB_KILLED:
+ return;
+ default:
+ info("intr status %d", urb->status);
+ }
+
d = urb->transfer_buffer;
net = pegasus->net;
if ( d[0] & 0xfc ) {
@@ -654,31 +560,23 @@ static void intr_callback( struct urb *urb )
if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
pegasus->stats.tx_carrier_errors++;
}
- switch ( urb->status ) {
- case USB_ST_NOERROR:
- break;
- case USB_ST_URB_KILLED:
- break;
- default:
- info("intr status %d", urb->status);
- }
}
#endif
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
static void pegasus_tx_timeout( struct net_device *net )
{
pegasus_t *pegasus = net->priv;
if ( !pegasus )
return;
-
- usb_unlink_urb( &pegasus->tx_urb );
+
warn("%s: Tx timed out.", net->name);
+ pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb( &pegasus->tx_urb );
pegasus->stats.tx_errors++;
- net->trans_start = jiffies;
-
- netif_wake_queue( net );
}
+#endif
static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
@@ -696,7 +594,6 @@ static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
pegasus->tx_buff, PEGASUS_MAX_MTU,
write_bulk_callback, pegasus );
pegasus->tx_urb.transfer_buffer_length = count;
- pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
if ((res = usb_submit_urb(&pegasus->tx_urb))) {
warn("failed tx_urb %d", res);
pegasus->stats.tx_errors++;
@@ -732,6 +629,14 @@ static inline void get_interrupt_interval( pegasus_t *pegasus )
__u8 data[2];
read_eprom_word( pegasus, 4, (__u16 *)data );
+ if ( data[1] < 0x80 ) {
+ info( "intr interval will be changed from %ums to %ums",
+ data[1], 0x80 );
+ data[1] = 0x80;
+#ifdef PEGASUS_WRITE_EEPROM
+ write_eprom_word( pegasus, 4, *(__u16 *)data );
+#endif
+ }
pegasus->intr_interval = data[1];
}
@@ -754,7 +659,6 @@ static int pegasus_open(struct net_device *net)
if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
warn( __FUNCTION__ " failed rx_urb %d", res );
#ifdef PEGASUS_USE_INTR
- get_interrupt_interval( pegasus );
FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
@@ -781,8 +685,9 @@ static int pegasus_close( struct net_device *net )
usb_unlink_urb( &pegasus->rx_urb );
usb_unlink_urb( &pegasus->tx_urb );
usb_unlink_urb( &pegasus->ctrl_urb );
+#ifdef PEGASUS_USE_INTR
usb_unlink_urb( &pegasus->intr_urb );
-
+#endif
MOD_DEC_USE_COUNT;
return 0;
@@ -798,12 +703,12 @@ static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
case SIOCDEVPRIVATE:
data[0] = pegasus->phy;
case SIOCDEVPRIVATE+1:
- read_phy_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+ read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
return 0;
case SIOCDEVPRIVATE+2:
if ( !capable(CAP_NET_ADMIN) )
return -EPERM;
- write_phy_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+ write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
return 0;
default:
return -EOPNOTSUPP;
@@ -838,34 +743,20 @@ static void pegasus_set_multicast( struct net_device *net )
}
-static int check_device_ids( __u16 vendor, __u16 product )
-{
- int i=0;
-
- while ( usb_dev_id[i].name ) {
- if ( (usb_dev_id[i].vendor == vendor) &&
- (usb_dev_id[i].device == product) )
- return i;
- i++;
- }
- return -1;
-}
-
-
static __u8 mii_phy_probe( pegasus_t *pegasus )
{
int i;
__u16 tmp;
for ( i=0; i < 32; i++ ) {
- read_phy_word( pegasus, i, MII_BMSR, &tmp );
+ read_mii_word( pegasus, i, MII_BMSR, &tmp );
if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )
continue;
else
return i;
}
- return 0;
+ return 0xff;
}
@@ -880,15 +771,12 @@ static inline void setup_pegasus_II( pegasus_t *pegasus )
}
-static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum )
+static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
- struct net_device *net;
- pegasus_t *pegasus;
- int dev_indx;
-
- if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
- return NULL;
- }
+ struct net_device *net;
+ pegasus_t *pegasus;
+ int dev_index = id - pegasus_ids;
if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
err("usb_set_configuration() failed");
@@ -902,7 +790,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum )
usb_inc_dev_use( dev );
memset(pegasus, 0, sizeof(struct pegasus));
- init_MUTEX( &pegasus-> ctrl_sem );
+ pegasus->dev_index = dev_index;
init_waitqueue_head( &pegasus->ctrl_wait );
net = init_etherdev( NULL, 0 );
@@ -926,7 +814,10 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum )
net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU;
- pegasus->features = usb_dev_id[dev_indx].private;
+ pegasus->features = usb_dev_id[dev_index].private;
+#ifdef PEGASUS_USE_INTR
+ get_interrupt_interval( pegasus );
+#endif
if ( reset_mac(pegasus) ) {
err("can't reset MAC");
unregister_netdev( pegasus->net );
@@ -935,21 +826,21 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum )
return NULL;
}
+ info( "%s: %s", net->name, usb_dev_id[dev_index].name );
+
set_ethernet_addr( pegasus );
-
+
if ( pegasus->features & PEGASUS_II ) {
info( "setup Pegasus II specific registers" );
setup_pegasus_II( pegasus );
}
pegasus->phy = mii_phy_probe( pegasus );
- if ( !pegasus->phy ) {
+ if ( pegasus->phy == 0xff ) {
warn( "can't locate MII phy, using default" );
pegasus->phy = 1;
}
- info( "%s: %s", net->name, usb_dev_id[dev_indx].name );
-
return pegasus;
}
@@ -975,6 +866,7 @@ static struct usb_driver pegasus_driver = {
name: "pegasus",
probe: pegasus_probe,
disconnect: pegasus_disconnect,
+ id_table: pegasus_ids,
};
int __init pegasus_init(void)
diff --git a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
new file mode 100644
index 000000000..740aaf389
--- /dev/null
+++ b/drivers/usb/pegasus.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
+ *
+ * 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
+ */
+
+
+#ifndef PEGASUS_DEV
+
+#define PEGASUS_II 0x80000000
+#define HAS_HOME_PNA 0x40000000
+
+#define PEGASUS_MTU 1500
+#define PEGASUS_MAX_MTU 1536
+
+#define EPROM_WRITE 0x01
+#define EPROM_READ 0x02
+#define EPROM_DONE 0x04
+#define EPROM_WR_ENABLE 0x10
+#define EPROM_LOAD 0x20
+
+#define MII_BMCR 0x00
+#define MII_BMSR 0x01
+#define BMSR_MEDIA 0x7808
+#define MII_ANLPA 0x05
+#define ANLPA_100TX_FD 0x0100
+#define ANLPA_100TX_HD 0x0080
+#define ANLPA_10T_FD 0x0040
+#define ANLPA_10T_HD 0x0020
+#define PHY_DONE 0x80
+#define PHY_READ 0x40
+#define PHY_WRITE 0x20
+#define DEFAULT_GPIO_RESET 0x24
+#define LINKSYS_GPIO_RESET 0x24
+#define DEFAULT_GPIO_SET 0x26
+
+#define PEGASUS_PRESENT 0x00000001
+#define PEGASUS_RUNNING 0x00000002
+#define PEGASUS_TX_BUSY 0x00000004
+#define PEGASUS_RX_BUSY 0x00000008
+#define CTRL_URB_RUNNING 0x00000010
+#define CTRL_URB_SLEEP 0x00000020
+#define PEGASUS_UNPLUG 0x00000040
+#define ETH_REGS_CHANGE 0x40000000
+#define ETH_REGS_CHANGED 0x80000000
+
+#define RX_MULTICAST 2
+#define RX_PROMISCUOUS 4
+
+#define REG_TIMEOUT (HZ)
+#define PEGASUS_TX_TIMEOUT (HZ*10)
+
+#define TX_UNDERRUN 0x80
+#define EXCESSIVE_COL 0x40
+#define LATE_COL 0x20
+#define NO_CARRIER 0x10
+#define LOSS_CARRIER 0x08
+#define JABBER_TIMEOUT 0x04
+
+#define PEGASUS_REQT_READ 0xc0
+#define PEGASUS_REQT_WRITE 0x40
+#define PEGASUS_REQ_GET_REGS 0xf0
+#define PEGASUS_REQ_SET_REGS 0xf1
+#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS
+#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
+
+enum pegasus_registers {
+ EthCtrl0 = 0,
+ EthCtrl1 = 1,
+ EthCtrl2 = 2,
+ EthID = 0x10,
+ Reg1d = 0x1d,
+ EpromOffset = 0x20,
+ EpromData = 0x21, /* 0x21 low, 0x22 high byte */
+ EpromCtrl = 0x23,
+ PhyAddr = 0x25,
+ PhyData = 0x26, /* 0x26 low, 0x27 high byte */
+ PhyCtrl = 0x28,
+ UsbStst = 0x2a,
+ EthTxStat0 = 0x2b,
+ EthTxStat1 = 0x2c,
+ EthRxStat = 0x2d,
+ Reg7b = 0x7b,
+ Gpio0 = 0x7e,
+ Gpio1 = 0x7f,
+ Reg81 = 0x81,
+};
+
+
+typedef struct pegasus {
+ struct usb_device *usb;
+ struct net_device *net;
+ struct net_device_stats stats;
+ unsigned flags;
+ unsigned features;
+ int dev_index;
+ int intr_interval;
+ struct urb ctrl_urb, rx_urb, tx_urb, intr_urb;
+ devrequest dr;
+ wait_queue_head_t ctrl_wait;
+ struct semaphore ctrl_sem;
+ unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
+ unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]);
+ unsigned char ALIGN(intr_buff[8]);
+ __u8 eth_regs[4];
+ __u8 phy;
+ __u8 gpio_res;
+} pegasus_t;
+
+
+struct usb_eth_dev {
+ char *name;
+ __u16 vendor;
+ __u16 device;
+ __u32 private; /* LSB is gpio reset value */
+};
+
+
+#define VENDOR_ACCTON 0x083a
+#define VENDOR_ADMTEK 0x07a6
+#define VENDOR_BILLIONTON 0x08dd
+#define VENDOR_COREGA 0x07aa
+#define VENDOR_DLINK1 0x2001
+#define VENDOR_DLINK2 0x07b8
+#define VENDOR_IODATA 0x04bb
+#define VENDOR_LANEED 0x056e
+#define VENDOR_LINKSYS 0x066b
+#define VENDOR_MELCO 0x0411
+#define VENDOR_SMC 0x0707
+#define VENDOR_SOHOWARE 0x15e8
+
+
+#else /* PEGASUS_DEV */
+
+
+PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
+ VENDOR_ADMTEK, 0x8511,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)",
+ VENDOR_ADMTEK, 0x0986,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4001,
+ LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4002,
+ LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK1, 0x4003,
+ DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK1, 0xabc1,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DU-E10", VENDOR_DLINK2, 0xabc1,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
+ LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
+ LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
+ LINKSYS_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+ LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
+ DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+ DEFAULT_GPIO_RESET )
+
+
+#endif /* PEGASUS_DEV */
diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c
index d3d1b4e6a..d247c0b28 100644
--- a/drivers/usb/plusb.c
+++ b/drivers/usb/plusb.c
@@ -1,9 +1,11 @@
/*****************************************************************************/
/*
- * plusb.c -- prolific pl-2302 driver.
+ * plusb.c -- prolific pl-2301/pl-2302 driver.
*
* Copyright (C) 2000 Deti Fliegl (deti@fliegl.de)
+ * Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2000 Eric Z. Ayers (eric@compgen.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
@@ -20,9 +22,100 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
+ * This driver creates a network interface (plusb0, plusb1, ...) that will
+ * send messages over a USB host-host cable based on the Prolific ASIC.
+ * It works a lot like plip or PP over an RS-232C null modem cable.
+ *
+ * Expect speeds of around 330Kbytes/second over a UHCI host controller.
+ * OHCI should be faster. Increase the MTU for faster transfers of large
+ * files. (16384 is a good size)
*
* $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
*
+ * Changelog:
+ *
+ * v0.1 deti
+ * Original Version of driver.
+ * v0.2 15 Sep 2000 pavel
+ * Patches to decrease latency by rescheduling the bottom half of
+ * interrupt code.
+ * v0.3 10 Oct 2000 eric
+ * Patches to work in v2.2 backport (v2.4 changes the way net_dev.name
+ * is allocated)
+ * v0.4 19 Oct 2000 eric
+ * Some more performance fixes. Lock re-submitting urbs.
+ * Lower the number of sk_buff's to queue.
+ * v0.5 25 Oct 2000 eric
+ * Removed use of usb_bulk_msg() all together. This caused
+ * the driver to block in an interrupt context.
+ * Consolidate read urb submission into read_urb_submit().
+ * Performance is the same as v0.4.
+ * v0.5.1 27 Oct 2000 eric
+ * Extra debugging messages to help diagnose problem with uchi.o stack.
+ * v0.5.2 27 Oct 2000 eric
+ * Set the 'start' flag for the network device in plusb_net_start()
+ * and plusb_net_stop() (doesn't help)
+ * v0.5.3 27 Oct 2000 pavel
+ * Commented out handlers when -EPIPE is received,
+ * (remove calls to usb_clear_halt()) Since the callback is in
+ * an interrupt context, it doesn't help, it just panics
+ * the kernel. (what do we do?)
+ * Under high load, dev_alloc_skb() fails, the read URB must
+ * be re-submitted.
+ * Added plusb_change_mtu() and increased the size of _BULK_DATA_LEN
+ * v0.5.4 31 Oct 2000 eric
+ * Fix race between plusb_net_xmit() and plusb_bulk_write_complete()
+ * v0.5.5 1 Nov 2000 eric
+ * Remove dev->start field, otherwise, it won't compile in 2.4
+ * Use dev_kfree_skb_any(). (important in 2.4 kernel)
+ * v0.5.6 2 Nov 2000 pavel,eric
+ * Add calls to netif_stop_queue() and netif_start_queue()
+ * Drop packets that come in while the free list is empty.
+ * (This version is being submitted after the release of 2.4-test10)
+ * v0.5.7 6 Nov 2000
+ * Fix to not re-submit the urb on error to help when cables
+ * are yanked (not tested)
+ *
+ *
+ * KNOWN PROBLEMS: (Any suggestions greatfully accepted!)
+ *
+ * 2 Nov 2000
+ * - The shutdown for this may not be entirely clean. Sometimes, the
+ * kernel will Oops when the cable is unplugged, or
+ * if the plusb module is removed.
+ * - If you ifdown a device and then ifup it again, the link will not
+ * always work. You have to 'rmmod plusb ; modprobe plusb' on
+ * both machines to get it to work again. Something must be wrong with
+ * plusb_net_open() and plusb_net_start() ? Maybe
+ * the 'suspend' and 'resume' entry points need to be
+ * implemented?
+ * - Needs to handle -EPIPE correctly in bulk complete handlers.
+ * (replace usb_clear_halt() function with async urbs?)
+ * - I think this code relies too much on one spinlock and does
+ * too much in the interrupt handler. The net1080 code is
+ * much more elegant, and should work for this chip. Its
+ * only drawback is that it is going to be tough to backport
+ * it to v2.2.
+ * - Occasionally the device will hang under the 'uhci.o'
+ * driver. The workaround is to ifdown the device and
+ * remove the modules, then re-insert them. You may have
+ * better luck with the 'usb-uhci.o' driver.
+ * - After using ifconfig down ; ifconfig up, sometimes packets
+ * continue to be received, but there is a framing problem.
+ *
+ * FUTURE DIRECTIONS:
+ *
+ * - Fix the known problems.
+ * - There isn't much functional difference between the net1080
+ * driver and this one. It would be neat if the same driver
+ * could handle both types of chips. Or if both drivers
+ * could handle both types of chips - this one is easier to
+ * backport to the 2.2 kernel.
+ * - Get rid of plusb_add_buf_tail and the single spinlock.
+ * Use a separate spinlock for the 2 lists, and use atomic
+ * operators for writeurb_submitted and readurb_submitted members.
+ *
+ *
*/
/*****************************************************************************/
@@ -40,23 +133,102 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-//#define DEBUG
+//#define DEBUG 1
#include <linux/usb.h>
-#include "plusb.h"
+/* Definitions formerly in plusb.h relocated. No need to export them -EZA */
+
+#define _PLUSB_INTPIPE 0x1
+#define _PLUSB_BULKOUTPIPE 0x2
+#define _PLUSB_BULKINPIPE 0x3
+
+#define _SKB_NUM 32
+
+/* increase size of BULK_DATA_LEN so we can use bigger MTU's*/
+#define _BULK_DATA_LEN 32768
+
+
+typedef struct
+{
+ int connected; /* indicates if this structure is active */
+ struct usb_device *usbdev;
+ /* keep track of USB structure */
+ int status; /* Prolific status byte returned from interrupt */
+ int in_bh; /* flag to indicate that we are in the bulk handler */
+ int opened; /* flag to indicate that network dev is open */
+
+ spinlock_t lock; /* Lock for the buffer list. re-used for
+ locking around submitting the readurb member.
+ */
+ urb_t *inturb; /* Read buffer for the interrupt callback */
+ unsigned char * interrupt_in_buffer;
+ /* holds data for the inturb*/
+ urb_t *readurb; /* Read buffer for the bulk data callback */
+ unsigned char * bulk_in_buffer;
+ /* kmalloc'ed data for the readurb */
+ int readurb_submitted;
+ /* Flag to indicate that readurb already sent */
+ urb_t *writeurb; /* Write buffer for the bulk data callback */
+ int writeurb_submitted;
+ /* Flag to indicate that writeurb already sent */
+
+ struct list_head tx_skb_list;
+ /* sk_buff's read from net device */
+ struct list_head free_skb_list;
+ /* free sk_buff list */
+ struct net_device net_dev;
+ /* handle to linux network device */
+ struct net_device_stats net_stats;
+ /* stats to return for ifconfig output */
+} plusb_t,*pplusb_t;
+
+/*
+ * skb_list - queue of packets from the network driver to be delivered to USB
+ */
+typedef struct
+{
+ struct list_head skb_list;
+ struct sk_buff *skb;
+ int state;
+ plusb_t *s;
+} skb_list_t,*pskb_list_t;
+
/* --------------------------------------------------------------------- */
#define NRPLUSB 4
+/*
+ * Interrupt endpoint status byte, from Prolific PL-2301 docs
+ * Check the 'download' link at www.prolifictech.com
+ */
+#define _PL_INT_RES1 0x80 /* reserved */
+#define _PL_INT_RES2 0x40 /* reserved */
+#define _PL_INT_RXD _PL_INT_RES2 /* Read data ready - Not documented by Prolific, but seems to work! */
+#define _PL_INT_TX_RDY 0x20 /* OK to transmit data */
+#define _PL_INT_RESET_O 0x10 /* reset output pipe */
+#define _PL_INT_RESET_I 0x08 /* reset input pipe */
+#define _PL_INT_TX_C 0x04 /* transmission complete */
+#define _PL_INT_TX_REQ 0x02 /* transmission received */
+#define _PL_INT_PEER_E 0x01 /* peer exists */
+
/*-------------------------------------------------------------------*/
static plusb_t plusb[NRPLUSB];
+static void plusb_write_bulk_complete(urb_t *purb);
+static void plusb_read_bulk_complete(urb_t *purb);
+static void plusb_int_complete(urb_t *purb);
+
/* --------------------------------------------------------------------- */
+
+/*
+ * plusb_add_buf_tail - Take the head of the src list and append it to
+ * the tail of the dest list
+ */
static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src)
{
- unsigned long flags;
+ unsigned long flags = 0;
struct list_head *tmp;
int ret = 0;
@@ -76,126 +248,227 @@ static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_he
}
/*-------------------------------------------------------------------*/
-static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
+/*
+ * dequeue_next_skb - submit the first thing on the tx_skb_list to the
+ * USB stack. This function should be called each time we get a new
+ * message to send to the other host, or each time a message is sucessfully
+ * sent.
+ */
+static void dequeue_next_skb(char * func, plusb_t * s)
{
- int ret;
+ skb_list_t * skb_list;
+ unsigned long flags = 0;
- dbg("plusb_my_bulk: len:%d",size);
+ if (!s->connected)
+ return;
+
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (!list_empty (&s->tx_skb_list) && !s->writeurb_submitted) {
+ int submit_ret;
+ skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
- ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
- if(ret<0) {
- err("plusb: usb_bulk_msg failed(%d)",ret);
+ if (skb_list->skb) {
+ s->writeurb_submitted = 1;
+
+ /* Use the buffer inside the sk_buff directly. why copy? */
+ FILL_BULK_URB_TO(s->writeurb, s->usbdev,
+ usb_sndbulkpipe(s->usbdev, _PLUSB_BULKOUTPIPE),
+ skb_list->skb->data, skb_list->skb->len,
+ plusb_write_bulk_complete, skb_list, 500);
+
+ dbg ("%s: %s: submitting urb. skb_list %p", s->net_dev.name, func, skb_list);
+
+ submit_ret = usb_submit_urb(s->writeurb);
+ if (submit_ret) {
+ s->writeurb_submitted = 0;
+ printk (KERN_CRIT "%s: %s: can't submit writeurb: %d\n",
+ s->net_dev.name, func, submit_ret);
+ }
+ } /* end if the skb value has been filled in */
}
- if( ret == -EPIPE ) {
- warn("CLEAR_FEATURE request to remove STALL condition.");
- if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
- err("request failed");
- }
-
- dbg("plusb_my_bulk: finished act: %d", *actual_length);
- return ret;
+ spin_unlock_irqrestore (&s->lock, flags);
}
-/* --------------------------------------------------------------------- */
-
-static void plusb_bh(void *context)
+/*
+ * submit_read_urb - re-submit the read URB to the stack
+ */
+void submit_read_urb(char * func, plusb_t * s)
{
- plusb_t *s=context;
- struct net_device_stats *stats=&s->net_stats;
- int ret=0;
- int actual_length;
- skb_list_t *skb_list;
- struct sk_buff *skb;
-
- dbg("plusb_bh: i:%d",in_interrupt());
-
- while(!list_empty(&s->tx_skb_list)) {
+ unsigned long flags=0;
- if(!(s->status&_PLUSB_TXOK))
- break;
-
- skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
- if(!skb_list->state) {
- dbg("plusb_bh: not yet ready");
- schedule();
- continue;
- }
-
- skb=skb_list->skb;
- ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
- skb->data, skb->len, &actual_length);
+ if (!s->connected)
+ return;
- if(ret || skb->len != actual_length ||!(skb->len%64)) {
- plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
- NULL, 0, &actual_length);
- }
-
- if(!ret) {
- stats->tx_packets++;
- stats->tx_bytes+=skb->len;
- }
- else {
- stats->tx_errors++;
- stats->tx_aborted_errors++;
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (!s->readurb_submitted) {
+ int ret;
+ s->readurb_submitted=1;
+ s->readurb->dev=s->usbdev;
+ ret = usb_submit_urb(s->readurb);
+ if (ret) {
+ printk (KERN_CRIT "%s: %s: error %d submitting read URB\n",
+ s->net_dev.name, func, ret);
+ s->readurb_submitted=0;
}
-
- dbg("plusb_bh: dev_kfree_skb");
-
- dev_kfree_skb(skb);
- skb_list->state=0;
- plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);
}
- dbg("plusb_bh: finished");
- s->in_bh=0;
+ spin_unlock_irqrestore (&s->lock, flags);
+
}
-
/* --------------------------------------------------------------------- */
+/*
+ * plusb_net_xmit - callback from the network device driver for outgoing data
+ *
+ * Data has arrived to the network device from the local machine and needs
+ * to be sent over the USB cable. This is in an interrupt, so we don't
+ * want to spend too much time in this function.
+ *
+ */
static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
plusb_t *s=dev->priv;
skb_list_t *skb_list;
- int ret=NET_XMIT_SUCCESS;
+ unsigned int flags;
dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt());
- if(!s->connected || list_empty(&s->free_skb_list)) {
- ret=NET_XMIT_CN;
- goto lab;
- }
+ if(!s->connected || !s->opened) {
+ /*
+ NOTE: If we get to this point, you'll return the error
+ kernel: virtual device plusb0 asks to queue packet
+
+ Other things we could do:
+ 1) just drop this packet
+ 2) drop other packets in the queue
+ */
+ return 1;
+ }
- plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list);
+ spin_lock_irqsave (&s->lock, flags);
+
+ if (list_empty(&s->free_skb_list)
+ || plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list)) {
+ /* The buffers on this side are full. DROP the packet
+ I think that this shouldn't happen with the correct
+ use of the netif_XXX functions -EZA
+ */
+ dbg ("plusb: Free list is empty.");
+ kfree_skb(skb);
+ s->net_stats.tx_dropped++;
+ spin_unlock_irqrestore (&s->lock, flags);
+ return 0;
+ }
+
skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list);
skb_list->skb=skb;
skb_list->state=1;
+ skb_list->s=s;
+
+ if (list_empty(&s->free_skb_list)) {
+ /* apply "backpressure". Tell the net layer to stop sending
+ the driver packets.
+ */
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore (&s->lock, flags);
+
+ /* If there is no write urb outstanding, pull the first thing
+ off of the list and submit it to the USB stack
+ */
+ dequeue_next_skb("plusb_net_xmit", s);
+
+ return 0;
+}
-lab:
- if(s->in_bh)
- return ret;
+/* --------------------------------------------------------------------- */
- dbg("plusb_net_xmit: queue_task");
+/*
+ * plusb_write_bulk_complete () - callback after the data has been
+ * sent to the USB device, or a timeout occured.
+ */
+static void plusb_write_bulk_complete(urb_t *purb)
+{
+ skb_list_t * skb_list=purb->context;
+ plusb_t *s=skb_list->s;
- s->in_bh=1;
- queue_task(&s->bh, &tq_scheduler);
+ dbg ("%s: plusb_write_bulk_complete: status:%d skb_list:%p\n",
+ s->net_dev.name, purb->status, skb_list);
- dbg("plusb_net_xmit: finished");
- return ret;
+ skb_list->state=0;
-}
+ if( purb->status == -EPIPE ) {
+
+ printk(KERN_CRIT "%s: plusb_write_bulk_complete: got -EPIPE and don't know what to do!\n",
+ s->net_dev.name);
+ }
+
+ if(!purb->status) {
+ s->net_stats.tx_packets++;
+ s->net_stats.tx_bytes+=skb_list->skb->len;
+ }
+ else {
+ err ("%s: plusb_write_bulk_complete: returned ERROR status:%d\n",
+ s->net_dev.name, purb->status);
-/* --------------------------------------------------------------------- */
+ s->net_stats.tx_errors++;
+ s->net_stats.tx_aborted_errors++;
+ }
+
+ dbg("plusb_bh: dev_kfree_skb");
+
+
+#if (LINUX_VERSION_CODE < 0x020300)
+ dev_kfree_skb(skb_list->skb);
+#else
+ /* NOTE: In 2.4 it's a problem to call dev_kfree_skb() in a hard IRQ:
+ Oct 28 23:42:14 bug kernel: Warning: kfree_skb on hard IRQ c023329a
+ */
+ dev_kfree_skb_any(skb_list->skb);
+#endif
+
+ skb_list->skb = NULL;
+ if (plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list)) {
+ err ("plusb: tx list empty. This shouldn't happen.");
+ }
+
+ purb->status = 0;
+ s->writeurb_submitted = 0;
+
+ netif_wake_queue((&s->net_dev));
+
+ dequeue_next_skb("plusb_write_bulk_complete", s);
+
+
+}
-static void plusb_bulk_complete(urb_t *purb)
+/*
+ * plusb_read_bulk_complete - Callback for data arriving from the USB device
+ *
+ * This gets called back when a full 'urb' is received from the remote system.
+ * This urb was allocated by this driver and is kept in the member: s->readurb
+ *
+ */
+static void plusb_read_bulk_complete(urb_t *purb)
{
+
plusb_t *s=purb->context;
- dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length);
+ dbg("plusb_read_bulk_complete: status:%d length:%d", purb->status,purb->actual_length);
+
if(!s->connected)
return;
- if( !purb->status) {
+ if( purb->status == -EPIPE ) {
+
+ printk(KERN_CRIT "%s: plusb_read_bulk_complete: got -EPIPE and I don't know what to do!\n",
+ s->net_dev.name);
+
+ } else if (!purb->status) {
struct sk_buff *skb;
unsigned char *dst;
int len=purb->transfer_buffer_length;
@@ -204,31 +477,69 @@ static void plusb_bulk_complete(urb_t *purb)
skb=dev_alloc_skb(len);
if(!skb) {
- err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
+ printk (KERN_CRIT "%s: plusb_read_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame\n", s->net_dev.name, len);
stats->rx_dropped++;
- return;
+ } else {
+ dst=(char *)skb_put(skb, len);
+ memcpy( dst, purb->transfer_buffer, len);
+
+ skb->dev=&s->net_dev;
+ skb->protocol=eth_type_trans(skb, skb->dev);
+ stats->rx_packets++;
+ stats->rx_bytes+=len;
+ netif_rx(skb);
}
+
+ }
+
+ s->readurb_submitted = 0;
+
+ if (purb->status) {
+ /* Give the system a chance to "catch its breath". Shortcut
+ re-submitting the read URB> It will be re-submitted if
+ another interrupt comes back. The problem scenario is that
+ the plub is pulled and the read returns an error.
+ You don't want to resumbit in this case.
+ */
+ err ("%s: plusb_read_bulk_complete: returned status %d\n",
+ s->net_dev.name, purb->status);
+ return;
+ }
- dst=(char *)skb_put(skb, len);
- memcpy( dst, purb->transfer_buffer, len);
- skb->dev=&s->net_dev;
- skb->protocol=eth_type_trans(skb, skb->dev);
- stats->rx_packets++;
- stats->rx_bytes+=len;
- netif_rx(skb);
- }
- else
- purb->status=0;
+ purb->status=0;
+
+ /* Keep it coming! resubmit the URB for reading.. Make sure
+ we aren't in contention with the interrupt callback.
+ */
+ submit_read_urb("plusb_read_bulk_complete", s);
}
/* --------------------------------------------------------------------- */
-
+/*
+ * plusb_int_complete - USB driver callback for interrupt msg from the device
+ *
+ * Interrupts are scheduled to go off on a periodic basis (see FILL_INT_URB)
+ * For the prolific device, this is basically just returning a register
+ * filled with bits. See the macro definitions for _PL_INT_XXX above.
+ * Most of these bits are for implementing a machine-machine protocol
+ * and can be set with a special message (described as the "Quicklink"
+ * feature in the prolific documentation.)
+ *
+ * I don't think we need any of that to work as a network device. If a
+ * message is lost, big deal - that's what UNIX networking expects from
+ * the physical layer.
+ *
+ */
static void plusb_int_complete(urb_t *purb)
{
plusb_t *s=purb->context;
s->status=((unsigned char*)purb->transfer_buffer)[0]&255;
+
#if 0
+ /* This isn't right because 0x20 is TX_RDY and
+ sometimes will not be set
+ */
if((s->status&0x3f)!=0x20) {
warn("invalid device status %02X", s->status);
return;
@@ -237,67 +548,95 @@ static void plusb_int_complete(urb_t *purb)
if(!s->connected)
return;
- if(s->status&_PLUSB_RXD) {
- int ret;
-
- if(s->bulkurb->status) {
- err("plusb_int_complete: URB still in use");
- return;
- }
-
- s->bulkurb->dev = s->usbdev;
- ret=usb_submit_urb(s->bulkurb);
- if(ret && ret!=-EBUSY) {
- err("plusb_int_complete: usb_submit_urb failed");
- }
- }
-
- if(purb->status || s->status!=160)
- dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status);
+ /* Don't turn this on unless you want to see the log flooded. */
+#if 0
+ printk("plusb_int_complete: PEER_E:%d TX_REQ:%d TX_C:%d RESET_IN:%d RESET_O: %d TX_RDY:%d RES1:%d RES2:%d\n",
+ s->status & _PL_INT_PEER_E ? 1 : 0,
+ s->status & _PL_INT_TX_REQ ? 1 : 0,
+ s->status & _PL_INT_TX_C ? 1 : 0,
+ s->status & _PL_INT_RESET_I ? 1 : 0,
+ s->status & _PL_INT_RESET_O ? 1 : 0,
+ s->status & _PL_INT_TX_RDY ? 1 : 0,
+ s->status & _PL_INT_RES1 ? 1 : 0,
+ s->status & _PL_INT_RES2 ? 1 : 0);
+#endif
+
+#if 1
+ /* At first glance, this logic appears to not really be needed, but
+ it can help recover from intermittent problems where the
+ usb_submit_urb() fails in the read callback. -EZA
+ */
+
+ /* Try to submit the read URB again. Make sure
+ we aren't in contention with the bulk read callback
+ */
+ submit_read_urb ("plusb_int_complete", s);
+
+ /* While we are at it, why not check to see if the
+ write urb should be re-submitted?
+ */
+ dequeue_next_skb("plusb_int_complete", s);
+
+#endif
+
}
/* --------------------------------------------------------------------- */
-
+/*
+ * plusb_free_all - deallocate all memory kept for an instance of the device.
+ */
static void plusb_free_all(plusb_t *s)
{
struct list_head *skb;
skb_list_t *skb_list;
dbg("plusb_free_all");
+
+ /* set a flag to tell all callbacks to cease and desist */
+ s->connected = 0;
+
+ /* If the interrupt handler is about to fire, let it finish up */
run_task_queue(&tq_immediate);
if(s->inturb) {
dbg("unlink inturb");
usb_unlink_urb(s->inturb);
- }
-
- if(s->inturb && s->inturb->transfer_buffer) {
- dbg("kfree inturb->transfer_buffer");
- kfree(s->inturb->transfer_buffer);
- s->inturb->transfer_buffer=NULL;
- }
-
- if(s->inturb) {
dbg("free_urb inturb");
usb_free_urb(s->inturb);
s->inturb=NULL;
}
+
+ if(s->interrupt_in_buffer) {
+ dbg("kfree s->interrupt_in_buffer");
+ kfree(s->interrupt_in_buffer);
+ s->interrupt_in_buffer=NULL;
+ }
- if(s->bulkurb) {
- dbg("unlink bulkurb");
- usb_unlink_urb(s->bulkurb);
+ if(s->readurb) {
+ dbg("unlink readurb");
+ usb_unlink_urb(s->readurb);
+ dbg("free_urb readurb:");
+ usb_free_urb(s->readurb);
+ s->readurb=NULL;
}
-
- if(s->bulkurb && s->bulkurb->transfer_buffer) {
- dbg("kfree bulkurb->transfer_buffer");
- kfree(s->bulkurb->transfer_buffer);
- s->bulkurb->transfer_buffer=NULL;
+
+ if(s->bulk_in_buffer) {
+ dbg("kfree s->bulk_in_buffer");
+ kfree(s->bulk_in_buffer);
+ s->bulk_in_buffer=NULL;
}
- if(s->bulkurb) {
- dbg("free_urb bulkurb");
- usb_free_urb(s->bulkurb);
- s->bulkurb=NULL;
+
+ s->readurb_submitted = 0;
+
+ if(s->writeurb) {
+ dbg("unlink writeurb");
+ usb_unlink_urb(s->writeurb);
+ dbg("free_urb writeurb:");
+ usb_free_urb(s->writeurb);
+ s->writeurb=NULL;
}
+
+ s->writeurb_submitted = 0;
while(!list_empty(&s->free_skb_list)) {
skb=s->free_skb_list.next;
@@ -310,20 +649,34 @@ static void plusb_free_all(plusb_t *s)
skb=s->tx_skb_list.next;
list_del(skb);
skb_list = list_entry (skb, skb_list_t, skb_list);
- kfree(skb_list);
+ if (skb_list->skb) {
+ dbg ("Freeing SKB in queue");
+#if (LINUX_VERSION_CODE < 0x020300)
+ dev_kfree_skb(skb_list->skb);
+#else
+ dev_kfree_skb_any(skb_list->skb);
+#endif
+ skb_list->skb = NULL;
+ }
+ kfree(skb_list);
}
+
+ s->in_bh=0;
+
dbg("plusb_free_all: finished");
}
/*-------------------------------------------------------------------*/
-
+/*
+ * plusb_alloc - allocate memory associated with one instance of the device
+ */
static int plusb_alloc(plusb_t *s)
{
int i;
skb_list_t *skb;
dbg("plusb_alloc");
-
+
for(i=0 ; i < _SKB_NUM ; i++) {
skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
if(!skb) {
@@ -341,47 +694,63 @@ static int plusb_alloc(plusb_t *s)
goto reject;
}
- dbg("bulkurb allocation:");
- s->bulkurb=usb_alloc_urb(0);
- if(!s->bulkurb) {
+ dbg("bulk read urb allocation:");
+ s->readurb=usb_alloc_urb(0);
+ if(!s->readurb) {
err("alloc_urb failed");
goto reject;
}
- dbg("bulkurb/inturb init:");
- s->inturb->dev=s->usbdev;
- s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE);
- s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL);
- if(!s->inturb->transfer_buffer) {
- err("kmalloc failed");
+ dbg("bulk write urb allocation:");
+ s->writeurb=usb_alloc_urb(0);
+ if(!s->writeurb) {
+ err("alloc_urb for writeurb failed");
goto reject;
}
- s->inturb->transfer_buffer_length=1;
- s->inturb->complete=plusb_int_complete;
- s->inturb->context=s;
- s->inturb->interval=10;
+ dbg("readurb/inturb init:");
+ s->interrupt_in_buffer=kmalloc(64, GFP_KERNEL);
+ if(!s->interrupt_in_buffer) {
+ err("kmalloc failed");
+ goto reject;
+ }
+
+ /* The original value of '10' makes this interrupt fire off a LOT.
+ It was set so low because the callback determined when to
+ sumbit the buld read URB. I've lowered it to 100 - the driver
+ doesn't depend on that logic anymore. -EZA
+ */
+ FILL_INT_URB(s->inturb, s->usbdev,
+ usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE),
+ s->interrupt_in_buffer, 1,
+ plusb_int_complete, s, HZ);
dbg("inturb submission:");
if(usb_submit_urb(s->inturb)<0) {
err("usb_submit_urb failed");
goto reject;
}
-
- dbg("bulkurb init:");
- s->bulkurb->dev=s->usbdev;
- s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE);
- s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
- if(!s->bulkurb->transfer_buffer) {
- err("kmalloc failed");
- goto reject;
- }
-
- s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN;
- s->bulkurb->complete=plusb_bulk_complete;
- s->bulkurb->context=s;
- dbg("plusb_alloc: finished");
+ dbg("readurb init:");
+ s->bulk_in_buffer = kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
+ if (!s->bulk_in_buffer) {
+ err("kmalloc %d bytes for bulk in buffer failed", _BULK_DATA_LEN);
+ }
+
+ FILL_BULK_URB(s->readurb, s->usbdev,
+ usb_rcvbulkpipe(s->usbdev, _PLUSB_BULKINPIPE),
+ s->bulk_in_buffer, _BULK_DATA_LEN,
+ plusb_read_bulk_complete, s);
+
+ /* The write urb will be initialized inside the network
+ interrupt.
+ */
+
+ /* get the bulk read going */
+ submit_read_urb("plusb_alloc", s);
+
+ dbg ("plusb_alloc: finished. readurb=%p writeurb=%p inturb=%p",
+ s->readurb, s->writeurb, s->inturb);
return 0;
@@ -404,8 +773,11 @@ static int plusb_net_open(struct net_device *dev)
return -ENOMEM;
s->opened=1;
- MOD_INC_USE_COUNT;
+ MOD_INC_USE_COUNT;
+
+ netif_start_queue(dev);
+
dbg("plusb_net_open: success");
return 0;
@@ -417,11 +789,14 @@ static int plusb_net_open(struct net_device *dev)
static int plusb_net_stop(struct net_device *dev)
{
plusb_t *s=dev->priv;
+
+ netif_stop_queue(dev);
dbg("plusb_net_stop");
- plusb_free_all(s);
s->opened=0;
+ plusb_free_all(s);
+
MOD_DEC_USE_COUNT;
dbg("plusb_net_stop:finished");
return 0;
@@ -459,7 +834,6 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
plusb_t *s = ptr;
dbg("plusb_disconnect");
- s->connected = 0;
plusb_free_all(s);
@@ -467,6 +841,11 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
dbg("unregistering netdev: %s",s->net_dev.name);
unregister_netdev(&s->net_dev);
s->net_dev.name[0] = '\0';
+#if (LINUX_VERSION_CODE < 0x020300)
+ dbg("plusb_disconnect: About to free name");
+ kfree (s->net_dev.name);
+ s->net_dev.name = NULL;
+#endif
}
dbg("plusb_disconnect: finished");
@@ -475,6 +854,22 @@ static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
/* --------------------------------------------------------------------- */
+static int plusb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > _BULK_DATA_LEN))
+ return -EINVAL;
+
+ printk("plusb: changing mtu to %d\n", new_mtu);
+ dev->mtu = new_mtu;
+
+ /* NOTE: Could we change the size of the READ URB here dynamically
+ to save kernel memory?
+ */
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
int plusb_net_init(struct net_device *dev)
{
dbg("plusb_net_init");
@@ -484,7 +879,14 @@ int plusb_net_init(struct net_device *dev)
dev->hard_start_xmit=plusb_net_xmit;
dev->get_stats = plusb_net_get_stats;
ether_setup(dev);
- dev->tx_queue_len = 0;
+ dev->change_mtu = plusb_change_mtu;
+ /* Setting the default MTU to 16K gives good performance for
+ me, and keeps the ping latency low too. Setting it up
+ to 32K made performance go down. -EZA
+ Pavel says it would be best not to do this...
+ */
+ /*dev->mtu=16384; */
+ dev->tx_queue_len = 0;
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
@@ -524,6 +926,42 @@ static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
return NULL;
}
+#if (LINUX_VERSION_CODE < 0x020300)
+ {
+ int i;
+
+ /* For Kernel version 2.2, the driver is responsible for
+ allocating this memory. For version 2.4, the rules
+ have apparently changed, but there is a nifty function
+ 'init_netdev' that might make this easier... It's in
+ ../net/net_init.c - but can we get there from here? (no)
+ -EZA
+ */
+
+ /* Find the device number... we seem to have lost it... -EZA */
+ for (i=0; i<NRPLUSB; i++) {
+ if (&plusb[i] == s)
+ break;
+ }
+
+ if(!s->net_dev.name) {
+ s->net_dev.name = kmalloc(strlen("plusbXXXX"), GFP_KERNEL);
+ sprintf (s->net_dev.name, "plusb%d", i);
+ s->net_dev.init=plusb_net_init;
+ s->net_dev.priv=s;
+
+ printk ("plusb_probe: Registering Device\n");
+ if(!register_netdev(&s->net_dev))
+ info("registered: %s", s->net_dev.name);
+ else {
+ err("register_netdev failed");
+ s->net_dev.name[0] = '\0';
+ }
+ dbg ("plusb_probe: Connected!");
+ }
+ }
+#else
+ /* Kernel version 2.3+ works a little bit differently than 2.2 */
if(!s->net_dev.name[0]) {
strcpy(s->net_dev.name, "plusb%d");
s->net_dev.init=plusb_net_init;
@@ -535,7 +973,8 @@ static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
s->net_dev.name[0] = '\0';
}
}
-
+#endif
+
s->connected = 1;
if(s->opened) {
@@ -567,8 +1006,6 @@ static int __init plusb_init (void)
for (u = 0; u < NRPLUSB; u++) {
plusb_t *s = &plusb[u];
memset (s, 0, sizeof (plusb_t));
- s->bh.routine = (void (*)(void *))plusb_bh;
- s->bh.data = s;
INIT_LIST_HEAD (&s->tx_skb_list);
INIT_LIST_HEAD (&s->free_skb_list);
spin_lock_init (&s->lock);
@@ -591,10 +1028,21 @@ static void __exit plusb_cleanup (void)
dbg("plusb_cleanup");
for (u = 0; u < NRPLUSB; u++) {
plusb_t *s = &plusb[u];
+#if (LINUX_VERSION_CODE < 0x020300)
+ if(s->net_dev.name) {
+ dbg("unregistering netdev: %s",s->net_dev.name);
+ unregister_netdev(&s->net_dev);
+ s->net_dev.name[0] = '\0';
+ kfree (s->net_dev.name);
+ s->net_dev.name = NULL;
+ }
+#else
if(s->net_dev.name[0]) {
dbg("unregistering netdev: %s",s->net_dev.name);
unregister_netdev(&s->net_dev);
+ s->net_dev.name[0] = '\0';
}
+#endif
}
usb_deregister (&plusb_driver);
dbg("plusb_cleanup: finished");
diff --git a/drivers/usb/plusb.h b/drivers/usb/plusb.h
deleted file mode 100644
index a77ae0f01..000000000
--- a/drivers/usb/plusb.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#define _PLUSB_INTPIPE 0x1
-#define _PLUSB_BULKOUTPIPE 0x2
-#define _PLUSB_BULKINPIPE 0x3
-
-#define _SKB_NUM 1000
-// 7 6 5 4 3 2 1 0
-// tx rx 1 0
-// 1110 0000 rxdata
-// 1010 0000 idle
-// 0010 0000 tx over
-// 0110 tx over + rxd
-
-#define _PLUSB_RXD 0x40
-#define _PLUSB_TXOK 0x80
-
-#ifdef __KERNEL__
-#define _BULK_DATA_LEN 16384
-
-typedef struct
-{
- struct list_head skb_list;
- struct sk_buff *skb;
- int state;
-} skb_list_t,*pskb_list_t;
-
-typedef struct
-{
- struct usb_device *usbdev;
-
- int status;
- int connected;
- int in_bh;
- int opened;
-
- spinlock_t lock;
-
- urb_t *inturb;
- urb_t *bulkurb;
-
- struct list_head tx_skb_list;
- struct list_head free_skb_list;
- struct tq_struct bh;
-
- struct net_device net_dev;
- struct net_device_stats net_stats;
-} plusb_t,*pplusb_t;
-
-#endif
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 7614373cf..c77ba35e2 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -393,15 +393,18 @@ static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t
return count;
}
-static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *epread, *epwrite;
struct usblp *usblp;
- int minor, i, alts = -1, bidir = 0;
+ int minor, i, bidir = 0;
+ int alts = dev->actconfig->interface[ifnum].act_altsetting;
int length, err;
char *buf;
+ /* If a bidirectional interface exists, use it. */
for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
interface = &dev->actconfig->interface[ifnum].altsetting[i];
@@ -411,18 +414,13 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
(interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
continue;
- if (alts == -1)
- alts = i;
-
- if (!bidir && interface->bInterfaceProtocol > 1) {
+ if (interface->bInterfaceProtocol > 1) {
bidir = 1;
alts = i;
+ break;
}
}
- if (alts == -1)
- return NULL;
-
interface = &dev->actconfig->interface[ifnum].altsetting[alts];
if (usb_set_interface(dev, ifnum, alts))
err("can't set desired altsetting %d on interface %d", alts, ifnum);
@@ -500,7 +498,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
}
#ifdef DEBUG
- usblp_check_status(usblp);
+ usblp_check_status(usblp, 0);
#endif
info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
@@ -544,12 +542,22 @@ static struct file_operations usblp_fops = {
release: usblp_release,
};
+static struct usb_device_id usblp_ids [] = {
+ { bInterfaceClass: 7, bInterfaceSubClass: 1, bInterfaceProtocol: 1},
+ { bInterfaceClass: 7, bInterfaceSubClass: 1, bInterfaceProtocol: 2},
+ { bInterfaceClass: 7, bInterfaceSubClass: 1, bInterfaceProtocol: 3},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usblp_ids);
+
static struct usb_driver usblp_driver = {
name: "usblp",
probe: usblp_probe,
disconnect: usblp_disconnect,
fops: &usblp_fops,
- minor: USBLP_MINOR_BASE
+ minor: USBLP_MINOR_BASE,
+ id_table: usblp_ids,
};
static int __init usblp_init(void)
diff --git a/drivers/usb/rio500.c b/drivers/usb/rio500.c
index e40e6c30f..e54ed66a2 100644
--- a/drivers/usb/rio500.c
+++ b/drivers/usb/rio500.c
@@ -407,19 +407,11 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
return read_count;
}
-static void *probe_rio(struct usb_device *dev, unsigned int ifnum)
+static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct rio_usb_data *rio = &rio_instance;
- if (dev->descriptor.idVendor != 0x841) {
- return NULL;
- }
-
- if (dev->descriptor.idProduct != 0x1 /* RIO 500 */ ) {
- warn(KERN_INFO "Rio player model not supported/tested.");
- return NULL;
- }
-
info("USB Rio found at address %d", dev->devnum);
rio->present = 1;
@@ -470,14 +462,20 @@ file_operations usb_rio_fops = {
release: close_rio,
};
-static struct
-usb_driver rio_driver = {
- "rio500",
- probe_rio,
- disconnect_rio,
- {NULL, NULL},
- &usb_rio_fops,
- RIO_MINOR
+static struct usb_device_id rio_table [] = {
+ { idVendor: 0x0841, idProduct: 1 }, /* Rio 500 */
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, rio_table);
+
+static struct usb_driver rio_driver = {
+ name: "rio500",
+ probe: probe_rio,
+ disconnect: disconnect_rio,
+ fops: &usb_rio_fops,
+ minor: RIO_MINOR,
+ id_table: rio_table,
};
int usb_rio_init(void)
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index 67ea8c8d8..2ee4ba127 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -244,6 +244,82 @@
*/
#include "scanner.h"
+/* Table of scanners that may work with this driver */
+static struct usb_device_id scanner_device_ids [] = {
+ /* Acer */
+ { idVendor: 0x04a5, idProduct: 0x2060 },/* Prisa Acerscan 620U & 640U (!)*/
+ { idVendor: 0x04a5, idProduct: 0x2040 },/* Prisa AcerScan 620U (!) */
+ { idVendor: 0x04a5, idProduct: 0x2022 },/* Vuego Scan Brisa 340U */
+ /* Agfa */
+ { idVendor: 0x06bd, idProduct: 0x0001 }, /* SnapScan 1212U */
+ { idVendor: 0x06bd, idProduct: 0x2061 }, /* Another SnapScan 1212U (?)*/
+ { idVendor: 0x06bd, idProduct: 0x0100 }, /* SnapScan Touch */
+ /* Colorado -- See Primax/Colorado below */
+ /* Epson -- See Seiko/Epson below */
+ /* Genius */
+ { idVendor: 0x0458, idProduct: 0x2001 }, /* ColorPage-Vivid Pro */
+ /* Hewlett Packard */
+ { idVendor: 0x03f0, idProduct: 0x0205 }, /* 3300C */
+ { idVendor: 0x03f0, idProduct: 0x0101 }, /* 4100C */
+ { idVendor: 0x03f0, idProduct: 0x0105 }, /* 4200C */
+ { idVendor: 0x03f0, idProduct: 0x0102 }, /* PhotoSmart S20 */
+ { idVendor: 0x03f0, idProduct: 0x0401 }, /* 5200C */
+ { idVendor: 0x03f0, idProduct: 0x0701 }, /* 5300C */
+ { idVendor: 0x03f0, idProduct: 0x0201 }, /* 6200C */
+ { idVendor: 0x03f0, idProduct: 0x0601 }, /* 6300C */
+ /* iVina */
+ { idVendor: 0x0638, idProduct: 0x0268 }, /* 1200U */
+ /* Microtek */
+ { idVendor: 0x05da, idProduct: 0x0099 }, /* ScanMaker X6 - X6U */
+ { idVendor: 0x05da, idProduct: 0x0094 }, /* Phantom 336CX - C3 */
+ { idVendor: 0x05da, idProduct: 0x00a0 }, /* Phantom 336CX - C3 #2 */
+ { idVendor: 0x05da, idProduct: 0x009a }, /* Phantom C6 */
+ { idVendor: 0x05da, idProduct: 0x00a3 }, /* ScanMaker V6USL */
+ { idVendor: 0x05da, idProduct: 0x80a3 }, /* ScanMaker V6USL #2 */
+ { idVendor: 0x05da, idProduct: 0x80ac }, /* ScanMaker V6UL - SpicyU */
+ /* Mustek */
+ { idVendor: 0x055f, idProduct: 0x0001 }, /* 1200 CU */
+ { idVendor: 0x0400, idProduct: 0x1000 }, /* BearPaw 1200 */
+ { idVendor: 0x055f, idProduct: 0x0002 }, /* 600 CU */
+ { idVendor: 0x055f, idProduct: 0x0003 }, /* 1200 USB */
+ { idVendor: 0x055f, idProduct: 0x0006 }, /* 1200 UB */
+ /* Primax/Colorado */
+ { idVendor: 0x0461, idProduct: 0x0300 }, /* G2-300 #1 */
+ { idVendor: 0x0461, idProduct: 0x0380 }, /* G2-600 #1 */
+ { idVendor: 0x0461, idProduct: 0x0301 }, /* G2E-300 #1 */
+ { idVendor: 0x0461, idProduct: 0x0381 }, /* ReadyScan 636i */
+ { idVendor: 0x0461, idProduct: 0x0302 }, /* G2-300 #2 */
+ { idVendor: 0x0461, idProduct: 0x0382 }, /* G2-600 #2 */
+ { idVendor: 0x0461, idProduct: 0x0303 }, /* G2E-300 #2 */
+ { idVendor: 0x0461, idProduct: 0x0383 }, /* G2E-600 */
+ { idVendor: 0x0461, idProduct: 0x0340 }, /* Colorado USB 9600 */
+ { idVendor: 0x0461, idProduct: 0x0360 }, /* Colorado USB 19200 */
+ { idVendor: 0x0461, idProduct: 0x0341 }, /* Colorado 600u */
+ { idVendor: 0x0461, idProduct: 0x0361 }, /* Colorado 1200u */
+ /* Seiko/Epson Corp. */
+ { idVendor: 0x04b8, idProduct: 0x0101 },/* Perfection 636U and 636Photo */
+ { idVendor: 0x04b8, idProduct: 0x0103 },/* Perfection 610 */
+ { idVendor: 0x04b8, idProduct: 0x0104 },/* Perfection 1200U and 1200Photo*/
+ { idVendor: 0x04b8, idProduct: 0x0107 },/* Expression 1600 */
+ /* Umax */
+ { idVendor: 0x1606, idProduct: 0x0010 }, /* Astra 1220U */
+ { idVendor: 0x1606, idProduct: 0x0002 }, /* Astra 1236U */
+ { idVendor: 0x1606, idProduct: 0x0030 }, /* Astra 2000U */
+ { idVendor: 0x1606, idProduct: 0x0230 }, /* Astra 2200U */
+ /* Visioneer */
+ { idVendor: 0x04a7, idProduct: 0x0221 }, /* OneTouch 5300 USB */
+ { idVendor: 0x04a7, idProduct: 0x0211 }, /* OneTouch 7600 USB */
+ { idVendor: 0x04a7, idProduct: 0x0231 }, /* 6100 USB */
+ { idVendor: 0x04a7, idProduct: 0x0311 }, /* 6200 EPP/USB */
+ { idVendor: 0x04a7, idProduct: 0x0321 }, /* OneTouch 8100 EPP/USB */
+ { idVendor: 0x04a7, idProduct: 0x0331 }, /* OneTouch 8600 EPP/USB */
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, scanner_device_ids);
+
+
static void
irq_scanner(struct urb *urb)
{
@@ -548,7 +624,8 @@ read_scanner(struct file * file, char * buffer,
}
static void *
-probe_scanner(struct usb_device *dev, unsigned int ifnum)
+probe_scanner(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct scn_usb_data *scn;
struct usb_interface_descriptor *interface;
@@ -591,7 +668,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum)
* Until we detect a device which is pleasing, we silently punt.
*/
- for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct scanner_device); ix++) {
+ for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct usb_device_id); ix++) {
if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
(dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
valid_device = 1;
@@ -875,12 +952,14 @@ file_operations usb_scanner_fops = {
static struct
usb_driver scanner_driver = {
- "usbscanner",
- probe_scanner,
- disconnect_scanner,
- { NULL, NULL },
- &usb_scanner_fops,
- SCN_BASE_MNR
+ name: "usbscanner",
+ probe: probe_scanner,
+ disconnect: disconnect_scanner,
+ fops: &usb_scanner_fops,
+ minor: SCN_BASE_MNR,
+ id_table: NULL, /* This would be scanner_device_ids, but we
+ need to check every USB device, in case
+ we match a user defined vendor/product ID. */
};
void __exit
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index c1ec964dc..e052e9a4f 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -100,79 +100,4 @@ struct scn_usb_data {
static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
-/* table of scanners that may work with this driver */
-static const struct scanner_device {
- __u16 idVendor;
- __u16 idProduct;
-} scanner_device_ids [] = {
- /* Acer */
- { 0x04a5, 0x2060 }, /* Prisa Acerscan 620U & 640U (!) */
- { 0x04a5, 0x2040 }, /* Prisa AcerScan 620U (!) */
- { 0x04a5, 0x2022 }, /* Vuego Scan Brisa 340U */
- /* Agfa */
- { 0x06bd, 0x0001 }, /* SnapScan 1212U */
- { 0x06bd, 0x2061 }, /* Another SnapScan 1212U (?) */
- { 0x06bd, 0x0100 }, /* SnapScan Touch */
- /* Colorado -- See Primax/Colorado below */
- /* Epson -- See Seiko/Epson below */
- /* Genius */
- { 0x0458, 0x2001 }, /* ColorPage-Vivid Pro */
- /* Hewlett Packard */
- { 0x03f0, 0x0205 }, /* 3300C */
- { 0x03f0, 0x0101 }, /* 4100C */
- { 0x03f0, 0x0105 }, /* 4200C */
- { 0x03f0, 0x0102 }, /* PhotoSmart S20 */
- { 0x03f0, 0x0401 }, /* 5200C */
- { 0x03f0, 0x0701 }, /* 5300C */
- { 0x03f0, 0x0201 }, /* 6200C */
- { 0x03f0, 0x0601 }, /* 6300C */
- /* iVina */
- { 0x0638, 0x0268 }, /* 1200U */
- /* Microtek */
- { 0x05da, 0x0099 }, /* ScanMaker X6 - X6U */
- { 0x05da, 0x0094 }, /* Phantom 336CX - C3 */
- { 0x05da, 0x00a0 }, /* Phantom 336CX - C3 #2 */
- { 0x05da, 0x009a }, /* Phantom C6 */
- { 0x05da, 0x00a3 }, /* ScanMaker V6USL */
- { 0x05da, 0x80a3 }, /* ScanMaker V6USL #2 */
- { 0x05da, 0x80ac }, /* ScanMaker V6UL - SpicyU */
- /* Mustek */
- { 0x055f, 0x0001 }, /* 1200 CU */
- { 0x0400, 0x1000 }, /* BearPaw 1200 */
- { 0x055f, 0x0002 }, /* 600 CU */
- { 0x055f, 0x0003 }, /* 1200 USB */
- { 0x055f, 0x0006 }, /* 1200 UB */
- /* Primax/Colorado */
- { 0x0461, 0x0300 }, /* G2-300 #1 */
- { 0x0461, 0x0380 }, /* G2-600 #1 */
- { 0x0461, 0x0301 }, /* G2E-300 #1 */
- { 0x0461, 0x0381 }, /* ReadyScan 636i */
- { 0x0461, 0x0302 }, /* G2-300 #2 */
- { 0x0461, 0x0382 }, /* G2-600 #2 */
- { 0x0461, 0x0303 }, /* G2E-300 #2 */
- { 0x0461, 0x0383 }, /* G2E-600 */
- { 0x0461, 0x0340 }, /* Colorado USB 9600 */
- { 0x0461, 0x0360 }, /* Colorado USB 19200 */
- { 0x0461, 0x0341 }, /* Colorado 600u */
- { 0x0461, 0x0361 }, /* Colorado 1200u */
- /* Seiko/Epson Corp. */
- { 0x04b8, 0x0101 }, /* Perfection 636U and 636Photo */
- { 0x04b8, 0x0103 }, /* Perfection 610 */
- { 0x04b8, 0x0104 }, /* Perfection 1200U and 1200Photo */
- { 0x04b8, 0x0107 }, /* Expression 1600 */
- /* Umax */
- { 0x1606, 0x0010 }, /* Astra 1220U */
- { 0x1606, 0x0002 }, /* Astra 1236U */
- { 0x1606, 0x0030 }, /* Astra 2000U */
- { 0x1606, 0x0230 }, /* Astra 2200U */
- /* Visioneer */
- { 0x04a7, 0x0221 }, /* OneTouch 5300 USB */
- { 0x04a7, 0x0211 }, /* OneTouch 7600 USB */
- { 0x04a7, 0x0231 }, /* 6100 USB */
- { 0x04a7, 0x0311 }, /* 6200 EPP/USB */
- { 0x04a7, 0x0321 }, /* OneTouch 8100 EPP/USB */
- { 0x04a7, 0x0331 }, /* OneTouch 8600 EPP/USB */
-};
-
-/* Forward declarations */
static struct usb_driver scanner_driver;
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index ce5d7b128..b90d4f52d 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
+obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
# Objects that export symbols.
export-objs := usbserial.o
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
new file mode 100644
index 000000000..8d38a7a9d
--- /dev/null
+++ b/drivers/usb/serial/belkin_sa.c
@@ -0,0 +1,576 @@
+/*
+ * Belkin USB Serial Adapter Driver
+ *
+ * Copyright (C) 2000
+ * William Greathouse (wgreathouse@smva.com)
+ *
+ * This program is largely derived from work by the linux-usb group
+ * and associated source files. Please see the usb/serial files for
+ * individual credits and copyrights.
+ *
+ * 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
+ *
+ * TODO:
+ * -- Add true modem contol line query capability. Currently we track the
+ * states reported by the interrupt and the states we request.
+ * -- Add error reporting back to application for UART error conditions.
+ * Just point me at how to implement this and I'll do it. I've put the
+ * framework in, but haven't analyzed the "tty_flip" interface yet.
+ * -- Add support for flush commands
+ * -- Add everything that is missing :)
+ *
+ * (11/06/2000) gkh
+ * - Added support for the old Belkin and Peracom devices.
+ * - Made the port able to be opened multiple times.
+ * - Added some defaults incase the line settings are things these devices
+ * can't support.
+ *
+ * 18-Oct-2000 William Greathouse
+ * Released into the wild (linux-usb-devel)
+ *
+ * 17-Oct-2000 William Greathouse
+ * Add code to recognize firmware version and set hardware flow control
+ * appropriately. Belkin states that firmware prior to 3.05 does not
+ * operate correctly in hardware handshake mode. I have verified this
+ * on firmware 2.05 -- for both RTS and DTR input flow control, the control
+ * line is not reset. The test performed by the Belkin Win* driver is
+ * to enable hardware flow control for firmware 2.06 or greater and
+ * for 1.00 or prior. I am only enabling for 2.06 or greater.
+ *
+ * 12-Oct-2000 William Greathouse
+ * First cut at supporting Belkin USB Serial Adapter F5U103
+ * I did not have a copy of the original work to support this
+ * adapter, so pardon any stupid mistakes. All of the information
+ * I am using to write this driver was acquired by using a modified
+ * UsbSnoop on Windows2000 and from examining the other USB drivers.
+ */
+
+#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>
+
+#include "usb-serial.h"
+#include "belkin_sa.h"
+
+/* function prototypes for a Belkin USB Serial Adapter F5U103 */
+static int belkin_sa_startup (struct usb_serial *serial);
+static void belkin_sa_shutdown (struct usb_serial *serial);
+static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_read_int_callback (struct urb *urb);
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
+static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );
+
+
+static __devinitdata struct usb_device_id id_table_combined [] = {
+ { idVendor: BELKIN_SA_VID, idProduct: BELKIN_SA_PID },
+ { idVendor: BELKIN_OLD_VID, idProduct: BELKIN_OLD_PID },
+ { idVendor: PERACOM_VID, idProduct: PERACOM_PID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id belkin_sa_table [] = {
+ { idVendor: BELKIN_SA_VID, idProduct: BELKIN_SA_PID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id belkin_old_table [] = {
+ { idVendor: BELKIN_OLD_VID, idProduct: BELKIN_OLD_PID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id peracom_table [] = {
+ { idVendor: PERACOM_VID, idProduct: PERACOM_PID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+/* All of the device info needed for the Belkin serial converter */
+struct usb_serial_device_type belkin_sa_device = {
+ name: "Belkin F5U103 USB Serial Adapter",
+ id_table: belkin_sa_table, /* the Belkin F5U103 device */
+ needs_interrupt_in: MUST_HAVE, /* this device must 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: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+
+/* This driver also supports the "old" school Belkin single port adaptor */
+struct usb_serial_device_type belkin_old_device = {
+ name: "Belkin USB Serial Adapter",
+ id_table: belkin_old_table, /* the old Belkin device */
+ needs_interrupt_in: MUST_HAVE, /* this device must 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: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+/* this driver also works for the Peracom single port adapter */
+struct usb_serial_device_type peracom_device = {
+ name: "Peracom single port USB Serial Adapter",
+ id_table: peracom_table, /* the Peracom device */
+ needs_interrupt_in: MUST_HAVE, /* this device must 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: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+
+struct belkin_sa_private {
+ unsigned long control_state;
+ unsigned char last_lsr;
+ unsigned char last_msr;
+ int bad_flow_control;
+};
+
+
+/*
+ * ***************************************************************************
+ * Belkin USB Serial Adapter F5U103 specific driver functions
+ * ***************************************************************************
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* assumes that struct usb_serial *serial is available */
+#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
+ (c), BELKIN_SA_SET_REQUEST_TYPE, \
+ (v), 0, NULL, 0, WDR_TIMEOUT)
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int belkin_sa_startup (struct usb_serial *serial)
+{
+ struct usb_device *dev = serial->dev;
+ struct belkin_sa_private *priv;
+
+ /* allocate the private data structure */
+ serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL);
+ if (!serial->port->private)
+ return (-1); /* error */
+ priv = (struct belkin_sa_private *)serial->port->private;
+ /* set initial values for control structures */
+ priv->control_state = 0;
+ priv->last_lsr = 0;
+ priv->last_msr = 0;
+ /* see comments at top of file */
+ priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0;
+ info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control);
+
+ init_waitqueue_head(&serial->port->write_wait);
+
+ return (0);
+}
+
+
+static void belkin_sa_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ belkin_sa_close (&serial->port[i], NULL);
+ }
+ /* My special items, the standard routines free my urbs */
+ if (serial->port->private)
+ kfree(serial->port->private);
+ }
+}
+
+
+static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
+
+ /*Start reading from the device*/
+ /* TODO: Look at possibility of submitting mulitple URBs to device to
+ * enhance buffering. Win trace shows 16 initial read URBs.
+ */
+ port->read_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->read_urb))
+ err("usb_submit_urb(read bulk) failed");
+
+ port->interrupt_in_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->interrupt_in_urb))
+ err(" usb_submit_urb(read int) failed");
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
+} /* belkin_sa_open */
+
+
+static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb); /* wgg - do I need this? I think so. */
+ port->active = 0;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+} /* belkin_sa_close */
+
+
+static void belkin_sa_read_int_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ struct usb_serial *serial;
+ unsigned char *data = urb->transfer_buffer;
+
+ /* the urb might have been killed. */
+ if (urb->status)
+ return;
+
+ if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return;
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return;
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ /* Handle known interrupt data */
+ /* ignore data[0] and data[1] */
+
+ priv->last_msr = data[BELKIN_SA_MSR_INDEX];
+
+ /* Record Control Line states */
+ if (priv->last_msr & BELKIN_SA_MSR_DSR)
+ priv->control_state |= TIOCM_DSR;
+ else
+ priv->control_state &= ~TIOCM_DSR;
+
+ if (priv->last_msr & BELKIN_SA_MSR_CTS)
+ priv->control_state |= TIOCM_CTS;
+ else
+ priv->control_state &= ~TIOCM_CTS;
+
+ if (priv->last_msr & BELKIN_SA_MSR_RI)
+ priv->control_state |= TIOCM_RI;
+ else
+ priv->control_state &= ~TIOCM_RI;
+
+ if (priv->last_msr & BELKIN_SA_MSR_CD)
+ priv->control_state |= TIOCM_CD;
+ else
+ priv->control_state &= ~TIOCM_CD;
+
+ /* Now to report any errors */
+ priv->last_lsr = data[BELKIN_SA_LSR_INDEX];
+#if 0
+ /*
+ * fill in the flip buffer here, but I do not know the relation
+ * to the current/next receive buffer or characters. I need
+ * to look in to this before committing any code.
+ */
+ if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
+ tty = port->tty;
+ /* Overrun Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_OE) {
+ }
+ /* Parity Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_PE) {
+ }
+ /* Framing Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_FE) {
+ }
+ /* Break Indicator */
+ if (priv->last_lsr & BELKIN_SA_LSR_BI) {
+ }
+ }
+#endif
+
+ /* INT urbs are automatically re-submitted */
+}
+
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_iflag = old_termios->c_iflag;
+ unsigned int old_cflag = old_termios->c_cflag;
+ __u16 urb_value = 0; /* Will hold the new flags */
+
+ /* Set the baud rate */
+ if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+ /* reassert DTR and (maybe) RTS on transition from B0 */
+ if( (old_cflag&CBAUD) == B0 ) {
+ priv->control_state |= (TIOCM_DTR|TIOCM_RTS);
+ if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
+ err("Set DTR error");
+ /* don't set RTS if using hardware flow control */
+ if (!(old_cflag&CRTSCTS) )
+ if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
+ err("Set RTS error");
+ }
+
+ switch(cflag & CBAUD) {
+ case B0: /* handled below */ break;
+ case B300: urb_value = BELKIN_SA_BAUD(300); break;
+ case B600: urb_value = BELKIN_SA_BAUD(600); break;
+ case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
+ case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
+ case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
+ case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
+ case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
+ case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
+ case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
+ case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
+ case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
+ default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
+ urb_value = BELKIN_SA_BAUD(9600); break;
+ }
+ if ((cflag & CBAUD) != B0 ) {
+ if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+ err("Set baudrate error");
+ } else {
+ /* Disable flow control */
+ if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
+ err("Disable flowcontrol error");
+
+ /* Drop RTS and DTR */
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
+ err("DTR LOW error");
+ if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
+ err("RTS LOW error");
+ }
+ }
+
+ /* set the parity */
+ if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
+ if (cflag & PARENB)
+ urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD : BELKIN_SA_PARITY_EVEN;
+ else
+ urb_value = BELKIN_SA_PARITY_NONE;
+ if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0)
+ err("Set parity error");
+ }
+
+ /* set the number of data bits */
+ if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value = BELKIN_SA_DATA_BITS(5); break;
+ case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
+ case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
+ case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
+ default: err("CSIZE was not CS5-CS8, using default of 8");
+ urb_value = BELKIN_SA_DATA_BITS(8);
+ break;
+ }
+ if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0)
+ err("Set data bits error");
+ }
+
+ /* set the number of stop bits */
+ if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+ urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) : BELKIN_SA_STOP_BITS(1);
+ if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, urb_value) < 0)
+ err("Set stop bits error");
+ }
+
+ /* Set flow control */
+ if( (iflag&IXOFF) != (old_iflag&IXOFF)
+ || (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
+ urb_value = 0;
+ if ((iflag & IXOFF) || (iflag & IXON))
+ urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+ else
+ urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+
+ if (cflag & CRTSCTS)
+ urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+ else
+ urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+
+ if (priv->bad_flow_control)
+ urb_value &= ~(BELKIN_SA_FLOW_IRTS);
+
+ if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0)
+ err("Set flow control error");
+ }
+} /* belkin_sa_set_termios */
+
+
+static void belkin_sa_break_ctl( struct usb_serial_port *port, int break_state )
+{
+ struct usb_serial *serial = port->serial;
+
+ if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
+ err("Set break_ctl %d", break_state);
+}
+
+
+static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ __u16 urb_value; /* Will hold the new flags */
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ int ret, mask;
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+ case TIOCMGET:
+ return put_user(priv->control_state, (unsigned long *) arg);
+ break;
+
+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+ /* RTS needs set */
+ urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0;
+ if (urb_value)
+ priv->control_state |= TIOCM_RTS;
+ else
+ priv->control_state &= ~TIOCM_RTS;
+
+ if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) {
+ err("Set RTS error %d", ret);
+ return(ret);
+ }
+ }
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+ /* DTR needs set */
+ urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0;
+ if (urb_value)
+ priv->control_state |= TIOCM_DTR;
+ else
+ priv->control_state &= ~TIOCM_DTR;
+ if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) {
+ err("Set DTR error %d", ret);
+ return(ret);
+ }
+ }
+ break;
+
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ return( 0 );
+
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ /* TODO */
+ return 0;
+
+ default:
+ dbg("belkin_sa_ioctl arg not supported - 0x%04x",cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ return 0;
+} /* belkin_sa_ioctl */
+
+
+static int __init belkin_sa_init (void)
+{
+ usb_serial_register (&belkin_sa_device);
+ usb_serial_register (&belkin_old_device);
+ usb_serial_register (&peracom_device);
+ return 0;
+}
+
+
+static void __exit belkin_sa_exit (void)
+{
+ usb_serial_deregister (&belkin_sa_device);
+ usb_serial_deregister (&belkin_old_device);
+ usb_serial_deregister (&peracom_device);
+}
+
+
+module_init (belkin_sa_init);
+module_exit (belkin_sa_exit);
+
+MODULE_DESCRIPTION("USB Belkin Serial converter driver");
diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
new file mode 100644
index 000000000..ee3603863
--- /dev/null
+++ b/drivers/usb/serial/belkin_sa.h
@@ -0,0 +1,113 @@
+/*
+ * Definitions for Belkin USB Serial Adapter Driver
+ *
+ * Copyright (C) 2000
+ * William Greathouse (wgreathouse@smva.com)
+ *
+ * This program is largely derived from work by the linux-usb group
+ * and associated source files. Please see the usb/serial files for
+ * individual credits and copyrights.
+ *
+ * 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
+ *
+ * (11/06/2000) gkh
+ * Added old Belkin and Peracom device ids, which this driver supports
+ *
+ * 12-Oct-2000 William Greathouse
+ * First cut at supporting Belkin USB Serial Adapter F5U103
+ * I did not have a copy of the original work to support this
+ * adapter, so pardon any stupid mistakes. All of the information
+ * I am using to write this driver was acquired by using a modified
+ * UsbSnoop on Windows2000.
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_BSA_H
+#define __LINUX_USB_SERIAL_BSA_H
+
+#define BELKIN_SA_VID 0x050d /* Vendor Id */
+#define BELKIN_SA_PID 0x0103 /* Product Id */
+
+#define BELKIN_OLD_VID 0x056c /* Belkin's "old" vendor id */
+#define BELKIN_OLD_PID 0x8007 /* Belkin's "old" single port serial converter's id */
+
+#define PERACOM_VID 0x0565 /* Peracom's vendor id */
+#define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */
+
+/* Vendor Request Interface */
+#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */
+#define BELKIN_SA_SET_STOP_BITS_REQUEST 1 /* Set stop bits (1,2) */
+#define BELKIN_SA_SET_DATA_BITS_REQUEST 2 /* Set data bits (5,6,7,8) */
+#define BELKIN_SA_SET_PARITY_REQUEST 3 /* Set parity (None, Even, Odd) */
+
+#define BELKIN_SA_SET_DTR_REQUEST 10 /* Set DTR state */
+#define BELKIN_SA_SET_RTS_REQUEST 11 /* Set RTS state */
+#define BELKIN_SA_SET_BREAK_REQUEST 12 /* Set BREAK state */
+
+#define BELKIN_SA_SET_FLOW_CTRL_REQUEST 16 /* Set flow control mode */
+
+
+#ifdef WHEN_I_LEARN_THIS
+#define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */
+ /* (always in Wininit sequence before flow control) */
+#define BELKIN_SA_RESET xx /* Reset the port */
+#define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */
+#endif
+
+#define BELKIN_SA_SET_REQUEST_TYPE 0x40
+
+#define BELKIN_SA_BAUD(b) (230400/b)
+
+#define BELKIN_SA_STOP_BITS(b) (b-1)
+
+#define BELKIN_SA_DATA_BITS(b) (b-5)
+
+#define BELKIN_SA_PARITY_NONE 0
+#define BELKIN_SA_PARITY_EVEN 1
+#define BELKIN_SA_PARITY_ODD 2
+#define BELKIN_SA_PARITY_MARK 3
+#define BELKIN_SA_PARITY_SPACE 4
+
+#define BELKIN_SA_FLOW_NONE 0x0000 /* No flow control */
+#define BELKIN_SA_FLOW_OCTS 0x0001 /* use CTS input to throttle output */
+#define BELKIN_SA_FLOW_ODSR 0x0002 /* use DSR input to throttle output */
+#define BELKIN_SA_FLOW_IDSR 0x0004 /* use DSR input to enable receive */
+#define BELKIN_SA_FLOW_IDTR 0x0008 /* use DTR output for input flow control */
+#define BELKIN_SA_FLOW_IRTS 0x0010 /* use RTS output for input flow control */
+#define BELKIN_SA_FLOW_ORTS 0x0020 /* use RTS to indicate data available to send */
+#define BELKIN_SA_FLOW_ERRSUB 0x0040 /* ???? guess ???? substitute inline errors */
+#define BELKIN_SA_FLOW_OXON 0x0080 /* use XON/XOFF for output flow control */
+#define BELKIN_SA_FLOW_IXON 0x0100 /* use XON/XOFF for input flow control */
+
+/*
+ * It seems that the interrupt pipe is closely modelled after the
+ * 16550 register layout. This is probably because the adapter can
+ * be used in a "DOS" environment to simulate a standard hardware port.
+ */
+#define BELKIN_SA_LSR_INDEX 2 /* Line Status Register */
+#define BELKIN_SA_LSR_RDR 0x01 /* receive data ready */
+#define BELKIN_SA_LSR_OE 0x02 /* overrun error */
+#define BELKIN_SA_LSR_PE 0x04 /* parity error */
+#define BELKIN_SA_LSR_FE 0x08 /* framing error */
+#define BELKIN_SA_LSR_BI 0x10 /* break indicator */
+#define BELKIN_SA_LSR_THE 0x20 /* transmit holding register empty */
+#define BELKIN_SA_LSR_TE 0x40 /* transmit register empty */
+#define BELKIN_SA_LSR_ERR 0x80 /* OE | PE | FE | BI */
+
+#define BELKIN_SA_MSR_INDEX 3 /* Modem Status Register */
+#define BELKIN_SA_MSR_DCTS 0x01 /* Delta CTS */
+#define BELKIN_SA_MSR_DDSR 0x02 /* Delta DSR */
+#define BELKIN_SA_MSR_DRI 0x04 /* Delta RI */
+#define BELKIN_SA_MSR_DCD 0x08 /* Delta CD */
+#define BELKIN_SA_MSR_CTS 0x10 /* Current CTS */
+#define BELKIN_SA_MSR_DSR 0x20 /* Current DSR */
+#define BELKIN_SA_MSR_RI 0x40 /* Current RI */
+#define BELKIN_SA_MSR_CD 0x80 /* Current CD */
+
+#endif /* __LINUX_USB_SERIAL_BSA_H */
+
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index f5635bb01..197752224 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1,5 +1,5 @@
/*
-* Digi AccelePort USB-4 Serial Converter
+* Digi AccelePort USB-4 and USB-2 Serial Converters
*
* Copyright 2000 by Digi International
*
@@ -14,6 +14,16 @@
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (11/01/2000) Adam J. Richter
+* usb_device_id table support
+*
+* (11/01/2000) pberger and borchers
+* -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused
+* USB 4 ports to hang on startup.
+* -- Serialized access to write urbs by adding the dp_write_urb_in_use
+* flag; otherwise, the driver caused SMP system hangs. Watching the
+* urb status is not sufficient.
+*
* (10/05/2000) gkh
* -- Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -213,7 +223,7 @@
* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
* are held when calling copy_to/from_user or printk.
*
-* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $
+* $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $
*/
#include <linux/config.h>
@@ -411,6 +421,7 @@ typedef struct digi_port {
int dp_in_buf_len;
unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];
unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];
+ int dp_write_urb_in_use;
unsigned int dp_modem_signals;
wait_queue_head_t dp_modem_change_wait;
int dp_open_count; /* inc on open, dec on close */
@@ -461,15 +472,29 @@ static int digi_read_oob_callback( struct urb *urb );
/* Statics */
+static __devinitdata struct usb_device_id id_table_combined [] = {
+ { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_2_ID },
+ { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_4_ID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id id_table_2 [] = {
+ { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_2_ID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id id_table_4 [] = {
+ { idVendor: DIGI_VENDOR_ID, idProduct: DIGI_4_ID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
/* device info needed for the Digi serial converter */
-static u16 digi_vendor_id = DIGI_VENDOR_ID;
-static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */
-static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */
static struct usb_serial_device_type digi_acceleport_2_device = {
name: "Digi USB",
- idVendor: &digi_vendor_id,
- idProduct: &digi_product_2_id,
+ id_table: id_table_2,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
@@ -495,8 +520,7 @@ static struct usb_serial_device_type digi_acceleport_2_device = {
static struct usb_serial_device_type digi_acceleport_4_device = {
name: "Digi USB",
- idVendor: &digi_vendor_id,
- idProduct: &digi_product_4_id,
+ id_table: id_table_4,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
@@ -629,7 +653,8 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co
while( count > 0 ) {
- while( oob_port->write_urb->status == -EINPROGRESS ) {
+ while( oob_port->write_urb->status == -EINPROGRESS
+ || oob_priv->dp_write_urb_in_use ) {
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
@@ -647,8 +672,9 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, co
memcpy( oob_port->write_urb->transfer_buffer, buf, len );
oob_port->write_urb->transfer_buffer_length = len;
oob_port->write_urb->dev = port->serial->dev;
-
+
if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+ oob_priv->dp_write_urb_in_use = 1;
count -= len;
buf += len;
}
@@ -702,8 +728,8 @@ count );
while( count > 0 && ret == 0 ) {
- while( port->write_urb->status == -EINPROGRESS
- && jiffies < timeout ) {
+ while( (port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use) && jiffies < timeout ) {
cond_wait_interruptible_timeout_irqrestore(
&port->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
@@ -736,6 +762,7 @@ count );
port->write_urb->dev = port->serial->dev;
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+ priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
count -= len;
buf += len;
@@ -783,7 +810,8 @@ port_priv->dp_port_num, modem_signals );
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
spin_lock( &port_priv->dp_port_lock );
- while( oob_port->write_urb->status == -EINPROGRESS ) {
+ while( oob_port->write_urb->status == -EINPROGRESS
+ || oob_priv->dp_write_urb_in_use ) {
spin_unlock( &port_priv->dp_port_lock );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
@@ -811,6 +839,7 @@ port_priv->dp_port_num, modem_signals );
oob_port->write_urb->dev = port->serial->dev;
if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+ oob_priv->dp_write_urb_in_use = 1;
port_priv->dp_modem_signals =
(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
@@ -1249,7 +1278,8 @@ priv->dp_port_num, count, from_user, in_interrupt() );
spin_lock_irqsave( &priv->dp_port_lock, flags );
/* wait for urb status clear to submit another urb */
- if( port->write_urb->status == -EINPROGRESS ) {
+ if( port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use ) {
/* buffer data if count is 1 (probably put_char) if possible */
if( count == 1 ) {
@@ -1292,6 +1322,7 @@ priv->dp_port_num, count, from_user, in_interrupt() );
memcpy( data, from_user ? user_buf : buf, new_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+ priv->dp_write_urb_in_use = 1;
ret = new_len;
priv->dp_out_buf_len = 0;
}
@@ -1337,6 +1368,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
== ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {
dbg( "digi_write_bulk_callback: oob callback" );
spin_lock( &priv->dp_port_lock );
+ priv->dp_write_urb_in_use = 0;
wake_up_interruptible( &port->write_wait );
spin_unlock( &priv->dp_port_lock );
return;
@@ -1349,6 +1381,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
/* try to send any buffered data on this port, if it is open */
spin_lock( &priv->dp_port_lock );
+ priv->dp_write_urb_in_use = 0;
if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS
&& priv->dp_out_buf_len > 0 ) {
@@ -1365,6 +1398,7 @@ dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
priv->dp_out_buf_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+ priv->dp_write_urb_in_use = 1;
priv->dp_out_buf_len = 0;
}
@@ -1397,7 +1431,8 @@ static int digi_write_room( struct usb_serial_port *port )
spin_lock_irqsave( &priv->dp_port_lock, flags );
- if( port->write_urb->status == -EINPROGRESS )
+ if( port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use )
room = 0;
else
room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
@@ -1416,7 +1451,8 @@ static int digi_chars_in_buffer( struct usb_serial_port *port )
digi_port_t *priv = (digi_port_t *)(port->private);
- if( port->write_urb->status == -EINPROGRESS ) {
+ if( port->write_urb->status == -EINPROGRESS
+ || priv->dp_write_urb_in_use ) {
dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
/* return( port->bulk_out_size - 2 ); */
return( 256 );
@@ -1601,6 +1637,7 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po
spin_lock_irqsave( &priv->dp_port_lock, flags );
port->active = 0;
+ priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
--priv->dp_open_count;
MOD_DEC_USE_COUNT;
@@ -1641,7 +1678,6 @@ static int digi_startup_device( struct usb_serial *serial )
port = &serial->port[i];
- port->write_urb->transfer_flags |= USB_DISABLE_SPD;
port->write_urb->dev = port->serial->dev;
if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
@@ -1689,6 +1725,7 @@ dbg( "digi_startup: TOP" );
priv->dp_port_num = i;
priv->dp_out_buf_len = 0;
priv->dp_in_buf_len = 0;
+ priv->dp_write_urb_in_use = 0;
priv->dp_modem_signals = 0;
init_waitqueue_head( &priv->dp_modem_change_wait );
priv->dp_open_count = 0;
@@ -2047,5 +2084,5 @@ module_exit(digi_exit);
MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
-MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver");
+MODULE_DESCRIPTION("Digi AccelePort USB-2/USB-4 Serial Converter driver");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 70f4cd1b0..fcdf71e84 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -12,6 +12,16 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/13/2000) Bill Ryder
+ * Added spinlock protected open code and close code.
+ * Multiple opens work (sort of - see webpage).
+ * Cleaned up comments. Removed multiple PID/VID definitions.
+ * Factorised cts/dtr code
+ * Made use of __FUNCTION__ in dbg's
+ *
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -68,8 +78,17 @@
#include "ftdi_sio.h"
-#define FTDI_VENDOR_ID 0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID 0x8372
+#define FTDI_VENDOR_ID FTDI_VID
+#define FTDI_SIO_SERIAL_CONVERTER_ID FTDI_SIO_PID
+#define FTDI_8U232AM_PID 0x6001
+
+static __devinitdata struct usb_device_id id_table_sio [] = {
+ { idVendor: FTDI_VID, idProduct: FTDI_SIO_PID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_sio);
+
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_startup (struct usb_serial *serial);
@@ -82,12 +101,9 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
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 */
+ id_table: id_table_sio,
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 */
@@ -105,63 +121,55 @@ struct usb_serial_device_type ftdi_sio_device = {
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
+ * See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date
+ * testing information
+ *
*
*/
#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+/* utility functions to set and unset dtr and rts */
+#define HIGH 1
+#define LOW 0
+static int set_rts(struct usb_device *dev,
+ unsigned int pipe,
+ int high_or_low)
+{
+ static char buf[1];
+ unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH :
+ FTDI_SIO_SET_RTS_LOW);
+ return(usb_control_msg(dev, pipe,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ ftdi_high_or_low, 0,
+ buf, 0, WDR_TIMEOUT));
+}
+static int set_dtr(struct usb_device *dev,
+ unsigned int pipe,
+ int high_or_low)
+{
+ static char buf[1];
+ unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH :
+ FTDI_SIO_SET_DTR_LOW);
+ return(usb_control_msg(dev, pipe,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ ftdi_high_or_low, 0,
+ buf, 0, WDR_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->port[0].write_wait);
+
return (0);
}
@@ -170,65 +178,55 @@ 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;
+ unsigned long flags; /* Used for spinlock */
int result;
char buf[1]; /* Needed for the usb_control_msg I think */
- dbg("ftdi_sio_open port %d", port->number);
+ dbg(__FUNCTION__ " 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 */
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ MOD_INC_USE_COUNT;
+ ++port->open_count;
- /* 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);
+ if (!port->active){
+ port->active = 1;
+ spin_unlock_irqrestore (&port->port_lock, flags);
- /* Setup termios */
- port->tty->termios->c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ /* 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);
-
- ftdi_sio_set_termios(port, &tmp_termios);
+ /* Setup termios */
+ port->tty->termios->c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- /* 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");
- }
+ /* ftdi_sio_set_termios will send usb control messages */
+ /* ftdi_sio_set_termios will set up port according to above list */
+
+ ftdi_sio_set_termios(port, &tmp_termios);
+
+ /* Turn on RTS and DTR since we are not flow controlling*/
+ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+ err("Error from DTR HIGH urb");
+ }
+ if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+ err("Error from RTS HIGH urb");
+ }
- /* Start reading from the device */
- FILL_BULK_URB(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ftdi_sio_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb);
- if (result)
- err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ /* Start reading from the device */
+ FILL_BULK_URB(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ftdi_sio_read_bulk_callback, port);
+ result = usb_submit_urb(port->read_urb);
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+ } else { /* the port was already active - so no initialisation was done */
+ spin_unlock_irqrestore (&port->port_lock, flags);
+ }
return (0);
} /* ftdi_sio_open */
@@ -239,41 +237,48 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
unsigned int c_cflag = port->tty->termios->c_cflag;
char buf[1];
+ unsigned long flags;
+
+ dbg( __FUNCTION__ " port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+ --port->open_count;
+
+ if (port->open_count <= 0) {
+ spin_unlock_irqrestore (&port->port_lock, flags);
+ 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 (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+ err("Error from DTR LOW urb");
+ }
+ /* drop RTS */
+ if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+ err("Error from RTS LOW urb");
+ }
+ } /* Note change no line is hupcl is off */
+
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+ port->open_count = 0;
+ } else {
+ spin_unlock_irqrestore (&port->port_lock, flags);
+ }
+
+ MOD_DEC_USE_COUNT;
- 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 */
@@ -292,7 +297,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
int result;
DECLARE_WAITQUEUE(wait, current);
- dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+ dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
if (count == 0) {
err("write request of 0 bytes");
@@ -309,8 +314,10 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
add_wait_queue(&port->write_wait, &wait);
set_current_state (TASK_INTERRUPTIBLE);
while (port->write_urb->status == -EINPROGRESS) {
- dbg("ftdi_sio - write in progress - retrying");
+ dbg(__FUNCTION__ " write in progress - retrying");
if (0 /* file->f_flags & O_NONBLOCK */) {
+ remove_wait_queue(&port->write_wait, &wait);
+ set_current_state(TASK_RUNNING);
rc = -EAGAIN;
goto err;
}
@@ -321,6 +328,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
goto err;
}
schedule();
+ set_current_state (TASK_INTERRUPTIBLE);
}
remove_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_RUNNING);
@@ -345,7 +353,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
first_byte = port->write_urb->transfer_buffer;
*first_byte = 1 | ((count-data_offset) << 2) ;
- dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+ dbg(__FUNCTION__ "Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
/* send the data out the bulk port */
@@ -360,7 +368,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
return 0;
}
- dbg("write returning: %d", count - data_offset);
+ dbg(__FUNCTION__ " write returning: %d", count - data_offset);
return (count - data_offset);
}
@@ -412,7 +420,7 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
int i;
int result;
- dbg("ftdi_sio read callback");
+ dbg(__FUNCTION__);
if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
return;
@@ -422,10 +430,6 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
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 */
@@ -439,6 +443,12 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb)
dbg("Just status");
}
+ /* TO DO -- check for hung up line and handle appropriately: */
+ /* send hangup (need to find out how to do this) */
+ /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */
+ /* if CD is dropped and the line is not CLOCAL then we should hangup */
+
+
if (urb->actual_length > data_offset) {
for (i = data_offset ; i < urb->actual_length ; ++i) {
tty_insert_flip_char(tty, data[i], 0);
@@ -468,10 +478,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct 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 */
+ __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);
+ dbg(__FUNCTION__ " port %d", port->number);
/* FIXME -For this cut I don't care if the line is really changing or
@@ -522,7 +532,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
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");
+ default: dbg(__FUNCTION__ "FTDI_SIO does not support the baudrate requested");
/* FIXME - how to return an error for this? */ break;
}
if ((cflag & CBAUD) == B0 ) {
@@ -535,18 +545,10 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
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) {
+ if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 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) {
+ if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
err("Error from RTS LOW urb");
}
@@ -563,7 +565,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
/* Set flow control */
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
- dbg("Setting to CRTSCTS flow control");
+ dbg(__FUNCTION__ "Setting to CRTSCTS flow control");
if (usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
@@ -576,7 +578,7 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
} else {
/* CHECK Assuming XON/XOFF handled by stack - not by device */
/* Disable flow control */
- dbg("Turning off hardware flow control");
+ dbg(__FUNCTION__ "Turning off hardware flow control");
if (usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
@@ -597,13 +599,13 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
char buf[1];
int ret, mask;
- dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+ dbg(__FUNCTION__ " cmd 0x%04x", cmd);
/* Based on code from acm.c and others */
switch (cmd) {
case TIOCMGET:
- dbg("TIOCMGET");
+ dbg(__FUNCTION__ "TIOCMGET");
/* Request the status from the device */
if ((ret = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
@@ -611,7 +613,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, 0,
buf, 1, HZ * 5)) < 0 ) {
- dbg("Get not get modem status of device");
+ dbg(__FUNCTION__ "Get not get modem status of device");
return(ret);
}
@@ -623,7 +625,7 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
break;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */
- dbg("TIOCMSET");
+ dbg(__FUNCTION__ "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,
@@ -648,26 +650,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
break;
case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
- dbg("TIOCMBIS");
+ dbg(__FUNCTION__ "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){
+ if ((ret = set_dtr(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ HIGH)) < 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){
+ }
+ if (mask & TIOCM_RTS) {
+ if ((ret = set_rts(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ HIGH)) < 0){
err("Urb to set RTS failed");
return(ret);
}
@@ -675,26 +671,20 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
break;
case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
- dbg("TIOCMBIC");
+ dbg(__FUNCTION__ "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){
+ if ((ret = set_dtr(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ LOW)) < 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){
+ if ((ret = set_rts(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ LOW)) < 0){
err("Urb to unset RTS failed");
return(ret);
}
@@ -714,11 +704,11 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns
/* 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);
+ dbg(__FUNCTION__ "arg not supported - it was 0x%04x",cmd);
return(-ENOIOCTLCMD);
break;
}
- dbg("ftdi_sio_ioctl returning 0");
+ dbg(__FUNCTION__ " returning 0");
return 0;
} /* ftdi_sio_ioctl */
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9c509ff15..885108cd0 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -22,6 +22,9 @@
Tip 'o the hat to Linuxcare for supporting staff in their work on
open source projects.
+ (11/01/2000) Adam J. Richter
+ usb_device_id table support.
+
(10/05/2000) gkh
Fixed bug with urb->dev not being set properly, now that the usb
core needs it.
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 666946181..8d249916c 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -117,28 +117,96 @@ struct ezusb_hex_record {
/* Device info for the Keyspan serial converter */
#define KEYSPAN_VENDOR_ID (0x06cd)
-static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
/* Product IDs for the five products supported, pre-renumeration */
-static __u16 keyspan_usa18x_pre_product_id = 0x0105;
-static __u16 keyspan_usa19_pre_product_id = 0x0103;
-static __u16 keyspan_usa19w_pre_product_id = 0x0106;
-static __u16 keyspan_usa28_pre_product_id = 0x0101;
-static __u16 keyspan_usa28x_pre_product_id = 0x0102;
+#define keyspan_usa18x_pre_product_id 0x0105
+#define keyspan_usa19_pre_product_id 0x0103
+#define keyspan_usa19w_pre_product_id 0x0106
+#define keyspan_usa28_pre_product_id 0x0101
+#define keyspan_usa28x_pre_product_id 0x0102
/* Product IDs post-renumeration */
-static __u16 keyspan_usa18x_product_id = 0x0112;
-static __u16 keyspan_usa19_product_id = 0x0107;
-static __u16 keyspan_usa19w_product_id = 0x0108;
-static __u16 keyspan_usa28_product_id = 0x010f;
-static __u16 keyspan_usa28x_product_id = 0x0110;
+#define keyspan_usa18x_product_id 0x0112
+#define keyspan_usa19_product_id 0x0107
+#define keyspan_usa19w_product_id 0x0108
+#define keyspan_usa28_product_id 0x010f
+#define keyspan_usa28x_product_id 0x0110
+
+static __devinitdata struct usb_device_id keyspan_ids_combined[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
+
+/* Eventually, we will not need separate id tables for each USB
+ ID pattern. But, for now, it looks like we need slightly different
+ behavior for each match. */
+
+static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_pre_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa18x_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa19_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa19w_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa28_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id keyspan_usa28x_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id},
+ { } /* Terminating entry */
+};
/* Structs for the devices, pre and post renumeration.
These are incomplete at present - HAB 20000708 */
struct usb_serial_device_type keyspan_usa18x_pre_device = {
name: "Keyspan USA18X - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa18x_pre_product_id,
+ id_table: keyspan_usa18x_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -151,8 +219,7 @@ struct usb_serial_device_type keyspan_usa18x_pre_device = {
struct usb_serial_device_type keyspan_usa19_pre_device = {
name: "Keyspan USA19 - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa19_pre_product_id,
+ id_table: keyspan_usa19_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -166,8 +233,7 @@ struct usb_serial_device_type keyspan_usa19_pre_device = {
struct usb_serial_device_type keyspan_usa19w_pre_device = {
name: "Keyspan USA19W - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa19w_pre_product_id,
+ id_table: keyspan_usa19w_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -181,8 +247,7 @@ struct usb_serial_device_type keyspan_usa19w_pre_device = {
struct usb_serial_device_type keyspan_usa28_pre_device = {
name: "Keyspan USA28 - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa28_pre_product_id,
+ id_table: keyspan_usa28_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -195,8 +260,7 @@ struct usb_serial_device_type keyspan_usa28_pre_device = {
struct usb_serial_device_type keyspan_usa28x_pre_device = {
name: "Keyspan USA28X - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa28x_pre_product_id,
+ id_table: keyspan_usa28x_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -210,8 +274,7 @@ struct usb_serial_device_type keyspan_usa28x_pre_device = {
struct usb_serial_device_type keyspan_usa18x_device = {
name: "Keyspan USA18X",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa18x_product_id,
+ id_table: keyspan_usa18x_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -228,8 +291,7 @@ struct usb_serial_device_type keyspan_usa18x_device = {
struct usb_serial_device_type keyspan_usa19_device = {
name: "Keyspan USA19",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa19_product_id,
+ id_table: keyspan_usa19_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
@@ -256,8 +318,7 @@ struct usb_serial_device_type keyspan_usa19_device = {
struct usb_serial_device_type keyspan_usa19w_device = {
name: "Keyspan USA19W",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa19w_product_id,
+ id_table: keyspan_usa19w_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -275,8 +336,7 @@ struct usb_serial_device_type keyspan_usa19w_device = {
struct usb_serial_device_type keyspan_usa28_device = {
name: "Keyspan USA28",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa28_product_id,
+ id_table: keyspan_usa28_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -294,8 +354,7 @@ struct usb_serial_device_type keyspan_usa28_device = {
struct usb_serial_device_type keyspan_usa28x_device = {
name: "Keyspan USA28X",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_usa28x_product_id,
+ id_table: keyspan_usa28x_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 51a1f10df..3114322c8 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -12,6 +12,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -93,12 +96,23 @@ struct keyspan_pda_private {
#define KEYSPAN_PDA_FAKE_ID 0x0103
#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-/* 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 __devinitdata struct usb_device_id id_table_combined [] = {
+ { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_FAKE_ID },
+ { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_ID },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+static __devinitdata struct usb_device_id id_table_std [] = {
+ { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_ID },
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id id_table_fake [] = {
+ { idVendor: KEYSPAN_VENDOR_ID, idProduct: KEYSPAN_PDA_FAKE_ID },
+ { } /* Terminating entry */
+};
static void keyspan_pda_wakeup_write( struct usb_serial_port *port )
{
@@ -746,8 +760,7 @@ static void keyspan_pda_shutdown (struct usb_serial *serial)
struct usb_serial_device_type keyspan_pda_fake_device = {
name: "Keyspan PDA - (prerenumeration)",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_pda_fake_product_id,
+ id_table: id_table_fake,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: DONT_CARE,
@@ -760,8 +773,7 @@ struct usb_serial_device_type keyspan_pda_fake_device = {
struct usb_serial_device_type keyspan_pda_device = {
name: "Keyspan PDA",
- idVendor: &keyspan_vendor_id,
- idProduct: &keyspan_pda_product_id,
+ id_table: id_table_std,
needs_interrupt_in: MUST_HAVE,
needs_bulk_in: DONT_CARE,
needs_bulk_out: MUST_HAVE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index dc832fa53..2b9f99f7c 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -10,6 +10,9 @@
*
* Please report both successes and troubles to the author at omninet@kroah.com
*
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -66,14 +69,17 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const u
static int omninet_write_room (struct usb_serial_port *port);
static void omninet_shutdown (struct usb_serial *serial);
-/* All of the device info needed for the omni.net */
-static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID;
-static __u16 zyxel_omninet_product_id = ZYXEL_OMNINET_ID;
+static __devinitdata struct usb_device_id id_table [] = {
+ { idVendor: ZYXEL_VENDOR_ID, idProduct: ZYXEL_OMNINET_ID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
struct usb_serial_device_type zyxel_omninet_device = {
name: "ZyXEL - omni.net lcd plus usb",
- idVendor: &zyxel_vendor_id,
- idProduct: &zyxel_omninet_product_id,
+ id_table: id_table,
needs_interrupt_in: MUST_HAVE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 5dde77426..913fb2f26 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -112,8 +112,7 @@ struct usb_serial {
/* This structure defines the individual serial converter. */
struct usb_serial_device_type {
char *name;
- __u16 *idVendor;
- __u16 *idProduct;
+ const struct usb_device_id *id_table;
char needs_interrupt_in;
char needs_bulk_in;
char needs_bulk_out;
@@ -125,7 +124,9 @@ struct usb_serial_device_type {
struct list_head driver_list;
/* function call to make before accepting driver */
- int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
+ /* return 0 to continue initialization, anything else to abort */
+ int (*startup) (struct usb_serial *serial);
+
void (*shutdown) (struct usb_serial *serial);
/* serial function calls */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 902a4e1d0..6b5d6e7f0 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -15,6 +15,11 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/01/2000) Adam J. Richter
+ * instead of using idVendor/idProduct pairs, usb serial drivers
+ * now identify their hardware interest with usb_device_id tables,
+ * which they usually have anyhow for use with MODULE_DEVICE_TABLE.
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -288,11 +293,12 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor");
MODULE_PARM(product, "i");
MODULE_PARM_DESC(product, "User specified USB idProduct");
+static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
+
/* 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 */
+ id_table: generic_device_ids,
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 */
@@ -316,15 +322,25 @@ 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_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id);
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,
+ id_table: NULL, /* check all devices */
};
+/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
+ the MODULE_DEVICE_TABLE declarations in each serial driver
+ cause the "hotplug" program to pull in whatever module is necessary
+ via modprobe, and modprobe will load usbserial because the serial
+ drivers depend on it.
+*/
+
+
static int serial_refcount;
static struct tty_driver serial_tty_driver;
static struct tty_struct * serial_tty[SERIAL_TTY_MINORS];
@@ -957,7 +973,8 @@ static void port_softint(void *private)
-static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_serial *serial = NULL;
struct usb_serial_port *port;
@@ -981,19 +998,17 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
int num_bulk_out = 0;
int num_ports;
int max_endpoints;
+ const struct usb_device_id *id_pattern = NULL;
/* loop through our list of known serial converters, and see if this
device matches. */
found = 0;
+ interface = &dev->actconfig->interface[ifnum];
list_for_each (tmp, &usb_serial_driver_list) {
type = list_entry(tmp, struct usb_serial_device_type, driver_list);
- 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))) {
+ id_pattern = usb_match_id(dev, interface, type->id_table);
+ if (id_pattern != NULL) {
dbg("descriptor matches");
found = 1;
break;
@@ -1009,7 +1024,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
/* check out the endpoints */
- interface = &dev->actconfig->interface[ifnum];
iface_desc = &interface->altsetting[0];
for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i];
@@ -1335,6 +1349,8 @@ int usb_serial_init(void)
}
#ifdef CONFIG_USB_SERIAL_GENERIC
+ generic_device_ids[0].idVendor = vendor;
+ generic_device_ids[0].idProduct = product;
/* register our generic driver with ourselves */
usb_serial_register (&generic_device);
#endif
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 868333c87..c078704f0 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -101,13 +104,20 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old
static void visor_write_bulk_callback (struct urb *urb);
static void visor_read_bulk_callback (struct urb *urb);
+
+static __devinitdata struct usb_device_id id_table [] = {
+ { idVendor: HANDSPRING_VENDOR_ID, idProduct: HANDSPRING_VISOR_ID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+
/* 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 */
+ id_table: id_table,
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 */
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 55abab383..83a822225 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (11/01/2000) Adam J. Richter
+ * usb_device_id table support
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
@@ -77,6 +80,31 @@
#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001
#define CONNECT_TECH_WHITE_HEAT_ID 0x8001
+/*
+ ID tables for whiteheat are unusual, because we want to different
+ things for different versions of the device. Eventually, this
+ will be doable from a single table. But, for now, we define two
+ separate ID tables, and then a third table that combines them
+ just for the purpose of exporting the autoloading information.
+*/
+static __devinitdata struct usb_device_id id_table_std [] = {
+ {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id id_table_prerenumeration [] = {
+ {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID},
+ { } /* Terminating entry */
+};
+
+static __devinitdata struct usb_device_id id_table_combined [] = {
+ {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_WHITE_HEAT_ID},
+ {idVendor: CONNECT_TECH_VENDOR_ID, idProduct: CONNECT_TECH_FAKE_WHITE_HEAT_ID},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
/* 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);
@@ -87,14 +115,9 @@ static void whiteheat_unthrottle (struct usb_serial_port *port);
static int whiteheat_startup (struct usb_serial *serial);
static void whiteheat_shutdown (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 */
+ id_table: id_table_prerenumeration,
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 */
@@ -104,10 +127,10 @@ struct usb_serial_device_type whiteheat_fake_device = {
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 */
+ id_table: id_table_std,
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 */
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 80ace9dac..cf82489de 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.15 2000/10/19 18:44:11 mdharm Exp $
+ * $Id: scsiglue.c,v 1.17 2000/11/02 21:27:49 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -47,6 +47,7 @@
#include "scsiglue.h"
#include "usb.h"
#include "debug.h"
+#include "transport.h"
#include <linux/malloc.h>
@@ -105,7 +106,7 @@ static int detect(struct SHT *sht)
/* Release all resources used by the virtual host
*
- * NOTE: There is no contention here, because we're allready deregistered
+ * NOTE: There is no contention here, because we're already deregistered
* the driver and we're doing each virtual host in turn, not in parallel
*/
static int release(struct Scsi_Host *psh)
@@ -218,6 +219,7 @@ static int bus_reset( Scsi_Cmnd *srb )
{
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
int i;
+ int result;
/* we use the usb_reset_device() function to handle this for us */
US_DEBUGP("bus_reset() called\n");
@@ -228,6 +230,15 @@ static int bus_reset( Scsi_Cmnd *srb )
return SUCCESS;
}
+ /* release the IRQ, if we have one */
+ down(&(us->irq_urb_sem));
+ if (us->irq_urb) {
+ US_DEBUGP("-- releasing irq URB\n");
+ result = usb_unlink_urb(us->irq_urb);
+ US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+ }
+ up(&(us->irq_urb_sem));
+
/* attempt to reset the port */
if (usb_reset_device(us->pusb_dev) < 0)
return FAILED;
@@ -237,6 +248,7 @@ static int bus_reset( Scsi_Cmnd *srb )
for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *intf =
&us->pusb_dev->actconfig->interface[i];
+ struct usb_device_id *id;
/* if this is an unclaimed interface, skip it */
if (!intf->driver) {
@@ -254,10 +266,22 @@ static int bus_reset( Scsi_Cmnd *srb )
US_DEBUGPX("simulating disconnect/reconnect.\n");
down(&intf->driver->serialize);
intf->driver->disconnect(us->pusb_dev, intf->private_data);
- intf->driver->probe(us->pusb_dev, i);
+ id = usb_match_id(us->pusb_dev, intf, intf->driver->id_table);
+ intf->driver->probe(us->pusb_dev, i, id);
up(&intf->driver->serialize);
}
+ /* re-allocate the IRQ URB and submit it to restore connectivity
+ * for CBI devices
+ */
+ if (us->protocol == US_PR_CBI) {
+ down(&(us->irq_urb_sem));
+ us->irq_urb->dev = us->pusb_dev;
+ result = usb_submit_urb(us->irq_urb);
+ US_DEBUGP("usb_submit_urb() returns %d\n", result);
+ up(&(us->irq_urb_sem));
+ }
+
US_DEBUGP("bus_reset() complete\n");
return SUCCESS;
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 6551d259c..dd72f334c 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.30 2000/10/24 02:01:18 mdharm Exp $
+ * $Id: transport.c,v 1.32 2000/11/03 00:18:04 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -91,11 +91,11 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
static char *lengths =
- /* 0123456789ABCDEF 0123456789ABCDEF */
+ /* 0123456789ABCDEF 0123456789ABCDEF */
"00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */
"XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */
- "M0HHB0X000H0HH0X" "XHH00HXX0TH0H0XX" /* 40-5F */
+ "M0HHB0X000H0HH0X" "XHH0HHXX0TH0H0XX" /* 40-5F */
"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
"XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
"X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */
@@ -185,6 +185,7 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes
SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes
SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes
+ SEND_OPC 54
SEND_VOLUME_TAG b6 !!! Think this is in bytes
SET_LIMITS 33
SET_LIMITS_12 b3
@@ -422,6 +423,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
if (status) {
/* something went wrong */
up(&(us->current_urb_sem));
+ current->state = TASK_RUNNING;
remove_wait_queue(&wqh, &wait);
kfree(dr);
return status;
@@ -479,6 +481,7 @@ int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
if (status) {
/* something went wrong */
up(&(us->current_urb_sem));
+ current->state = TASK_RUNNING;
remove_wait_queue(&wqh, &wait);
return status;
}
@@ -544,7 +547,7 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
/* uh oh... we have an error code, so something went wrong. */
if (result) {
- /* NAK - that means we've retried a few times allready */
+ /* NAK - that means we've retried a few times already */
if (result == -ETIMEDOUT) {
US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
return US_BULK_TRANSFER_FAILED;
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 8d41b1c0c..a7129ba25 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.51 2000/10/19 18:49:51 mdharm Exp $
+ * $Id: usb.c,v 1.54 2000/10/31 21:32:10 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -243,6 +243,7 @@ static int usb_stor_control_thread(void * __us)
/* handle those devices which can't do a START_STOP */
if ((us->srb->cmnd[0] == START_STOP) &&
(us->flags & US_FL_START_STOP)) {
+ US_DEBUGP("Skipping START_STOP command\n");
us->srb->result = GOOD << 1;
set_current_state(TASK_INTERRUPTIBLE);
@@ -311,11 +312,15 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("-- US_ACT_EXIT command recieved\n");
break;
}
+
+ set_current_state(TASK_INTERRUPTIBLE);
} /* for (;;) */
/* notify the exit routine that we're actually exiting now */
up(&(us->notify));
+ remove_wait_queue(&(us->wqh), &wait);
+
return 0;
}
@@ -423,8 +428,8 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
+ US_SC_UFI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP },
{ 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
@@ -504,7 +509,7 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_FREECOM
- { 0x07ab, 0xfc01, 0x0921, 0x0921,
+ { 0x07ab, 0xfc01, 0x0000, 0x9999,
"Freecom",
"USB-IDE",
US_SC_QIC, US_PR_FREECOM, freecom_init, 0},
@@ -754,7 +759,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/*
* Now check if we have seen this GUID before
* We're looking for a device with a matching GUID that isn't
- * allready on the system
+ * already on the system
*/
ss = us_list;
while ((ss != NULL) &&
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 2105cb595..9d424a61a 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -654,6 +654,7 @@ static int sohci_unlink_urb (urb_t * urb)
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && (urb->status == USB_ST_URB_PENDING))
timeout = schedule_timeout (timeout);
+ current->state = TASK_RUNNING;
remove_wait_queue (&unlink_wakeup, &wait);
if (urb->status == USB_ST_URB_PENDING) {
err ("unlink URB timeout");
@@ -765,6 +766,7 @@ static int sohci_free_dev (struct usb_device * usb_dev)
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && dev->ed_cnt)
timeout = schedule_timeout (timeout);
+ current->state = TASK_RUNNING;
remove_wait_queue (&freedev_wakeup, &wait);
if (dev->ed_cnt) {
err ("free device %d timeout", usb_dev->devnum);
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 7e59346aa..5b1b76003 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -7,6 +7,9 @@
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
@@ -460,6 +463,124 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac
iface->private_data = NULL;
}
+
+/* usb_match_id searches an array of usb_device_id's and returns
+ the first one that matches the device and interface.
+
+ Parameters:
+ "id" is an array of usb_device_id's is terminated by an entry
+ containing all zeroes.
+
+ "dev" and "interface" are the device and interface for which
+ a match is sought.
+
+ If no match is found or if the "id" pointer is NULL, then
+ usb_match_id returns NULL.
+
+
+ What constitutes a match:
+
+ A zero in any element of a usb_device_id entry is a wildcard
+ (i.e., that field always matches). For there to be a match,
+ *every* nonzero element of the usb_device_id must match the
+ provided device and interface in. The comparison is for equality,
+ except for one pair of fields: usb_match_id.bcdDevice_{lo,hi} define
+ an inclusive range that dev->descriptor.bcdDevice must be in.
+
+ If interface->altsettings does not exist (i.e., there are no
+ interfaces defined), then bInterface{Class,SubClass,Protocol}
+ only match if they are all zeroes.
+
+
+ What constitutes a good "usb_device_id"?
+
+ The match algorithm is very simple, so that intelligence in
+ driver selection must come from smart driver id records.
+ Unless you have good reasons to use another selection policy,
+ provide match elements only in related groups:
+
+ * device specifiers (vendor and product IDs; and maybe
+ a revision range for that product);
+ * generic device specs (class/subclass/protocol);
+ * interface specs (class/subclass/protocol).
+
+ Within those groups, work from least specific to most specific.
+ For example, don't give a product version range without vendor
+ and product IDs.
+
+ "driver_info" is not considered by the kernel matching algorithm,
+ but you can create a wildcard "matches anything" usb_device_id
+ as your driver's "modules.usbmap" entry if you provide only an
+ id with a nonzero "driver_info" field.
+*/
+
+const struct usb_device_id *
+usb_match_id(struct usb_device *dev, struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_interface_descriptor *intf = 0;
+
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
+ if (id == NULL)
+ return NULL;
+
+ /* It is important to check that id->driver_info is nonzero,
+ since an entry that is all zeroes except for a nonzero
+ id->driver_info is the way to create an entry that
+ indicates that the driver want to examine every
+ device and interface. */
+ for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+ id->driver_info; id++) {
+
+ if (id->idVendor &&
+ id->idVendor != dev->descriptor.idVendor)
+ continue;
+
+ if (id->idProduct &&
+ id->idProduct != dev->descriptor.idProduct)
+ continue;
+
+ /* No need to test id->bcdDevice_lo != 0, since 0 is never
+ greater than any unsigned number. */
+ if (id->bcdDevice_lo > dev->descriptor.bcdDevice)
+ continue;
+
+ if (id->bcdDevice_hi &&
+ id->bcdDevice_hi < dev->descriptor.bcdDevice)
+ continue;
+
+ if (id->bDeviceClass &&
+ id->bDeviceClass != dev->descriptor.bDeviceClass)
+ continue;
+
+ if (id->bDeviceSubClass &&
+ id->bDeviceSubClass!= dev->descriptor.bDeviceClass)
+ continue;
+
+ if (id->bDeviceProtocol &&
+ id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)
+ continue;
+
+ intf = &interface->altsetting [interface->act_altsetting];
+
+ if (id->bInterfaceClass
+ && id->bInterfaceClass != intf->bInterfaceClass)
+ continue;
+
+ if (id->bInterfaceSubClass &&
+ id->bInterfaceSubClass != intf->bInterfaceSubClass)
+ continue;
+
+ if (id->bInterfaceProtocol
+ && id->bInterfaceProtocol != intf->bInterfaceProtocol)
+ continue;
+
+ return id;
+ }
+
+ return NULL;
+}
+
/*
* This entrypoint gets called for each new device.
*
@@ -478,8 +599,12 @@ void usb_driver_release_interface(struct usb_driver *driver, struct usb_interfac
*/
static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
{
- struct list_head *tmp = usb_driver_list.next;
+ struct list_head *tmp;
struct usb_interface *interface;
+ void *private;
+ const struct usb_device_id *id;
+ struct usb_driver *driver;
+ int i;
if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
err("bad find_interface_driver params");
@@ -491,141 +616,52 @@ static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
if (usb_interface_claimed(interface))
return -1;
- while (tmp != &usb_driver_list) {
- void *private;
- struct usb_driver *driver = list_entry(tmp, struct usb_driver,
- driver_list);
-
+ private = NULL;
+ for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
+
+ driver = list_entry(tmp, struct usb_driver, driver_list);
tmp = tmp->next;
- down(&driver->serialize);
+ down(&driver->serialize);
+ id = driver->id_table;
/* new style driver? */
- if (driver->bind) {
- const struct usb_device_id *id = driver->id_table;
-
- if (id) {
- /* scan device ids for a match */
- for (;; id++) {
- struct usb_interface_descriptor *intf = 0;
-
- /* done? */
- if (!id->idVendor && !id->bDeviceClass && !id->bInterfaceClass) {
- id = 0;
- break;
- }
+ if (id) {
+ for (i = 0; i < interface->num_altsetting; i++) {
+ interface->act_altsetting = i;
+ id = usb_match_id(dev, interface, id);
+ if (id) {
+ private = driver->probe(dev,ifnum,id);
+ if (private != NULL)
+ break;
+ }
+ }
+ /* if driver not bound, leave defaults unchanged */
+ if (private == NULL)
+ interface->act_altsetting = 0;
+ }
+ else /* "old style" driver */
+ private = driver->probe(dev, ifnum, NULL);
- /* Vendor match, possibly product-specific? */
- if (id->idVendor && id->idVendor == dev->descriptor.idVendor) {
- if (id->idProduct && id->idProduct != dev->descriptor.idProduct)
- continue;
- break;
- }
-
- /* Device class match? */
- if (id->bDeviceClass
- && id->bDeviceClass == dev->descriptor.bDeviceClass) {
- if (id->bDeviceSubClass && id->bDeviceSubClass
- != dev->descriptor.bDeviceClass)
- continue;
- if (id->bDeviceProtocol && id->bDeviceProtocol
- != dev->descriptor.bDeviceProtocol)
- continue;
- break;
- }
-
- /* Interface class match? */
- if (!interface->altsetting || interface->num_altsetting < 1)
- continue;
- intf = &interface->altsetting [0];
- if (id->bInterfaceClass
- && id->bInterfaceClass == intf->bInterfaceClass) {
- if (id->bInterfaceSubClass && id->bInterfaceSubClass
- != intf->bInterfaceClass)
- continue;
- if (id->bInterfaceProtocol && id->bInterfaceProtocol
- != intf->bInterfaceProtocol)
- continue;
- break;
- }
- }
-
- /* is this driver interested in this interface? */
- if (id)
- private = driver->bind(dev, ifnum, id);
- else
- private = 0;
- } else {
- /* "old style" driver, but using new interface */
- private = driver->bind(dev, ifnum, 0);
- }
-
- /* "old style" driver */
- } else
- private = driver->probe(dev, ifnum);
up(&driver->serialize);
- if (!private)
- continue;
- usb_driver_claim_interface(driver, interface, private);
-
- return 0;
+ if (private) {
+ usb_driver_claim_interface(driver, interface, private);
+ return 0;
+ }
}
-
+
return -1;
}
-#if defined(CONFIG_KMOD) && defined(CONFIG_HOTPLUG)
+#ifdef CONFIG_HOTPLUG
/*
* USB hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when USB devices get added or removed.
- */
-
-static int to_bcd (char *buf, __u16 *bcdValue)
-{
- int retval = 0;
- char *value = (char *) bcdValue;
- int temp;
-
- /* digits are 0-9 then ":;<=>?" for devices using
- * non-bcd (non-standard!) values here ... */
-
- /* No leading (or later, trailing) zeroes since scripts do
- * literal matches, and that's how they're doing them. */
- if ((temp = value [1] & 0xf0) != 0) {
- temp >>= 4;
- temp += '0';
- *buf++ = (char) temp;
- retval++;
- }
-
- temp = value [1] & 0x0f;
- temp += '0';
- *buf++ = (char) temp;
- retval++;
-
- *buf++ = '.';
- retval++;
-
- temp = value [0] & 0xf0;
- temp >>= 4;
- temp += '0';
- *buf++ = (char) temp;
- retval++;
-
- if ((temp = value [0] & 0x0f) != 0) {
- temp += '0';
- *buf++ = (char) temp;
- retval++;
- }
- *buf++ = 0;
-
- return retval;
-}
-
-/*
+ *
* This invokes a user mode policy agent, typically helping to load driver
- * or other modules, configure the device, or both.
+ * or other modules, configure the device, and more. Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* Some synchronization is important: removes can't start processing
* before the add-device processing completes, and vice versa. That keeps
@@ -696,9 +732,7 @@ static void call_policy (char *verb, struct usb_device *dev)
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
- * XXX how little intelligence can we hardwire?
- * (a) mount point: /devfs, /dev, /proc/bus/usb etc.
- * (b) naming convention: bus1/device3, 001/003 etc.
+ * FIXME reduce hardwired intelligence here
*/
envp [i++] = "DEVFS=/proc/bus/usb";
envp [i++] = scratch;
@@ -706,33 +740,34 @@ static void call_policy (char *verb, struct usb_device *dev)
dev->bus->busnum, dev->devnum) + 1;
#endif
- /* per-device configuration hacks are often necessary */
+ /* per-device configuration hacks are common */
envp [i++] = scratch;
- scratch += sprintf (scratch, "PRODUCT=%x/%x/",
+ scratch += sprintf (scratch, "PRODUCT=%x/%x/%x",
dev->descriptor.idVendor,
- dev->descriptor.idProduct);
- scratch += to_bcd (scratch, &dev->descriptor.bcdDevice) + 1;
+ dev->descriptor.idProduct,
+ dev->descriptor.bcdDevice) + 1;
- /* otherwise, use a simple (so far) generic driver binding model */
+ /* class-based driver binding models */
envp [i++] = scratch;
+ scratch += sprintf (scratch, "TYPE=%d/%d/%d",
+ dev->descriptor.bDeviceClass,
+ dev->descriptor.bDeviceSubClass,
+ dev->descriptor.bDeviceProtocol) + 1;
if (dev->descriptor.bDeviceClass == 0) {
int alt = dev->actconfig->interface [0].act_altsetting;
- /* simple/common case: one config, one interface, one driver
- * unsimple cases: everything else
+ /* a simple/common case: one config, one interface, one driver
+ * with current altsetting being a reasonable setting.
+ * everything needs a smart agent and usbdevfs; or can rely on
+ * device-specific binding policies.
*/
+ envp [i++] = scratch;
scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
+ 1;
/* INTERFACE-0, INTERFACE-1, ... ? */
- } else {
- /* simple/common case: generic device, handled generically */
- scratch += sprintf (scratch, "TYPE=%d/%d/%d",
- dev->descriptor.bDeviceClass,
- dev->descriptor.bDeviceSubClass,
- dev->descriptor.bDeviceProtocol) + 1;
}
envp [i++] = 0;
/* assert: (scratch - buf) < sizeof buf */
@@ -753,7 +788,7 @@ static inline void
call_policy (char *verb, struct usb_device *dev)
{ }
-#endif /* KMOD && HOTPLUG */
+#endif /* KMOD */
/*
@@ -916,6 +951,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
if (status) {
// something went wrong
usb_free_urb(urb);
+ current->state = TASK_RUNNING;
remove_wait_queue(&wqh, &wait);
return status;
}
@@ -926,6 +962,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
} else
status = 1;
+ current->state = TASK_RUNNING;
remove_wait_queue(&wqh, &wait);
if (!status) {
@@ -968,6 +1005,11 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
/*-------------------------------------------------------------------*/
+/* usb_control_msg() - builds control urb, and waits for completion */
+/* Synchronous behavior - don't use this function from within an */
+/* interrupt context, (like a bottom half handler.) In this case, */
+/* use usb_submit_urb() directly instead. */
+
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
@@ -993,8 +1035,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
}
/*-------------------------------------------------------------------*/
-/* compatibility wrapper, builds bulk urb, and waits for completion */
-/* synchronous behavior */
+/* usb_bulk_msg() Builds a bulk urb, and waits for completion. */
+/* Synchronous behavior - don't use this function from within an */
+/* interrupt context, (like a bottom half handler.) In this case, */
+/* use usb_submit_urb() directly instead. */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
@@ -2149,6 +2193,7 @@ EXPORT_SYMBOL(usb_inc_dev_use);
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
index bbf4b59ac..7fd1ebd7c 100644
--- a/drivers/usb/usbkbd.c
+++ b/drivers/usb/usbkbd.c
@@ -59,6 +59,7 @@ static unsigned char usb_kbd_keycode[256] = {
struct usb_kbd {
struct input_dev dev;
+ struct usb_device *usbdev;
unsigned char new[8];
unsigned char old[8];
struct urb irq, led;
@@ -116,6 +117,7 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i
return 0;
kbd->leds = kbd->newleds;
+ kbd->led.dev = kbd->usbdev;
if (usb_submit_urb(&kbd->led))
err("usb_submit_urb(leds) failed");
@@ -133,6 +135,7 @@ static void usb_kbd_led(struct urb *urb)
return;
kbd->leds = kbd->newleds;
+ kbd->led.dev = kbd->usbdev;
if (usb_submit_urb(&kbd->led))
err("usb_submit_urb(leds) failed");
}
@@ -144,6 +147,7 @@ static int usb_kbd_open(struct input_dev *dev)
if (kbd->open++)
return 0;
+ kbd->irq.dev = kbd->usbdev;
if (usb_submit_urb(&kbd->irq))
return -EIO;
@@ -158,20 +162,19 @@ static void usb_kbd_close(struct input_dev *dev)
usb_unlink_urb(&kbd->irq);
}
-static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
+ struct usb_interface *iface;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_kbd *kbd;
int i, pipe, maxp;
char *buf;
- if (dev->descriptor.bNumConfigurations != 1) return NULL;
- interface = dev->config[0].interface[ifnum].altsetting + 0;
+ iface = &dev->actconfig->interface[ifnum];
+ interface = &iface->altsetting[iface->act_altsetting];
- if (interface->bInterfaceClass != 3) return NULL;
- if (interface->bInterfaceSubClass != 1) return NULL;
- if (interface->bInterfaceProtocol != 1) return NULL;
if (interface->bNumEndpoints != 1) return NULL;
endpoint = interface->endpoint + 0;
@@ -187,6 +190,8 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
memset(kbd, 0, sizeof(struct usb_kbd));
+ kbd->usbdev = dev;
+
kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
@@ -251,10 +256,18 @@ static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
kfree(kbd);
}
+static struct usb_device_id usb_kbd_id_table [] = {
+ { bInterfaceClass: 3, bInterfaceSubClass: 1, bInterfaceProtocol: 1},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
+
static struct usb_driver usb_kbd_driver = {
name: "keyboard",
probe: usb_kbd_probe,
- disconnect: usb_kbd_disconnect
+ disconnect: usb_kbd_disconnect,
+ id_table: usb_kbd_id_table,
};
static int __init usb_kbd_init(void)
diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c
index 1e873b285..b6473e11a 100644
--- a/drivers/usb/usbmouse.c
+++ b/drivers/usb/usbmouse.c
@@ -1,5 +1,5 @@
/*
- * $Id: usbmouse.c,v 1.5 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: usbmouse.c,v 1.6 2000/08/14 21:05:26 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -41,9 +41,9 @@ MODULE_DESCRIPTION("USB HID Boot Protocol mouse driver");
struct usb_mouse {
signed char data[8];
char name[128];
+ struct usb_device *usbdev;
struct input_dev dev;
struct urb irq;
- struct usb_device *my_usb_device; // for resubmitting my urb
int open;
};
@@ -73,7 +73,7 @@ static int usb_mouse_open(struct input_dev *dev)
if (mouse->open++)
return 0;
- mouse->irq.dev = mouse->my_usb_device;
+ mouse->irq.dev = mouse->usbdev;
if (usb_submit_urb(&mouse->irq))
return -EIO;
@@ -88,20 +88,19 @@ static void usb_mouse_close(struct input_dev *dev)
usb_unlink_urb(&mouse->irq);
}
-static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
+static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
+ struct usb_interface *iface;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_mouse *mouse;
int pipe, maxp;
char *buf;
- if (dev->descriptor.bNumConfigurations != 1) return NULL;
- interface = dev->config[0].interface[ifnum].altsetting + 0;
+ iface = &dev->actconfig->interface[ifnum];
+ interface = &iface->altsetting[iface->act_altsetting];
- if (interface->bInterfaceClass != 3) return NULL;
- if (interface->bInterfaceSubClass != 1) return NULL;
- if (interface->bInterfaceProtocol != 2) return NULL;
if (interface->bNumEndpoints != 1) return NULL;
endpoint = interface->endpoint + 0;
@@ -116,6 +115,8 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
memset(mouse, 0, sizeof(struct usb_mouse));
+ mouse->usbdev = dev;
+
mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
@@ -150,7 +151,6 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
kfree(buf);
- mouse->my_usb_device = dev;
FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
usb_mouse_irq, mouse, endpoint->bInterval);
@@ -170,10 +170,18 @@ static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
kfree(mouse);
}
+static struct usb_device_id usb_mouse_id_table [] = {
+ { bInterfaceClass: 3, bInterfaceSubClass: 1, bInterfaceProtocol: 2},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
+
static struct usb_driver usb_mouse_driver = {
name: "usb_mouse",
probe: usb_mouse_probe,
disconnect: usb_mouse_disconnect,
+ id_table: usb_mouse_id_table,
};
static int __init usb_mouse_init(void)
diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c
index da61b5214..f97f5f639 100644
--- a/drivers/usb/uss720.c
+++ b/drivers/usb/uss720.c
@@ -32,6 +32,7 @@
* 0.3 10.08.99 fixing merge errors
* 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable
* 0.5 20.09.99 usb_control_msg wrapper used
+ * Nov01.00 usb_device_table support by Adam J. Richter
*
*/
@@ -534,7 +535,8 @@ static struct parport_operations parport_uss720_ops =
/* --------------------------------------------------------------------- */
-static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum)
+static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum,
+ const struct usb_device_id *id)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
@@ -542,11 +544,6 @@ static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum)
struct parport *pp;
int i;
- if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) &&
- (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) &&
- (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284))
- return NULL;
-
printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
@@ -626,11 +623,22 @@ static void uss720_disconnect(struct usb_device *usbdev, void *ptr)
MOD_DEC_USE_COUNT;
}
+/* table of cables that work through this driver */
+static struct usb_device_id uss720_table [] = {
+ { idVendor: 0x047e, idProduct: 0x1001},
+ { idVendor: 0x0557, idProduct: 0x2001},
+ { idVendor: 0x0729, idProduct: 0x1284},
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, uss720_table);
+
+
static struct usb_driver uss720_driver = {
- "uss720",
- uss720_probe,
- uss720_disconnect,
- { NULL, NULL }
+ name: "uss720",
+ probe: uss720_probe,
+ disconnect: uss720_disconnect,
+ id_table: uss720_table,
};
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/wacom.c b/drivers/usb/wacom.c
index 4dcc86436..af813ceab 100644
--- a/drivers/usb/wacom.c
+++ b/drivers/usb/wacom.c
@@ -1,10 +1,11 @@
/*
- * $Id: wacom.c,v 1.9 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: wacom.c,v 1.11 2000/10/18 12:12:26 vojtech Exp $
*
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
* Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
* Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
+ * Copyright (c) 2000 James E. Blair <corvus@gnu.org>
*
* USB Wacom Graphire and Wacom Intuos tablet support
*
@@ -21,23 +22,25 @@
* v1.8 (vp) - Submit URB only when operating, moved to CVS,
* use input_report_key instead of report_btn and
* other cleanups
+ * v1.11 (vp) - Add URB ->dev setting for new kernels
+ * v1.11 (jb) - Add support for the 4D Mouse & Lens
*/
/*
* 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
+ * 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
@@ -70,17 +73,17 @@ MODULE_DESCRIPTION("USB Wacom Graphire and Wacom Intuos tablet driver");
* byte 5: Y high bits
* byte 6: pen pressure low bits / mouse wheel
* byte 7: pen presure high bits / mouse distance
- *
+ *
* There are also two single-byte feature reports (2 and 3).
*
* Wacom Intuos status packet:
*
* byte 0: report ID (2)
- * byte 1: bit7 1 - sync bit
+ * byte 1: bit7 1 - sync bit
* bit6 pointer in range
* bit5 pointer type report
* bit4 0 ?
- * bit3 0 ?
+ * bit3 mouse packet type
* bit2 pen button2
* bit1 pen button1
* bit0 0 ?
@@ -88,12 +91,38 @@ MODULE_DESCRIPTION("USB Wacom Graphire and Wacom Intuos tablet driver");
* byte 3: X low bits
* byte 4: Y high bits
* byte 5: Y low bits
+ *
+ * Pen packet:
+ *
* byte 6: bits 0-7: pressure (bits 2-9)
* byte 7: bits 6-7: pressure (bits 0-1)
* byte 7: bits 0-5: X tilt (bits 1-6)
* byte 8: bit 7: X tilt (bit 0)
* byte 8: bits 0-6: Y tilt (bits 0-6)
* byte 9: bits 4-7: distance
+ *
+ * Mouse packet type 0:
+ *
+ * byte 6: bits 0-7: wheel (bits 2-9)
+ * byte 7: bits 6-7: wheel (bits 0-1)
+ * byte 7: bits 0-5: 0
+ * byte 8: bits 6-7: 0
+ * byte 8: bit 5: left extra button
+ * byte 8: bit 4: right extra button
+ * byte 8: bit 3: wheel (sign)
+ * byte 8: bit 2: right button
+ * byte 8: bit 1: middle button
+ * byte 8: bit 0: left button
+ * byte 9: bits 4-7: distance
+ *
+ * Mouse packet type 1:
+ *
+ * byte 6: bits 0-7: rotation (bits 2-9)
+ * byte 7: bits 6-7: rotation (bits 0-1)
+ * byte 7: bit 5: rotation (sign)
+ * byte 7: bits 0-4: 0
+ * byte 8: bits 0-7: 0
+ * byte 9: bits 4-7: distance
*/
#define USB_VENDOR_ID_WACOM 0x056a
@@ -192,7 +221,7 @@ static void wacom_intuos_irq(struct urb *urb)
case 0x0fa: wacom->tool = BTN_TOOL_RUBBER; break; /* Eraser */
case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH; break; /* Airbrush */
default: wacom->tool = BTN_TOOL_PEN; break; /* Unknown tool */
- }
+ }
input_report_key(dev, wacom->tool, 1);
return;
}
@@ -205,31 +234,63 @@ static void wacom_intuos_irq(struct urb *urb)
input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
- input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
- input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- input_report_key(dev, BTN_STYLUS, data[1] & 2);
- input_report_key(dev, BTN_STYLUS2, data[1] & 4);
- input_report_key(dev, BTN_TOUCH, t > 10);
+ switch (wacom->tool) {
+
+ case BTN_TOOL_PENCIL:
+ case BTN_TOOL_PEN:
+ case BTN_TOOL_BRUSH:
+ case BTN_TOOL_RUBBER:
+ case BTN_TOOL_AIRBRUSH:
+
+ input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+ input_report_key(dev, BTN_STYLUS, data[1] & 2);
+ input_report_key(dev, BTN_STYLUS2, data[1] & 4);
+ input_report_key(dev, BTN_TOUCH, t > 10);
+ break;
+
+ case BTN_TOOL_MOUSE:
+ case BTN_TOOL_LENS:
+
+ if (data[1] & 0x02) { /* Rotation packet */
+ input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+ ((__u32)data[6] << 2) | ((data[7] >> 6) & 3):
+ (-(((__u32)data[6] << 2) | ((data[7] >> 6) & 3))) - 1);
+ break;
+ }
+
+ input_report_key(dev, BTN_LEFT, data[8] & 0x01);
+ input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
+ input_report_key(dev, BTN_SIDE, data[8] & 0x20);
+ input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
+ input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ?
+ ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
+ -((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ break;
+ }
}
#define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
+#define WACOM_INTUOS_BUTTONS (BIT(BTN_SIDE) | BIT(BTN_EXTRA))
+#define WACOM_INTUOS_ABS (BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE))
struct wacom_features wacom_features[] = {
{ "Wacom Graphire", 0x10, 8, 10206, 7422, 511, 32, wacom_graphire_irq,
- BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 },
+ BIT(EV_REL), 0, 0, 0 },
{ "Wacom Intuos 4x5", 0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq,
- 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
{ "Wacom Intuos 6x8", 0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq,
- 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
{ "Wacom Intuos 9x12", 0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq,
- 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
{ "Wacom Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
- 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
{ "Wacom Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
- 0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+ 0, WACOM_INTUOS_ABS, 0, WACOM_INTUOS_BUTTONS, WACOM_INTUOS_TOOLS },
{ NULL , 0 }
};
@@ -275,7 +336,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit;
wacom->dev.relbit[0] |= wacom->features->relbit;
- wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit;
+ wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | wacom->features->btnbit;
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
@@ -286,6 +347,14 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
wacom->dev.absmax[ABS_TILT_X] = 127;
wacom->dev.absmax[ABS_TILT_Y] = 127;
+ wacom->dev.absmin[ABS_RZ] = -900;
+ wacom->dev.absmax[ABS_RZ] = 899;
+ wacom->dev.absmin[ABS_THROTTLE] = -1023;
+ wacom->dev.absmax[ABS_THROTTLE] = 1023;
+
+ wacom->dev.absfuzz[ABS_X] = 4;
+ wacom->dev.absfuzz[ABS_Y] = 4;
+
wacom->dev.private = wacom;
wacom->dev.open = wacom_open;
wacom->dev.close = wacom_close;
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 688f576cf..331343d15 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -89,7 +89,6 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
-obj-$(CONFIG_FB_SIS) += sisfb.o
ifeq ($(CONFIG_FB_MATROX),y)
SUB_DIRS += matrox
@@ -110,6 +109,16 @@ else
endif
endif
+ifeq ($(CONFIG_FB_SIS),y)
+SUB_DIRS += sis
+obj-y += sis/sisfb.o
+else
+ ifeq ($(CONFIG_FB_SIS),m)
+ MOD_SUB_DIRS += sis
+ endif
+endif
+
+
obj-$(CONFIG_FB_SUN3) += sun3fb.o
obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
index bcc2b9b7b..e8c0c97da 100644
--- a/drivers/video/S3triofb.c
+++ b/drivers/video/S3triofb.c
@@ -60,8 +60,6 @@
#define IO_OUT16VAL(v, r) (((v) << 8) | (r))
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
static int currcon = 0;
static struct display disp;
static struct fb_info fb_info;
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 20cf8ef70..e6ad28fcf 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -598,8 +598,6 @@ static u_short maxfmode, chipset;
#define highw(x) ((u_long)(x)>>16 & 0xffff)
#define loww(x) ((u_long)(x) & 0xffff)
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER
#define VBlankOff() custom.intena = IF_COPER
@@ -921,7 +919,7 @@ static struct fb_videomode ami_modedb[] __initdata = {
#endif
};
-#define NUM_TOTAL_MODES arraysize(ami_modedb)
+#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb)
static const char *mode_option __initdata = NULL;
static int round_down_bpp = 1; /* for mode probing */
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 3ad46bc68..c09a691a8 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -86,8 +86,6 @@
#define SWITCH_NONE 0x00
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
@@ -429,7 +427,7 @@ static struct fb_var_screeninfo atafb_predefined[] = {
0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
};
-static int num_atafb_predefined=arraysize(atafb_predefined);
+static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
static int
diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c
index 57626f05c..e490910c9 100644
--- a/drivers/video/clgenfb.c
+++ b/drivers/video/clgenfb.c
@@ -99,8 +99,6 @@
#define assert(expr)
#endif
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#ifdef TRUE
#undef TRUE
#endif
@@ -450,7 +448,7 @@ static const struct {
}
};
-#define NUM_TOTAL_MODES arraysize(clgenfb_predefined)
+#define NUM_TOTAL_MODES ARRAY_SIZE(clgenfb_predefined)
static struct fb_var_screeninfo clgenfb_default;
/*
@@ -2431,7 +2429,7 @@ static struct pci_dev * __init clgen_pci_dev_get (clgen_board_t *btype)
DPRINTK ("ENTER\n");
- for (i = 0; i < arraysize(clgen_pci_probe_list); i++) {
+ for (i = 0; i < ARRAY_SIZE(clgen_pci_probe_list); i++) {
pdev = NULL;
while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS,
clgen_pci_probe_list[i].device, pdev)) != NULL) {
@@ -2582,7 +2580,7 @@ static int __init clgen_zorro_find (struct zorro_dev **z_o,
assert (z_o != NULL);
assert (btype != NULL);
- for (i = 0; i < arraysize(clgen_zorro_probe_list); i++)
+ for (i = 0; i < ARRAY_SIZE(clgen_zorro_probe_list); i++)
if ((z = zorro_find_device(clgen_zorro_probe_list[i].id, NULL)))
break;
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index 5c4af6bf0..4510d1165 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -107,8 +107,6 @@ static void cv64_dump(void);
#define DPRINTK(fmt, args...)
#endif
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
@@ -221,7 +219,7 @@ static struct {
}}
};
-#define NUM_TOTAL_MODES arraysize(cyberfb_predefined)
+#define NUM_TOTAL_MODES ARRAY_SIZE(cyberfb_predefined)
static int Cyberfb_inverse = 0;
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index d9f5c0579..12bd1e526 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -144,8 +144,6 @@ static void *fm2fb_mem;
static unsigned long fm2fb_reg_phys;
static volatile unsigned char *fm2fb_reg;
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
static int currcon = 0;
static struct display disp;
static struct fb_info fb_info;
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index 1bbcc3fbd..43829e53c 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -77,8 +77,6 @@
#define MON_ID_REG 0xe4100000 /* unused */
#define RESET_REG 0xe4180000 /* Write only */
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
static int currcon = 0;
static struct display disp;
static struct fb_info fb_info;
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index 9e3be3e27..df23d1aff 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -28,8 +28,6 @@
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
static struct display disp;
static struct fb_info fb_info;
@@ -107,7 +105,7 @@ static void hpfb_encode_var(struct fb_var_screeninfo *var,
var->lower_margin=0;
var->hsync_len=0;
var->vsync_len=0;
- for(i=0;i<arraysize(var->reserved);i++)
+ for(i=0;i<ARRAY_SIZE(var->reserved);i++)
var->reserved[i]=0;
}
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index 13e843c3d..ad1aeac38 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -56,8 +56,6 @@
#define PAT_MEM_SIZE 16*3
#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
struct retz3fb_par {
int xres;
int yres;
@@ -253,7 +251,7 @@ static struct {
};
-#define NUM_TOTAL_MODES arraysize(retz3fb_predefined)
+#define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined)
static struct fb_var_screeninfo retz3fb_default;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index c68d1b5ff..fcb662e8e 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/rivafb.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
* Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
*
@@ -17,12 +17,12 @@
* KGI code provided the basis for state storage, init, and mode switching.
*
* This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
+ * License. See the file COPYING in the main directory of this archive
* for more details.
*/
/* version number of this driver */
-#define RIVAFB_VERSION "0.7.2"
+#define RIVAFB_VERSION "0.7.3"
#include <linux/config.h>
#include <linux/module.h>
@@ -311,7 +311,7 @@ static const struct riva_regs reg_template = {
/**
* riva_set_dispsw
- * @rivainfo: pointer to internal driver struct for a given Riva card
+ * @rinfo: pointer to internal driver struct for a given Riva card
*
* DESCRIPTION:
* Sets up console Low level operations depending on the current? color depth
@@ -514,14 +514,14 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
rinfo->ctrl_base = ioremap (rinfo->ctrl_base_phys,
rinfo->base0_region_size);
if (!rinfo->ctrl_base) {
- printk (KERN_ERR PFX "cannot ioremap ctrl base\n");
+ printk (KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_free_base1;
}
rinfo->fb_base = ioremap (rinfo->fb_base_phys,
rinfo->base1_region_size);
if (!rinfo->fb_base) {
- printk (KERN_ERR PFX "cannot ioremap ctrl base\n");
+ printk (KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
@@ -539,7 +539,7 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
switch (rinfo->riva.Architecture) {
case 3:
rinfo->riva.PRAMIN =
- (unsigned *) (rinfo->ctrl_base + 0x00C00000);
+ (unsigned *) (rinfo->fb_base + 0x00C00000);
break;
case 4:
case 5:
@@ -584,7 +584,8 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
pci_set_drvdata (pd, rinfo);
- printk ("PCI Riva NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
+ printk (KERN_INFO PFX
+ "PCI Riva NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
rinfo->riva.Architecture,
RIVAFB_VERSION,
rinfo->drvr_name,
@@ -859,7 +860,7 @@ static int rivafb_set_var (struct fb_var_screeninfo *var, int con,
v.blue.offset = 0;
#endif
v.red.length = 5;
- v.green.length = 6;
+ v.green.length = 5;
v.blue.length = 5;
break;
#endif
@@ -1046,7 +1047,7 @@ static int rivafb_set_cmap (struct fb_cmap *cmap, int kspc, int con,
/**
* rivafb_pan_display
* @var: standard kernel fb changeable data
- * @par: riva-specific hardware info about current video mode
+ * @con:
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
@@ -1292,7 +1293,7 @@ static int riva_getcolreg (unsigned regno, unsigned *red, unsigned *green,
{
struct rivafb_info *rivainfo = (struct rivafb_info *) info;
- if (regno > 255)
+ if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
return 1;
*red = rivainfo->palette[regno].red;
@@ -1341,10 +1342,15 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
assert (rivainfo != NULL);
assert (rivainfo->currcon_display != NULL);
- if (regno > 255)
+ p = rivainfo->currcon_display;
+
+ if (regno >= riva_get_cmap_len(&p->var))
return -EINVAL;
- p = rivainfo->currcon_display;
+ rivainfo->palette[regno].red = red;
+ rivainfo->palette[regno].green = green;
+ rivainfo->palette[regno].blue = blue;
+
if (p->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
@@ -1361,27 +1367,14 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
break;
}
-#ifdef FBCON_HAS_CFB8
switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
case 8:
/* "transparent" stuff is completely ignored. */
riva_wclut (regno, red >> shift, green >> shift, blue >> shift);
break;
- default:
- /* do nothing */
- break;
- }
#endif /* FBCON_HAS_CFB8 */
- rivainfo->palette[regno].red = red;
- rivainfo->palette[regno].green = green;
- rivainfo->palette[regno].blue = blue;
-
- if (regno >= 16)
- return 0;
-
- switch (p->var.bits_per_pixel) {
-
#ifdef FBCON_HAS_CFB16
case 16:
assert (regno < 16);
@@ -1392,8 +1385,8 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
((green & 0xf800) << 2) | ((blue & 0xf800) >> 3);
#else
rivainfo->con_cmap.cfb16[regno] =
- ((red & 0xf800) >> 0) |
- ((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
+ ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
#endif
break;
#endif /* FBCON_HAS_CFB16 */
diff --git a/drivers/video/sis/Makefile b/drivers/video/sis/Makefile
new file mode 100644
index 000000000..2e657f107
--- /dev/null
+++ b/drivers/video/sis/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the SiS framebuffer device driver
+#
+
+O_TARGET := sisfb.o
+O_OBJS := sis_main.o sis_300.o sis_301.o
+#O_OBJS := sis_300.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+
diff --git a/drivers/video/sis/initdef.h b/drivers/video/sis/initdef.h
new file mode 100644
index 000000000..e0ab914ec
--- /dev/null
+++ b/drivers/video/sis/initdef.h
@@ -0,0 +1,138 @@
+#include "sis.h"
+
+#define PRIMARY_VGA 1 //1: SiS is primary vga 0:SiS is secondary vga
+#define ModeInfoFlag 0x07
+#define MemoryInfoFlag 0x1E0
+#define MemorySizeShift 0x05
+#define ModeText 0x00
+#define ModeCGA 0x01
+#define ModeEGA 0x02
+#define ModeVGA 0x03
+#define Mode15Bpp 0x04
+#define Mode16Bpp 0x05
+#define Mode24Bpp 0x06
+#define Mode32Bpp 0x07
+#define CRT1Len 17
+#define DoubleScanMode 0x8000
+#define ADR_CRT2PtrData 0x20E //address of CRT2PtrData in ROM image
+#define offset_Zurac 0x210
+#define ADR_LVDSDesPtrData 0x212
+#define ADR_LVDSCRT1DataPtr 0x214
+
+#define SoftDRAMType 0x80 //5/19/2000,Mars,for soft setting dram type
+#define SoftSettingAddr 0x52
+#define ModeSettingAddr 0x53
+
+#define InterlaceMode 0x80
+#define HalfDCLK 0x1000
+#define DACInfoFlag 0x18
+#define LineCompareOff 0x400
+#define ActivePAL 0x20
+#define ActivePALShift 5
+
+
+#define SelectCRT2Rate 0x4
+#define ProgrammingCRT2 0x1
+#define CRT2DisplayFlag 0x2000
+#define SetCRT2ToRAMDAC 0x0040
+#define Charx8Dot 0x0200
+#define LCDDataLen 8
+#define SetCRT2ToLCD 0x0020
+#define SetCRT2ToHiVisionTV 0x0080
+#define HiTVDataLen 12
+#define TVDataLen 16
+#define SetPALTV 0x0100
+#define SetInSlaveMode 0x0200
+#define SetCRT2ToTV 0x009C
+#define SetNotSimuTVMode 0x0400
+#define SetSimuScanMode 0x0001
+#define DriverMode 0x4000
+#define CRT2Mode 0x0800
+//#define ReIndexEnhLCD 4
+#define HalfDCLK 0x1000
+//#define HiVisionTVHT 2100
+//#define HiVisionTVVT 2100
+#define NTSCHT 1716
+#define NTSCVT 525
+#define PALHT 1728
+#define PALVT 625
+
+#define VCLKStartFreq 25
+//Freq of first item in VCLKTable
+
+#define SoftDramType 0x80
+#define VCLK65 0x09
+#define VCLK108_2 0x14
+//#define LCDIs1280x1024Panel 0x04
+//#define HiVisionVCLK 0x22
+#define TVSimuMode 0x02
+#define SetCRT2ToSVIDEO 0x08
+//#define LCDRGB18Bit 0x20
+#define LCDRGB18Bit 0x01
+#define Panel1280x1024 0x03
+#define Panel1024x768 0x02
+#define Panel800x600 0x01
+#define RPLLDIV2XO 0x04
+#define LoadDACFlag 0x1000
+#define AfterLockCRT2 0x4000
+#define SupportRAMDAC2 0x0040
+#define SupportLCD 0x0020
+//#define Support1024x768LCD 0x0020
+//#define Support1280x1024LCD 0x0040
+#define SetCRT2ToAVIDEO 0x0004
+#define SetCRT2ToSCART 0x0010
+//#define NoSupportSimuTV 0x0100
+#define NoSupportSimuTV 0x2000
+#define Ext2StructSize 5
+#define SupportTV 0x0008
+//#define TVVCLKDIV2 0x020
+//#define TVVCLK 0x021
+#define TVVCLKDIV2 0x021
+#define TVVCLK 0x022
+#define SwitchToCRT2 0x0002
+#define LCDVESATiming 0x08
+#define SetSCARTOutput 0x01
+#define SCARTSense 0x04
+#define Monitor1Sense 0x20
+#define Monitor2Sense 0x10
+#define SVIDEOSense 0x02
+#define AVIDEOSense 0x01
+#define LCDSense 0x08
+#define BoardTVType 0x02
+#define HotPlugFunction 0x08
+#define StStructSize 0x06
+
+#define ExtChip301 0x02
+#define ExtChipLVDS 0x04
+#define ExtChipTrumpion 0x06
+#define LCDNonExpanding 0x10
+#define LCDNonExpandingShift 4
+#define LVDSDataLen 6
+#define EnableLVDSDDA 0x10
+#define LCDSync 0x20
+#define SyncPP 0x0000
+#define LCDSyncBit 0xE0
+#define LVDSDesDataLen 3
+#define LVDSCRT1Len 15
+#define ActiveNonExpanding 0x40
+#define ActiveNonExpandingShift 6
+#define ModeSwitchStatus 0x0F
+#define SoftTVType 0x40
+
+#define PanelType00 0x00
+#define PanelType01 0x08
+#define PanelType02 0x10
+#define PanelType03 0x18
+#define PanelType04 0x20
+#define PanelType05 0x28
+#define PanelType06 0x30
+#define PanelType07 0x38
+#define PanelType08 0x40
+#define PanelType09 0x48
+#define PanelType0A 0x50
+#define PanelType0B 0x58
+#define PanelType0C 0x60
+#define PanelType0D 0x68
+#define PanelType0E 0x70
+#define PanelType0F 0x78
+
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
new file mode 100644
index 000000000..3f4843a77
--- /dev/null
+++ b/drivers/video/sis/sis.h
@@ -0,0 +1,64 @@
+#ifndef _SISFB_LOCAL
+#define _SISFB_LOCAL
+#include <linux/types.h>
+
+#undef NOBIOS
+#undef CONFIG_FB_SIS_LINUXBIOS
+
+#ifdef NOBIOS
+#undef CONFIG_FB_SIS_LINUXBIOS
+#endif
+
+#define TRUE 1
+#define FALSE 0
+#define NO_ERROR 0
+
+/* Data type conversion */
+#define UCHAR unsigned char
+#define USHORT unsigned short
+#define ULONG unsigned long
+#define SHORT short
+#define BOOLEAN int
+#define VOID void
+
+#define IND_SIS_CRT2_PORT_04 0x04 - 0x30
+#define IND_SIS_CRT2_PORT_10 0x10 - 0x30
+#define IND_SIS_CRT2_PORT_12 0x12 - 0x30
+#define IND_SIS_CRT2_PORT_14 0x14 - 0x30
+
+#define ClearALLBuffer(x) ClearBuffer(x)
+
+/* Data struct for setmode codes */
+typedef enum _CHIP_TYPE {
+ SIS_GENERIC = 0,
+ SIS_Glamour, //300
+ SIS_Trojan, //630
+ SIS_Spartan, //540
+ SIS_730,
+ MAX_SIS_CHIP
+} CHIP_TYPE;
+
+typedef enum _LCD_TYPE {
+ LCD1024 = 1,
+ LCD1280,
+ LCD2048,
+ LCD1920,
+ LCD1600,
+ LCD800,
+ LCD640
+} LCD_TYPE;
+
+
+typedef struct _HW_DEVICE_EXTENSION
+{
+ unsigned long VirtualRomBase;
+ char *VirtualVideoMemoryAddress;
+ unsigned short IOAddress;
+ CHIP_TYPE jChipID;
+ int bIntegratedMMEnabled;
+ LCD_TYPE usLCDType;
+ u8 revision_id;
+ u8 uVBChipID;
+} HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
+
+#endif
diff --git a/drivers/video/sis/sis_300.c b/drivers/video/sis/sis_300.c
new file mode 100644
index 000000000..5fbbee13b
--- /dev/null
+++ b/drivers/video/sis/sis_300.c
@@ -0,0 +1,1524 @@
+/* Recently Update by v1.09.50 */
+#include <linux/config.h>
+#include "sis_300.h"
+
+#if defined(ALLOC_PRAGMA)
+#pragma alloc_text(PAGE,SiSSetMode)
+#pragma alloc_text(PAGE,SiSInit300)
+#endif
+
+
+#ifdef NOBIOS
+BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ ULONG FBAddr = (ULONG)HwDeviceExtension->VirtualVideoMemoryAddress;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+ UCHAR i,temp,AGP;
+ ULONG j,k,ulTemp;
+ UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32;
+ UCHAR SR14;
+ ULONG Temp;
+
+ if(ROMAddr==0) return (FALSE);
+ if(FBAddr==0) return (FALSE);
+ if(BaseAddr==0) return (FALSE);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE);
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+ Set_LVDS_TRUMPION();
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+ SR14 = (UCHAR)GetReg1(P3c4,0x14);
+ SR19 = (UCHAR)GetReg1(P3c4,0x19);
+ SR1A = (UCHAR)GetReg1(P3c4,0x1A);
+ for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register
+ for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register
+ for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0);
+ for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0);
+
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ temp=(UCHAR)SR1A; // 3.Set Define Extended register
+ else
+ {
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if((temp&SoftDRAMType)==0){
+ temp=(UCHAR)GetReg1(P3c4,0x3A); // 3.Set Define Extended register
+ }
+ }
+ RAMType=temp&0x07;
+ SetMemoryClock(ROMAddr);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ ulTemp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp | 0x01;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp & 0xFE;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+ for(k=0; k<5; k++)
+ {
+ for(j=0; j<0xffff; j++)
+ {
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+ }
+ }
+
+ SR07=*((UCHAR *)(ROMAddr+0xA4));
+ SetReg1(P3c4,0x07,SR07);
+ if (HwDeviceExtension->jChipID == SIS_Glamour )
+ {
+ for(i=0x15;i<=0x1C;i++)
+ {
+ temp=*((UCHAR *)(ROMAddr+0xA5+((i-0x15)*8)+RAMType));
+ SetReg1(P3c4,i,temp);
+ }
+ }
+
+ SR1F=*((UCHAR *)(ROMAddr+0xE5));
+ SetReg1(P3c4,0x1F,SR1F);
+
+ AGP=1; // Get AGP
+ temp=(UCHAR)GetReg1(P3c4,0x3A);
+ temp=temp&0x30;
+ if(temp==0x30) AGP=0; // PCI
+
+ SR21=*((UCHAR *)(ROMAddr+0xE6));
+ if(AGP==0) SR21=SR21&0xEF; // PCI
+ SetReg1(P3c4,0x21,SR21);
+
+ SR22=*((UCHAR *)(ROMAddr+0xE7));
+ if(AGP==1) SR22=SR22&0x20; // AGP
+ SetReg1(P3c4,0x22,SR22);
+
+ SR23=*((UCHAR *)(ROMAddr+0xE8));
+ SetReg1(P3c4,0x23,SR23);
+
+ SR24=*((UCHAR *)(ROMAddr+0xE9));
+ SetReg1(P3c4,0x24,SR24);
+
+ SR25=*((UCHAR *)(ROMAddr+0xEA));
+ SetReg1(P3c4,0x25,SR25);
+
+ SR32=*((UCHAR *)(ROMAddr+0xEB));
+ SetReg1(P3c4,0x32,SR32);
+
+ SR11=0x0F;
+ SetReg1(P3c4,0x11,SR11);
+
+ if(IF_DEF_LVDS==1){ //LVDS
+ temp=ExtChipLVDS;
+ }else if(IF_DEF_TRUMPION==1){ //Trumpion
+ temp=ExtChipTrumpion;
+ }else{ //301
+ temp=ExtChip301;
+ }
+ SetReg1(P3d4,0x37,temp);
+
+ //For SiS 630/540 Chip
+ //Restore SR14, SR19 and SR1A
+ SetReg1(P3c4,0x14,SR14);
+ SetReg1(P3c4,0x19,SR19);
+ SetReg1(P3c4,0x1A,SR1A);
+
+ SetReg3(P3c6,0xff); // Reset register
+ ClearDAC(P3c8); // Reset register
+ DetectMonitor(HwDeviceExtension); //sense CRT1
+ GetSenseStatus(HwDeviceExtension,BaseAddr,ROMAddr);//sense CRT2
+
+ return(TRUE);
+}
+
+VOID Set_LVDS_TRUMPION(VOID)
+{
+ IF_DEF_LVDS=0;
+ IF_DEF_TRUMPION=0;
+}
+
+VOID SetMemoryClock(ULONG ROMAddr)
+{
+ UCHAR data,i;
+
+ MCLKData=*((USHORT *)(ROMAddr+0x20C)); // MCLKData Table
+ MCLKData=MCLKData+RAMType*5;
+ ECLKData=MCLKData+0x28;
+
+ for(i=0x28;i<=0x2A;i++) { // Set MCLK
+ data=*((UCHAR *)(ROMAddr+MCLKData));
+ SetReg1(P3c4,i,data);
+ MCLKData++;
+ }
+
+ for(i=0x2E;i<=0x30;i++) { // Set ECLK
+ data=*((UCHAR *)(ROMAddr+ECLKData));
+ SetReg1(P3c4,i,data);
+ ECLKData++;
+ }
+}
+#endif /* NOBIOS */
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ ULONG ROMAddr = 0;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+ UCHAR i,temp,AGP;
+ ULONG j,k,ulTemp;
+ UCHAR SR07,SR11,SR19,SR1A,SR1F,SR21,SR22,SR23,SR24,SR25,SR32;
+ UCHAR SR14;
+ ULONG Temp;
+
+ if(BaseAddr==0) return (FALSE);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ if(!HwDeviceExtension->bIntegratedMMEnabled) return (FALSE);
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+
+ SR14 = (UCHAR)GetReg1(P3c4,0x14);
+ SR19 = (UCHAR)GetReg1(P3c4,0x19);
+ SR1A = (UCHAR)GetReg1(P3c4,0x1A);
+
+ for(i=0x06;i< 0x20;i++) SetReg1(P3c4,i,0); // 2.Reset Extended register
+ for(i=0x21;i<=0x27;i++) SetReg1(P3c4,i,0); // Reset Extended register
+ for(i=0x31;i<=0x3D;i++) SetReg1(P3c4,i,0);
+ for(i=0x30;i<=0x37;i++) SetReg1(P3d4,i,0);
+
+ temp=(UCHAR)SR1A; // 3.Set Define Extended register
+
+ RAMType=temp&0x07;
+ SetMemoryClock(ROMAddr);
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ ulTemp = (ULONG)GetReg1(P3c4, 0x05);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp | 0x01;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x3C);
+ Temp = Temp & 0xFE;
+ SetReg1(P3c4, 0x3C, (USHORT)Temp);
+
+ for(k=0; k<5; k++)
+ for(j=0; j<0xffff; j++)
+ Temp = (ULONG)GetReg1(P3c4, 0x05);
+
+ SR07=SRegsInit[0x07];
+ SetReg1(P3c4,0x07,SR07);
+
+ SR1F=SRegsInit[0x1F];
+ SetReg1(P3c4,0x1F,SR1F);
+
+ AGP=1; // Get AGP
+ temp=(UCHAR)GetReg1(P3c4,0x3A);
+ temp=temp&0x30;
+ if(temp==0x30) AGP=0; // PCI
+
+ SR21=SRegsInit[0x21];
+ if(AGP==0) SR21=SR21&0xEF; // PCI
+ SetReg1(P3c4,0x21,SR21);
+
+ SR22=SRegsInit[0x22];
+ if(AGP==1) SR22=SR22&0x20; // AGP
+ SetReg1(P3c4,0x22,SR22);
+
+ SR23=SRegsInit[0x23];
+ SetReg1(P3c4,0x23,SR23);
+
+ SR24=SRegsInit[0x24];
+ SetReg1(P3c4,0x24,SR24);
+
+ SR25=SRegsInit[0x25];
+ SetReg1(P3c4,0x25,SR25);
+
+ SR32=SRegsInit[0x32];
+ SetReg1(P3c4,0x32,SR32);
+
+ SR11=0x0F;
+ SetReg1(P3c4,0x11,SR11);
+
+ temp=ExtChip301;
+ SetReg1(P3d4,0x37,temp);
+
+ SetReg1(P3c4,0x14,SR14);
+ SetReg1(P3c4,0x19,SR19);
+ SetReg1(P3c4,0x1A,SR1A);
+
+ SetReg3(P3c6,0xff); // Reset register
+ ClearDAC(P3c8); // Reset register
+ DetectMonitor(HwDeviceExtension); //sense CRT1
+
+ return(TRUE);
+}
+
+VOID SetMemoryClock(ULONG ROMAddr)
+{
+ UCHAR i;
+ USHORT idx;
+
+ u8 MCLK[] = {
+ 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM
+ 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM
+ 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM
+ 0x37, 0x22, 0x80, 0x33, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01,
+ 0x37, 0x61, 0x80, 0x00, 0x01
+ };
+
+ u8 ECLK[] = {
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x53, 0x43, 0x80, 0x00, 0x01,
+ 0x55, 0x43, 0x80, 0x00, 0x01,
+ 0x52, 0x43, 0x80, 0x00, 0x01,
+ 0x3f, 0x42, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01,
+ 0x54, 0x43, 0x80, 0x00, 0x01
+ };
+
+ idx = RAMType * 5;
+
+ for (i = 0x28; i <= 0x2A; i++) { // Set MCLK
+ SetReg1(P3c4, i, MCLK[idx]);
+ idx++;
+ }
+
+ idx = RAMType * 5;
+ for (i = 0x2E; i <= 0x30; i++) { // Set ECLK
+ SetReg1(P3c4, i, ECLK[idx]);
+ idx++;
+ }
+
+}
+
+#endif /* CONFIG_FB_SIS_LINUXBIOS */
+
+// =========================================
+// ======== SiS SetMode Function ==========
+// =========================================
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo)
+{
+ ULONG i;
+ USHORT cr30flag,cr31flag;
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+
+ cr30flag=(UCHAR)GetReg1(P3d4,0x30);
+
+ if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){
+ SetReg1(P3d4,0x34,ModeNo);
+ //SetSeqRegs(ROMAddr);
+ {
+ UCHAR SRdata;
+ SRdata = SRegs[0x01] | 0x20;
+ SetReg1(P3c4, 0x01, SRdata);
+
+ for (i = 02; i <= 04; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+ }
+
+ //SetMiscRegs(ROMAddr);
+ {
+ SetReg3(P3c2, 0x23);
+ }
+
+ //SetCRTCRegs(ROMAddr);
+ {
+ UCHAR CRTCdata;
+
+ CRTCdata = (UCHAR) GetReg1(P3d4, 0x11);
+ SetReg1(P3d4, 0x11, CRTCdata);
+
+ for (i = 0; i <= 0x18; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ }
+
+ //SetATTRegs(ROMAddr);
+ {
+ for (i = 0; i <= 0x13; i++) {
+ GetReg2(P3da);
+ SetReg3(P3c0, i);
+ SetReg3(P3c0, ARegs[i]);
+ }
+ GetReg2(P3da);
+ SetReg3(P3c0, 0x14);
+ SetReg3(P3c0, 0x00);
+ GetReg2(P3da);
+ SetReg3(P3c0, 0x20);
+ }
+
+ //SetGRCRegs(ROMAddr);
+ {
+ for (i = 0; i <= 0x08; i++)
+ SetReg1(P3ce, i, GRegs[i]);
+ }
+
+ //ClearExt1Regs();
+ {
+ for (i = 0x0A; i <= 0x0E; i++)
+ SetReg1(P3c4, i, 0x00);
+ }
+
+
+ //SetSync(ROMAddr);
+ {
+ SetReg3(P3c2, MReg);
+ }
+
+ //SetCRT1CRTC(ROMAddr);
+ {
+ UCHAR data;
+
+ data = (UCHAR) GetReg1(P3d4, 0x11);
+ data = data & 0x7F;
+ SetReg1(P3d4, 0x11, data);
+
+ for (i = 0; i <= 0x07; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x10; i <= 0x12; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x15; i <= 0x16; i++)
+ SetReg1(P3d4, i, CRegs[i]);
+ for (i = 0x0A; i <= 0x0C; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+
+ data = SRegs[0x0E] & 0xE0;
+ SetReg1(P3c4, 0x0E, data);
+
+ SetReg1(P3d4, 0x09, CRegs[0x09]);
+ }
+
+ //SetCRT1Offset(ROMAddr);
+ {
+ SetReg1(P3c4, 0x0E, SRegs[0x0E]);
+ SetReg1(P3c4, 0x10, SRegs[0x10]);
+ }
+
+ //SetCRT1VCLK(HwDeviceExtension, ROMAddr);
+ {
+ SetReg1(P3c4, 0x31, 0);
+
+ for (i = 0x2B; i <= 0x2C; i++)
+ SetReg1(P3c4, i, SRegs[i]);
+ SetReg1(P3c4, 0x2D, 0x80);
+ }
+
+ //SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo);
+ {
+ SetReg1(P3c4, 0x32, SRegs[0x32]);
+ SetReg1(P3c4, 0x07, SRegs[0x07]);
+ }
+
+ //SetCRT1FIFO2(ROMAddr);
+ {
+ SetReg1(P3c4, 0x15, SRegs[0x15]);
+
+ SetReg4(0xcf8, 0x80000050);
+ SetReg4(0xcfc, 0xc5041e04);
+
+ SetReg1(P3c4, 0x08, SRegs[0x08]);
+ SetReg1(P3c4, 0x0F, SRegs[0x0F]);
+ SetReg1(P3c4, 0x3b, 0x00);
+ SetReg1(P3c4, 0x09, SRegs[0x09]);
+ }
+
+ //SetCRT1ModeRegs(ROMAddr, ModeNo);
+ {
+ SetReg1(P3c4, 0x06, SRegs[0x06]);
+ SetReg1(P3c4, 0x01, SRegs[0x01]);
+ SetReg1(P3c4, 0x0F, SRegs[0x0F]);
+ SetReg1(P3c4, 0x21, SRegs[0x21]);
+ }
+
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ {
+ //SetInterlace(ROMAddr,ModeNo);
+ SetReg1(P3d4, 0x19, CRegs[0x19]);
+ SetReg1(P3d4, 0x1A, CRegs[0x1A]);
+ }
+
+ LoadDAC(ROMAddr);
+
+ ClearBuffer(HwDeviceExtension);
+ }
+
+ cr31flag=(UCHAR)GetReg1(P3d4,0x31);
+ DisplayOn(); // 16.DisplayOn
+ return(NO_ERROR);
+}
+
+VOID LoadDAC(ULONG ROMAddr)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+
+ time=256;
+ table=VGA_DAC;
+ j=16;
+
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,0x00);
+
+ for(i=0;i<j;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) {
+ data2=0;
+ if(data&0x01) data2=0x2A;
+ if(data&0x02) data2=data2+0x15;
+ SetReg3(P3c9,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(P3c9,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC(dl,ah,al,dh);
+ }
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC(dl,ah,al,dh);
+ }
+ dl++;
+ }
+ si=si+5;
+ }
+ }
+}
+
+VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(P3c9,(USHORT)dh);
+ SetReg3(P3c9,(USHORT)bh);
+ SetReg3(P3c9,(USHORT)bl);
+}
+
+
+VOID DisplayOn()
+{
+ USHORT data;
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xDF;
+ SetReg1(P3c4,0x01,data);
+}
+
+
+#else
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo)
+{
+ ULONG temp;
+ USHORT cr30flag,cr31flag;
+ ULONG ROMAddr = (ULONG)HwDeviceExtension->VirtualRomBase;
+ USHORT BaseAddr = (USHORT)HwDeviceExtension->IOAddress;
+
+ P3c4=BaseAddr+0x14;
+ P3d4=BaseAddr+0x24;
+ P3c0=BaseAddr+0x10;
+ P3ce=BaseAddr+0x1e;
+ P3c2=BaseAddr+0x12;
+ P3ca=BaseAddr+0x1a;
+ P3c6=BaseAddr+0x16;
+ P3c7=BaseAddr+0x17;
+ P3c8=BaseAddr+0x18;
+ P3c9=BaseAddr+0x19;
+ P3da=BaseAddr+0x2A;
+ if(ModeNo&0x80){
+ ModeNo=ModeNo&0x7F;
+ flag_clearbuffer=0;
+ }else{
+ flag_clearbuffer=1;
+ }
+
+ PresetScratchregister(P3d4,HwDeviceExtension); //add for CRT2
+
+ SetReg1(P3c4,0x05,0x86); // 1.Openkey
+ temp=SearchModeID(ROMAddr,ModeNo); // 2.Get ModeID Table
+ if(temp==0) return(0);
+
+ SetTVSystem(HwDeviceExtension,ROMAddr); //add for CRT2
+ GetLCDDDCInfo(HwDeviceExtension); //add for CRT2
+ GetVBInfo(BaseAddr,ROMAddr); //add for CRT2
+ GetLCDResInfo(ROMAddr,P3d4); //add for CRT2
+
+ temp=CheckMemorySize(ROMAddr); // 3.Check memory size
+ if(temp==0) return(0);
+ cr30flag=(UCHAR)GetReg1(P3d4,0x30);
+ if(((cr30flag&0x01)==1)||((cr30flag&0x02)==0)){
+ // if cr30 d[0]=1 or d[1]=0 set crt1
+ SetReg1(P3d4,0x34,ModeNo);
+ // set CR34->CRT1 ModeNofor CRT2 FIFO
+ GetModePtr(ROMAddr,ModeNo); // 4.GetModePtr
+ SetSeqRegs(ROMAddr); // 5.SetSeqRegs
+ SetMiscRegs(ROMAddr); // 6.SetMiscRegs
+ SetCRTCRegs(ROMAddr); // 7.SetCRTCRegs
+ SetATTRegs(ROMAddr); // 8.SetATTRegs
+ SetGRCRegs(ROMAddr); // 9.SetGRCRegs
+ ClearExt1Regs(); // 10.Clear Ext1Regs
+ temp=GetRatePtr(ROMAddr,ModeNo); // 11.GetRatePtr
+ if(temp) {
+ SetSync(ROMAddr); // 12.SetSync
+ SetCRT1CRTC(ROMAddr); // 13.SetCRT1CRTC
+ SetCRT1Offset(ROMAddr); // 14.SetCRT1Offset
+ SetCRT1VCLK(HwDeviceExtension, ROMAddr); // 15.SetCRT1VCLK
+ SetVCLKState(HwDeviceExtension, ROMAddr, ModeNo);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ SetCRT1FIFO2(ROMAddr);
+ else
+ SetCRT1FIFO(ROMAddr);
+ }
+ SetCRT1ModeRegs(ROMAddr, ModeNo);
+ if(HwDeviceExtension->jChipID >= SIS_Trojan)
+ SetInterlace(ROMAddr,ModeNo);
+ LoadDAC(ROMAddr);
+ if(flag_clearbuffer) ClearBuffer(HwDeviceExtension);
+ }
+
+ cr31flag=(UCHAR)GetReg1(P3d4,0x31);
+ if(((cr30flag&0x01)==1)||((cr30flag&0x03)==0x02)
+ ||(((cr30flag&0x03)==0x00)&&((cr31flag&0x20)==0x20))){
+ //if CR30 d[0]=1 or d[1:0]=10, set CRT2 or cr30 cr31== 0x00 0x20
+ SetCRT2Group(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension); //CRT2
+ }
+ DisplayOn(); // 16.DisplayOn
+ return(NO_ERROR);
+}
+
+BOOLEAN SearchModeID(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR ModeID;
+ USHORT usIDLength;
+
+ ModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset)); // Offset 0x20A
+ usIDLength = GetModeIDLength(ROMAddr, ModeNo);
+ while(ModeID!=0xff && ModeID!=ModeNo) {
+ ModeIDOffset=ModeIDOffset+usIDLength;
+ ModeID=*((UCHAR *)(ROMAddr+ModeIDOffset));
+ }
+ if(ModeID==0xff) return(FALSE);
+ else return(TRUE);
+}
+
+BOOLEAN CheckMemorySize(ULONG ROMAddr)
+{
+ USHORT memorysize;
+ USHORT modeflag;
+ USHORT temp;
+
+ modeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ ModeType=modeflag&ModeInfoFlag; // Get mode type
+
+ memorysize=modeflag&MemoryInfoFlag;
+ memorysize=memorysize>MemorySizeShift;
+ memorysize++; // Get memory size
+
+ temp=GetReg1(P3c4,0x14); // Get DRAM Size
+ temp=temp&0x3F;
+ temp++;
+
+ if(temp<memorysize) return(FALSE);
+ else return(TRUE);
+}
+
+VOID GetModePtr(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR index;
+
+ StandTable=*((USHORT *)(ROMAddr+0x202)); // Get First 0x202
+ // StandTable Offset
+ if(ModeNo<=13) {
+ index=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+St_ModeFlag
+ }
+ else {
+ if(ModeType <= 0x02) index=0x1B; // 02 -> ModeEGA
+ else index=0x0F;
+ }
+
+ StandTable=StandTable+64*index; // Get ModeNo StandTable
+
+}
+
+VOID SetSeqRegs(ULONG ROMAddr)
+{
+ UCHAR SRdata;
+ USHORT i;
+
+ SetReg1(P3c4,0x00,0x03); // Set SR0
+ StandTable=StandTable+0x05;
+ SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR01 from file
+ if(IF_DEF_LVDS==1){
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+ SRdata=SRdata|0x01;
+ }
+ }
+ }
+ }
+
+ SRdata=SRdata|0x20;
+ SetReg1(P3c4,0x01,SRdata); // Set SR1
+ for(i=02;i<=04;i++) {
+ StandTable++;
+ SRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get SR2,3,4 from file
+ SetReg1(P3c4,i,SRdata); // Set SR2 3 4
+ }
+}
+
+VOID SetMiscRegs(ULONG ROMAddr)
+{
+ UCHAR Miscdata;
+
+ StandTable++;
+ Miscdata=*((UCHAR *)(ROMAddr+StandTable)); // Get Misc from file
+ SetReg3(P3c2,Miscdata); // Set Misc(3c2)
+}
+
+VOID SetCRTCRegs(ULONG ROMAddr)
+{
+ UCHAR CRTCdata;
+ USHORT i;
+
+ CRTCdata=(UCHAR)GetReg1(P3d4,0x11);
+ CRTCdata=CRTCdata&0x7f;
+ SetReg1(P3d4,0x11,CRTCdata); // Unlock CRTC
+
+ for(i=0;i<=0x18;i++) {
+ StandTable++;
+ CRTCdata=*((UCHAR *)(ROMAddr+StandTable)); // Get CRTC from file
+ SetReg1(P3d4,i,CRTCdata); // Set CRTC(3d4)
+ }
+}
+
+VOID SetATTRegs(ULONG ROMAddr)
+{
+ UCHAR ARdata;
+ USHORT i;
+
+ for(i=0;i<=0x13;i++) {
+ StandTable++;
+ ARdata=*((UCHAR *)(ROMAddr+StandTable)); // Get AR for file
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+ if(i==0x13){
+ ARdata=0;
+ }
+ }
+ }
+ }
+ }
+ GetReg2(P3da); // reset 3da
+ SetReg3(P3c0,i); // set index
+ SetReg3(P3c0,ARdata); // set data
+ }
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ if(VBInfo&SetInSlaveMode){
+ if(LCDInfo&LCDNonExpanding){
+
+ }
+ }
+ }
+ }
+ GetReg2(P3da); // reset 3da
+ SetReg3(P3c0,0x14); // set index
+ SetReg3(P3c0,0x00); // set data
+
+ GetReg2(P3da); // Enable Attribute
+ SetReg3(P3c0,0x20);
+}
+
+VOID SetGRCRegs(ULONG ROMAddr)
+{
+ UCHAR GRdata;
+ USHORT i;
+
+ for(i=0;i<=0x08;i++) {
+ StandTable++;
+ GRdata=*((UCHAR *)(ROMAddr+StandTable)); // Get GR from file
+ SetReg1(P3ce,i,GRdata); // Set GR(3ce)
+ }
+ if(ModeType>ModeVGA){
+ GRdata=(UCHAR)GetReg1(P3ce,0x05);
+ GRdata=GRdata&0xBF;
+ SetReg1(P3ce,0x05,GRdata);
+ }
+}
+
+VOID ClearExt1Regs()
+{
+ USHORT i;
+
+ for(i=0x0A;i<=0x0E;i++) SetReg1(P3c4,i,0x00); // Clear SR0A-SR0E
+}
+
+
+BOOLEAN GetRatePtr(ULONG ROMAddr, USHORT ModeNo)
+{
+ SHORT index;
+ USHORT temp;
+ USHORT ulRefIndexLength;
+
+ if(ModeNo<0x14) return(FALSE); // Mode No <= 13h then return
+
+ index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33
+ index=index&0x0F; // Frame rate index
+ if(index!=0) index--;
+ REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+
+ ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
+ do {
+ temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex
+ if(temp==0xFFFF) break;
+ temp=temp&ModeInfoFlag;
+ if(temp<ModeType) break;
+
+ REFIndex=REFIndex+ulRefIndexLength; // rate size
+ index--;
+ } while(index>=0);
+
+ REFIndex=REFIndex-ulRefIndexLength; // rate size
+ return(TRUE);
+}
+
+VOID SetSync(ULONG ROMAddr)
+{
+ USHORT sync;
+ USHORT temp;
+
+ sync=*((USHORT *)(ROMAddr+REFIndex)); // di+0x00
+ sync=sync&0xC0;
+ temp=0x2F;
+ temp=temp|sync;
+ SetReg3(P3c2,temp); // Set Misc(3c2)
+}
+
+VOID SetCRT1CRTC(ULONG ROMAddr)
+{
+ UCHAR index;
+ UCHAR data;
+ USHORT i;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x02)); // Get index
+ index=index&0x03F;
+ CRT1Table=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ CRT1Table=CRT1Table+index*CRT1Len;
+
+ data=(UCHAR)GetReg1(P3d4,0x11);
+ data=data&0x7F;
+ SetReg1(P3d4,0x11,data); // Unlock CRTC
+
+ CRT1Table--;
+ for(i=0;i<=0x05;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x06;i<=0x07;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x10;i<=0x12;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x15;i<=0x16;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3d4,i,data);
+ }
+ for(i=0x0A;i<=0x0C;i++) {
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ SetReg1(P3c4,i,data);
+ }
+
+ CRT1Table++;
+ data=*((UCHAR *)(ROMAddr+CRT1Table));
+ data=data&0xE0;
+ SetReg1(P3c4,0x0E,data);
+
+ data=(UCHAR)GetReg1(P3d4,0x09);
+ data=data&0xDF;
+ i=*((UCHAR *)(ROMAddr+CRT1Table));
+ i=i&0x01;
+ i=i<<5;
+ data=data|i;
+ i=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ i=i&DoubleScanMode;
+ if(i) data=data|0x80;
+ SetReg1(P3d4,0x09,data);
+
+ if(ModeType>0x03) SetReg1(P3d4,0x14,0x4F);
+}
+
+VOID SetCRT1Offset(ULONG ROMAddr)
+{
+ USHORT temp,ah,al;
+ USHORT temp2,i;
+ USHORT DisplayUnit;
+
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo
+ temp=temp>>4; // index
+ ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // ScreenOffset
+ temp=*((UCHAR *)(ROMAddr+ScreenOffset+temp)); // data
+
+ temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ temp2=temp2&InterlaceMode;
+ if(temp2) temp=temp<<1;
+ temp2=ModeType-ModeEGA;
+ switch (temp2) {
+ case 0 : temp2=1; break;
+ case 1 : temp2=2; break;
+ case 2 : temp2=4; break;
+ case 3 : temp2=4; break;
+ case 4 : temp2=6; break;
+ case 5 : temp2=8; break;
+ }
+ temp=temp*temp2;
+ DisplayUnit=temp;
+
+ temp2=temp;
+ temp=temp>>8;
+ temp=temp&0x0F;
+ i=GetReg1(P3c4,0x0E);
+ i=i&0xF0;
+ i=i|temp;
+ SetReg1(P3c4,0x0E,i);
+
+ temp=(UCHAR)temp2;
+ temp=temp&0xFF;
+ SetReg1(P3d4,0x13,temp);
+
+ temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ temp2=temp2&InterlaceMode;
+ if(temp2) DisplayUnit>>=1;
+
+ DisplayUnit=DisplayUnit<<5;
+ ah=(DisplayUnit&0xff00)>>8;
+ al=DisplayUnit&0x00ff;
+ if(al==0) ah=ah+1;
+ else ah=ah+2;
+ SetReg1(P3c4,0x10,ah);
+}
+
+
+VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr)
+{
+ USHORT i;
+ UCHAR index,data;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data;
+
+ SetReg1(P3c4,0x31,0);
+ for(i=0x2B;i<=0x2C;i++) {
+ data=*((UCHAR *)(ROMAddr+VCLKData));
+ SetReg1(P3c4,i,data);
+ VCLKData++;
+ }
+ SetReg1(P3c4,0x2D,0x80);
+}
+
+
+VOID SetCRT1ModeRegs(ULONG ROMAddr, USHORT ModeNo)
+{
+
+ USHORT data,data2,data3;
+
+ if(ModeNo>0x13) data=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ else data=0;
+
+ data2=0;
+ if(ModeNo>0x13)
+ if(ModeType>0x02) {
+ data2=data2|0x02;
+ data3=ModeType-ModeVGA;
+ data3=data3<<2;
+ data2=data2|data3;
+ }
+
+ data=data&InterlaceMode;
+ if(data) data2=data2|0x20;
+ SetReg1(P3c4,0x06,data2);
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xF7;
+ data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data2=data2&HalfDCLK;
+ if(data2) data=data|0x08;
+ SetReg1(P3c4,0x01,data);
+
+ data=GetReg1(P3c4,0x0F);
+ data=data&0xF7;
+ data2=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data2=data2&LineCompareOff;
+ if(data2) data=data|0x08;
+ SetReg1(P3c4,0x0F,data);
+
+ data=GetReg1(P3c4,0x21);
+ data=data&0x1F;
+ if(ModeType==0x00) data=data|0x60; // Text Mode
+ else if(ModeType<=0x02) data=data|0x00; // EGA Mode
+ else data=data|0xA0; // VGA Mode
+ SetReg1(P3c4,0x21,data);
+}
+
+VOID SetVCLKState(PHW_DEVICE_EXTENSION HwDeviceExtension, ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT data,data2;
+ USHORT VCLK;
+ UCHAR index;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData));
+ if(ModeNo<=0x13) VCLK=0;
+
+ data=GetReg1(P3c4,0x07);
+ data=data&0x7B;
+ if(VCLK>=150) data=data|0x80; // VCLK > 150
+ SetReg1(P3c4,0x07,data);
+
+ data=GetReg1(P3c4,0x32);
+ data=data&0xD7;
+ if(VCLK>=150) data=data|0x08; // VCLK > 150
+ SetReg1(P3c4,0x32,data);
+
+ data2=0x03;
+ if(VCLK>135) data2=0x02;
+ if(VCLK>160) data2=0x01;
+ if(VCLK>260) data2=0x00;
+ data=GetReg1(P3c4,0x07);
+ data=data&0xFC;
+ data=data|data2;
+ SetReg1(P3c4,0x07,data);
+}
+
+VOID LoadDAC(ULONG ROMAddr)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+
+ data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data=data&DACInfoFlag;
+ time=64;
+ if(data==0x00) table=MDA_DAC;
+ if(data==0x08) table=CGA_DAC;
+ if(data==0x10) table=EGA_DAC;
+ if(data==0x18) {
+ time=256;
+ table=VGA_DAC;
+ }
+ if(time==256) j=16;
+ else j=time;
+
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,0x00);
+
+ for(i=0;i<j;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) {
+ data2=0;
+ if(data&0x01) data2=0x2A;
+ if(data&0x02) data2=data2+0x15;
+ SetReg3(P3c9,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(P3c9,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC(dl,ah,al,dh);
+ }
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC(dl,ah,al,dh);
+ }
+ dl++;
+ }
+ si=si+5;
+ }
+ }
+}
+
+VOID WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(P3c9,(USHORT)dh);
+ SetReg3(P3c9,(USHORT)bh);
+ SetReg3(P3c9,(USHORT)bl);
+}
+
+
+VOID DisplayOn()
+{
+ USHORT data;
+
+ data=GetReg1(P3c4,0x01);
+ data=data&0xDF;
+ SetReg1(P3c4,0x01,data);
+}
+
+USHORT GetModeIDLength(ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT modeidlength;
+ USHORT usModeIDOffset;
+ USHORT PreviousWord,CurrentWord;
+
+ modeidlength=0;
+ usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ // maybe = 2Exx or xx2E
+ CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
+ PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A
+ while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801)) {
+ modeidlength++;
+ usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize
+ CurrentWord=*((USHORT *)(ROMAddr+usModeIDOffset));
+ PreviousWord=*((USHORT *)(ROMAddr+usModeIDOffset-2));
+ }
+ modeidlength++;
+ return(modeidlength);
+}
+
+USHORT GetRefindexLength(ULONG ROMAddr, USHORT ModeNo)
+{
+ UCHAR ModeID;
+ UCHAR temp;
+ USHORT refindexlength;
+ USHORT usModeIDOffset;
+ USHORT usREFIndex;
+ USHORT usIDLength;
+
+ usModeIDOffset=*((USHORT *)(ROMAddr+0x20A)); // Get EModeIDTable
+ ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
+ usIDLength = GetModeIDLength(ROMAddr, ModeNo);
+ while(ModeID!=0x40) {
+ usModeIDOffset=usModeIDOffset+usIDLength; // 10 <= ExtStructSize
+ ModeID=*((UCHAR *)(ROMAddr+usModeIDOffset));
+ }
+
+ refindexlength=1;
+ usREFIndex=*((USHORT *)(ROMAddr+usModeIDOffset+0x04)); // si+Ext_point
+ usREFIndex++;
+ temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex
+ while(temp!=0xFF) {
+ refindexlength++;
+ usREFIndex++;
+ temp=*((UCHAR *)(ROMAddr+usREFIndex)); // di => REFIndex
+ }
+ return(refindexlength);
+}
+
+VOID SetInterlace(ULONG ROMAddr, USHORT ModeNo)
+{
+ ULONG Temp;
+ USHORT data,Temp2;
+
+ Temp = (ULONG)GetReg1(P3d4, 0x01);
+ Temp++;
+ Temp=Temp*8;
+
+ if(Temp==1024) data=0x0035;
+ else if(Temp==1280) data=0x0048;
+ else data=0x0000;
+
+ Temp2=*((USHORT *)(ROMAddr+REFIndex+0x00));
+ Temp2 &= InterlaceMode;
+ if(Temp2 == 0) data=0x0000;
+
+ SetReg1(P3d4,0x19,data);
+
+ Temp = (ULONG)GetReg1(P3d4, 0x1A);
+ Temp2= (USHORT)(Temp & 0xFC);
+ SetReg1(P3d4,0x1A,(USHORT)Temp);
+
+ Temp = (ULONG)GetReg1(P3c4, 0x0f);
+ Temp2= (USHORT)Temp & 0xBF;
+ if(ModeNo==0x37) Temp2=Temp2|0x40;
+ SetReg1(P3d4,0x1A,(USHORT)Temp2);
+}
+
+VOID SetCRT1FIFO(ULONG ROMAddr)
+{
+ USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK;
+ USHORT ah,bl,A,B;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK
+
+ MCLKOffset=*((USHORT *)(ROMAddr+0x20C));
+ index=GetReg1(P3c4,0x3A);
+ index=index&07;
+ MCLKOffset=MCLKOffset+index*5;
+ MCLK=*((UCHAR *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK
+
+ data2=ModeType-0x02;
+ switch (data2) {
+ case 0 : colorth=1; break;
+ case 1 : colorth=2; break;
+ case 2 : colorth=4; break;
+ case 3 : colorth=4; break;
+ case 4 : colorth=6; break;
+ case 5 : colorth=8; break;
+ }
+
+ do{
+ B=(CalcDelay(ROMAddr,0)*VCLK*colorth);
+ B=B/(16*MCLK);
+ B++;
+
+ A=(CalcDelay(ROMAddr,1)*VCLK*colorth);
+ A=A/(16*MCLK);
+ A++;
+
+ if(A<4) A=0;
+ else A=A-4;
+
+ if(A>B) bl=A;
+ else bl=B;
+
+ bl++;
+ if(bl>0x13) {
+ data=GetReg1(P3c4,0x16);
+ data=data>>6;
+ if(data!=0) {
+ data--;
+ data=data<<6;
+ data2=GetReg1(P3c4,0x16);
+ data2=(data2&0x3f)|data;
+ SetReg1(P3c4,0x16,data2);
+ }
+ else bl=0x13;
+ }
+ } while(bl>0x13);
+
+ ah=bl;
+ ah=ah<<4;
+ ah=ah|0x0f;
+ SetReg1(P3c4,0x08,ah);
+
+ data=bl;
+ data=data&0x10;
+ data=data<<1;
+ data2=GetReg1(P3c4,0x0F);
+ data2=data2&0x9f;
+ data2=data2|data;
+ SetReg1(P3c4,0x0F,data2);
+
+ data=bl+3;
+ if(data>0x0f) data=0x0f;
+ SetReg1(P3c4,0x3b,0x00);
+ data2=GetReg1(P3c4,0x09);
+ data2=data2&0xF0;
+ data2=data2|data;
+ SetReg1(P3c4,0x09,data2);
+}
+
+static USHORT CalcDelay(ULONG ROMAddr,USHORT key)
+{
+ USHORT data,data2,temp0,temp1;
+ UCHAR ThLowA[]={61,3,52,5,68,7,100,11,
+ 43,3,42,5,54,7, 78,11,
+ 34,3,37,5,47,7, 67,11};
+ UCHAR ThLowB[]={81,4,72,6,88,8,120,12,
+ 55,4,54,6,66,8, 90,12,
+ 42,4,45,6,55,8, 75,12};
+ UCHAR ThTiming[]= {1,2,2,3,0,1,1,2};
+
+ data=GetReg1(P3c4,0x16);
+ data=data>>6;
+ data2=GetReg1(P3c4,0x14);
+ data2=(data2>>4)&0x0C;
+ data=data|data2;
+ data=data<1;
+ if(key==0) {
+ temp0=(USHORT)ThLowA[data];
+ temp1=(USHORT)ThLowA[data+1];
+ }
+ else {
+ temp0=(USHORT)ThLowB[data];
+ temp1=(USHORT)ThLowB[data+1];
+ }
+
+ data2=0;
+ data=GetReg1(P3c4,0x18);
+ if(data&0x02) data2=data2|0x01;
+ if(data&0x20) data2=data2|0x02;
+ if(data&0x40) data2=data2|0x04;
+
+ data=temp1*ThTiming[data2]+temp0;
+ return(data);
+}
+
+VOID SetCRT1FIFO2(ULONG ROMAddr)
+{
+ USHORT colorth=0,index,data,VCLK,data2,MCLKOffset,MCLK;
+ USHORT ah,bl,B;
+ ULONG eax;
+
+ index=*((UCHAR *)(ROMAddr+REFIndex+0x03));
+ index=index&0x03F;
+ CRT1VCLKLen=GetVCLKLen(ROMAddr);
+ data=index*CRT1VCLKLen;
+ VCLKData=*((USHORT *)(ROMAddr+0x208));
+ VCLKData=VCLKData+data+(CRT1VCLKLen-2);
+ VCLK=*((USHORT *)(ROMAddr+VCLKData)); // Get VCLK
+
+ MCLKOffset=*((USHORT *)(ROMAddr+0x20C));
+ index=GetReg1(P3c4,0x1A);
+ index=index&07;
+ MCLKOffset=MCLKOffset+index*5;
+ MCLK=*((USHORT *)(ROMAddr+MCLKOffset+0x03)); // Get MCLK
+
+ data2=ModeType-0x02;
+ switch (data2) {
+ case 0 : colorth=1; break;
+ case 1 : colorth=1; break;
+ case 2 : colorth=2; break;
+ case 3 : colorth=2; break;
+ case 4 : colorth=3; break;
+ case 5 : colorth=4; break;
+ }
+
+ do{
+ B=(CalcDelay2(ROMAddr,0)*VCLK*colorth);
+ if (B%(16*MCLK) == 0)
+ {
+ B=B/(16*MCLK);
+ bl=B+1;
+ }
+ else
+ {
+ B=B/(16*MCLK);
+ bl=B+2;
+ }
+
+ if(bl>0x13) {
+ data=GetReg1(P3c4,0x15);
+ data=data&0xf0;
+ if(data!=0xb0) {
+ data=data+0x20;
+ if(data==0xa0) data=0x30;
+
+ data2=GetReg1(P3c4,0x15);
+ data2=(data2&0x0f)|data;
+ SetReg1(P3c4,0x15,data2);
+ }
+ else bl=0x13;
+ }
+ } while(bl>0x13);
+
+ data2=GetReg1(P3c4,0x15);
+ data2=(data2&0xf0)>>4;
+ data2=data2<<24;
+
+ SetReg4(0xcf8,0x80000050);
+ eax=GetReg3(0xcfc);
+ eax=eax&0x0f0ffffff;
+ eax=eax|data2;
+ SetReg4(0xcfc,eax);
+
+ ah=bl;
+ ah=ah<<4;
+ ah=ah|0x0f;
+ SetReg1(P3c4,0x08,ah);
+
+ data=bl;
+ data=data&0x10;
+ data=data<<1;
+ data2=GetReg1(P3c4,0x0F);
+ data2=data2&0x9f;
+ data2=data2|data;
+ SetReg1(P3c4,0x0F,data2);
+
+ data=bl+3;
+ if(data>0x0f) data=0x0f;
+ SetReg1(P3c4,0x3b,0x00);
+ data2=GetReg1(P3c4,0x09);
+ data2=data2&0xF0;
+ data2=data2|data;
+ SetReg1(P3c4,0x09,data2);
+}
+
+USHORT CalcDelay2(ULONG ROMAddr,USHORT key)
+{
+ USHORT data,index;
+ UCHAR LatencyFactor[]={88,80,78,72,70,00,
+ 00,79,77,71,69,49,
+ 88,80,78,72,70,00,
+ 00,72,70,64,62,44};
+
+ index=0;
+ data=GetReg1(P3c4,0x14);
+ if(data&0x80) index=index+12;
+
+ data=GetReg1(P3c4,0x15);
+ data=(data&0xf0)>>4;
+ if(data&0x01) index=index+6;
+
+ data=data>>1;
+ index=index+data;
+ data=LatencyFactor[index];
+
+ return(data);
+}
+
+#endif /* CONFIG_FB_SIS_LINUXBIOS */
diff --git a/drivers/video/sis/sis_300.h b/drivers/video/sis/sis_300.h
new file mode 100644
index 000000000..c7f89e454
--- /dev/null
+++ b/drivers/video/sis/sis_300.h
@@ -0,0 +1,163 @@
+#include <linux/config.h>
+#include "initdef.h"
+
+USHORT DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
+ {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
+ {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
+ {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
+ {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
+ {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
+ {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
+ {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
+ {0x09,0x08,0x01,0x01,0x00}};
+
+USHORT MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F};
+
+USHORT CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
+
+USHORT EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+ 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+ 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+ 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+ 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+ 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+ 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
+
+USHORT VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+ 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+
+ 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+ 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+ 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+ 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+ 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+ 0x0B,0x0C,0x0D,0x0F,0x10};
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+unsigned char SRegsInit[] = {
+ 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13,
+ 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00,
+ 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43,
+ 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff
+};
+
+unsigned char SRegs[] = {
+ 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13,
+ 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00,
+ 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0,
+ 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43,
+ 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF,
+ 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF
+};
+
+unsigned char CRegs[] = {
+ 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff
+}; // clear CR11[7]
+
+unsigned char GRegs[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00
+};
+
+unsigned char ARegs[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+unsigned char MReg = 0x6f;
+
+#endif
+
+USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+USHORT CRT1VCLKLen; //VCLKData table length of bytes of each entry
+USHORT flag_clearbuffer; //0: no clear frame buffer 1:clear frame buffer
+int RAMType;
+int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData;
+int REFIndex,ModeType;
+USHORT IF_DEF_LVDS,IF_DEF_TRUMPION;
+USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo;
+
+//int init300(int,int,int);
+VOID SetMemoryClock(ULONG);
+VOID SetDRAMSize(PHW_DEVICE_EXTENSION);
+//extern "C" int ChkBUSWidth(int);
+
+//int setmode(int,int,int,int);
+BOOLEAN SearchModeID(ULONG, USHORT);
+BOOLEAN CheckMemorySize(ULONG);
+VOID GetModePtr(ULONG, USHORT);
+BOOLEAN GetRatePtr(ULONG, USHORT);
+VOID SetSeqRegs(ULONG);
+VOID SetMiscRegs(ULONG);
+VOID SetCRTCRegs(ULONG);
+VOID SetATTRegs(ULONG);
+VOID SetGRCRegs(ULONG);
+VOID ClearExt1Regs(VOID);
+VOID SetSync(ULONG);
+VOID SetCRT1CRTC(ULONG);
+VOID SetCRT1Offset(ULONG);
+VOID SetCRT1FIFO(ULONG);
+VOID SetCRT1FIFO2(ULONG);
+VOID SetCRT1VCLK(PHW_DEVICE_EXTENSION, ULONG);
+VOID LoadDAC(ULONG);
+VOID DisplayOn(VOID);
+VOID SetCRT1ModeRegs(ULONG, USHORT);
+VOID SetVCLKState(PHW_DEVICE_EXTENSION, ULONG, USHORT);
+VOID WriteDAC(USHORT, USHORT, USHORT, USHORT);
+VOID ClearBuffer(PHW_DEVICE_EXTENSION);
+USHORT ChkBUSWidth(ULONG);
+USHORT GetModeIDLength(ULONG, USHORT);
+USHORT GetRefindexLength(ULONG, USHORT);
+VOID SetInterlace(ULONG, USHORT);
+USHORT CalcDelay2(ULONG ,USHORT);
+void Set_LVDS_TRUMPION(VOID);
+BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+static USHORT CalcDelay(ULONG ,USHORT);
+#endif
+
+extern BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr);
+extern VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4);
+extern VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr);
+extern BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr);
+extern BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension);
+extern USHORT GetVCLKLen(ULONG ROMAddr);
+extern void SetReg1(u16 port, u16 index, u16 data);
+extern void SetReg3(u16 port, u16 data);
+extern void SetReg4(u16 port, unsigned long data);
+extern u8 GetReg1(u16 port, u16 index);
+extern u8 GetReg2(u16 port);
+extern u32 GetReg3(u16 port);
+extern void ClearDAC(u16 port);
diff --git a/drivers/video/sis/sis_301.c b/drivers/video/sis/sis_301.c
new file mode 100644
index 000000000..195fd28f1
--- /dev/null
+++ b/drivers/video/sis/sis_301.c
@@ -0,0 +1,2868 @@
+/* Recently Update by v1.09.50 */
+
+#include <linux/config.h>
+#include "sis_301.h"
+
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+
+BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp;
+
+ SetFlag=SetFlag|ProgrammingCRT2;
+ SearchModeID(ROMAddr,ModeNo);
+
+ temp=GetRatePtrCRT2(ROMAddr,ModeNo);
+ if(((temp&0x02)==0) && ((VBInfo&CRT2DisplayFlag)==0))
+ return(FALSE);
+ SaveCRT2Info(ModeNo);
+ DisableBridge(BaseAddr);
+ UnLockCRT2(BaseAddr);
+ SetDefCRT2ExtRegs(BaseAddr);
+ SetCRT2ModeRegs(BaseAddr,ModeNo);
+ if(VBInfo&CRT2DisplayFlag){
+ LockCRT2(BaseAddr);
+ return 0;
+ }
+ GetCRT2Data(ROMAddr,ModeNo);
+ if(IF_DEF_LVDS==1){ //LVDS
+ GetLVDSDesData(ROMAddr,ModeNo);
+ }
+ SetGroup1(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ if(IF_DEF_LVDS==0){
+ SetGroup2(BaseAddr,ROMAddr);
+ SetGroup3(BaseAddr);
+ SetGroup4(BaseAddr,ROMAddr,ModeNo);
+ SetGroup5(BaseAddr,ROMAddr);
+ }else{ //LVDS
+ if(IF_DEF_TRUMPION==0){
+ ModCRT1CRTC(ROMAddr,ModeNo);
+ }
+ SetCRT2ECLK(ROMAddr,ModeNo);
+ }
+
+ EnableCRT2();
+ EnableBridge(BaseAddr);
+ SetLockRegs();
+ LockCRT2(BaseAddr);
+
+ return 1;
+}
+
+VOID overwriteregs(ULONG ROMAddr,USHORT BaseAddr)
+{
+ int i;
+ USHORT Part1Port; //reg data is for 1024x768 16bit 85hz
+ int p1reg[0x29]={0x84,0x76,0x4B,0x21,0x00,0x00,0x00,0x00,0x1F,0x51,
+ 0x0C,0x10,0x44,0x90,0x1E,0xFF,0x00,0x34,0x13,0x10,
+ 0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x97,0x16,
+ 0xA3};
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ for(i=0;i<29;i++){
+ SetReg1(Part1Port,(USHORT)i,(USHORT)p1reg[i]);
+ }
+}
+
+VOID SetDefCRT2ExtRegs(USHORT BaseAddr)
+{
+ USHORT Part1Port,Part2Port,Part4Port;
+ USHORT temp;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ SetReg1(Part1Port,0x02,0x40);
+ SetReg1(Part4Port,0x10,0x80);
+ temp=(UCHAR)GetReg1(P3c4,0x16);
+ temp=temp&0xC3;
+ SetReg1(P3d4,0x35,temp);
+}
+
+USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo)
+{ //return bit0=>0:standard mode 1:extended mode
+ SHORT index; // bit1=>0:crt2 no support this mode
+ USHORT temp; // 1:crt2 support this mode
+ USHORT ulRefIndexLength;
+ USHORT temp1;
+ SHORT LCDRefreshIndex[4]={0x0,0x0,0x03,0x01};
+ // LCDPanel:no lcd,800x600,1024x768,1280x1024
+ if(ModeNo<0x14) return(0); // Mode No <= 13h then return
+
+ index=GetReg1(P3d4,0x33); // Get 3d4 CRTC33
+ index=index>>SelectCRT2Rate; //For CRT2,cl=SelectCRT2Rate=4, shr ah,cl
+ index=index&0x0F; // Frame rate index
+ if(index!=0) index--;
+
+ if(IF_DEF_TRUMPION==1){
+ if(VBInfo&SetSimuScanMode){
+ index=0;
+ }
+ }
+ if(SetFlag&ProgrammingCRT2){
+ if(VBInfo&SetCRT2ToLCD){
+ if(IF_DEF_LVDS==0){
+ temp=LCDResInfo;
+ temp1=LCDRefreshIndex[temp];
+ if(index>temp1){
+ index=temp1;
+ }
+ }else{
+ index=0;
+ }
+ }
+ }
+
+ REFIndex=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+
+ ulRefIndexLength =Ext2StructSize;
+ do {
+ temp=*((USHORT *)(ROMAddr+REFIndex)); // di => REFIndex
+ if(temp==0xFFFF) break;
+ temp=temp&ModeInfoFlag;
+ if(temp<ModeType) break;
+
+ REFIndex=REFIndex+ulRefIndexLength; // rate size
+ index--;
+ if(index<0){
+ if(!(VBInfo&SetCRT2ToRAMDAC)){
+ if(VBInfo&SetInSlaveMode){
+ temp1=*((USHORT *)(ROMAddr+REFIndex+0-Ext2StructSize));
+ if(temp1&InterlaceMode){
+ index=0;
+ }
+ }
+ }
+ }
+ } while(index>=0);
+
+ REFIndex=REFIndex-ulRefIndexLength; // rate size
+
+ if((SetFlag&ProgrammingCRT2)){
+ temp1=AjustCRT2Rate(ROMAddr);
+ }else{
+ temp1=0;
+ }
+
+ return(0x01|(temp1<<1));
+}
+
+BOOLEAN AjustCRT2Rate(ULONG ROMAddr)
+{
+ USHORT tempbx=0,tempax,temp;
+ USHORT tempextinfoflag;
+ tempax=0;
+
+ if(IF_DEF_LVDS==0){
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempax=tempax|SupportRAMDAC2;
+ }
+ if(VBInfo&SetCRT2ToLCD){
+ tempax=tempax|SupportLCD;
+ if(LCDResInfo!=Panel1280x1024){
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(temp>=9){
+ tempax=0;
+ }
+ }
+ }
+ if(VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)){
+ tempax=tempax|SupportTV;
+ if(!(VBInfo&SetPALTV)){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag&NoSupportSimuTV){
+ if(VBInfo&SetInSlaveMode){
+ if(!(VBInfo&SetNotSimuTVMode)){
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x04)); // si+Ext_point
+ }else{ //for LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ tempax=tempax|SupportLCD;
+ temp=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(temp>0x08){ //1024x768
+ return 0;
+ }
+ if(LCDResInfo<Panel1024x768){
+ if(temp>0x07){ //800x600
+ return 0;
+ }
+ if(temp==0x04){ //512x384
+ return 0;
+ }
+ }
+ }
+ }
+
+ for(;REFIndex>tempbx;REFIndex-=Ext2StructSize){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag&tempax){
+ return 1;
+ }
+ }
+ for(REFIndex=tempbx;;REFIndex+=Ext2StructSize){
+ tempextinfoflag=*((USHORT *)(ROMAddr+REFIndex+0x0)); //di+Ext_InfoFlag
+ if(tempextinfoflag==0x0FFFF){
+ return 0;
+ }
+ if(tempextinfoflag&tempax){
+ return 1;
+ }
+ }
+ return(FALSE);
+}
+
+VOID SaveCRT2Info(USHORT ModeNo){
+ USHORT temp1,temp2,temp3;
+ temp1=(VBInfo&SetInSlaveMode)>>8;
+ temp2=~(SetInSlaveMode>>8);
+ temp3=(UCHAR)GetReg1(P3d4,0x31);
+ temp3=((temp3&temp2)|temp1);
+ SetReg1(P3d4,0x31,(USHORT)temp3);
+ temp3=(UCHAR)GetReg1(P3d4,0x35);
+ temp3=temp3&0xF3;
+ SetReg1(P3d4,0x35,(USHORT)temp3);
+}
+
+VOID DisableLockRegs(){
+ UCHAR temp3;
+ temp3=(UCHAR)GetReg1(P3c4,0x32);
+ temp3=temp3&0xDF;
+ SetReg1(P3c4,0x32,(USHORT)temp3);
+}
+
+VOID DisableCRT2(){
+ UCHAR temp3;
+ temp3=(UCHAR)GetReg1(P3c4,0x1E);
+ temp3=temp3&0xDF;
+ SetReg1(P3c4,0x1E,(USHORT)temp3);
+}
+
+void DisableBridge(USHORT BaseAddr)
+{
+ USHORT Part2Port,Part1Port;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==0){
+ SetRegANDOR(Part2Port,0x00,0xDF,0x00); //Set Part2 Index0 D[5]=0
+ DisableLockRegs(); // SR 32
+ DisableCRT2(); // SR 1E
+ }else{
+ DisableLockRegs();
+ DisableCRT2();
+ if(IF_DEF_TRUMPION==0){
+ UnLockCRT2(BaseAddr);
+ SetRegANDOR(Part1Port,0x02,0xFF,0x40); //set Part1Port ,index 2, D6=1,
+ }
+ }
+}
+
+VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo)
+{
+ if(IF_DEF_LVDS==0){ //301
+ GetCRT2Data301(ROMAddr,ModeNo);
+ return;
+ }else{ //LVDS
+ GetCRT2DataLVDS(ROMAddr,ModeNo);
+ return;
+ }
+}
+
+VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,OldREFIndex;
+
+ OldREFIndex=(USHORT)REFIndex; //push di
+ GetResInfo(ROMAddr,ModeNo);
+ GetCRT2Ptr(ROMAddr,ModeNo);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex));
+ tempax=tempax&0x0FFF;
+ VGAHT=tempax;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+1));
+ tempax=tempax>>4;
+ tempax=tempax&0x07FF;
+ VGAVT=tempax;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+3));
+ tempax=tempax&0x0FFF;
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+4));
+ tempbx=tempbx>>4;
+ tempbx=tempbx&0x07FF;
+
+ HT=tempax;
+ VT=tempbx;
+
+ if(IF_DEF_TRUMPION==0){
+ if(VBInfo&SetCRT2ToLCD){
+ if(!(LCDInfo&LCDNonExpanding)){
+ if(LCDResInfo==Panel800x600){
+ tempax=800;
+ tempbx=600;
+ }else if(LCDResInfo==Panel1024x768){
+ tempax=1024;
+ tempbx=768;
+ }else{
+ tempax=1280;
+ tempbx=1024;
+ }
+ HDE=tempax;
+ VDE=tempbx;
+ }
+ }
+ }
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,modeflag1,OldREFIndex;
+ USHORT tempal,tempah,tempbl;
+
+ OldREFIndex=(USHORT)REFIndex; //push di
+ RVBHRS=50;NewFlickerMode=0;RY1COE=0;
+ RY2COE=0;RY3COE=0;RY4COE=0;
+
+ GetResInfo(ROMAddr,ModeNo);
+ if(VBInfo&SetCRT2ToRAMDAC){
+ GetRAMDAC2DATA(ROMAddr,ModeNo);
+ REFIndex=OldREFIndex; //pop di
+ return;
+ }
+ GetCRT2Ptr(ROMAddr,ModeNo);
+
+ tempal=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=*((UCHAR *)(ROMAddr+REFIndex+4));
+ tempax=tempal|(((tempah<<8)>>7)&0xFF00);
+ RVBHCMAX=tempax;
+
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+1));
+ RVBHCFACT=tempal;
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+2));
+ VGAHT=(tempax&0x0FFF);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+3));
+ VGAVT=((tempax>>4)&0x07FF);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+5));
+ tempax=(tempax&0x0FFF);
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+6));
+ tempbx=((tempbx>>4)&0x07FF);
+ tempbl=tempbx&0x00FF;
+
+ if(VBInfo&SetCRT2ToTV){
+ tempax=*((USHORT *)(ROMAddr+REFIndex+5));
+ tempax=(tempax&0x0FFF);
+ HDE=tempax;
+ tempax=*((USHORT *)(ROMAddr+REFIndex+6));
+ tempax=((tempax>>4)&0x07FF);
+ VDE=tempax;
+ //skipp something about hivisiontv
+ tempax=*((USHORT *)(ROMAddr+REFIndex+8));
+ tempbl=(tempax>>8);
+ tempax=tempax&0x0FFF;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){
+ tempax=*((USHORT *)(ROMAddr+REFIndex+10));
+ }
+ RVBHRS=tempax;
+ NewFlickerMode=(tempbl&0x080);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+12));
+ RY1COE=(tempax&0x00FF);
+ RY2COE=((tempax&0xFF00)>>8);
+ tempax=*((USHORT *)(ROMAddr+REFIndex+14));
+ RY3COE=(tempax&0x00FF);
+ RY4COE=((tempax&0xFF00)>>8);
+ if(!(VBInfo&SetPALTV)){
+ tempax=NTSCHT;
+ tempbx=NTSCVT;
+ }else{
+ tempax=PALHT;
+ tempbx=PALVT;
+ }
+ }
+ HT=tempax;
+ VT=tempbx;
+ if(!(VBInfo&SetCRT2ToLCD)){
+ REFIndex=OldREFIndex; //pop di
+ return;
+ }
+
+ tempax=1024;
+ if(VGAVDE==350){ //cx->VGAVDE
+ tempbx=560;
+ }else if(VGAVDE==400){
+ tempbx=640;
+ }else{
+ tempbx=768;
+ }
+
+ if(LCDResInfo==Panel1280x1024){
+ tempax=1280;
+ if(VGAVDE==360){
+ tempbx=768;
+ }else if(VGAVDE==375){
+ tempbx=800;
+ }else if(VGAVDE==405){
+ tempbx=864;
+ }else{
+ tempbx=1024;
+ }
+ }
+
+ HDE=tempax;
+ VDE=tempbx;
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT temp,xres,yres,modeflag1;
+ if(ModeNo<=0x13){
+ temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo
+ xres=StResInfo[temp][0];
+ yres=StResInfo[temp][1];
+ }else{
+ temp=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); // si+Ext_ResInfo
+ xres=ModeResInfo[temp][0]; //xres->ax
+ yres=ModeResInfo[temp][1]; //yres->bx
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){ xres=xres*2;}
+ if(modeflag1&DoubleScanMode){yres=yres*2;}
+ }
+ if(!(LCDResInfo==Panel1024x768)){
+ if(yres==400) yres=405;
+ if(yres==350) yres=360;
+ if(SetFlag&LCDVESATiming){
+ if(yres==360) yres=375;
+ }
+ }
+ VGAHDE=xres;
+ HDE=xres;
+ VGAVDE=yres;
+ VDE=yres;
+}
+
+VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT old_REFIndex,tempax;
+
+ old_REFIndex=(USHORT)REFIndex; //push di
+ REFIndex=GetLVDSDesPtr(ROMAddr,ModeNo);
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex));
+ tempax=tempax&0x0FFF;
+ LCDHDES=tempax;
+
+ if(LCDInfo&LCDNonExpanding){ //hw walk-a-round
+ if(LCDResInfo>=Panel1024x768){
+ if(ModeNo<=0x13){
+ LCDHDES=320;
+ }
+ }
+ }
+
+ tempax=*((USHORT *)(ROMAddr+REFIndex+1));
+ tempax=tempax>>4;
+ tempax=tempax&0x07FF;
+ LCDVDES=tempax;
+
+ REFIndex=old_REFIndex; //pop di
+ return;
+}
+
+
+VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempax,tempbx,tempbh,modeflag1,t1=0,t2;
+ RVBHCMAX=1;RVBHCFACT=1;
+ if(ModeNo<=0x13){
+ tempax=*((UCHAR *)(ROMAddr+REFIndex+10));
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+16));
+ }else{
+ t1=*((UCHAR *)(ROMAddr+REFIndex+0x2)); //Ext_CRT1CRTC=2
+ t1=t1&0x03F; //[06/29/2000] fix bug for vbios >=v1.07.00
+ t1=t1*CRT1Len;
+ REFIndex=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ REFIndex=REFIndex+t1;
+ t1=*((UCHAR *)(ROMAddr+REFIndex+0));
+ t2=*((UCHAR *)(ROMAddr+REFIndex+14));
+ tempax=(t1&0xFF)|((t2&0x03)<<8);
+ tempbx=*((USHORT *)(ROMAddr+REFIndex+6));
+ t1=*((UCHAR *)(ROMAddr+REFIndex+13));
+ t1=(t1&0x01)<<2;
+ }
+
+ tempbh=tempbx>>8;
+ tempbh=((tempbh&0x20)>>4)|(tempbh&0x01);
+ tempbh=tempbh|t1;
+ tempbx=(tempbx&0xFF)|(tempbh<<8);
+ tempax=tempax+5;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&Charx8Dot){
+ tempax=tempax*8;
+ }else{
+ tempax=tempax*9;
+ }
+
+ VGAHT=tempax;
+ HT=tempax;
+ tempbx++;
+ VGAVT=tempbx;
+ VT=tempbx;
+
+}
+
+VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempcl,tempbx,tempal,tempax,CRT2PtrData;
+
+ if(IF_DEF_LVDS==0){
+ if(VBInfo&SetCRT2ToLCD){ //LCD
+ tempbx=0; //default tempbx=0 -> ExtLCD1Data
+ tempcl=LCDDataLen;
+ if(LCDResInfo==Panel1024x768){
+ tempbx=0;
+ }else if(LCDResInfo==Panel1280x1024){
+ tempbx=1;
+ }
+ if(!(SetFlag&LCDVESATiming)) tempbx+=5;
+ }else if(VBInfo&SetPALTV){
+ tempcl=TVDataLen;
+ tempbx=3;
+ }else{
+ tempbx=4;
+ tempcl=TVDataLen;
+ }
+ if(SetFlag&TVSimuMode){
+ tempbx=tempbx+4;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+
+ tempax=tempal*tempcl;
+ REFIndex=*((USHORT *)(ROMAddr+tempbx*2+0x20E));
+ REFIndex+=tempax;
+ }else{ //for LVDS
+
+ tempcl=LVDSDataLen;
+ tempbx=LCDResInfo-Panel800x600;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+3;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+ tempax=tempal*tempcl;
+ CRT2PtrData=*((USHORT *)(ROMAddr+ADR_CRT2PtrData)); //ADR_CRT2PtrData is defined in init.def
+ REFIndex=*((USHORT *)(ROMAddr+CRT2PtrData+tempbx*2));
+ REFIndex+=tempax;
+ }
+}
+
+VOID UnLockCRT2(USHORT BaseAddr)
+{
+ UCHAR temp3;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ temp3=(UCHAR)GetReg1(Part1Port,0x24);
+ temp3=temp3|0x01;
+ SetReg1(Part1Port,0x24,(USHORT)temp3);
+}
+
+VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo)
+{
+ USHORT i,j;
+ USHORT tempah=0,temp3;
+ SHORT tempcl;
+ USHORT Part4Port;
+ USHORT Part1Port;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ for(i=0,j=4;i<3;i++,j++){
+ SetReg1(Part1Port,j,0);
+ }
+
+ tempcl=(USHORT)ModeType;
+ if(ModeNo>0x13){
+ tempcl=tempcl-ModeVGA;
+ if(tempcl>=0){
+ tempah=((0x010>>tempcl)|0x080);
+ }
+ }else{
+ tempah=0x080;
+ }
+
+ if(VBInfo&SetInSlaveMode){
+ tempah=(tempah^0x0A0);
+ }
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0,tempah);
+
+ if(IF_DEF_LVDS==0){ //301
+ tempah=0x01;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempah=(tempah|0x02);
+ }
+ if(!(VBInfo&SetCRT2ToRAMDAC)){
+ tempah=(tempah^0x05);
+ if(!(VBInfo&SetCRT2ToLCD)){
+ tempah=(tempah^0x01);
+ }
+ }
+ tempah=(tempah<<5)&0xFF;
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0x01,tempah);
+
+ tempah=tempah>>5;
+ if((ModeType==ModeVGA)&&(!(VBInfo&SetInSlaveMode))){
+ tempah=tempah|0x010;
+ }
+ if(LCDResInfo!=Panel1024x768){
+ tempah=tempah|0x080;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ if(VBInfo&SetInSlaveMode){
+ tempah=tempah|0x020;
+ }
+ }
+
+ temp3=(UCHAR)GetReg1(Part4Port,0x0D);
+ temp3=temp3&(~0x0BF);
+ temp3=temp3|tempah;
+ SetReg1(Part4Port,0x0D,(USHORT)temp3);
+ }else{ //LVDS
+ tempah=0;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempah=tempah|0x02;
+ }
+ tempah=(tempah<<5)&0x0FF;
+ if(VBInfo&CRT2DisplayFlag){
+ tempah=0;
+ }
+ SetReg1(Part1Port,0x01,tempah);
+ }
+}
+
+VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ if(IF_DEF_LVDS==0){ //301
+ SetGroup1_301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ }else{ //LVDS
+ SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+ }
+}
+VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp1,temp2,tempcl,tempch,tempbh,tempal,tempah,tempax,tempbx;
+ USHORT tempcx,OldREFIndex,lcdhdee;
+ USHORT Part1Port;
+ USHORT temppush1,temppush2;
+ unsigned long int tempeax,tempebx,tempecx,templong;
+
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ OldREFIndex=(USHORT)REFIndex; //push di
+
+ SetCRT2Offset(Part1Port,ROMAddr);
+ SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension);
+ SetCRT2Sync(BaseAddr,ROMAddr,ModeNo);
+
+ temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09
+ SetReg1(Part1Port,0x08,temp1);
+ temp1=(((VGAHT-1)&0xFF00)>>8)<<4;
+ SetRegANDOR(Part1Port,0x09,~0x0F0,temp1);
+
+
+ temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C
+ SetReg1(Part1Port,0x0A,temp1);
+
+ temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C
+ temp2=(VGAHT-VGAHDE)>>2; //cx
+ temp1=temp1+temp2;
+ temp2=(temp2<<1)+temp1;
+ tempcl=temp2&0x0FF;
+ //
+ SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF));
+ tempah=(temp1&0xFF00)>>8;
+ tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF;
+ tempah=tempah|tempbh;
+ SetReg1(Part1Port,0x0C,tempah);
+ SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D
+ tempcx=(VGAVT-1);
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12
+ tempbx=VGAVDE-1;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12
+ tempah=((tempbx&0xFF00)<<3)>>8;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part1Port,0x12,tempah);
+
+ tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11
+ tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11
+ //
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x10,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F);
+ SetReg1(Part1Port,0x11,tempah);
+
+ SetRegANDOR(Part1Port,0x13,~0x03C,tempah);
+
+ tempax=LCDHDES;
+ tempbx=HDE;
+ tempcx=HT;
+ tempcx=tempcx-tempbx; //HT-HDE
+ tempax=tempax+tempbx; //lcdhdee
+ tempbx=HT;
+ if(tempax>=tempbx){
+ tempax=tempax-tempbx;
+ }
+
+ lcdhdee=tempax;
+ tempcx=tempcx>>2; //temp
+ tempcx=tempcx+tempax; //lcdhrs
+ if(tempcx>=tempbx){
+ tempcx=tempcx-tempbx;
+ }
+
+ tempax=tempcx;
+ tempax=tempax>>3; //BPLHRS
+ tempah=tempax&0x0FF;
+ SetReg1(Part1Port,0x14,tempah); //Part1_14h
+ tempah=tempah+2;
+ tempah=tempah+0x01F;
+ tempcl=tempcx&0x0FF;
+ tempcl=tempcl&0x07;
+ tempcl=(tempcl<<5)&0xFF; //BPHLHSKEW
+ tempah=tempah|tempcl;
+ SetReg1(Part1Port,0x15,tempah); //Part1_15h
+ tempbx=lcdhdee; //lcdhdee
+ tempcx=LCDHDES; //lcdhdes
+ tempah=(tempcx&0xFF);
+ tempah=tempah&0x07; //BPLHDESKEW
+ SetReg1(Part1Port,0x1A,tempah); //Part1_1Ah
+ tempcx=tempcx>>3; //BPLHDES
+ tempah=(tempcx&0xFF);
+ SetReg1(Part1Port,0x16,tempah); //Part1_16h
+ tempbx=tempbx>>3; //BPLHDEE
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x17,tempah); //Part1_17h
+
+ tempcx=VGAVT;
+ tempbx=VGAVDE;
+ tempcx=tempcx-tempbx; //VGAVT-VGAVDE
+ tempbx=LCDVDES; //VGAVDES
+ temppush1=tempbx; //push bx temppush1
+ if(IF_DEF_TRUMPION==0){
+ if(LCDResInfo==Panel800x600){
+ tempax=600;
+ }else{
+ tempax=768;
+ }
+ }else{
+ tempax=VGAVDE;
+ }
+ tempbx=tempbx+tempax;
+ tempax=VT; //VT
+ if(tempbx>=VT){
+ tempbx=tempbx-tempax;
+ }
+ temppush2=tempbx; //push bx temppush2
+ tempcx=tempcx>>1;
+ tempbx=tempbx+tempcx;
+ tempbx++; //BPLVRS
+ if(tempbx>=tempax){
+ tempbx=tempbx-tempax;
+ }
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x18,tempah); //Part1_18h
+ tempcx=tempcx>>3;
+ tempcx=tempcx+tempbx;
+ tempcx++; //BPLVRE
+ tempah=tempcx&0xFF;
+ tempah=tempah&0x0F;
+ tempah=tempah|0x030;
+ SetRegANDOR(Part1Port,0x19,~0x03F,tempah); //Part1_19h
+ tempbh=(tempbx&0xFF00)>>8;
+ tempbh=tempbh&0x07;
+ tempah=tempbh;
+ tempah=(tempah<<3)&0xFF; //BPLDESKEW =0
+ tempbx=VGAVDE;
+ if(tempbx!=VDE){
+ tempah=tempah|0x40;
+ }
+ SetRegANDOR(Part1Port,0x1A,0x07,tempah); //Part1_1Ah
+ tempecx=VGAVT;
+ tempebx=VDE;
+ tempeax=VGAVDE;
+ tempecx=tempecx-tempeax; //VGAVT-VGAVDE
+ tempeax=tempeax*64;
+ templong=tempeax/tempebx;
+ if(templong*tempebx<tempeax){
+ templong++;
+ }
+ tempebx=templong; //BPLVCFACT
+ if(SetFlag&EnableLVDSDDA){
+ tempebx=tempebx&0x03F;
+ }
+ tempah=(USHORT)(tempebx&0x0FF);
+ SetReg1(Part1Port,0x1E,tempah); //Part1_1Eh
+ tempbx=temppush2; //pop bx temppush2 BPLVDEE
+ tempcx=temppush1; //pop cx temppush1 NPLVDES
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=tempah&0x07;
+ tempah=tempbh;
+ tempah=tempah<<3;
+ tempch=(tempcx&0xFF00)>>8;
+ tempch=tempah&0x07;
+ tempah=tempah|tempch;
+ SetReg1(Part1Port,0x1D,tempah); //Part1_1Dh
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x1C,tempah); //Part1_1Ch
+ tempah=tempcx&0xFF;
+ SetReg1(Part1Port,0x1B,tempah); //Part1_1Bh
+
+ tempecx=VGAHDE;
+ tempebx=HDE;
+ tempeax=tempecx;
+ tempeax=tempeax<<6;
+ tempeax=tempeax<<10;
+ tempeax=tempeax/tempebx;
+ if(tempebx==tempecx){
+ tempeax=65535;
+ }
+ tempecx=tempeax;
+ tempeax=VGAHT;
+ tempeax=tempeax<<6;
+ tempeax=tempeax<<10;
+ tempeax=tempeax/tempecx;
+ tempecx=tempecx<<16;
+ tempeax=tempeax-1;
+ tempax=(USHORT)(tempeax&0x00FFFF);
+ tempcx=tempax;
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x1F,tempah); //Part1_1Fh
+ tempbx=VDE;
+ tempbx--; //BENPLACCEND
+ if(SetFlag&EnableLVDSDDA){
+ tempbx=1;
+ }
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<3)&0xFF;
+ tempch=(tempcx&0xFF00)>>8;
+ tempch=tempch&0x07;
+ tempah=tempah|tempch;
+ SetReg1(Part1Port,0x20,tempah); //Part1_20h
+ tempah=tempbx&0xFF;
+ SetReg1(Part1Port,0x21,tempah); //Part1_21h
+ tempecx=tempecx>>16; //BPLHCFACT
+ temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(temp1&HalfDCLK){
+ tempecx=tempecx>>1;
+ }
+ tempcx=(USHORT)(tempecx&0x0FFFF);
+ tempah=(tempcx&0xFF00)>>8;
+ SetReg1(Part1Port,0x22,tempah); //Part1_22h
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x23,tempah); //Part1_23h
+ if(IF_DEF_TRUMPION==1){
+ tempal=(USHORT)*((UCHAR *)(ROMAddr+ModeIDOffset+0x05)); // si+St_ResInfo
+ if(ModeNo>0x13){
+ SetFlag=SetFlag|ProgrammingCRT2;
+ GetRatePtrCRT2(ROMAddr,ModeNo);
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ tempal=tempal&0x1F;
+ }
+ tempah=0x80;
+ tempal=tempal*tempah;
+ REFIndex= offset_Zurac; //offset Zurac need added in rompost.asm
+ REFIndex=REFIndex+tempal;
+ SetTPData(); //this function not implemented yet
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ SetTPData();
+ }
+
+ REFIndex=OldREFIndex; //pop di
+ return;
+}
+
+VOID SetTPData(VOID)
+{
+ return;
+}
+
+VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp1,temp2,tempcl,tempch,tempbl,tempbh,tempal,tempah,tempax,tempbx;
+ USHORT tempcx,OldREFIndex;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ OldREFIndex=(USHORT)REFIndex; //push di
+
+ SetCRT2Offset(Part1Port,ROMAddr);
+ SetCRT2FIFO(Part1Port,ROMAddr,ModeNo,HwDeviceExtension);
+ SetCRT2Sync(BaseAddr,ROMAddr,ModeNo);
+
+ GetCRT1Ptr(ROMAddr);
+
+ temp1=(VGAHT-1)&0x0FF; //BTVGA2HT 0x08,0x09
+ SetReg1(Part1Port,0x08,temp1);
+ temp1=(((VGAHT-1)&0xFF00)>>8)<<4;
+ SetRegANDOR(Part1Port,0x09,~0x0F0,temp1);
+
+ temp1=(VGAHDE+12)&0x0FF; //BTVGA2HDEE 0x0A,0x0C
+ SetReg1(Part1Port,0x0A,temp1);
+
+ temp1=VGAHDE+12; //bx BTVGA@HRS 0x0B,0x0C
+ temp2=(VGAHT-VGAHDE)>>2; //cx
+ temp1=temp1+temp2;
+ temp2=(temp2<<1)+temp1;
+ tempcl=temp2&0x0FF;
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempbl=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+4
+ tempbh=*((UCHAR *)(ROMAddr+REFIndex+14)); //di+14
+ temp1=((tempbh>>6)<<8)|tempbl; //temp1->bx
+ temp1=(temp1-1)<<3;
+ tempcl=*((UCHAR *)(ROMAddr+REFIndex+5)); //di+5
+ tempch=*((UCHAR *)(ROMAddr+REFIndex+15)); //di+15
+ tempcl=tempcl&0x01F;
+ tempch=(tempch&0x04)<<(6-2);
+ tempcl=((tempcl|tempch)-1)<<3;
+ }
+ SetReg1(Part1Port,0x0B,(USHORT)(temp1&0x0FF));
+ tempah=(temp1&0xFF00)>>8;
+ tempbh=((((VGAHDE+12)&0xFF00)>>8)<<4)&0x0FF;
+ tempah=tempah|tempbh;
+ SetReg1(Part1Port,0x0C,tempah);
+ SetReg1(Part1Port,0x0D,tempcl); //BTVGA2HRE 0x0D
+ tempcx=(VGAVT-1);
+ tempah=tempcx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah); //BTVGA2TV 0x0E,0x12
+ tempbx=VGAVDE-1;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0F,tempah); //BTVGA2VDEE 0x0F,0x12
+ tempah=((tempbx&0xFF00)<<3)>>8;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part1Port,0x12,tempah);
+
+ tempbx=(VGAVT+VGAVDE)>>1; //BTVGA2VRS 0x10,0x11
+ tempcx=((VGAVT-VGAVDE)>>4)+tempbx+1; //BTVGA2VRE 0x11
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempbx=*((UCHAR *)(ROMAddr+REFIndex+8)); //di+8
+ temp1=*((UCHAR *)(ROMAddr+REFIndex+7)); //di+7
+ if(temp1&0x04){
+ tempbx=tempbx|0x0100;
+ }
+ if(temp1&0x080){
+ tempbx=tempbx|0x0200;
+ }
+ temp1=*((UCHAR *)(ROMAddr+REFIndex+13)); //di+13
+ if(temp1&0x08){
+ tempbx=tempbx|0x0400;
+ }
+ tempcl= *((UCHAR *)(ROMAddr+REFIndex+9)); //di+9
+ tempcx=(tempcx&0xFF00)|(tempcl&0x00FF);
+ }
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x10,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ tempah=((tempbh<<4)&0x0FF)|(tempcx&0x0F);
+ SetReg1(Part1Port,0x11,tempah);
+
+ if(HwDeviceExtension->jChipID == SIS_Glamour)
+ {
+ tempah=0x10;
+ if((LCDResInfo!=Panel1024x768)&&(LCDResInfo==Panel1280x1024)){
+ tempah=0x20;
+ }
+ }else{
+ tempah=0x20;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ tempah=0x08;
+ }
+
+ SetRegANDOR(Part1Port,0x13,~0x03C,tempah);
+
+ if(!(VBInfo&SetInSlaveMode)){
+ REFIndex=OldREFIndex;
+ return;
+ }
+ if(VBInfo&SetCRT2ToTV){
+ tempax=0xFFFF;
+ }else{
+ tempax=GetVGAHT2();
+ }
+ tempcl=0x08; //Reg 0x03 Horozontal Total
+ temp1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(!(temp1&Charx8Dot)){ //temp1->St_ModeFlag
+ tempcl=0x09;
+ }
+ if(tempax>=VGAHT){
+ tempax=VGAHT;
+ }
+ if(temp1&HalfDCLK){
+ tempax=tempax>>1;
+ }
+ tempax=(tempax/tempcl)-5;
+ tempbl=tempax;
+ tempah=0xFF; //set MAX HT
+ SetReg1(Part1Port,0x03,tempah);
+
+ tempax=VGAHDE; //0x04 Horizontal Display End
+ if(temp1&HalfDCLK){
+ tempax=tempax>>1;
+ }
+ tempax=(tempax/tempcl)-1;
+ tempbh=tempax;
+ SetReg1(Part1Port,0x04,tempax);
+
+ tempah=tempbh;
+ if(VBInfo&SetCRT2ToTV){
+ tempah=tempah+2;
+ }
+ SetReg1(Part1Port,0x05,tempah); //0x05 Horizontal Display Start
+ SetReg1(Part1Port,0x06,0x03); //0x06 Horizontal Blank end
+ //0x07 horizontal Retrace Start
+ tempcx=(tempbl+tempbh)>>1;
+ tempah=(tempcx&0xFF)+2;
+
+ if(VBInfo&SetCRT2ToTV){
+ tempah=tempah-1;
+ if(!(temp1&HalfDCLK)){
+ if((temp1&Charx8Dot)){
+ tempah=tempah+4;
+ if(VGAHDE>=800){
+ tempah=tempah-6;
+ }
+ }
+ }
+ }else{
+ if(!(temp1&HalfDCLK)){
+ tempah=tempah-4;
+ if(VGAHDE>=800){
+ tempah=tempah-7;
+ if(ModeType==ModeEGA){
+ if(VGAVDE==1024){
+ tempah=tempah+15;
+ if(LCDResInfo!=Panel1280x1024){
+ tempah=tempah+7;
+ }
+ }
+ }
+ if(VGAHDE>=1280){
+ tempah=tempah+28;
+ }
+ }
+ }
+ }
+
+ SetReg1(Part1Port,0x07,tempah);//0x07 Horizontal Retrace Start
+
+ SetReg1(Part1Port,0x08,0); //0x08 Horizontal Retrace End
+ SetReg1(Part1Port,0x18,0x03); //0x18 SR08
+ SetReg1(Part1Port,0x19,0); //0x19 SR0C
+ SetReg1(Part1Port,0x09,0xFF); //0x09 Set Max VT
+
+ tempcx=0x121;
+ tempcl=0x21;
+ tempch=0x01;
+ tempbx=VGAVDE; //0x0E Virtical Display End
+ if(tempbx==360) tempbx=350;
+ if(tempbx==375) tempbx=350;
+ if(tempbx==405) tempbx=400;
+ tempbx--;
+ tempah=tempbx&0x0FF;
+ SetReg1(Part1Port,0x0E,tempah);
+ SetReg1(Part1Port,0x10,tempah);//0x10 vertical Blank Start
+ tempbh=(tempbx&0xFF00)>>8;
+ if(tempbh&0x01){
+ tempcl=tempcl|0x0A;
+ }
+ tempah=0;tempal=0x0B;
+ if(temp1&DoubleScanMode){
+ tempah=tempah|0x080;
+ }
+ if(tempbh&0x02){
+ tempcl=tempcl|0x040;
+ tempah=tempah|0x020;
+ }
+ SetReg1(Part1Port,0x0B,tempah);
+ if(tempbh&0x04){
+ tempch=tempch|0x06;
+ }
+
+ SetReg1(Part1Port,0x11,0); //0x11 Vertival Blank End
+
+ tempax=VGAVT-tempbx; //0x0C Vertical Retrace Start
+ tempax=tempax>>2;
+ temp2=tempax; //push ax
+ tempax=tempax<<1;
+ tempbx=tempax+tempbx;
+ if((SetFlag&TVSimuMode)&&(VBInfo&SetPALTV)&&(VGAHDE==800)){
+ tempbx=tempbx+40;
+ }
+ tempah=(tempbx&0x0FF);
+ SetReg1(Part1Port,0x0C,tempah);
+ tempbh=(tempbx&0xFF00)>>8;
+ if(tempbh&0x01){
+ tempcl=tempcl|0x04;
+ }
+ if(tempbh&0x02){
+ tempcl=tempcl|0x080;
+ }
+ if(tempbh&0x04){
+ tempch=tempch|0x08;
+ }
+
+ tempax=temp2; //pop ax
+ tempax=(tempax>>2)+1;
+ tempbx=tempbx+tempax;
+ tempah=(tempbx&0x0FF)&0x0F;
+ SetReg1(Part1Port,0x0D,tempah); //0x0D vertical Retrace End
+ tempbl=tempbx&0x0FF;
+ if(tempbl&0x10){
+ tempch=tempch|0x020;
+ }
+
+ tempah=tempcl;
+ SetReg1(Part1Port,0x0A,tempah); //0x0A CR07
+ tempah=tempch;
+ SetReg1(Part1Port,0x17,tempah); //0x17 SR0A
+ tempax=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempah=(tempax&0xFF00)>>8;
+ tempah=(tempah>>1)&0x09;
+ SetReg1(Part1Port,0x16,tempah); //0x16 SR01
+ SetReg1(Part1Port,0x0F,0); //0x0F CR14
+ SetReg1(Part1Port,0x12,0); //0x12 CR17
+ SetReg1(Part1Port,0x1A,0); //0x1A SR0E
+
+ REFIndex=OldREFIndex; //pop di
+}
+
+VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr)
+{
+ USHORT offset;
+ if(VBInfo&SetInSlaveMode){
+ return;
+ }
+ offset=GetOffset(ROMAddr);
+ SetReg1(Part1Port,0x07,(USHORT)(offset&0xFF));
+ SetReg1(Part1Port,0x09,(USHORT)((offset&0xFF00)>>8));
+ SetReg1(Part1Port,0x03,(USHORT)(((offset>>3)&0xFF)+1));
+}
+
+USHORT GetOffset(ULONG ROMAddr)
+{
+ USHORT tempal,temp1,colordepth;
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x03)); // si+Ext_ModeInfo
+ tempal=(tempal>>4)&0xFF;
+ ScreenOffset=*((USHORT *)(ROMAddr+0x206)); // Get ScreeOffset table
+ tempal=*((UCHAR *)(ROMAddr+ScreenOffset+tempal)); // get ScreenOffset
+ tempal=tempal&0xFF;
+ temp1=*((UCHAR *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ if(temp1&InterlaceMode){
+ tempal=tempal<<1;
+ }
+ colordepth=GetColorDepth(ROMAddr);
+ return(tempal*colordepth);
+}
+
+USHORT GetColorDepth(ULONG ROMAddr)
+{
+ USHORT ColorDepth[6]={1,2,4,4,6,8};
+ USHORT temp;
+ int temp1;
+ temp=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ temp1=(temp&ModeInfoFlag)-ModeEGA;
+ if(temp1<0) temp1=0;
+ return(ColorDepth[temp1]);
+}
+
+VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT temp,temp1,temp2,temp3,flag;
+ USHORT vclk2ptr,latencyindex;
+ USHORT oldREFIndex,CRT1ModeNo,oldModeIDOffset;
+ long int longtemp;
+
+ USHORT LatencyFactor[48]={ 88, 80, 78, 72, 70, 00, // 64 bit BQ=2
+ 00, 79, 77, 71, 69, 49, // 64 bit BQ=1
+ 88, 80, 78, 72, 70, 00, // 128 bit BQ=2
+ 00, 72, 70, 64, 62, 44, // 128 bit BQ=1
+ 73, 65, 63, 57, 55, 00, // 64 bit BQ=2
+ 00, 64, 62, 56, 54, 34, // 64 bit BQ=1
+ 78, 70, 68, 62, 60, 00, // 128 bit BQ=2
+ 00, 62, 60, 54, 52, 34}; // 128 bit BQ=1
+
+ oldREFIndex=(USHORT)REFIndex; //push REFIndex(CRT2 now)
+ oldModeIDOffset=(USHORT)ModeIDOffset; //push ModeIDOffset
+
+ CRT1ModeNo=(UCHAR)GetReg1(P3d4,0x34); //get CRT1 ModeNo
+ SearchModeID(ROMAddr,CRT1ModeNo); //Get ModeID Table
+
+ GetRatePtr(ROMAddr,CRT1ModeNo); //Set REFIndex-> for crt1 refreshrate
+ temp1=GetVCLK(ROMAddr,CRT1ModeNo,HwDeviceExtension);
+ temp2=GetColorTh(ROMAddr);
+ temp3=GetMCLK(ROMAddr);
+ temp=((USHORT)(temp1*temp2)/temp3); //temp->bx
+ temp1=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ temp1=temp1>>6;
+ temp1=temp1<<1;
+ if(temp1==0) temp1=1;
+ temp1=temp1<<2; //temp1->ax
+
+ longtemp=temp1-temp;
+
+ temp2=(USHORT)((28*16)/(int)longtemp); //temp2->cx
+ if(!((temp2*(int)longtemp)==(28*16))) temp2++;
+
+ if( HwDeviceExtension->jChipID == SIS_Glamour ){
+ temp1=CalcDelay();
+ }else{ //for Trojan and Spartan
+ flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ if(flag&0x80){
+ latencyindex=12; //128 bit
+ }else{
+ latencyindex=0; //64 bit
+ }
+ flag=GetQueueConfig();
+ if(!(flag&0x01)){
+ latencyindex+=24; //GUI timing =0
+ }
+ if(flag&0x10){
+ latencyindex+=6; //BQ =2
+ }
+ latencyindex=latencyindex + (flag>>5);
+ temp1= LatencyFactor[latencyindex];
+ temp1=temp1+15;
+ flag=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ if(!(flag&0x80)){
+ temp1=temp1+5; //64 bit
+ }
+ }
+
+ temp2=temp2+temp1;
+ REFIndex=oldREFIndex; //pop REFIndex(CRT2)
+ ModeIDOffset=oldModeIDOffset; //pop ModeIDOffset
+
+ vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo);
+ temp1=*((USHORT *)(ROMAddr+vclk2ptr+(VCLKLen-2)));
+ temp3=GetColorTh(ROMAddr);
+ longtemp=temp1*temp2*temp3;
+ temp3=GetMCLK(ROMAddr);
+ temp3=temp3<<4;
+ temp2=(int)(longtemp/temp3);
+ if((long int)temp2*(long int)temp3<(long int)longtemp) temp2++; //temp2->cx
+
+ temp1=(UCHAR)GetReg1(Part1Port,0x01); //part1port index 01
+
+
+ if( (HwDeviceExtension->jChipID == SIS_Trojan ) &&
+ ((HwDeviceExtension->revision_id & 0xf0) == 0x30) ) /* 630s */
+ {
+ temp1=(temp1&(~0x1F))|0x19;
+ }else
+ {
+ temp1=(temp1&(~0x1F))|0x16;
+ }
+ SetReg1(Part1Port,0x01,temp1);
+
+ if(temp2<=6) temp2=6;
+ if(temp2>0x14) temp2=0x14;
+ temp1=(UCHAR)GetReg1(Part1Port,0x02); //part1port index 02
+ temp1=(temp1&(~0x1F))|temp2;
+ SetReg1(Part1Port,0x02,temp1);
+}
+
+USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT tempptr;
+ USHORT temp1;
+ tempptr=GetVCLKPtr(ROMAddr,ModeNo);
+ temp1=*((USHORT *)(ROMAddr+tempptr+(VCLKLen-2)));
+
+ return temp1;
+}
+
+USHORT GetQueueConfig(void)
+{
+ USHORT tempal,tempbl;
+ ULONG tempeax;
+
+ SetReg4(0xcf8,0x80000050);
+ tempeax=GetReg3(0xcfc);
+ tempeax=(tempeax>>24)&0x0f;
+ tempbl=(USHORT)tempeax;
+ tempbl=tempbl<<4;
+
+ SetReg4(0xcf8,0x800000A0);
+ tempeax=GetReg3(0xcfc);
+ tempeax=(tempeax>>24)&0x0f;
+ tempal=(USHORT)tempeax;
+ tempbl=tempbl|tempal;
+
+ return(tempbl);
+}
+
+USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal;
+ tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch
+ tempal=((tempal>>2)&0x03);
+ if(ModeNo>0x13){
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ }
+ VCLKLen=GetVCLKLen(ROMAddr);
+ tempal=tempal*VCLKLen;
+ tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData
+ return ((USHORT)tempal);
+}
+
+USHORT GetColorTh(ULONG ROMAddr)
+{
+ USHORT temp;
+ temp=GetColorDepth(ROMAddr);
+ temp=temp>>1;
+ if(temp==0) temp++;
+ return temp;
+}
+
+USHORT GetMCLK(ULONG ROMAddr)
+{
+ USHORT tempmclkptr;
+ USHORT tempmclk;
+ tempmclkptr=GetMCLKPtr(ROMAddr);
+ tempmclk=*((USHORT *)(ROMAddr+tempmclkptr+0x03)); //di+3
+ return tempmclk;
+}
+
+USHORT GetMCLKPtr(ULONG ROMAddr)
+{
+ USHORT tempdi;
+ USHORT tempdramtype,tempax;
+
+ tempdi=*((USHORT *)(ROMAddr+0x20C)); // MCLKData
+ tempdramtype=GetDRAMType(ROMAddr);
+ tempax=5*tempdramtype;
+ tempdi=tempdi+tempax;
+ return (tempdi);
+}
+
+USHORT GetDRAMType(ULONG ROMAddr)
+{
+ USHORT tsoftsetting,temp3;
+
+ tsoftsetting=*((UCHAR *)(ROMAddr+0x52));
+ if(!(tsoftsetting&SoftDramType)){
+ temp3=(UCHAR)GetReg1(P3c4,0x3A);
+ tsoftsetting=temp3;
+ }
+ tsoftsetting=tsoftsetting&0x07;
+ return(tsoftsetting);
+}
+
+static USHORT CalcDelay()
+{
+ USHORT tempal,tempah,temp1,tempbx;
+ USHORT ThTiming[8]={1,2,2,3,0,1,1,2};
+ USHORT ThLowB[24]={81,4,72,6,88,8,120,12,
+ 55,4,54,6,66,8,90,12,
+ 42,4,45,6,55,8,75,12};
+
+ tempah=(UCHAR)GetReg1(P3c4,0x18); //SR_18
+ tempah=tempah&0x62;
+ tempah=tempah>>1;
+ tempal=tempah;
+ tempah=tempah>>3;
+ tempal=tempal|tempah;
+ tempal=tempal&0x07;
+
+ temp1=ThTiming[tempal]; //temp1->cl
+
+ tempbx=(UCHAR)GetReg1(P3c4,0x16); //SR_16
+ tempbx=tempbx>>6;
+ tempah=(UCHAR)GetReg1(P3c4,0x14); //SR_14
+ tempah=((tempah>>4)&0x0C);
+ tempbx=((tempbx|tempah)<<1);
+
+ tempal=ThLowB[tempbx+1]*temp1;
+ tempbx=ThLowB[tempbx];
+ tempbx=tempal+tempbx;
+
+ return(tempbx);
+}
+
+USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal;
+ USHORT LCDXlat1VCLK[4]={VCLK65,VCLK65,VCLK65,VCLK65};
+ USHORT LCDXlat2VCLK[4]={VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
+
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x04)); // di+Ext_CRT2CRTC
+ }
+ tempal=tempal>>6;
+ if(LCDResInfo!=Panel1024x768){
+ tempal=LCDXlat2VCLK[tempal];
+ }else{
+ tempal=LCDXlat1VCLK[tempal];
+ }
+
+ if(VBInfo&SetCRT2ToLCD){
+ tempal=tempal;
+ }else if(VBInfo&SetCRT2ToTV){
+ if(SetFlag&RPLLDIV2XO){
+ tempal=TVVCLKDIV2;
+ }else{
+ tempal=TVVCLK;
+ }
+ }else{
+ tempal=(UCHAR)GetReg2((USHORT)(P3ca+0x02)); // Port 3cch
+ tempal=((tempal>>2)&0x03);
+ if(ModeNo>0x13){
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ }
+ }
+ VCLKLen=GetVCLKLen(ROMAddr);
+ tempal=tempal*VCLKLen;
+ tempal=tempal+(*((USHORT *)(ROMAddr+0x208))); // VCLKData
+ return ((USHORT)tempal);
+}
+
+USHORT GetVCLKLen(ULONG ROMAddr)
+{
+ USHORT VCLKDataStart,vclklabel,temp;
+ VCLKDataStart=*((USHORT *)(ROMAddr+0x208));
+ for(temp=0;;temp++){
+ vclklabel=*((USHORT *)(ROMAddr+VCLKDataStart+temp));
+ if(vclklabel==VCLKStartFreq){
+ temp=temp+2;
+ return(temp);
+ }
+ }
+ return(0);
+}
+
+
+VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT temp1,tempah=0;
+ USHORT temp;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ if(IF_DEF_LVDS==1){ //LVDS
+ if(VBInfo&SetCRT2ToLCD){
+ tempah=LCDInfo;
+ if(!(tempah&LCDSync)){
+ temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ tempah=(temp>>8)&0x0C0;
+ }else{
+ tempah=tempah&0x0C0;
+ }
+ }
+ }else{
+ temp=*((USHORT *)(ROMAddr+REFIndex)); //di+Ext_InfoFlag
+ tempah=(temp>>8)&0x0C0;
+ }
+ temp1=(UCHAR)GetReg1(Part1Port,0x19); //part1port index 02
+ temp1=(temp1&(~0x0C0))|tempah;
+ SetReg1(Part1Port,0x19,temp1);
+}
+
+VOID GetCRT1Ptr(ULONG ROMAddr)
+{
+ USHORT temprefcrt1;
+ USHORT temp;
+ temp=*((UCHAR *)(ROMAddr+REFIndex+0x02)); //di+Ext_CRT1CRTC
+ temp=temp&0x03F;
+ temp=temp*CRT1Len;
+ temprefcrt1=*((USHORT *)(ROMAddr+0x204)); // Get CRT1Table
+ REFIndex=temprefcrt1+temp; // di->CRT1Table+Ext_CRT1CRTC*CRT1Len
+}
+
+USHORT GetVGAHT2()
+{
+ long int temp1,temp2;
+
+ temp1=(VGAVT-VGAVDE)*RVBHCMAX;
+ temp1=temp1&0x0FFFF;
+ temp2=(VT-VDE)*RVBHCFACT;
+ temp2=temp2&0x0FFFF;
+ temp2=temp2*HT;
+ temp2=temp2/temp1;
+ return((USHORT)temp2);
+}
+
+VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT tempah,tempbl,tempbh,tempcl,i,j,tempcx,pushcx,tempbx,tempax;
+ USHORT tempmodeflag,tempflowflag;
+ UCHAR *temp1;
+ USHORT *temp2;
+ USHORT pushbx;
+ USHORT Part2Port;
+ long int longtemp;
+
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+
+ tempcx=VBInfo;
+ tempah=VBInfo&0x0FF;
+ tempbl=VBInfo&0x0FF;
+ tempbh=VBInfo&0x0FF;
+ tempbx=(tempbl&0xFF)|(tempbh<<8);
+ tempbl=tempbl&0x10;
+ tempbh=(tempbh&0x04)<<1;
+ tempah=(tempah&0x08)>>1;
+ tempah=tempah|tempbh;
+ tempbl=tempbl>>3;
+ tempah=tempah|tempbl;
+ tempah=tempah^0x0C;
+
+ if(VBInfo&SetPALTV){
+ temp1=(UCHAR *)(ROMAddr+0x0F1); //PALPhase
+ temp2=PALTiming;
+ }else{
+ tempah=tempah|0x10;
+ temp1=(UCHAR *)(ROMAddr+0x0ED); //NTSCPhase
+ temp2=NTSCTiming;
+ }
+
+ SetReg1(Part2Port,0x0,tempah);
+ for(i=0x31;i<=0x34;i++,temp1++){
+ SetReg1(Part2Port,i,*(UCHAR *)temp1);
+ }
+ for(i=0x01,j=0;i<=0x2D;i++,j++){
+ SetReg1(Part2Port,i,temp2[j]);
+ }
+ for(i=0x39;i<=0x45;i++,j++){
+ SetReg1(Part2Port,i,temp2[j]); //di->temp2[j]
+ }
+
+ tempah=GetReg1(Part2Port,0x0A);
+ tempah=tempah|NewFlickerMode;
+ SetReg1(Part2Port,0x0A,tempah);
+
+ SetReg1(Part2Port,0x35,RY1COE);
+ SetReg1(Part2Port,0x36,RY2COE);
+ SetReg1(Part2Port,0x37,RY3COE);
+ SetReg1(Part2Port,0x38,RY4COE);
+
+ tempcx=HT-1;
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x1B,tempah);
+ tempah=(tempcx&0xFF00)>>8;
+ SetRegANDOR(Part2Port,0x1D,~0x0F,(UCHAR)tempah);
+
+ tempcx=HT>>1;
+ pushcx=tempcx;
+
+ tempcx=tempcx+7;
+ tempah=(tempcx&0xFF);
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x22,~0x0F0,tempah);
+
+
+ tempbx=temp2[j];
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x24,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x25,~0x0F0,tempah);
+
+ tempbx=tempbx+8;
+
+ tempah=((tempbx&0xFF)<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x29,~0x0F0,tempah);
+
+ tempcx=tempcx+temp2[++j];
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x27,tempah);
+ tempah=(((tempcx&0xFF00)>>8)<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x28,~0x0F0,tempah);
+
+ tempcx=tempcx+8;
+
+ tempah=tempcx&0xFF;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2A,~0x0F0,tempah);
+
+ tempcx=pushcx; //pop cx
+ tempcx=tempcx-temp2[++j];
+ tempah=tempcx&0xFF;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2D,~0x0F0,tempah);
+
+ tempcx=tempcx-11;
+ if(!(VBInfo&SetCRT2ToTV)){
+ tempax=GetVGAHT2();
+ tempcx=tempax-1;
+ }
+ tempah=tempcx&0xFF;
+ SetReg1(Part2Port,0x2E,tempah);
+
+ tempbx=VDE;
+ if(VGAVDE==360){
+ tempbx=746;
+ }
+ if(VGAVDE==375){
+ tempbx=746;
+ }
+ if(VGAVDE==405){
+ tempbx=853;
+ }
+ if((VBInfo&SetCRT2ToTV)){
+ tempbx=tempbx>>1;
+ }
+
+ tempbx=tempbx-2;
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x2F,tempah);
+
+ tempah=(tempcx&0xFF00)>>8;
+ tempbh=(tempbx&0xFF00)>>8;
+ tempbh=(tempbh<<6)&0xFF;
+ tempah=tempah|tempbh;
+ //assuming <<ifndef>> hivisiontv
+ tempah=tempah|0x10;
+ if(!(VBInfo&SetCRT2ToSVIDEO)){
+ tempah=tempah|0x20;
+ }
+
+ SetReg1(Part2Port,0x30,tempah);
+
+ tempbh=0;
+ tempbx=tempbx&0xFF;
+
+ tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempflowflag=0;
+ if(!(tempmodeflag&HalfDCLK)){
+ tempcx=VGAHDE;
+ if(tempcx>=HDE){
+ tempbh=tempbh|0x20;
+ tempbx=(tempbh<<8)|(tempbx&0xFF);
+ tempah=0;
+ }
+ }
+ tempcx=0x0101;
+ if(!(tempbh&0x20)){
+ if(tempmodeflag&HalfDCLK){
+ tempcl=((tempcx&0xFF)<<1)&0xFF;
+ tempcx=(tempcx&0xFF00)|tempcl;
+ }
+ pushbx=tempbx;
+ tempax=VGAHDE;
+ tempbx=(tempcx&0xFF00)>>8;
+ longtemp=tempax*tempbx;
+ tempcx=tempcx&0xFF;
+ longtemp=longtemp/tempcx;
+ longtemp=longtemp*8*1024;
+ tempax=(USHORT)((longtemp)/HDE);
+ if(tempax*HDE<longtemp){
+ tempax=tempax+1;
+ }else{
+ tempax=tempax;
+ }
+ tempbx=pushbx;
+ tempah=((tempax&0xFF00)>>8)&0x01F;
+ tempbh=tempbh|tempah;
+ tempah=tempax&0xFF;
+ }
+
+ SetReg1(Part2Port,0x44,tempah);
+ tempah=tempbh;
+ SetRegANDOR(Part2Port,0x45,~0x03F,tempah);
+
+ if(VBInfo&SetCRT2ToTV){
+ return;
+ }
+
+ tempah=0x01;
+ if(LCDResInfo==Panel1280x1024){
+ if(ModeType==ModeEGA){
+ if(VGAHDE>=1024){
+ tempah=0x02;
+ }
+ }
+ }
+ SetReg1(Part2Port,0x0B,tempah);
+
+ tempbx=HDE-1; //RHACTE=HDE-1
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x2C,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x2B,~0x0F0,tempah);
+
+ tempbx=VDE-1; //RTVACTEO=(VDE-1)&0xFF
+ tempah=tempbx&0xFF;
+ SetReg1(Part2Port,0x03,tempah);
+ tempah=((tempbx&0xFF00)>>8)&0x07;
+ SetRegANDOR(Part2Port,0x0C,~0x07,tempah);
+
+ tempcx=VT-1;
+ tempah=tempcx&0xFF; //RVTVT=VT-1
+ SetReg1(Part2Port,0x19,tempah);
+ tempah=(tempcx&0xFF00)>>8;
+ tempah=(tempah<<5)&0xFF;
+ if(LCDInfo&LCDRGB18Bit){
+ tempah=tempah|0x10;
+ }
+ SetReg1(Part2Port,0x1A,tempah);
+
+ tempcx++;
+ if(LCDResInfo==Panel1024x768){
+ tempbx=768;
+ }else{
+ tempbx=1024;
+ }
+
+ if(tempbx==VDE){
+ tempax=1;
+ }else{
+ tempax=tempbx;
+ tempax=(tempax-VDE)>>1;
+ }
+ tempcx=tempcx-tempax; //lcdvdes
+ tempbx=tempbx-tempax; //lcdvdee
+
+ tempah=tempcx&0xFF; //RVEQ1EQ=lcdvdes
+ SetReg1(Part2Port,0x05,tempah);
+ tempah=tempbx&0xFF; //RVEQ2EQ=lcdvdee
+ SetReg1(Part2Port,0x06,tempah);
+
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<3)&0xFF;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ //RTVACTSE=(lcdvdes&0x700>>8)+(lcdvdee&0x700>>5);
+ SetReg1(Part2Port,0x02,tempah);
+
+
+ tempcx=(VT-VDE)>>4; //(VT-VDE)>>4
+ tempbx=(VT+VDE)>>1;
+ tempah=tempbx&0xFF; //RTVACTEE=lcdvrs
+ SetReg1(Part2Port,0x04,tempah);
+
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ tempbx=tempbx+tempcx+1;
+ tempbl=(tempbx&0x0F);
+ tempah=tempah|tempbl; //RTVACTSO=lcdvrs&0x700>>4+lcdvre
+ SetReg1(Part2Port,0x01,tempah);
+
+ tempah=GetReg1(Part2Port,0x09);
+ tempah=tempah&0xF0;
+ SetReg1(Part2Port,0x09,tempah);
+
+ tempah=GetReg1(Part2Port,0x0A);
+ tempah=tempah&0xF0;
+ SetReg1(Part2Port,0x0A,tempah);
+
+ tempcx=(HT-HDE)>>2; //(HT-HDE)>>2
+ tempbx=(HDE+7); //lcdhdee
+ tempah=tempbx&0xFF; //RHEQPLE=lcdhdee
+ SetReg1(Part2Port,0x23,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ SetRegANDOR(Part2Port,0x25,~0x0F,tempah);
+
+ SetReg1(Part2Port,0x1F,0x07); //RHBLKE=lcdhdes
+ tempah=GetReg1(Part2Port,0x20);
+ tempah=tempah&0x0F;
+ SetReg1(Part2Port,0x20,tempah);
+
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF; //RHBURSTS=lcdhrs
+ SetReg1(Part2Port,0x1C,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ tempah=(tempah<<4)&0xFF;
+ SetRegANDOR(Part2Port,0x1D,~0x0F0,tempah);
+
+ tempbx=tempbx+tempcx;
+ tempah=tempbx&0xFF; //RHSYEXP2S=lcdhre
+ SetReg1(Part2Port,0x21,tempah);
+
+ tempah=GetReg1(Part2Port,0x17);
+ tempah=tempah&0xFB;
+ SetReg1(Part2Port,0x17,tempah);
+
+ tempah=GetReg1(Part2Port,0x18);
+ tempah=tempah&0xDF;
+ SetReg1(Part2Port,0x18,tempah);
+ return;
+}
+
+VOID SetGroup3(USHORT BaseAddr)
+{
+ USHORT i;
+ USHORT *tempdi;
+ USHORT Part3Port;
+ Part3Port=BaseAddr+IND_SIS_CRT2_PORT_12;
+ if(VBInfo&SetPALTV){
+ tempdi=PALGroup3Data;
+ }else{
+ tempdi=NTSCGroup3Data;
+ }
+
+ for(i=0;i<=0x3E;i++){
+ SetReg1(Part3Port,i,tempdi[i]);
+ }
+ return;
+}
+
+VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT Part4Port;
+ USHORT tempax,tempah,tempcx,tempbx,tempbh,tempch,tempmodeflag;
+ long int tempebx,tempeax,templong;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+
+ tempax=0x0c;
+ if(VBInfo&SetCRT2ToTV){
+ if(VBInfo&SetInSlaveMode){
+ if(!(SetFlag&TVSimuMode)){
+ SetFlag=SetFlag|RPLLDIV2XO;
+ tempax=tempax|0x04000;
+ }
+ }else{
+ SetFlag=SetFlag|RPLLDIV2XO;
+ tempax=tempax|0x04000;
+ }
+ }
+
+ if(LCDResInfo!=Panel1024x768){
+ tempax=tempax|0x08000;
+ }
+ tempah=(tempax&0xFF00)>>8;
+ SetReg1(Part4Port,0x0C,tempah);
+
+ tempah=RVBHCFACT;
+ SetReg1(Part4Port,0x13,tempah);
+
+ tempbx=RVBHCMAX;
+ tempah=tempbx&0xFF;
+ SetReg1(Part4Port,0x14,tempah);
+ tempbh=(((tempbx&0xFF00)>>8)<<7)&0xFF;
+
+ tempcx=VGAHT-1;
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x16,tempah);
+ tempch=(((tempcx&0xFF00)>>8)<<3)&0xFF;
+ tempbh=tempbh|tempch;
+
+ tempcx=VGAVT-1;
+ if(!(VBInfo&SetCRT2ToTV)){
+ tempcx=tempcx-5;
+ }
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x17,tempah);
+ tempbh=tempbh|((tempcx&0xFF00)>>8);
+ tempah=tempbh;
+ SetReg1(Part4Port,0x15,tempah);
+
+ tempcx=VBInfo;
+ tempbx=VGAHDE;
+ tempmodeflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(tempmodeflag&HalfDCLK){
+ tempbx=tempbx>>1;
+ }
+
+ if(VBInfo&SetCRT2ToLCD){
+ tempah=0;
+ if(tempbx>800){
+ tempah=0x60;
+ }
+ }else{
+ tempah=0x080;
+ }
+ if(LCDResInfo!=Panel1280x1024){
+ tempah=tempah|0x0A;
+ }
+
+ SetRegANDOR(Part4Port,0x0E,~0xEF,tempah);
+
+ tempebx=VDE;
+
+ tempcx=RVBHRS;
+ tempah=tempcx&0xFF;
+ SetReg1(Part4Port,0x18,tempah);
+
+ tempeax=VGAVDE;
+ tempcx=tempcx|0x04000;
+ tempeax=tempeax-tempebx;
+ if(tempeax<0){
+ tempcx=tempcx^(0x04000);
+ tempeax=VGAVDE;
+ }
+
+ templong=(tempeax*256*1024)/tempebx;
+ if(tempeax*256*1024-templong*tempebx>0){
+ tempebx=templong+1;
+ }else{
+ tempebx=templong;
+ }
+
+
+ tempah=(USHORT)(tempebx&0xFF);
+ SetReg1(Part4Port,0x1B,tempah);
+ tempah=(USHORT)((tempebx&0xFF00)>>8);
+ SetReg1(Part4Port,0x1A,tempah);
+ tempebx=tempebx>>16;
+ tempah=(USHORT)(tempebx&0xFF);
+ tempah=(tempah<<4)&0xFF;
+ tempah=tempah|((tempcx&0xFF00)>>8);
+ SetReg1(Part4Port,0x19,tempah);
+
+ SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo);
+}
+
+VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT vclk2ptr;
+ USHORT tempah,temp1;
+ USHORT Part4Port;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ vclk2ptr=GetVCLK2Ptr(ROMAddr,ModeNo);
+ SetReg1(Part4Port,0x0A,0x01);
+ tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x01)); //di+1
+ SetReg1(Part4Port,0x0B,tempah);
+ tempah=*((UCHAR *)(ROMAddr+vclk2ptr+0x00)); //di
+ SetReg1(Part4Port,0x0A,tempah);
+ SetReg1(Part4Port,0x12,0x00);
+ tempah=0x08;
+ if(VBInfo&SetCRT2ToRAMDAC){
+ tempah=tempah|0x020;
+ }
+ temp1=GetReg1(Part4Port,0x12);
+ tempah=tempah|temp1;
+ SetReg1(Part4Port,0x12,tempah);
+}
+
+VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT Part5Port;
+ USHORT Pindex,Pdata;
+ Part5Port=BaseAddr+IND_SIS_CRT2_PORT_14+2;
+ Pindex=Part5Port;
+ Pdata=Part5Port+1;
+ if(ModeType==ModeVGA){
+ if(!(VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){
+ EnableCRT2();
+ LoadDAC2(ROMAddr,Part5Port);
+ }
+ }
+ return;
+}
+
+VOID EnableCRT2()
+{
+ USHORT temp1;
+ temp1=GetReg1(P3c4,0x1E);
+ temp1=temp1|0x20;
+ SetReg1(P3c4,0x1E,temp1); //SR 1E
+}
+
+VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port)
+{
+ USHORT data,data2;
+ USHORT time,i,j,k;
+ USHORT m,n,o;
+ USHORT si,di,bx,dl;
+ USHORT al,ah,dh;
+ USHORT *table=VGA_DAC;
+ USHORT Pindex,Pdata;
+ Pindex=Part5Port;
+ Pdata=Part5Port+1;
+ data=*((USHORT *)(ROMAddr+ModeIDOffset+0x01));
+ data=data&DACInfoFlag;
+ time=64;
+ if(data==0x00) table=MDA_DAC;
+ if(data==0x08) table=CGA_DAC;
+ if(data==0x10) table=EGA_DAC;
+ if(data==0x18) {
+ time=256;
+ table=VGA_DAC;
+ }
+ if(time==256) j=16;
+ else j=time;
+
+ //SetReg3(P3c6,0xFF);
+ SetReg3(Pindex,0x00);
+
+ for(i=0;i<j;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) {
+ data2=0;
+ if(data&0x01) data2=0x2A;
+ if(data&0x02) data2=data2+0x15;
+ SetReg3(Pdata,data2);
+ data=data>>2;
+ }
+ }
+
+ if(time==256) {
+ for(i=16;i<32;i++) {
+ data=table[i];
+ for(k=0;k<3;k++) SetReg3(Pdata,data);
+ }
+ si=32;
+ for(m=0;m<9;m++) {
+ di=si;
+ bx=si+0x04;
+ dl=0;
+ for(n=0;n<3;n++) {
+ for(o=0;o<5;o++) {
+ dh=table[si];
+ ah=table[di];
+ al=table[bx];
+ si++;
+ WriteDAC2(Pdata,dl,ah,al,dh);
+ } // for 5
+ si=si-2;
+ for(o=0;o<3;o++) {
+ dh=table[bx];
+ ah=table[di];
+ al=table[si];
+ si--;
+ WriteDAC2(Pdata,dl,ah,al,dh);
+ } // for 3
+ dl++;
+ } // for 3
+ si=si+5;
+ } // for 9
+ }
+}
+
+VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh)
+{
+ USHORT temp;
+ USHORT bh,bl;
+
+ bh=ah;
+ bl=al;
+ if(dl!=0) {
+ temp=bh;
+ bh=dh;
+ dh=temp;
+ if(dl==1) {
+ temp=bl;
+ bl=dh;
+ dh=temp;
+ }
+ else {
+ temp=bl;
+ bl=bh;
+ bh=temp;
+ }
+ }
+ SetReg3(Pdata,(USHORT)dh);
+ SetReg3(Pdata,(USHORT)bh);
+ SetReg3(Pdata,(USHORT)bl);
+}
+
+VOID LockCRT2(USHORT BaseAddr)
+{
+ USHORT Part1Port;
+ USHORT Part4Port;
+ USHORT temp1;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ temp1=GetReg1(Part1Port,0x24);
+ temp1=temp1&0xFE;
+ SetReg1(Part1Port,0x24,temp1);
+}
+
+VOID SetLockRegs()
+{
+ USHORT temp1;
+
+ if((VBInfo&SetInSlaveMode)&&(!(VBInfo&SetCRT2ToRAMDAC))){
+ VBLongWait();
+ temp1=GetReg1(P3c4,0x32);
+ temp1=temp1|0x20;
+ SetReg1(P3c4,0x32,temp1);
+ VBLongWait();
+ }
+}
+
+VOID EnableBridge(USHORT BaseAddr)
+{
+ USHORT part2_02,part2_05;
+ USHORT Part2Port,Part1Port;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==0){
+ part2_02=(UCHAR)GetReg1(Part2Port,0x02);
+ part2_05=(UCHAR)GetReg1(Part2Port,0x05);
+ SetReg1(Part2Port,0x02,0x38);
+ SetReg1(Part2Port,0x05,0xFF);
+ LongWait();
+ SetRegANDOR(Part2Port,0x00,~0x0E0,0x020);
+ WaitVBRetrace(BaseAddr);
+ SetReg1(Part2Port,0x02,part2_02);
+ SetReg1(Part2Port,0x05,part2_05);
+ }else{
+ EnableCRT2();
+ UnLockCRT2(BaseAddr);
+ SetRegANDOR(Part1Port,0x02,~0x040,0x0);
+ }
+}
+
+USHORT GetLockInfo(USHORT pattern)
+{
+ USHORT temp1;
+ temp1=GetReg1(P3d4,0x36);
+ return(temp1&pattern);
+}
+
+VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT flag1,tempbx,tempbl,tempbh,tempah;
+
+ SetFlag=0;
+ tempbx=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ tempbl=tempbx&ModeInfoFlag;
+ ModeType=tempbl;
+ tempbx=0;
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ tempbl=GetReg1(P3d4,0x30);
+ tempbh=GetReg1(P3d4,0x31);
+ if(!(tempbl&0x07C)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ if(IF_DEF_LVDS==1){ //for LVDS
+ if(!(tempbl&SetCRT2ToLCD)){
+ VBInfo=CRT2DisplayFlag;
+ return;
+ }
+ }
+ if(IF_DEF_LVDS==0){ //for 301
+ if(tempbl&SetCRT2ToRAMDAC){
+ tempbl=tempbl&(SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToLCD){
+ tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToSCART){
+ tempbl=tempbl&(SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
+ }else if(tempbl&SetCRT2ToHiVisionTV){
+ tempbl=tempbl&(SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
+ }
+ }else{ //for LVDS
+ if(tempbl&SetCRT2ToLCD){
+ tempbl=tempbl&(SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+ }
+ }
+ tempah=GetReg1(P3d4,0x31);
+ if(tempah&(CRT2DisplayFlag>>8)){
+ if(!(tempbl&(SwitchToCRT2|SetSimuScanMode))){
+ tempbx=SetSimuScanMode|CRT2DisplayFlag;
+ tempbh=((tempbx&0xFF00)>>8);
+ tempbl=tempbx&0xFF;
+ }
+ }
+ if(!(tempbh&(DriverMode>>8))){
+ tempbl=tempbl|SetSimuScanMode;
+ }
+ VBInfo=tempbl|(tempbh<<8);
+ if(!(VBInfo&SetSimuScanMode)){
+ if(!(VBInfo&SwitchToCRT2)){
+ if(BridgeIsEnable(BaseAddr)){
+ if(BridgeInSlave()){
+ VBInfo=VBInfo|SetSimuScanMode;
+ }
+ }
+ }
+ }
+ if(!((VBInfo&(SetSimuScanMode|SwitchToCRT2)))){
+ return;
+ }
+ if(!(VBInfo&DriverMode)){
+ VBInfo=VBInfo|SetInSlaveMode;
+ if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){
+ SetFlag=SetFlag|TVSimuMode;
+ }
+ return;
+ }
+ flag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(!(flag1&(CRT2Mode|CRT2DisplayFlag))){
+ VBInfo=VBInfo|SetInSlaveMode;
+ if((VBInfo&SetCRT2ToTV)&&(!(VBInfo&SetNotSimuTVMode))){
+ SetFlag=SetFlag|TVSimuMode;
+ }
+ }
+}
+
+BOOLEAN BridgeIsEnable(USHORT BaseAddr)
+{
+ USHORT flag1;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+
+ if(IF_DEF_LVDS==1){
+ return 1;
+ }
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){ return 0;}
+ flag1=GetReg1(Part1Port,0x0);
+ if(flag1&0x0a0){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+BOOLEAN BridgeInSlave()
+{
+ USHORT flag1;
+ flag1=GetReg1(P3d4,0x31);
+ if(flag1&(SetInSlaveMode>>8)){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
+BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4)
+{
+ USHORT tempah,tempbh,tempflag;
+
+ tempah=(UCHAR)GetReg1(P3d4,0x36);
+ tempbh=tempah;
+ tempah=tempah&0x0F;
+ if(tempah>Panel1280x1024) tempah=Panel1024x768;
+ LCDResInfo=tempah;
+ tempbh=tempbh>>4;
+ LCDTypeInfo=tempbh;
+
+ tempah=(UCHAR)GetReg1(P3d4,0x37);
+ LCDInfo=tempah;
+ if(IF_DEF_TRUMPION){
+ LCDInfo=LCDInfo&(~LCDNonExpanding);
+ }
+ if(IF_DEF_LVDS==1){
+ tempflag=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(tempflag&HalfDCLK){
+ if(IF_DEF_TRUMPION==0){
+ if(!(LCDInfo&LCDNonExpanding)){
+ if(LCDResInfo==Panel1024x768){
+ tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(tempflag==4){ //512x384
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }else{
+ if(LCDResInfo==Panel800x600){
+ tempflag=*((UCHAR *)(ROMAddr+ModeIDOffset+0x09)); //si+Ext_ResInfo
+ if(tempflag==3){ //400x300
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }
+ }
+ }else{
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }else{
+ SetFlag=SetFlag|EnableLVDSDDA;
+ }
+ }
+ }
+
+ if(!(VBInfo&SetCRT2ToLCD)){
+ return 1;
+ }
+ if(!(VBInfo&(SetSimuScanMode|SwitchToCRT2))){
+ return 1;
+ }
+ if(VBInfo&SetInSlaveMode){
+ if(VBInfo&SetNotSimuTVMode){
+ SetFlag=SetFlag|LCDVESATiming;
+ }
+ }else{
+ SetFlag=SetFlag|LCDVESATiming;
+ }
+ return 1;
+}
+
+VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ SetReg1(P3d4,0x37,0x00);
+}
+
+BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT tempah;
+ tempah=(HwDeviceExtension->usLCDType);// set in sisv.c
+ //0:no lcd 1:1024x768 2:1280x1024
+ if(tempah>0) tempah++; // usLCDType:
+ // 0:no lcd 1:800x600 2:1024x768 3:1280x1024
+ SetReg1(P3d4,0x36,tempah);//cr 36 0:no LCD 1:800x600 2:1024x768 3:1280x1024
+ if(tempah>0) return 1;
+ else return 0;
+}
+
+VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr)
+{
+ USHORT tempah,temp;
+
+ if(IF_DEF_LVDS==0){ //301
+ if(PRIMARY_VGA==1){ //primary vga
+ if(HwDeviceExtension->jChipID >= SIS_Trojan){
+ tempah=GetReg1(P3c4,0x17);
+ if(tempah&ModeSwitchStatus){
+ tempah=GetReg1(P3c4,0x16);
+ tempah=tempah&ActivePAL;
+ tempah=tempah>>ActivePALShift;
+ }else{
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if(temp&SoftTVType){
+ tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr));
+ }else{
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ }
+ }
+ }else{
+ temp=*((UCHAR *)(ROMAddr+SoftSettingAddr));
+ if(temp&SoftTVType){
+ tempah=*((UCHAR *)(ROMAddr+ModeSettingAddr));
+ }else{
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ }
+ }
+ tempah=tempah&0x01; //get SR 38 D0 TV Type Selection
+ //0:NTSC 1:PAL
+ SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0
+ }
+ else{ //Secondary
+ tempah=GetReg1(P3c4,0x38); //SR 38
+ tempah=tempah&0x01; //get SR 38 D0 TV Type Selection
+ //0:NTSC 1:PAL
+ SetRegANDOR(P3d4,0x31,~0x01,tempah);//set CR 31 D0= SR 38 D0
+ }
+ return;
+ }else{ //LVDS
+ tempah=GetReg1(P3c4,0x16); //SR 16
+ tempah=tempah&ActiveNonExpanding;
+ tempah=tempah>>ActiveNonExpandingShift;
+ tempah=tempah&0x01;
+ tempah=tempah<<LCDNonExpandingShift;
+ SetRegANDOR(P3d4,0x37,~LCDNonExpanding,tempah);
+ return;
+ }
+}
+
+BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr)
+{
+ USHORT flag1,tempbx,tempal,tempah,tempcx,i;
+ USHORT Part2Port,Part4Port;
+ USHORT RGBSenseData,YCSenseData,VideoSenseData;
+ USHORT P2reg0,SenseModeNo,OutputSelect;
+ Part2Port=BaseAddr+IND_SIS_CRT2_PORT_10;
+ Part4Port=BaseAddr+IND_SIS_CRT2_PORT_14;
+ RGBSenseData=*((USHORT *)(ROMAddr+0xF8)); //0:F8 in rompost.asm
+ YCSenseData=*((USHORT *)(ROMAddr+0xFA)); //0:FA in rompost.asm
+ VideoSenseData=*((USHORT *)(ROMAddr+0xFC)); //0:FC in rompost.asm
+
+ if(IF_DEF_LVDS==1){
+ GetPanelID();
+ tempah=LCDSense;
+ SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32
+ return 0;
+ }
+
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if(!(flag1&0x20)){ return 0;}
+ P2reg0=GetReg1(Part2Port,0x00); //save Part2 Reg index 0
+
+ if(!(BridgeIsEnable(BaseAddr))){
+ SenseModeNo=0x2E;
+ ModeType=ModeVGA;
+ VBInfo=SetCRT2ToRAMDAC;
+ SetFlag=0;
+ SetCRT2Group(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+ //here perform I/O delay ,read SR 05
+ for(i=0;i<0x7FFF;i++){
+ flag1=GetReg1(P3c4,0x05);
+ }
+ }
+
+ SetReg1(Part2Port,0x00,0x1C); //Set part2 index 0= 0x1C
+ tempah=0;
+
+ OutputSelect=*((UCHAR *)(ROMAddr+0xFE)); //OutputSelect 0:FE in Rompost.asm
+ if(OutputSelect&SetSCARTOutput){
+ tempal=SCARTSense;
+ }else{
+ tempal=Monitor2Sense;
+ }
+ tempbx=RGBSenseData;
+ tempcx=0x0E08;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|tempal;
+ }
+ }
+ tempbx=YCSenseData;
+ tempcx=0x0604;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|SVIDEOSense;
+ //Skipped lines about HiTVSense, assuming not HiTV
+ }
+ }
+
+ //Assuming not HiTV ,below is of ifndef HiVisionTV
+ if(OutputSelect&BoardTVType){
+ tempbx=VideoSenseData;
+ tempcx=0x0804;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|AVIDEOSense;
+ }
+ }
+ }else{
+ if(!(tempah&SVIDEOSense)){
+ tempbx=VideoSenseData;
+ tempcx=0x0804;
+ if(Sense(Part4Port,tempbx,tempcx)){
+ if(Sense(Part4Port,tempbx,tempcx)){
+ tempah=tempah|AVIDEOSense;
+ }
+ }
+ }
+ }
+ //end of ifndef HivisionTv
+ if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){
+ if(SenseLCD(HwDeviceExtension,Part4Port,ROMAddr)){
+ tempah=tempah|LCDSense;
+ }
+ }
+
+ tempbx=0;
+ tempcx=0;
+ Sense(Part4Port,tempbx,tempcx);
+
+ SetRegANDOR(P3d4,0x32,~0x5F,tempah); //Set CR 32
+ SetReg1(Part2Port,0x00,P2reg0); //recover Part2 reg index 0
+
+ //here skipped lines about DisableCRT2Display
+ return 0;
+}
+
+BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx)
+{
+ USHORT tempah,tempcl,tempch;
+
+ tempah=inputbx&0xFF;
+ SetReg1(Part4Port,0x11,tempah);//Part4 index 11
+ tempah=(inputbx&0xFF00)>>8;
+ tempcl=inputcx&0xFF;
+ tempah=tempah|tempcl;
+ SetRegANDOR(Part4Port,0x10,~0x1F,tempah);//Part4 index 10
+
+ tempch=(inputcx&0xFF00)>>8;
+ tempch=tempch&0x7F;
+ //here skipped lines about call Delay
+ tempah=GetReg1(Part4Port,0x03); //Part4 index 03
+ tempah=tempah^(0x0E);
+ tempah=tempah&tempch;
+ if(tempah>0) return 1;
+ else return 0;
+}
+
+BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr)
+{
+ USHORT SoftSetting;
+ USHORT tempah;
+ SoftSetting=*((UCHAR *)(ROMAddr+0x52));//0:52 in rompost.asm
+ if(GetLCDDDCInfo(HwDeviceExtension)){
+ return 1;
+ }
+ if(SoftSetting&HotPlugFunction){
+ tempah=GetReg1(Part4Port,0x0F);
+ tempah=tempah&0x3F;
+ SetReg1(Part4Port,0x0F,tempah); //Part4 index 0F
+ if(Sense(Part4Port,0x0,0x9010)){
+ return 1;
+ }else{
+ return 0;
+ }
+ }else{
+ return 0;
+ }
+}
+#endif
+
+VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+ USHORT temp1;
+ temp1=GetReg1(Port,Index); //part1port index 02
+ temp1=(temp1&(DataAND))|DataOR;
+ SetReg1(Port,Index,temp1);
+}
+
+BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension)
+{
+ USHORT flag1 ;
+ USHORT DAC_TEST_PARMS[3]={0x0F,0x0F,0x0F};
+ USHORT DAC_CLR_PARMS[3]={0x00,0x00,0x00};
+
+ flag1=GetReg1(P3c4,0x38); //call BridgeisOn
+ if((flag1&0x20)){
+ SetReg1(P3d4,0x30,0x41);
+ }
+
+ SiSSetMode(HwDeviceExtension,0x2E); //set mode to 0x2E instead of 0x3
+
+ ClearDAC(P3c8);
+ ClearALLBuffer(HwDeviceExtension);
+
+ LongWait(); //wait vertical retrace
+ LongWait();
+
+ flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],
+ DAC_TEST_PARMS[2]);
+ if(flag1==0){
+ flag1=TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],
+ DAC_TEST_PARMS[2]);
+ }
+ if(flag1==1){
+ SetRegANDOR(P3d4,0x32,~Monitor1Sense,Monitor1Sense);
+ }else{
+ SetRegANDOR(P3d4,0x32,~Monitor1Sense,0x0);
+ }
+ TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
+
+ SetReg1(P3d4,0x34,0x4A); //Preset default CRT1 ModeNo =0x4A
+ //which is used in SetCRT2FIFO()
+ return 1;
+}
+
+BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3)
+{
+ USHORT temp;
+ SetReg3(P3c6,0xFF);
+ SetReg3(P3c8,0x00);
+ SetReg3(P3c9,d1);
+ SetReg3(P3c9,d2);
+ SetReg3(P3c9,d3);
+ WaitDisplay(); //wait horizontal retrace
+ temp=GetReg2(P3c2);
+ if(temp&0x10) return 1;
+ else return 0;
+}
+
+VOID WaitDisplay(void)
+{
+ USHORT temp;
+
+ for(temp=0;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x01;
+ }
+ for(;temp==1;){
+ temp=GetReg2(P3da);
+ temp=temp&0x01;
+ }
+}
+
+VOID LongWait(void)
+{
+ USHORT temp;
+
+ for(temp=1;temp>0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+ for(;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+}
+
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+
+VOID VBLongWait(VOID)
+{
+ USHORT regsr1f,tempah,temp;
+
+ regsr1f=GetReg1(P3c4,0x1F);
+ tempah=regsr1f&(~0xC0);
+ SetReg1(P3c4,0x1F,tempah);
+
+ for(temp=1;temp>0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+ for(;temp==0;){
+ temp=GetReg2(P3da);
+ temp=temp&0x08;
+ }
+
+ SetReg1(P3c4,0x1F,regsr1f);
+ return;
+}
+
+BOOLEAN WaitVBRetrace(USHORT BaseAddr)
+{
+ USHORT temp;
+ USHORT Part1Port;
+ Part1Port=BaseAddr+IND_SIS_CRT2_PORT_04;
+ temp=GetReg1(Part1Port,0x00);
+ if(!(temp&0x80)){
+ return 0;
+ }
+
+ for(temp=0;temp==0;){
+ temp=GetReg1(Part1Port,0x25);
+ temp=temp&0x01;
+ }
+ for(;temp>0;){
+ temp=GetReg1(Part1Port,0x25);
+ temp=temp&0x01;
+ }
+ return 1;
+}
+
+BOOLEAN GetPanelID(VOID)
+{
+ USHORT PanelTypeTable[16]={ SyncPP|Panel800x600|PanelType00,
+ SyncPP|Panel1024x768|PanelType01,
+ SyncPP|Panel1024x768|PanelType02,
+ SyncPP|Panel1024x768|PanelType03,
+ SyncPP|Panel1024x768|PanelType04,
+ SyncPP|Panel1024x768|PanelType05,
+ SyncPP|Panel1024x768|PanelType06,
+ SyncPP|Panel1024x768|PanelType07,
+ SyncPP|Panel1024x768|PanelType08,
+ SyncPP|Panel1024x768|PanelType09,
+ SyncPP|Panel800x600|PanelType0A,
+ SyncPP|Panel1024x768|PanelType0B,
+ SyncPP|Panel1024x768|PanelType0C,
+ SyncPP|Panel1024x768|PanelType0D,
+ SyncPP|Panel1024x768|PanelType0E,
+ SyncPP|Panel1024x768|PanelType0F};
+ // Bit 15 BPLVSPLTY
+ // Bit 14 BPLHSPLTY
+ // Bit 6-3 Panel Type
+ // Bit 2-0 Display Resolution(001:800x600 010:1024x768 011:1280x1024)
+ USHORT tempah,tempbx;
+ USHORT return_flag;
+
+ tempah=GetReg1(P3c4,0x18);
+ tempbx=tempah&0x0F;
+ if(tempah&0x10){
+ return_flag=1;
+ }else{
+ return_flag=0;
+ }
+
+ if(return_flag==0){
+ if(IF_DEF_LVDS==1){
+ tempbx=0;
+ tempah=GetReg1(P3c4,0x38);
+ if(tempah&0x40) tempbx=tempbx|0x08;
+ if(tempah&0x20) tempbx=tempbx|0x02;
+ if(tempah&0x01) tempbx=tempbx|0x01;
+ tempah=GetReg1(P3c4,0x39);
+ if(tempah&0x80) tempbx=tempbx|0x04;
+ }else{
+ return 0;
+ }
+ }
+
+ if(IF_DEF_TRUMPION==1){
+ tempbx=1;
+ }
+ tempbx=PanelTypeTable[tempbx]; //LVDS table entry
+ tempbx=tempbx|(USHORT)(LCDSync<<8);
+
+ tempah=tempbx&0x0FF;
+ SetReg1(P3d4,0x36,tempah);
+ tempah=(tempbx&0xFF00)>>8;
+ SetRegANDOR(P3d4,0x37,~LCDSyncBit,tempah);
+ return 1;
+}
+
+VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT OldREFIndex,temp,tempah,i,modeflag1;
+
+ OldREFIndex=(USHORT)REFIndex;
+ temp=GetLVDSCRT1Ptr(ROMAddr,ModeNo);
+ if(temp==0){
+ REFIndex=OldREFIndex;
+ return;
+ }
+ tempah=(UCHAR)GetReg1(P3d4,0x11);//unlock cr0-7
+ tempah=tempah&0x7F;
+ SetReg1(P3d4,0x11,tempah);
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,0x0,tempah);
+ REFIndex++;
+ for(i=0x02;i<=0x05;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x06;i<=0x07;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x10;i<=0x11;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+ for(i=0x15;i<=0x16;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3d4,i,tempah);
+ }
+
+ for(i=0x0A;i<=0x0C;REFIndex++){
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3c4,i,tempah);
+ }
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=tempah&0x0E0;
+ SetReg1(P3c4,0x0E,tempah);
+
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ tempah=tempah&0x01;
+ tempah=tempah<<5;
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&DoubleScanMode){
+ tempah=tempah|0x080;
+ }
+ SetRegANDOR(P3d4,0x09,~0x020,tempah);
+ REFIndex=OldREFIndex;
+ return;
+}
+
+VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo)
+{
+ USHORT OldREFIndex,tempah,tempal;
+ USHORT P3cc=P3c9+3;
+ OldREFIndex=(USHORT)REFIndex;
+ if(IF_DEF_TRUMPION==0){ //no trumpion
+ tempal=GetReg2(P3cc);
+ tempal=tempal&0x0C;
+ SetReg3(P3c2,tempal);
+ REFIndex=GetVCLKPtr(ROMAddr,ModeNo);
+ }else{ //trumpion
+ SetFlag=SetFlag&(~ProgrammingCRT2);
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+0x03)); //di+Ext_CRTVCLK
+ tempal=tempal&0x03F;
+ if(tempal==0x02){ //31.5MHz
+ REFIndex=REFIndex-Ext2StructSize;
+ }
+ REFIndex=GetVCLKPtr(ROMAddr,ModeNo);
+ SetFlag=SetFlag|ProgrammingCRT2;
+ }
+ tempal=0x02B;
+ if(!(VBInfo&SetInSlaveMode)){
+ tempal=tempal+3;
+ }
+ tempah=*((UCHAR *)(ROMAddr+REFIndex));
+ SetReg1(P3c4,tempal,tempah);
+ tempah=*((UCHAR *)(ROMAddr+REFIndex+1));
+ tempal++;
+ SetReg1(P3c4,tempal,tempah);
+ REFIndex=OldREFIndex;
+ return;
+}
+
+USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempcl,tempbx,tempal,tempptr,LVDSDesPtrData;
+ tempcl=LVDSDesDataLen;
+ tempbx=LCDTypeInfo;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+16;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x1F;
+ tempal=tempal*tempcl;
+ tempbx=tempbx<<1;
+ LVDSDesPtrData=*((USHORT *)(ROMAddr+ADR_LVDSDesPtrData));
+ tempptr=*((USHORT *)(ROMAddr+LVDSDesPtrData+tempbx));
+ tempptr=tempptr+tempal;
+ return(tempptr);
+
+}
+
+BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo)
+{
+ USHORT tempal,tempbx,modeflag1;
+ USHORT LVDSCRT1DataPtr;
+
+ if(!(VBInfo&SetInSlaveMode)){
+ return 0;
+ }
+ if(ModeNo<=0x13){
+ tempal=*((UCHAR *)(ROMAddr+ModeIDOffset+0x04)); // si+St_CRT2CRTC
+ }else{
+ tempal=*((UCHAR *)(ROMAddr+REFIndex+4)); //di+Ext_CRT2CRTC
+ }
+ tempal=tempal&0x3F;
+
+ tempbx=LCDResInfo;
+ tempbx=tempbx-Panel800x600;
+ if(LCDInfo&LCDNonExpanding){
+ tempbx=tempbx+6;
+ }
+ modeflag1=*((USHORT *)(ROMAddr+ModeIDOffset+0x01)); // si+St_ModeFlag
+ if(modeflag1&HalfDCLK){
+ tempbx=tempbx+3;
+ }
+ tempbx=tempbx<<1;
+ LVDSCRT1DataPtr=*((USHORT *)(ROMAddr+ADR_LVDSCRT1DataPtr));
+ REFIndex=*((USHORT *)(ROMAddr+LVDSCRT1DataPtr+tempbx));
+ tempal=tempal*LVDSCRT1Len;
+ REFIndex=REFIndex+tempal;
+ return 1;
+}
+
+#endif
diff --git a/drivers/video/sis/sis_301.h b/drivers/video/sis/sis_301.h
new file mode 100644
index 000000000..89e280c0a
--- /dev/null
+++ b/drivers/video/sis/sis_301.h
@@ -0,0 +1,224 @@
+#include <linux/config.h>
+#include "initdef.h"
+
+USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE;
+USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE;
+;USHORT LCDResInfo,LCDTypeInfo,LCDInfo;
+USHORT VCLKLen;
+USHORT LCDHDES,LCDVDES;
+
+USHORT StResInfo[5][2]={{640,400},{640,350},{720,400},{720,350},{640,480}};
+
+USHORT ModeResInfo[15][4]={{320,200,8,8},{320,240,8,8},{320,400,8,8},
+ {400,300,8,8},{512,384,8,8},{640,400,8,16},
+ {640,480,8,16},{800,600,8,16},{1024,768,8,16},
+ {1280,1024,8,16},{1600,1200,8,16},{1920,1440,8,16},
+ {720,480,8,16},{720,576,8,16},{1280,960,8,16}};
+
+
+USHORT NTSCTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C,
+ 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B,
+ 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017,
+ 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002,
+ 0x003,0x00A,0x065,0x09D,0x008,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x050,0x000,0x040,
+ 0x00044,0x002DB,0x0003B};//Ajust xxx
+
+USHORT PALTiming[61]={ 0x019,0x052,0x035,0x06E,0x004,0x038,0x03D,0x070,
+ 0x094,0x049,0x001,0x012,0x006,0x03E,0x035,0x06D,
+ 0x006,0x014,0x03E,0x035,0x06D,0x000,0x045,0x02B,
+ 0x070,0x050,0x000,0x097,0x000,0x0D7,0x05D,0x017,
+ 0x088,0x000,0x045,0x000,0x000,0x0E8,0x000,0x002,
+ 0x00D,0x000,0x068,0x0B0,0x00B,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x063,0x000,0x040,
+ 0x0003E,0x002E1,0x00028};//Ajust xxx
+
+USHORT HiTVTiming[61]={0x017,0x01D,0x003,0x009,0x005,0x006,0x00C,0x00C,
+ 0x094,0x049,0x001,0x00A,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x085,0x01B,
+ 0x00C,0x050,0x000,0x099,0x000,0x0EC,0x04A,0x017,
+ 0x088,0x000,0x04B,0x000,0x000,0x0E2,0x000,0x002,
+ 0x003,0x00A,0x065,0x09D,0x008,
+ 0x092,0x08F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x014,0x050,0x000,0x040,
+ 0x00027,0x0FFFC,0x0003B};//Ajust xxx
+
+USHORT HiTVTimingSimu[61]={0x020,0x054,0x02C,0x060,0x008,0x031,0x03A,0x061,
+ 0x028,0x002,0x001,0x03D,0x006,0x00D,0x004,0x00A,
+ 0x006,0x014,0x00D,0x004,0x00A,0x000,0x0C5,0x03F,
+ 0x064,0x090,0x000,0x0AA,0x000,0x006,0x060,0x003,
+ 0x011,0x005,0x011,0x00F,0x010,0x011,0x000,0x000,
+ 0x005,0x005,0x034,0x034,0x008,
+ 0x092,0x00F,0x040,0x060,0x080,0x014,0x090,0x08C,
+ 0x060,0x004,0x05F,0x000,0x060,
+ 0x0000E,0x0FFFC,0x00042};//Ajust xxx
+
+USHORT HiTVGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x05B,
+ 0x0FF,0x021,0x0AD,0x0AD,0x055,0x077,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x06E,0x060,0x02D,0x056,0x047,0x070,0x044,
+ 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080,
+ 0x045,0x07D,0x003,0x0A5,0x076,0x020,0x01A,0x0A4,
+ 0x014,0x005,0x003,0x07E,0x064,0x031,0x014,0x075,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+USHORT HiTVGroup3Simu[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x094,
+ 0x0DA,0x020,0x0B7,0x0B7,0x055,0x047,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x06E,0x060,0x015,0x026,0x0D3,0x0E4,0x011,
+ 0x056,0x036,0x04F,0x06E,0x03F,0x080,0x000,0x080,
+ 0x066,0x035,0x001,0x047,0x00E,0x010,0x0BE,0x0B4,
+ 0x001,0x005,0x003,0x07E,0x065,0x031,0x014,0x075,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+USHORT NTSCGroup3Data[63]= {0x000,0x014,0x015,0x025,0x055,0x015,0x00B,0x089,
+ 0x0D7,0x040,0x0B0,0x0B0,0x0FF,0x0C4,0x045,0x0A6,
+ 0x025,0x02F,0x067,0x0F6,0x0BF,0x0FF,0x08E,0x020,
+ 0x08C,0x0DA,0x060,0x092,0x0C8,0x055,0x08B,0x000,
+ 0x051,0x004,0x018,0x00A,0x0F8,0x087,0x000,0x080,
+ 0x03B,0x03B,0x000,0x0F0,0x0F0,0x000,0x0F0,0x0F0,
+ 0x000,0x051,0x00F,0x00F,0x008,0x00F,0x008,0x06F,
+ 0x018,0x005,0x005,0x005,0x04C,0x0AA,0x001};
+
+USHORT PALGroup3Data[63]={0x000,0x01A,0x022,0x063,0x062,0x022,0x008,0x085,
+ 0x0C3,0x020,0x0A4,0x0A4,0x055,0x047,0x02A,0x0A6,
+ 0x025,0x02F,0x047,0x0FA,0x0C8,0x0FF,0x08E,0x020,
+ 0x08C,0x0DC,0x060,0x092,0x0C8,0x04F,0x085,0x000,
+ 0x056,0x036,0x04F,0x06E,0x0FE,0x083,0x054,0x081,
+ 0x030,0x030,0x000,0x0F3,0x0F3,0x000,0x0A2,0x0A2,
+ 0x000,0x048,0x0FE,0x07E,0x008,0x040,0x008,0x091,
+ 0x018,0x005,0x018,0x005,0x04C,0x0A8,0x001};
+
+VOID overwriteregs(ULONG ROMAddr, USHORT BaseAddr);
+VOID SetDefCRT2ExtRegs(USHORT BaseAddr);
+BOOLEAN SetCRT2Group(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo);
+BOOLEAN AjustCRT2Rate(ULONG ROMAddr);
+VOID SaveCRT2Info(USHORT ModeNo);
+VOID DisableLockRegs(VOID);
+VOID DisableCRT2(VOID);
+VOID DisableBridge(USHORT BaseAddr);
+VOID GetCRT2Data(ULONG ROMAddr,USHORT ModeNo);
+VOID GetResInfo(ULONG ROMAddr,USHORT ModeNo);
+VOID GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo);
+VOID UnLockCRT2(USHORT BaseAddr);
+VOID SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo);
+VOID SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr);
+USHORT GetOffset(ULONG ROMAddr);
+USHORT GetColorDepth(ULONG ROMAddr);
+VOID SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetVCLK(ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo);
+USHORT GetColorTh(ULONG ROMAddr);
+USHORT GetMCLK(ULONG ROMAddr);
+USHORT GetMCLKPtr(ULONG ROMAddr);
+USHORT GetDRAMType(ULONG ROMAddr);
+#ifndef CONFIG_FB_SIS_LINUXBIOS
+static USHORT CalcDelay(VOID);
+#endif
+USHORT GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT1Ptr(ULONG ROMAddr);
+VOID SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
+USHORT GetVGAHT2(VOID);
+VOID SetGroup2(USHORT BaseAddr,ULONG ROMAddr);
+VOID SetGroup3(USHORT BaseAddr);
+VOID SetGroup4(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
+VOID SetGroup5(USHORT BaseAddr,ULONG ROMAddr);
+VOID EnableCRT2(VOID);
+VOID LoadDAC2(ULONG ROMAddr,USHORT Part5Port);
+VOID WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh);
+VOID LockCRT2(USHORT BaseAddr);
+VOID SetLockRegs(VOID);
+VOID EnableBridge(USHORT BaseAddr);
+USHORT GetLockInfo(USHORT pattern);
+VOID GetVBInfo(USHORT BaseAddr,ULONG ROMAddr);
+BOOLEAN BridgeIsEnable(USHORT BaseAddr);
+BOOLEAN BridgeInSlave(VOID);
+BOOLEAN GetLCDResInfo(ULONG ROMAddr,USHORT P3d4);
+VOID PresetScratchregister(USHORT P3d4,PHW_DEVICE_EXTENSION HwDeviceExtension);
+BOOLEAN GetLCDDDCInfo(PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetTVSystem(PHW_DEVICE_EXTENSION HwDeviceExtension,ULONG ROMAddr);
+BOOLEAN GetSenseStatus(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr);
+BOOLEAN Sense(USHORT Part4Port,USHORT inputbx,USHORT inputcx);
+BOOLEAN SenseLCD(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT Part4Port,ULONG ROMAddr);
+BOOLEAN TestMonitorType(USHORT d1,USHORT d2,USHORT d3);
+VOID WaitDisplay(VOID);
+BOOLEAN DetectMonitor(PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID LongWait(VOID);
+//VOID ClearALLBuffer(PHW_DEVICE_EXTENSION HwDeviceExtension);
+USHORT GetQueueConfig(VOID);
+VOID VBLongWait(VOID);
+USHORT GetVCLKLen(ULONG ROMAddr);
+BOOLEAN WaitVBRetrace(USHORT BaseAddr);
+VOID GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo);
+VOID ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo);
+VOID SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo);
+VOID GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo);
+VOID GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo);
+USHORT GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo);
+VOID SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+ PHW_DEVICE_EXTENSION HwDeviceExtension);
+VOID SetTPData(VOID);
+BOOLEAN GetPanelID(VOID);
+BOOLEAN GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo);
+
+extern USHORT DRAMType[17][5];
+extern USHORT MDA_DAC[];
+extern USHORT CGA_DAC[];
+extern USHORT EGA_DAC[];
+extern USHORT VGA_DAC[];
+
+extern USHORT P3c4,P3d4,P3c0,P3ce,P3c2,P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+extern USHORT flag_clearbuffer; //0:no clear frame buffer 1:clear frame buffer
+extern int RAMType;
+extern int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,VCLKData,MCLKData, ECLKData;
+extern int REFIndex,ModeType;
+extern USHORT VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo;
+extern USHORT IF_DEF_LVDS,IF_DEF_TRUMPION;
+
+extern VOID SetMemoryClock(ULONG);
+extern VOID SetDRAMSize(PHW_DEVICE_EXTENSION);
+extern BOOLEAN SearchModeID(ULONG, USHORT);
+extern BOOLEAN CheckMemorySize(ULONG);
+extern VOID GetModePtr(ULONG, USHORT);
+extern BOOLEAN GetRatePtr(ULONG, USHORT);
+extern VOID SetSeqRegs(ULONG);
+extern VOID SetMiscRegs(ULONG);
+extern VOID SetCRTCRegs(ULONG);
+extern VOID SetATTRegs(ULONG);
+extern VOID SetGRCRegs(ULONG);
+extern VOID ClearExt1Regs(VOID);
+extern VOID SetSync(ULONG);
+extern VOID SetCRT1CRTC(ULONG);
+extern VOID SetCRT1Offset(ULONG);
+extern VOID SetCRT1FIFO(ULONG);
+extern VOID SetCRT1VCLK(ULONG);
+extern VOID LoadDAC(ULONG);
+extern VOID DisplayOn(VOID);
+extern VOID SetCRT1ModeRegs(ULONG, USHORT);
+extern VOID SetVCLKState(ULONG, USHORT);
+extern VOID WriteDAC(USHORT, USHORT, USHORT, USHORT);
+extern VOID ClearBuffer(PHW_DEVICE_EXTENSION);
+//extern VOID ClearDAC(ULONG);
+extern void ClearDAC(u16 port);
+extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+extern void SetReg1(u16 port, u16 index, u16 data);
+extern void SetReg3(u16 port, u16 data);
+extern void SetReg4(u16 port, unsigned long data);
+extern u8 GetReg1(u16 port, u16 index);
+extern u8 GetReg2(u16 port);
+extern u32 GetReg3(u16 port);
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
new file mode 100644
index 000000000..592180c18
--- /dev/null
+++ b/drivers/video/sis/sis_main.c
@@ -0,0 +1,2374 @@
+/*
+ * SiS 300/630/540 frame buffer device For Kernal 2.4.x
+ *
+ * This driver is partly based on the VBE 2.0 compliant graphic
+ * boards framebuffer driver, which is
+ *
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#define EXPORT_SYMTAB
+#undef SISFBDEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/sisfb.h>
+#include <linux/fs.h>
+
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "sis.h"
+#ifdef NOBIOS
+#include "bios.h"
+#endif
+
+/* ------------------- Constant Definitions ------------------------- */
+
+/* capabilities */
+#define TURBO_QUEUE_CAP 0x80
+#define HW_CURSOR_CAP 0x40
+
+/* VGA register Offsets */
+#define SEQ_ADR (0x14)
+#define SEQ_DATA (0x15)
+#define DAC_ADR (0x18)
+#define DAC_DATA (0x19)
+#define CRTC_ADR (0x24)
+#define CRTC_DATA (0x25)
+
+#define DAC2_ADR 0x16 - 0x30
+#define DAC2_DATA 0x17 - 0x30
+
+
+/* SiS indexed register indexes */
+#define IND_SIS_PASSWORD (0x05)
+#define IND_SIS_DRAM_SIZE (0x14)
+#define IND_SIS_MODULE_ENABLE (0x1E)
+#define IND_SIS_PCI_ADDRESS_SET (0x20)
+#define IND_SIS_TURBOQUEUE_ADR (0x26)
+#define IND_SIS_TURBOQUEUE_SET (0x27)
+
+/* Sis register value */
+#define SIS_PASSWORD (0x86)
+
+#define SIS_2D_ENABLE (0x40)
+
+#define SIS_MEM_MAP_IO_ENABLE (0x01)
+#define SIS_PCI_ADDR_ENABLE (0x80)
+
+//#define MMIO_SIZE 0x10000 /* 64K MMIO capability */
+#define MAX_ROM_SCAN 0x10000
+
+#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
+#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
+
+/* Mode set stuff */
+#define DEFAULT_MODE 0 /* 640x480x8 */
+#define DEFAULT_LCDMODE 9 /* 800x600x8 */
+#define DEFAULT_TVMODE 9 /* 800x600x8 */
+
+/* heap stuff */
+#define OH_ALLOC_SIZE 4000
+#define SENTINEL 0x7fffffff
+
+#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
+#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
+
+/* ------------------- Global Variables ----------------------------- */
+
+struct video_info ivideo;
+HW_DEVICE_EXTENSION HwExt={0,0,0,0,0,0};
+
+struct GlyInfo {
+ unsigned char ch;
+ int fontwidth;
+ int fontheight;
+ u8 gmask[72];
+ int ngmask;
+};
+
+/* Supported SiS Chips list */
+static struct board {
+ u16 vendor, device;
+ const char *name;
+} dev_list[] = {
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
+ {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_730_VGA, "SIS 730"},
+ {0, 0, NULL}
+};
+
+/* card parameters */
+unsigned long rom_base;
+unsigned long rom_vbase;
+
+/* mode */
+static int video_type = FB_TYPE_PACKED_PIXELS;
+static int video_linelength;
+static int video_cmap_len;
+static int sisfb_off = 0;
+static int crt1off = 0;
+
+static struct fb_var_screeninfo default_var = {
+ 0, 0, 0, 0,
+ 0, 0,
+ 0,
+ 0,
+ {0, 8, 0},
+ {0, 8, 0},
+ {0, 8, 0},
+ {0, 0, 0},
+ 0,
+ FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ FB_VMODE_NONINTERLACED,
+ {0, 0, 0, 0, 0, 0}
+};
+
+static struct display disp;
+static struct fb_info fb_info;
+static struct {
+ u16 blue, green, red, pad;
+} palette[256];
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} fbcon_cmap;
+
+static int inverse = 0;
+static int currcon = 0;
+
+static struct display_switch sisfb_sw;
+
+static u8 caps = 0;
+static unsigned long MMIO_SIZE = 0;
+
+/* ModeSet stuff */
+unsigned char uDispType = 0;
+int mode_idx = -1;
+u8 mode_no = 0;
+u8 rate_idx = 0;
+
+static const struct _sisbios_mode {
+ char name[15];
+ u8 mode_no;
+ u16 xres;
+ u16 yres;
+ u16 bpp;
+ u16 rate_idx;
+ u16 cols;
+ u16 rows;
+} sisbios_mode[] = {
+ {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
+ {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
+ {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
+ {"720x480x8", 0x31, 720, 480, 8, 1, 90, 30}, /* NTSC TV */
+ {"720x480x16", 0x33, 720, 480, 16, 1, 90, 30},
+ {"720x480x32", 0x35, 720, 480, 32, 1, 90, 30},
+ {"720x576x8", 0x32, 720, 576, 8, 1, 90, 36}, /* PAL TV */
+ {"720x576x16", 0x34, 720, 576, 16, 1, 90, 36},
+ {"720x576x32", 0x36, 720, 576, 32, 1, 90, 36},
+ {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
+ {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
+ {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
+ {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
+ {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
+ {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
+ {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
+ {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
+ {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
+ {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
+ {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
+ {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
+ {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
+ {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
+ {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
+ {"\0", 0x00, 0, 0, 0, 0, 0, 0}
+};
+
+static struct _vrate {
+ u16 idx;
+ u16 xres;
+ u16 yres;
+ u16 refresh;
+} vrate[] = {
+ {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
+ {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
+ {1, 720, 480, 60},
+ {1, 720, 576, 50},
+ {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
+ {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
+ {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
+ {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
+ {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
+ {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
+ {5, 1600, 1200, 85},
+ {1, 1920, 1440, 60},
+ {0, 0, 0, 0}
+};
+
+
+/* HEAP stuff */
+
+struct OH {
+ struct OH *pohNext;
+ struct OH *pohPrev;
+ unsigned long ulOffset;
+ unsigned long ulSize;
+};
+
+struct OHALLOC {
+ struct OHALLOC *pohaNext;
+ struct OH aoh[1];
+};
+
+struct HEAP {
+ struct OH ohFree;
+ struct OH ohUsed;
+ struct OH *pohFreeList;
+ struct OHALLOC *pohaChain;
+
+ unsigned long ulMaxFreeSize;
+};
+
+struct HEAP heap;
+unsigned long heap_start;
+unsigned long heap_end;
+unsigned long heap_size;
+
+unsigned int tqueue_pos;
+unsigned long hwcursor_vbase;
+
+
+/* -------------------- Macro definitions --------------------------- */
+
+#ifdef SISFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define vgawb(reg,data) \
+ (outb(data, ivideo.vga_base+reg))
+#define vgaww(reg,data) \
+ (outw(data, ivideo.vga_base+reg))
+#define vgawl(reg,data) \
+ (outl(data, ivideo.vga_base+reg))
+#define vgarb(reg) \
+ (inb(ivideo.vga_base+reg))
+
+/* ---------------------- Routine Prototype ------------------------- */
+
+/* Interface used by the world */
+int sisfb_setup(char *options);
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info);
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info);
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+
+/* Interface to the low level console driver */
+int sisfb_init(void);
+static int sisfb_update_var(int con, struct fb_info *info);
+static int sisfb_switch(int con, struct fb_info *info);
+static void sisfb_blank(int blank, struct fb_info *info);
+
+/* Internal routines */
+static void crtc_to_var(struct fb_var_screeninfo *var);
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
+static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info);
+static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info);
+static void do_install_cmap(int con, struct fb_info *info);
+static int do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+
+/* set-mode routines */
+void SetReg1(u16 port, u16 index, u16 data);
+void SetReg3(u16 port, u16 data);
+void SetReg4(u16 port, unsigned long data);
+u8 GetReg1(u16 port, u16 index);
+u8 GetReg2(u16 port);
+u32 GetReg3(u16 port);
+extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,
+ USHORT ModeNo);
+extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
+static void pre_setmode(void);
+static void post_setmode(void);
+static void search_mode(const char *name);
+static u8 search_refresh_rate(unsigned int rate);
+
+/* heap routines */
+static int sisfb_heap_init(void);
+static struct OH *poh_new_node(void);
+static struct OH *poh_allocate(unsigned long size);
+static struct OH *poh_free(unsigned long base);
+static void delete_node(struct OH *poh);
+static void insert_node(struct OH *pohList, struct OH *poh);
+static void free_node(struct OH *poh);
+
+/* ---------------------- Internal Routines ------------------------- */
+
+inline static u32 RD32(unsigned char *base, s32 off)
+{
+ return readl(base + off);
+}
+
+inline static void WR32(unsigned char *base, s32 off, u32 v)
+{
+ writel(v, base + off);
+}
+
+inline static void WR16(unsigned char *base, s32 off, u16 v)
+{
+ writew(v, base + off);
+}
+
+inline static void WR8(unsigned char *base, s32 off, u8 v)
+{
+ writeb(v, base + off);
+}
+
+inline static u32 regrl(s32 off)
+{
+ return RD32(ivideo.mmio_vbase, off);
+}
+
+inline static void regwl(s32 off, u32 v)
+{
+ WR32(ivideo.mmio_vbase, off, v);
+}
+
+inline static void regww(s32 off, u16 v)
+{
+ WR16(ivideo.mmio_vbase, off, v);
+}
+
+inline static void regwb(s32 off, u8 v)
+{
+ WR8(ivideo.mmio_vbase, off, v);
+}
+
+/*
+ * Get CRTC registers to set var
+ */
+static void crtc_to_var(struct fb_var_screeninfo *var)
+{
+ u16 VRE, VBE, VRS, VBS, VDE, VT;
+ u16 HRE, HBE, HRS, HBS, HDE, HT;
+ u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
+ int A, B, C, D, E, F, temp;
+ double hrate, drate;
+
+ vgawb(SEQ_ADR, 0x6);
+ uSRdata = vgarb(SEQ_DATA);
+
+ if (uSRdata & 0x20)
+ var->vmode = FB_VMODE_INTERLACED;
+ else
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ switch ((uSRdata & 0x1c) >> 2) {
+ case 0:
+ var->bits_per_pixel = 8;
+ break;
+ case 2:
+ var->bits_per_pixel = 16;
+ break;
+ case 4:
+ var->bits_per_pixel = 32;
+ break;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ video_cmap_len = 256;
+ break;
+ case 16: /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ video_cmap_len = 16;
+
+ break;
+ case 24: /* RGB 888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ video_cmap_len = 16;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ video_cmap_len = 16;
+ break;
+ }
+
+ vgawb(SEQ_ADR, 0xa);
+ uSRdata = vgarb(SEQ_DATA);
+
+ vgawb(CRTC_ADR, 0x6);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x7);
+ uCRdata2 = vgarb(CRTC_DATA);
+ VT =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
+ ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
+ 10);
+ A = VT + 2;
+
+ vgawb(CRTC_ADR, 0x12);
+ uCRdata = vgarb(CRTC_DATA);
+ VDE =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
+ ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
+ E = VDE + 1;
+
+ vgawb(CRTC_ADR, 0x10);
+ uCRdata = vgarb(CRTC_DATA);
+ VRS =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
+ ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
+ F = VRS + 1 - E;
+
+ vgawb(CRTC_ADR, 0x15);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x9);
+ uCRdata3 = vgarb(CRTC_DATA);
+ VBS =
+ (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
+ ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
+
+ vgawb(CRTC_ADR, 0x16);
+ uCRdata = vgarb(CRTC_DATA);
+ VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
+ temp = VBE - ((E - 1) & 511);
+ B = (temp > 0) ? temp : (temp + 512);
+
+ vgawb(CRTC_ADR, 0x11);
+ uCRdata = vgarb(CRTC_DATA);
+ VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
+ temp = VRE - ((E + F - 1) & 31);
+ C = (temp > 0) ? temp : (temp + 32);
+
+ D = B - F - C;
+
+ var->yres = var->yres_virtual = E;
+ var->upper_margin = D;
+ var->lower_margin = F;
+ var->vsync_len = C;
+
+ vgawb(SEQ_ADR, 0xb);
+ uSRdata = vgarb(SEQ_DATA);
+
+ vgawb(CRTC_ADR, 0x0);
+ uCRdata = vgarb(CRTC_DATA);
+ HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
+ A = HT + 5;
+
+ vgawb(CRTC_ADR, 0x1);
+ uCRdata = vgarb(CRTC_DATA);
+ HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
+ E = HDE + 1;
+
+ vgawb(CRTC_ADR, 0x4);
+ uCRdata = vgarb(CRTC_DATA);
+ HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
+ F = HRS - E - 3;
+
+ vgawb(CRTC_ADR, 0x2);
+ uCRdata = vgarb(CRTC_DATA);
+ HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
+
+ vgawb(SEQ_ADR, 0xc);
+ uSRdata = vgarb(SEQ_DATA);
+ vgawb(CRTC_ADR, 0x3);
+ uCRdata = vgarb(CRTC_DATA);
+ vgawb(CRTC_ADR, 0x5);
+ uCRdata2 = vgarb(CRTC_DATA);
+ HBE =
+ (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
+ ((u16) (uSRdata & 0x03) << 6);
+ HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
+
+ temp = HBE - ((E - 1) & 255);
+ B = (temp > 0) ? temp : (temp + 256);
+
+ temp = HRE - ((E + F + 3) & 63);
+ C = (temp > 0) ? temp : (temp + 64);
+
+ D = B - F - C;
+
+ var->xres = var->xres_virtual = E * 8;
+ var->left_margin = D * 8;
+ var->right_margin = F * 8;
+ var->hsync_len = C * 8;
+
+ var->activate = FB_ACTIVATE_NOW;
+
+ var->sync = 0;
+
+ uMRdata = vgarb(0x1C);
+ if (uMRdata & 0x80)
+ var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if (uMRdata & 0x40)
+ var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ else
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ VT += 2;
+ VT <<= 1;
+ HT = (HT + 5) * 8;
+
+ hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+ drate = hrate * HT;
+ var->pixclock = (u32) (1E12 / drate);
+}
+
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
+{
+ struct fb_fix_screeninfo fix;
+ struct display *display;
+ struct display_switch *sw;
+ u32 flags;
+
+ if (con >= 0)
+ display = &fb_display[con];
+ else
+ display = &disp; /* used during initialization */
+
+ sisfb_get_fix(&fix, con, 0);
+
+ display->screen_base = ivideo.video_vbase;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ /*display->can_soft_blank = 1; */
+ display->can_soft_blank = 0;
+ display->inverse = inverse;
+ display->var = *var;
+
+ save_flags(flags);
+ switch (ivideo.video_bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ sw = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ sw = &fbcon_cfb16;
+ display->dispsw_data = fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ sw = &fbcon_cfb24;
+ display->dispsw_data = fbcon_cmap.cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ sw = &fbcon_cfb32;
+ display->dispsw_data = fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ sw = &fbcon_dummy;
+ return;
+ }
+ memcpy(&sisfb_sw, sw, sizeof(*sw));
+ display->dispsw = &sisfb_sw;
+ restore_flags(flags);
+
+ display->scrollmode = SCROLL_YREDRAW;
+ sisfb_sw.bmove = fbcon_redraw_bmove;
+
+}
+
+/*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+ unsigned *transp, struct fb_info *fb_info)
+{
+ if (regno >= video_cmap_len)
+ return 1;
+
+ *red = palette[regno].red;
+ *green = palette[regno].green;
+ *blue = palette[regno].blue;
+ *transp = 0;
+ return 0;
+}
+
+/*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ */
+static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *fb_info)
+{
+
+ if (regno >= video_cmap_len)
+ return 1;
+
+ palette[regno].red = red;
+ palette[regno].green = green;
+ palette[regno].blue = blue;
+
+ switch (ivideo.video_bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ vgawb(DAC_ADR, regno);
+ vgawb(DAC_DATA, red >> 10);
+ vgawb(DAC_DATA, green >> 10);
+ vgawb(DAC_DATA, blue >> 10);
+ if(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ /* VB connected */
+ vgawb(DAC2_ADR, regno);
+ vgawb(DAC2_DATA, red >> 8);
+ vgawb(DAC2_DATA, green >> 8);
+ vgawb(DAC2_DATA, blue >> 8);
+ }
+
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 15:
+ case 16:
+ fbcon_cmap.cfb16[regno] =
+ ((red & 0xf800)) |
+ ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb24[regno] =
+ (red << 16) | (green << 8) | (blue);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ fbcon_cmap.cfb32[regno] =
+ (red << 16) | (green << 8) | (blue);
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+ if (con != currcon)
+ return;
+
+ if (fb_display[con].cmap.len)
+ fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
+ else
+ fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
+ sis_setcolreg, info);
+}
+
+static int do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info)
+{
+ unsigned int htotal =
+ var->left_margin + var->xres + var->right_margin +
+ var->hsync_len;
+ unsigned int vtotal =
+ var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+ double drate = 0, hrate = 0;
+ int found_mode = 0;
+ int old_mode;
+
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+ vtotal <<= 1;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ vtotal <<= 2;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+ var->yres <<= 1;
+
+
+ if (!htotal || !vtotal) {
+ DPRINTK("Invalid 'var' Information!\n");
+ return 1;
+ }
+
+ drate = 1E12 / var->pixclock;
+ hrate = drate / htotal;
+ ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+
+ old_mode = mode_idx;
+ mode_idx = 0;
+
+ while ((sisbios_mode[mode_idx].mode_no != 0)
+ && (sisbios_mode[mode_idx].xres <= var->xres)) {
+ if ((sisbios_mode[mode_idx].xres == var->xres)
+ && (sisbios_mode[mode_idx].yres == var->yres)
+ && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
+ mode_no = sisbios_mode[mode_idx].mode_no;
+ found_mode = 1;
+ break;
+ }
+ mode_idx++;
+ }
+
+ if(found_mode)
+ {
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ switch(HwExt.usLCDType)
+ {
+ case LCD1024:
+ if(var->xres > 1024)
+ found_mode = 0;
+ break;
+ case LCD1280:
+ if(var->xres > 1280)
+ found_mode = 0;
+ break;
+ case LCD2048:
+ if(var->xres > 2048)
+ found_mode = 0;
+ break;
+ case LCD1920:
+ if(var->xres > 1920)
+ found_mode = 0;
+ break;
+ case LCD1600:
+ if(var->xres > 1600)
+ found_mode = 0;
+ break;
+ case LCD800:
+ if(var->xres > 800)
+ found_mode = 0;
+ break;
+ case LCD640:
+ if(var->xres > 640)
+ found_mode = 0;
+ break;
+ default:
+ found_mode = 0;
+ }
+ if(var->xres == 720) /* mode only for TV */
+ found_mode = 0;
+ break;
+ case MASK_DISPTYPE_TV:
+ switch(var->xres)
+ {
+ case 800:
+ case 640:
+ break;
+ case 720:
+ if(ivideo.TV_type == TVMODE_NTSC)
+ {
+ if(sisbios_mode[mode_idx].yres != 480)
+ found_mode = 0;
+ }
+ else if(ivideo.TV_type == TVMODE_PAL)
+ {
+ if(sisbios_mode[mode_idx].yres != 576)
+ found_mode = 0;
+ }
+ break;
+ default:
+ /* illegal mode */
+ found_mode = 0;
+ }
+ break;
+ }
+ }
+
+ if (!found_mode) {
+ printk("sisfb does not support mode %dx%d-%d\n", var->xres,
+ var->yres, var->bits_per_pixel);
+ mode_idx = old_mode;
+ return 1;
+ }
+
+ if (search_refresh_rate(ivideo.refresh_rate) == 0) {
+ /* not supported rate */
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ ivideo.refresh_rate = 60;
+ }
+
+ if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+ pre_setmode();
+
+ if (SiSSetMode(&HwExt, mode_no)) {
+ DPRINTK("sisfb: set mode[0x%x]: failed\n",
+ mode_no);
+ return 1;
+ }
+
+ post_setmode();
+
+ printk(KERN_DEBUG "Current Mode: %dx%dx%d-%d \n", sisbios_mode[mode_idx].xres,
+ sisbios_mode[mode_idx].yres, sisbios_mode[mode_idx].bpp, ivideo.refresh_rate);
+
+ ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
+ ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
+ ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
+ ivideo.org_x = ivideo.org_y = 0;
+ video_linelength =
+ ivideo.video_width * (ivideo.video_bpp >> 3);
+
+ DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
+ ivideo.video_width, ivideo.video_height,
+ ivideo.video_bpp, video_linelength);
+ }
+
+ return 0;
+}
+
+/* ---------------------- Draw Funtions ----------------------------- */
+
+static void sis_get_glyph(struct GlyInfo *gly)
+{
+ struct display *p = &fb_display[currcon];
+ u16 c;
+ u8 *cdat;
+ int widthb;
+ u8 *gbuf = gly->gmask;
+ int size;
+
+
+ gly->fontheight = fontheight(p);
+ gly->fontwidth = fontwidth(p);
+ widthb = (fontwidth(p) + 7) / 8;
+
+ c = gly->ch & p->charmask;
+ if (fontwidth(p) <= 8)
+ cdat = p->fontdata + c * fontheight(p);
+ else
+ cdat = p->fontdata + (c * fontheight(p) << 1);
+
+ size = fontheight(p) * widthb;
+ memcpy(gbuf, cdat, size);
+ gly->ngmask = size;
+}
+
+
+/* ---------------------- HEAP Routines ----------------------------- */
+
+/*
+ * Heap Initialization
+ */
+
+static int sisfb_heap_init(void)
+{
+ struct OH *poh;
+ u8 jTemp, tq_state;
+
+ if(ivideo.video_size > 0x800000)
+ /* video ram is large than 8M */
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
+ else
+ heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
+
+ heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
+ heap_size = heap_end - heap_start;
+
+
+ /* Setting for Turbo Queue */
+ if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
+ tqueue_pos =
+ (ivideo.video_size -
+ TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
+ jTemp = (u8) (tqueue_pos & 0xff);
+ vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
+ tq_state = vgarb(SEQ_DATA);
+ tq_state |= 0xf0;
+ tq_state &= 0xfc;
+ tq_state |= (u8) (tqueue_pos >> 8);
+ vgawb(SEQ_DATA, tq_state);
+ vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
+ vgawb(SEQ_DATA, jTemp);
+
+ caps |= TURBO_QUEUE_CAP;
+
+ heap_end -= TURBO_QUEUE_AREA_SIZE;
+ heap_size -= TURBO_QUEUE_AREA_SIZE;
+ }
+
+ /* Setting for HW cursor(4K) */
+ if (heap_size >= HW_CURSOR_AREA_SIZE) {
+ heap_end -= HW_CURSOR_AREA_SIZE;
+ heap_size -= HW_CURSOR_AREA_SIZE;
+ hwcursor_vbase = heap_end;
+
+ caps |= HW_CURSOR_CAP;
+ }
+
+ heap.pohaChain = NULL;
+ heap.pohFreeList = NULL;
+
+ poh = poh_new_node();
+
+ if (poh == NULL)
+ return 1;
+
+ /* The first node describles the entire heap size */
+ poh->pohNext = &heap.ohFree;
+ poh->pohPrev = &heap.ohFree;
+ poh->ulSize = heap_end - heap_start + 1;
+ poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
+
+ DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
+ (char *) heap_start, (char *) heap_end,
+ (unsigned int) poh->ulSize / 1024);
+
+ DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
+ (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
+
+ /* The second node in our free list sentinel */
+ heap.ohFree.pohNext = poh;
+ heap.ohFree.pohPrev = poh;
+ heap.ohFree.ulSize = 0;
+ heap.ulMaxFreeSize = poh->ulSize;
+
+ /* Initialize the discardable list */
+ heap.ohUsed.pohNext = &heap.ohUsed;
+ heap.ohUsed.pohPrev = &heap.ohUsed;
+ heap.ohUsed.ulSize = SENTINEL;
+
+ return 0;
+}
+
+/*
+ * Allocates a basic memory unit in which we'll pack our data structures.
+ */
+
+static struct OH *poh_new_node(void)
+{
+ int i;
+ unsigned long cOhs;
+ struct OHALLOC *poha;
+ struct OH *poh;
+
+ if (heap.pohFreeList == NULL) {
+ poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+
+ poha->pohaNext = heap.pohaChain;
+ heap.pohaChain = poha;
+
+ cOhs =
+ (OH_ALLOC_SIZE -
+ sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
+
+ poh = &poha->aoh[0];
+ for (i = cOhs - 1; i != 0; i--) {
+ poh->pohNext = poh + 1;
+ poh = poh + 1;
+ }
+
+ poh->pohNext = NULL;
+ heap.pohFreeList = &poha->aoh[0];
+ }
+
+ poh = heap.pohFreeList;
+ heap.pohFreeList = poh->pohNext;
+
+ return (poh);
+}
+
+/*
+ * Allocates space, return NULL when failed
+ */
+
+static struct OH *poh_allocate(unsigned long size)
+{
+ struct OH *pohThis;
+ struct OH *pohRoot;
+ int bAllocated = 0;
+
+ if (size > heap.ulMaxFreeSize) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ pohThis = heap.ohFree.pohNext;
+
+ while (pohThis != &heap.ohFree) {
+ if (size <= pohThis->ulSize) {
+ bAllocated = 1;
+ break;
+ }
+ pohThis = pohThis->pohNext;
+ }
+
+ if (!bAllocated) {
+ DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ if (size == pohThis->ulSize) {
+ pohRoot = pohThis;
+ delete_node(pohThis);
+ } else {
+ pohRoot = poh_new_node();
+
+ if (pohRoot == NULL) {
+ return (NULL);
+ }
+
+ pohRoot->ulOffset = pohThis->ulOffset;
+ pohRoot->ulSize = size;
+
+ pohThis->ulOffset += size;
+ pohThis->ulSize -= size;
+ }
+
+ heap.ulMaxFreeSize -= size;
+
+ pohThis = &heap.ohUsed;
+ insert_node(pohThis, pohRoot);
+
+ return (pohRoot);
+}
+
+/*
+ * To remove a node from a list.
+ */
+
+static void delete_node(struct OH *poh)
+{
+ struct OH *pohPrev;
+ struct OH *pohNext;
+
+
+ pohPrev = poh->pohPrev;
+ pohNext = poh->pohNext;
+
+ pohPrev->pohNext = pohNext;
+ pohNext->pohPrev = pohPrev;
+
+ return;
+}
+
+/*
+ * To insert a node into a list.
+ */
+
+static void insert_node(struct OH *pohList, struct OH *poh)
+{
+ struct OH *pohTemp;
+
+ pohTemp = pohList->pohNext;
+
+ pohList->pohNext = poh;
+ pohTemp->pohPrev = poh;
+
+ poh->pohPrev = pohList;
+ poh->pohNext = pohTemp;
+}
+
+/*
+ * Frees an off-screen heap allocation.
+ */
+
+static struct OH *poh_free(unsigned long base)
+{
+
+ struct OH *pohThis;
+ struct OH *pohFreed;
+ struct OH *pohPrev;
+ struct OH *pohNext;
+ unsigned long ulUpper;
+ unsigned long ulLower;
+ int foundNode = 0;
+
+ pohFreed = heap.ohUsed.pohNext;
+
+ while (pohFreed != &heap.ohUsed) {
+ if (pohFreed->ulOffset == base) {
+ foundNode = 1;
+ break;
+ }
+
+ pohFreed = pohFreed->pohNext;
+ }
+
+ if (!foundNode)
+ return (NULL);
+
+ heap.ulMaxFreeSize += pohFreed->ulSize;
+
+ pohPrev = pohNext = NULL;
+ ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
+ ulLower = pohFreed->ulOffset;
+
+ pohThis = heap.ohFree.pohNext;
+
+ while (pohThis != &heap.ohFree) {
+ if (pohThis->ulOffset == ulUpper) {
+ pohNext = pohThis;
+ }
+ else if ((pohThis->ulOffset + pohThis->ulSize) ==
+ ulLower) {
+ pohPrev = pohThis;
+ }
+ pohThis = pohThis->pohNext;
+ }
+
+ delete_node(pohFreed);
+
+ if (pohPrev && pohNext) {
+ pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
+ delete_node(pohNext);
+ free_node(pohFreed);
+ free_node(pohNext);
+ return (pohPrev);
+ }
+
+ if (pohPrev) {
+ pohPrev->ulSize += pohFreed->ulSize;
+ free_node(pohFreed);
+ return (pohPrev);
+ }
+
+ if (pohNext) {
+ pohNext->ulSize += pohFreed->ulSize;
+ pohNext->ulOffset = pohFreed->ulOffset;
+ free_node(pohFreed);
+ return (pohNext);
+ }
+
+ insert_node(&heap.ohFree, pohFreed);
+
+ return (pohFreed);
+}
+
+/*
+ * Frees our basic data structure allocation unit by adding it to a free
+ * list.
+ */
+
+static void free_node(struct OH *poh)
+{
+ if (poh == NULL) {
+ return;
+ }
+
+ poh->pohNext = heap.pohFreeList;
+ heap.pohFreeList = poh;
+
+ return;
+}
+
+void sis_malloc(struct sis_memreq *req)
+{
+ struct OH *poh;
+
+ poh = poh_allocate(req->size);
+
+ if (poh == NULL) {
+ req->offset = 0;
+ req->size = 0;
+ DPRINTK("sisfb: VMEM Allocation Failed\n");
+ } else {
+ DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
+ (char *) (poh->ulOffset +
+ (unsigned long) ivideo.video_vbase));
+
+ req->offset = poh->ulOffset;
+ req->size = poh->ulSize;
+ }
+
+}
+
+void sis_free(unsigned long base)
+{
+ struct OH *poh;
+
+ poh = poh_free(base);
+
+ if (poh == NULL) {
+ DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
+ (unsigned int) base);
+ }
+}
+
+void sis_dispinfo(struct ap_data *rec)
+{
+ rec->minfo.bpp = ivideo.video_bpp;
+ rec->minfo.xres = ivideo.video_width;
+ rec->minfo.yres = ivideo.video_height;
+ rec->minfo.v_xres = ivideo.video_vwidth;
+ rec->minfo.v_yres = ivideo.video_vheight;
+ rec->minfo.org_x = ivideo.org_x;
+ rec->minfo.org_y = ivideo.org_y;
+ rec->minfo.vrate = ivideo.refresh_rate;
+ rec->iobase = ivideo.vga_base - 0x30;
+ rec->mem_size = ivideo.video_size;
+ rec->disp_state = ivideo.disp_state;
+ switch(HwExt.jChipID)
+ {
+ case SIS_Glamour:
+ rec->chip = SiS_300;
+ break;
+ case SIS_Trojan:
+ if((HwExt.revision_id & 0xf0) == 0x30)
+ rec->chip = SiS_630S;
+ else
+ rec->chip = SiS_630;
+ break;
+ case SIS_Spartan:
+ rec->chip = SiS_540;
+ break;
+ case SIS_730:
+ rec->chip = SiS_730;
+ break;
+ default:
+ rec->chip = SiS_UNKNOWN;
+ break;
+ }
+}
+
+
+/* ---------------------- SetMode Routines -------------------------- */
+
+void SetReg1(u16 port, u16 index, u16 data)
+{
+ outb((u8) (index & 0xff), port);
+ port++;
+ outb((u8) (data & 0xff), port);
+}
+
+void SetReg3(u16 port, u16 data)
+{
+ outb((u8) (data & 0xff), port);
+}
+
+void SetReg4(u16 port, unsigned long data)
+{
+ outl((u32) (data & 0xffffffff), port);
+}
+
+u8 GetReg1(u16 port, u16 index)
+{
+ u8 data;
+
+ outb((u8) (index & 0xff), port);
+ port += 1;
+ data = inb(port);
+ return (data);
+}
+
+u8 GetReg2(u16 port)
+{
+ u8 data;
+
+ data = inb(port);
+
+ return (data);
+}
+
+u32 GetReg3(u16 port)
+{
+ u32 data;
+
+ data = inl(port);
+ return (data);
+}
+
+void ClearDAC(u16 port)
+{
+ int i,j;
+
+ vgawb(DAC_ADR, 0x00);
+ for(i=0; i<256; i++)
+ for(j=0; j<3; j++)
+ vgawb(DAC_DATA, 0);
+}
+
+void ClearBuffer(PHW_DEVICE_EXTENSION pHwExt)
+{
+ memset((char *) ivideo.video_vbase, 0,
+ video_linelength * ivideo.video_height);
+}
+
+static void pre_setmode(void)
+{
+ unsigned char uCR30=0, uCR31=0;
+
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_CRT2:
+ uCR30 = 0x41;
+ uCR31 = 0x40;
+ break;
+ case MASK_DISPTYPE_LCD:
+ uCR30 = 0x21;
+ uCR31 = 0x40;
+ break;
+ case MASK_DISPTYPE_TV:
+ if(ivideo.TV_type == TVMODE_HIVISION)
+ uCR30 = 0x81;
+ else if(ivideo.TV_plug == TVPLUG_SVIDEO)
+ uCR30 = 0x09;
+ else if(ivideo.TV_plug == TVPLUG_COMPOSITE)
+ uCR30 = 0x05;
+ else if(ivideo.TV_plug == TVPLUG_SCART)
+ uCR30 = 0x11;
+ uCR31 = 0x40; /* CR31[0] will be set in setmode() */
+ break;
+ default:
+ uCR30 = 0x00;
+ uCR31 = 0x60;
+ }
+
+ vgawb(CRTC_ADR, 0x30);
+ vgawb(CRTC_DATA, uCR30);
+ vgawb(CRTC_ADR, 0x31);
+ vgawb(CRTC_DATA, uCR31);
+ vgawb(CRTC_ADR, 0x33);
+ vgawb(CRTC_DATA, rate_idx & 0x0f);
+}
+
+static void post_setmode(void)
+{
+ u8 uTemp;
+
+ vgawb(CRTC_ADR, 0x17);
+ uTemp = vgarb(CRTC_DATA);
+
+ if(crt1off) /* turn off CRT1 */
+ uTemp &= ~0x80;
+ else /* turn on CRT1 */
+ uTemp |= 0x80;
+ vgawb(CRTC_DATA, uTemp);
+
+ /* disable 24-bit palette RAM and Gamma correction */
+ vgawb(SEQ_ADR, 0x07);
+ uTemp = vgarb(SEQ_DATA);
+ uTemp &= ~0x04;
+ vgawb(SEQ_DATA, uTemp);
+}
+
+static void search_mode(const char *name)
+{
+ int i = 0;
+
+ if (name == NULL)
+ return;
+
+ while (sisbios_mode[i].mode_no != 0) {
+ if (!strcmp(name, sisbios_mode[i].name)) {
+ mode_idx = i;
+ break;
+ }
+ i++;
+ }
+
+ if (mode_idx < 0)
+ DPRINTK("Invalid user mode : %s\n", name);
+}
+
+static u8 search_refresh_rate(unsigned int rate)
+{
+ u16 xres, yres;
+ int i = 0;
+
+ xres = sisbios_mode[mode_idx].xres;
+ yres = sisbios_mode[mode_idx].yres;
+
+ while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
+ if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
+ && (vrate[i].refresh == rate)) {
+ rate_idx = vrate[i].idx;
+ return rate_idx;
+ }
+ i++;
+ }
+
+ DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
+ yres);
+
+ return 0;
+}
+
+/* ------------------ Public Routines ------------------------------- */
+
+/*
+ * Get the Fixed Part of the Display
+ */
+
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, fb_info.modename);
+
+ fix->smem_start = ivideo.video_base;
+ if(ivideo.video_size > 0x800000)
+ fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
+ else
+ fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
+
+ fix->type = video_type;
+ fix->type_aux = 0;
+ if (ivideo.video_bpp == 8)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+ fix->line_length = video_linelength;
+ fix->mmio_start = ivideo.mmio_base;
+ fix->mmio_len = MMIO_SIZE;
+ fix->accel = FB_ACCEL_SIS_GLAMOUR;
+ fix->reserved[0] = ivideo.video_size & 0xFFFF;
+ fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+ fix->reserved[2] = caps; /* capabilities */
+
+ return 0;
+}
+
+/*
+ * Get the User Defined Part of the Display
+ */
+
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
+
+ if (con == -1)
+ memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+/*
+ * Set the User Defined Part of the Display
+ */
+
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+ int err;
+ unsigned int cols, rows;
+
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+ /* Set mode */
+ if (do_set_var(var, con == currcon, info)) {
+ crtc_to_var(var); /* return current mode to user */
+ return -EINVAL;
+ }
+
+ /* get actual setting value */
+ crtc_to_var(var);
+
+ /* update display of current console */
+ sisfb_set_disp(con, var);
+
+ if (info->changevar)
+ (*info->changevar) (con);
+
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+ return err;
+
+ do_install_cmap(con, info);
+
+ /* inform console to update struct display */
+ cols = sisbios_mode[mode_idx].cols;
+ rows = sisbios_mode[mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+ return 0;
+}
+
+
+/*
+ * Get the Colormap
+ */
+
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
+
+ if (con == currcon)
+ return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+ else if (fb_display[con].cmap.len) /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+/*
+ * Set the Colormap
+ */
+
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ int err;
+
+ if (!fb_display[con].cmap.len) { /* no colormap allocated */
+ err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
+ if (err)
+ return err;
+ }
+ if (con == currcon) /* current console */
+ return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ return 0;
+}
+
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if(!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_malloc((struct sis_memreq *) arg);
+ break;
+ case FBIO_FREE:
+ if(!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ sis_free(*(unsigned long *) arg);
+ break;
+ case FBIOGET_GLYPH:
+ sis_get_glyph((struct GlyInfo *) arg);
+ break;
+ case FBIOGET_HWCINFO:
+ {
+ unsigned long *hwc_offset = (unsigned long *) arg;
+
+ if (caps & HW_CURSOR_CAP)
+ *hwc_offset = hwcursor_vbase -
+ (unsigned long) ivideo.video_vbase;
+ else
+ *hwc_offset = 0;
+
+ break;
+ }
+ case FBIOPUT_MODEINFO:
+ {
+ struct mode_info *x = (struct mode_info *)arg;
+
+ /* Set Mode Parameters by XServer */
+ ivideo.video_bpp = x->bpp;
+ ivideo.video_width = x->xres;
+ ivideo.video_height = x->yres;
+ ivideo.video_vwidth = x->v_xres;
+ ivideo.video_vheight = x->v_yres;
+ ivideo.org_x = x->org_x;
+ ivideo.org_y = x->org_y;
+ ivideo.refresh_rate = x->vrate;
+
+ break;
+ }
+ case FBIOGET_DISPINFO:
+ sis_dispinfo((struct ap_data *)arg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sisfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fb_var_screeninfo var;
+ unsigned long start;
+ unsigned long off;
+ u32 len;
+
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* frame buffer memory */
+ start = (unsigned long) ivideo.video_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+
+ if (off >= len) {
+ /* memory mapped io */
+ off -= len;
+ sisfb_get_var(&var, currcon, info);
+ if (var.accel_flags)
+ return -EINVAL;
+ start = (unsigned long) ivideo.mmio_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
+ }
+
+ start &= PAGE_MASK;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+
+#if defined(__i386__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+ if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+static struct fb_ops sisfb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: sisfb_get_fix,
+ fb_get_var: sisfb_get_var,
+ fb_set_var: sisfb_set_var,
+ fb_get_cmap: sisfb_get_cmap,
+ fb_set_cmap: sisfb_set_cmap,
+ fb_ioctl: sisfb_ioctl,
+ fb_mmap: sisfb_mmap,
+};
+
+int sisfb_setup(char *options)
+{
+ char *this_opt;
+
+ fb_info.fontname[0] = '\0';
+ ivideo.refresh_rate = 0;
+
+ if (!options || !*options)
+ return 0;
+
+ for (this_opt = strtok(options, ","); this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if (!*this_opt)
+ continue;
+
+ if (!strcmp(this_opt, "inverse")) {
+ inverse = 1;
+ fb_invert_cmaps();
+ } else if (!strncmp(this_opt, "font:", 5)) {
+ strcpy(fb_info.fontname, this_opt + 5);
+ } else if (!strncmp(this_opt, "mode:", 5)) {
+ search_mode(this_opt + 5);
+ } else if (!strncmp(this_opt, "vrate:", 6)) {
+ ivideo.refresh_rate =
+ simple_strtoul(this_opt + 6, NULL, 0);
+ } else if (!strncmp(this_opt, "off", 3)) {
+ sisfb_off = 1;
+ } else if (!strncmp(this_opt, "crt1off", 7)) {
+ crt1off = 1;
+ } else
+ DPRINTK("invalid parameter %s\n", this_opt);
+ }
+ return 0;
+}
+
+static int sisfb_update_var(int con, struct fb_info *info)
+{
+ return 0;
+}
+
+/*
+ * Switch Console (called by fbcon.c)
+ */
+
+static int sisfb_switch(int con, struct fb_info *info)
+{
+ int cols, rows;
+
+ DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
+
+ /* update colormap of current console */
+ if (fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+
+ fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+ /* same mode, needn't change mode actually */
+
+ if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
+ {
+ currcon = con;
+ return 1;
+ }
+
+ currcon = con;
+
+ do_set_var(&fb_display[con].var, 1, info);
+
+ sisfb_set_disp(con, &fb_display[con].var);
+
+ /* Install new colormap */
+ do_install_cmap(con, info);
+
+ cols = sisbios_mode[mode_idx].cols;
+ rows = sisbios_mode[mode_idx].rows;
+ vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+ sisfb_update_var(con, info);
+
+ return 1;
+
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void sisfb_blank(int blank, struct fb_info *info)
+{
+ u8 CRData;
+
+ vgawb(CRTC_ADR, 0x17);
+ CRData = vgarb(CRTC_DATA);
+
+ if (blank > 0) /* turn off CRT1 */
+ CRData &= 0x7f;
+ else /* turn on CRT1 */
+ CRData |= 0x80;
+
+ vgawb(CRTC_ADR, 0x17);
+ vgawb(CRTC_DATA, CRData);
+}
+
+int has_VB(void)
+{
+ u8 uSR38, uSR39, uVBChipID;
+
+ vgawb(SEQ_ADR, 0x38);
+ uSR38 = vgarb(SEQ_DATA);
+ vgawb(SEQ_ADR, 0x39);
+ uSR39 = vgarb(SEQ_DATA);
+ vgawb(IND_SIS_CRT2_PORT_14, 0x0);
+ uVBChipID = vgarb(IND_SIS_CRT2_PORT_14+1);
+
+ if (
+ ( (HwExt.jChipID == SIS_Glamour) && (uSR38 & 0x20) ) /* 300 */
+ ||
+ ( (HwExt.jChipID >= SIS_Trojan ) && (uSR38 & 0x20) && (!(uSR39 & 0x80)) ) /* 630/540 */
+ ||
+ ( (HwExt.jChipID == SIS_Trojan ) && ((HwExt.revision_id & 0xf0) == 0x30) && (uVBChipID == 1) ) /* 630s */
+ ||
+ ( (HwExt.jChipID == SIS_730) && (uVBChipID == 1) ) /* 730 */
+ )
+ {
+ ivideo.hasVB = HASVB_301;
+ return TRUE;
+ }
+ else
+ {
+ ivideo.hasVB = HASVB_NONE;
+ return FALSE;
+ }
+}
+
+void sis_get301info(void)
+{
+ u8 uCRData;
+ unsigned long disp_state=0;
+
+ if (HwExt.jChipID >= SIS_Trojan)
+ {
+ if (!has_VB())
+ {
+ vgawb(CRTC_ADR, 0x37);
+ uCRData = vgarb(CRTC_DATA);
+
+ switch((uCRData >> 1) & 0x07)
+ {
+ case 2:
+ ivideo.hasVB = HASVB_LVDS;
+ break;
+ case 4:
+ ivideo.hasVB = HASVB_LVDS_CHRONTEL;
+ break;
+ case 3:
+ ivideo.hasVB = HASVB_TRUMPION;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ has_VB();
+ }
+
+ vgawb(CRTC_ADR, 0x32);
+ uCRData = vgarb(CRTC_DATA);
+
+ switch(uDispType)
+ {
+ case MASK_DISPTYPE_CRT2:
+ disp_state = DISPTYPE_CRT2;
+ break;
+ case MASK_DISPTYPE_LCD:
+ disp_state = DISPTYPE_LCD;
+ break;
+ case MASK_DISPTYPE_TV:
+ disp_state = DISPTYPE_TV;
+ break;
+ }
+
+ if(disp_state & 0x7)
+ {
+ if(crt1off)
+ disp_state |= DISPMODE_SINGLE;
+ else
+ disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
+ }
+ else
+ disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+
+ ivideo.disp_state = disp_state;
+}
+
+
+int __init sisfb_init(void)
+{
+ struct pci_dev *pdev = NULL;
+ struct board *b;
+ int pdev_valid = 0;
+ unsigned char jTemp;
+ u8 uSRData, uCRData;
+
+ outb(0x77, 0x80);
+
+ if (sisfb_off)
+ return -ENXIO;
+
+ pci_for_each_dev(pdev) {
+ for (b = dev_list; b->vendor; b++)
+ {
+ if ((b->vendor == pdev->vendor)
+ && (b->device == pdev->device))
+ {
+ pdev_valid = 1;
+ strcpy(fb_info.modename, b->name);
+ ivideo.chip_id = pdev->device;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &HwExt.revision_id);
+ break;
+ }
+ }
+
+ if (pdev_valid)
+ break;
+ }
+
+ if (!pdev_valid)
+ return -1;
+
+ switch(ivideo.chip_id)
+ {
+ case PCI_DEVICE_ID_SI_300:
+ HwExt.jChipID = SIS_Glamour;
+ break;
+ case PCI_DEVICE_ID_SI_630_VGA:
+ HwExt.jChipID = SIS_Trojan;
+ break;
+ case PCI_DEVICE_ID_SI_540_VGA:
+ HwExt.jChipID = SIS_Spartan;
+ break;
+ case PCI_DEVICE_ID_SI_730_VGA:
+ HwExt.jChipID = SIS_730;
+ break;
+ }
+
+ ivideo.video_base = pci_resource_start(pdev, 0);
+ ivideo.mmio_base = pci_resource_start(pdev, 1);
+ ivideo.vga_base = pci_resource_start(pdev, 2) + 0x30;
+
+ HwExt.IOAddress = (unsigned short)ivideo.vga_base;
+ rom_base = 0x000C0000;
+
+ MMIO_SIZE = pci_resource_len(pdev, 1);
+
+#ifdef NOBIOS
+ if (pci_enable_device(pdev))
+ return -EIO;
+ /* Image file instead of VGA-bios */
+ HwExt.VirtualRomBase = rom_vbase = (unsigned long) RomData;
+#else
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ if (pci_enable_device(pdev))
+ return -EIO;
+ HwExt.VirtualRomBase = rom_vbase = 0;
+#else
+ request_region(rom_base, 32, "sisfb");
+ HwExt.VirtualRomBase = rom_vbase
+ = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
+#endif
+#endif
+ /* set passwd */
+ vgawb(SEQ_ADR, IND_SIS_PASSWORD);
+ vgawb(SEQ_DATA, SIS_PASSWORD);
+
+ /* Enable MMIO & PCI linear address */
+ vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
+ jTemp = vgarb(SEQ_DATA);
+ jTemp |= SIS_PCI_ADDR_ENABLE;
+ jTemp |= SIS_MEM_MAP_IO_ENABLE;
+ vgawb(SEQ_DATA, jTemp);
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ pdev_valid = 0;
+ pci_for_each_dev(pdev) {
+ u8 uPCIData=0;
+
+ if ((pdev->vendor == PCI_VENDOR_ID_SI) && (pdev->device==0x630))
+ {
+ pci_read_config_byte(pdev, 0x63, &uPCIData);
+ uPCIData = (uPCIData & 0x70) >> 4;
+ ivideo.video_size = (unsigned int)(1 << (uPCIData+21));
+ pdev_valid = 1;
+ break;
+ }
+ }
+
+ if (!pdev_valid)
+ return -1;
+#else
+ vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
+ ivideo.video_size = ((unsigned int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
+#endif
+
+
+ /* get CRT2 connection state */
+ vgawb(SEQ_ADR, 0x17);
+ uSRData = vgarb(SEQ_DATA);
+ vgawb(CRTC_ADR, 0x32);
+ uCRData = vgarb(CRTC_DATA);
+
+ ivideo.TV_plug = ivideo.TV_type = 0;
+ if((uSRData&0x0F) && (HwExt.jChipID>=SIS_Trojan))
+ {
+ /* CRT1 connect detection */
+ if((uSRData & 0x01) && !crt1off)
+ crt1off = 0;
+ else
+ {
+ if(uSRData&0x0E) /* DISP2 connected */
+ crt1off = 1;
+ else
+ crt1off = 0;
+ }
+
+ /* detection priority : CRT2 > LCD > TV */
+ if(uSRData & 0x08 )
+ uDispType = MASK_DISPTYPE_CRT2;
+ else if(uSRData & 0x02)
+ uDispType = MASK_DISPTYPE_LCD;
+ else if(uSRData & 0x04)
+ {
+ if(uSRData & 0x80)
+ {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+ else if(uSRData & 0x20)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if(uSRData & 0x10)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if(uSRData & 0x40)
+ ivideo.TV_plug = TVPLUG_SCART;
+
+ if(ivideo.TV_type == 0)
+ {
+ u8 uSR16;
+ vgawb(SEQ_ADR, 0x16);
+ uSR16 = vgarb(SEQ_DATA);
+ if(uSR16 & 0x20)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
+
+ uDispType = MASK_DISPTYPE_TV;
+ }
+ }
+ else
+ {
+ if((uCRData & 0x20) && !crt1off)
+ crt1off = 0;
+ else
+ {
+ if(uCRData&0x5F) /* DISP2 connected */
+ crt1off = 1;
+ else
+ crt1off = 0;
+ }
+
+ if(uCRData & 0x10)
+ uDispType = MASK_DISPTYPE_CRT2;
+ else if(uCRData & 0x08)
+ uDispType = MASK_DISPTYPE_LCD;
+ else if(uCRData & 0x47)
+ {
+ uDispType = MASK_DISPTYPE_TV;
+
+ if(uCRData & 0x40)
+ {
+ ivideo.TV_type = TVMODE_HIVISION;
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ }
+ else if(uCRData & 0x02)
+ ivideo.TV_plug = TVPLUG_SVIDEO;
+ else if(uCRData & 0x01)
+ ivideo.TV_plug = TVPLUG_COMPOSITE;
+ else if(uCRData & 0x04)
+ ivideo.TV_plug = TVPLUG_SCART;
+
+ if(ivideo.TV_type == 0)
+ {
+ u8 uTemp;
+ uTemp = *((u8 *)(HwExt.VirtualRomBase+0x52));
+ if(uTemp&0x40)
+ {
+ uTemp=*((u8 *)(HwExt.VirtualRomBase+0x53));
+ }
+ else
+ {
+ vgawb(SEQ_ADR, 0x38);
+ uTemp = vgarb(SEQ_DATA);
+ }
+ if(uTemp & 0x01)
+ ivideo.TV_type = TVMODE_PAL;
+ else
+ ivideo.TV_type = TVMODE_NTSC;
+ }
+ }
+ }
+
+ if(uDispType == MASK_DISPTYPE_LCD) // LCD conntected
+ {
+ // TODO: set LCDType by EDID
+ HwExt.usLCDType = LCD1024;
+ }
+
+ if (HwExt.jChipID >= SIS_Trojan)
+ {
+ vgawb(SEQ_ADR, 0x1A);
+ uSRData = vgarb(SEQ_DATA);
+ if (uSRData & 0x10)
+ HwExt.bIntegratedMMEnabled = TRUE;
+ else
+ HwExt.bIntegratedMMEnabled = FALSE;
+ }
+
+ if(mode_idx >= 0) /* mode found */
+ {
+ /* Filtering mode for VB */
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ switch(HwExt.usLCDType)
+ {
+ case LCD1024:
+ if(sisbios_mode[mode_idx].xres > 1024)
+ mode_idx = -1;
+ break;
+ case LCD1280:
+ if(sisbios_mode[mode_idx].xres > 1280)
+ mode_idx = -1;
+ break;
+ case LCD2048:
+ if(sisbios_mode[mode_idx].xres > 2048)
+ mode_idx = -1;
+ break;
+ case LCD1920:
+ if(sisbios_mode[mode_idx].xres > 1920)
+ mode_idx = -1;
+ break;
+ case LCD1600:
+ if(sisbios_mode[mode_idx].xres > 1600)
+ mode_idx = -1;
+ break;
+ case LCD800:
+ if(sisbios_mode[mode_idx].xres > 800)
+ mode_idx = -1;
+ break;
+ case LCD640:
+ if(sisbios_mode[mode_idx].xres > 640)
+ mode_idx = -1;
+ break;
+ default:
+ mode_idx = -1;
+ }
+
+ if(sisbios_mode[mode_idx].xres == 720) /* only for TV */
+ mode_idx = -1;
+ break;
+ case MASK_DISPTYPE_TV:
+ switch(sisbios_mode[mode_idx].xres)
+ {
+ case 800:
+ case 640:
+ break;
+ case 720:
+ if(ivideo.TV_type == TVMODE_NTSC)
+ {
+ if(sisbios_mode[mode_idx].yres != 480)
+ mode_idx = -1;
+ }
+ else if(ivideo.TV_type == TVMODE_PAL)
+ {
+ if(sisbios_mode[mode_idx].yres != 576)
+ mode_idx = -1;
+ }
+ break;
+ default:
+ /* illegal mode */
+ mode_idx = -1;
+ }
+ break;
+ }
+ }
+
+ if (mode_idx < 0)
+ {
+ switch(uDispType & MASK_DISPTYPE_DISP2)
+ {
+ case MASK_DISPTYPE_LCD:
+ mode_idx = DEFAULT_LCDMODE;
+ break;
+ case MASK_DISPTYPE_TV:
+ mode_idx = DEFAULT_TVMODE;
+ break;
+ default:
+ mode_idx = DEFAULT_MODE;
+ }
+ }
+
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ mode_idx = DEFAULT_MODE;
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ /* set to default refresh rate 60MHz */
+ ivideo.refresh_rate = 60;
+#endif
+
+ mode_no = sisbios_mode[mode_idx].mode_no;
+
+ if (ivideo.refresh_rate != 0)
+ search_refresh_rate(ivideo.refresh_rate);
+
+ if (rate_idx == 0) {
+ rate_idx = sisbios_mode[mode_idx].rate_idx;
+ /* set to default refresh rate 60MHz */
+ ivideo.refresh_rate = 60;
+ }
+
+ ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
+ ivideo.video_vwidth = ivideo.video_width = sisbios_mode[mode_idx].xres;
+ ivideo.video_vheight = ivideo.video_height = sisbios_mode[mode_idx].yres;
+ ivideo.org_x = ivideo.org_y = 0;
+ video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+
+ printk(KERN_DEBUG "FB base: 0x%lx, size: 0x%dK\n",
+ ivideo.video_base, (unsigned int)ivideo.video_size/1024);
+ printk(KERN_DEBUG "MMIO base: 0x%lx, size: 0x%dK\n",
+ ivideo.mmio_base, (unsigned int)MMIO_SIZE/1024);
+
+
+ if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB"))
+ {
+ printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(ivideo.mmio_base, MMIO_SIZE, "sisfb MMIO"))
+ {
+ printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
+ release_mem_region(ivideo.video_base, ivideo.video_size);
+ return -ENODEV;
+ }
+
+ HwExt.VirtualVideoMemoryAddress = ivideo.video_vbase
+ = ioremap(ivideo.video_base, ivideo.video_size);
+ ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
+
+#ifdef NOBIOS
+ SiSInit300(&HwExt);
+#else
+#ifdef CONFIG_FB_SIS_LINUXBIOS
+ SiSInit300(&HwExt);
+#endif
+#endif
+ printk(KERN_INFO
+ "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ ivideo.video_base, ivideo.video_vbase,
+ ivideo.video_size / 1024);
+ printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
+ ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
+ video_linelength);
+
+ /* enable 2D engine */
+ vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
+ jTemp = vgarb(SEQ_DATA);
+ jTemp |= SIS_2D_ENABLE;
+ vgawb(SEQ_DATA, jTemp);
+
+ pre_setmode();
+
+ if (SiSSetMode(&HwExt, mode_no)) {
+ DPRINTK("sisfb: set mode[0x%x]: failed\n", mode_no);
+ return -1;
+ }
+
+ post_setmode();
+
+ /* Get VB functions */
+ sis_get301info();
+
+ crtc_to_var(&default_var);
+
+ fb_info.changevar = NULL;
+ fb_info.node = -1;
+ fb_info.fbops = &sisfb_ops;
+ fb_info.disp = &disp;
+ fb_info.switch_con = &sisfb_switch;
+ fb_info.updatevar = &sisfb_update_var;
+ fb_info.blank = &sisfb_blank;
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ sisfb_set_disp(-1, &default_var);
+
+ if (sisfb_heap_init()) {
+ DPRINTK("sisfb: Failed to enable offscreen heap\n");
+ }
+
+ /* to avoid the inversed bgcolor bug of the initial state */
+ vc_resize_con(1, 1, 0);
+
+ if (register_framebuffer(&fb_info) < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.node), fb_info.modename);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+static char *mode = NULL;
+static unsigned int rate = 0;
+static unsigned int crt1 = 1;
+
+MODULE_PARM(mode, "s");
+MODULE_PARM(rate, "i");
+MODULE_PARM(crt1, "i"); /* default: CRT1 enable */
+
+int init_module(void)
+{
+ if (mode)
+ search_mode(mode);
+
+ ivideo.refresh_rate = rate;
+
+ if(crt1 == 0)
+ crt1off = 1;
+ else
+ crt1off = 0;
+
+ sisfb_init();
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_framebuffer(&fb_info);
+}
+#endif /* MODULE */
+
+
+EXPORT_SYMBOL(sis_malloc);
+EXPORT_SYMBOL(sis_free);
+
+EXPORT_SYMBOL(ivideo);
diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c
deleted file mode 100644
index c2d460b99..000000000
--- a/drivers/video/sisfb.c
+++ /dev/null
@@ -1,3619 +0,0 @@
-/*
- * SiS 300/630/540 frame buffer device For Kernal 2.4.x
- *
- * This driver is partly based on the VBE 2.0 compliant graphic
- * boards framebuffer driver, which is
- *
- * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
-
-#define EXPORT_SYMTAB
-#undef SISFBDEBUG
-#undef CONFIG_FB_SIS_LINUXBIOS
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/console.h>
-#include <linux/selection.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vt_kern.h>
-#include <linux/capability.h>
-#include <linux/sisfb.h>
-
-#include <asm/io.h>
-#include <asm/mtrr.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
-/* ------------------- Constant Definitions ------------------------- */
-
-#define FALSE 0
-#define TRUE 1
-
-/* Draw Function
-#define FBIOGET_GLYPH 0x4620
-#define FBIOGET_HWCINFO 0x4621
-*/
-#define BR(x) (0x8200 | (x) << 2)
-
-#define BITBLT 0x00000000
-#define COLOREXP 0x00000001
-#define ENCOLOREXP 0x00000002
-#define MULTIPLE_SCANLINE 0x00000003
-#define LINE 0x00000004
-#define TRAPAZOID_FILL 0x00000005
-#define TRANSPARENT_BITBLT 0x00000006
-
-#define SRCVIDEO 0x00000000
-#define SRCSYSTEM 0x00000010
-#define SRCAGP 0x00000020
-
-#define PATFG 0x00000000
-#define PATPATREG 0x00000040
-#define PATMONO 0x00000080
-
-#define X_INC 0x00010000
-#define X_DEC 0x00000000
-#define Y_INC 0x00020000
-#define Y_DEC 0x00000000
-
-#define NOCLIP 0x00000000
-#define NOMERGECLIP 0x04000000
-#define CLIPENABLE 0x00040000
-#define CLIPWITHOUTMERGE 0x04040000
-
-#define OPAQUE 0x00000000
-#define TRANSPARENT 0x00100000
-
-#define DSTAGP 0x02000000
-#define DSTVIDEO 0x02000000
-
-#define LINE_STYLE 0x00800000
-#define NO_RESET_COUNTER 0x00400000
-#define NO_LAST_PIXEL 0x00200000
-
-/* capabilities */
-#define TURBO_QUEUE_CAP 0x80
-#define HW_CURSOR_CAP 0x40
-
-/* VGA register Offsets */
-#define SEQ_ADR (0x14)
-#define SEQ_DATA (0x15)
-#define DAC_ADR (0x18)
-#define DAC_DATA (0x19)
-#define CRTC_ADR (0x24)
-#define CRTC_DATA (0x25)
-
-/* SiS indexed register indexes */
-#define IND_SIS_PASSWORD (0x05)
-#define IND_SIS_DRAM_SIZE (0x14)
-#define IND_SIS_MODULE_ENABLE (0x1E)
-#define IND_SIS_PCI_ADDRESS_SET (0x20)
-#define IND_SIS_TURBOQUEUE_ADR (0x26)
-#define IND_SIS_TURBOQUEUE_SET (0x27)
-
-/* Sis register value */
-#define SIS_PASSWORD (0x86)
-
-#define SIS_2D_ENABLE (0x40)
-
-#define SIS_MEM_MAP_IO_ENABLE (0x01)
-#define SIS_PCI_ADDR_ENABLE (0x80)
-
-#define MMIO_SIZE 0x20000 /* 128K MMIO capability */
-#define MAX_ROM_SCAN 0x10000
-
-#define RESERVED_MEM_SIZE_4M 0x400000 /* 4M */
-#define RESERVED_MEM_SIZE_8M 0x800000 /* 8M */
-
-/* Mode set stuff */
-#define DEFAULT_MODE 0
-
-#define ModeInfoFlag 0x07
-#define MemoryInfoFlag 0x1E0
-#define MemorySizeShift 0x05
-#define ModeVGA 0x03
-#define ModeEGA 0x02
-#define CRT1Len 17
-#define DoubleScanMode 0x8000
-#define HalfDCLK 0x1000
-
-#define InterlaceMode 0x80
-#define LineCompareOff 0x400
-#define DACInfoFlag 0x18
-
-#define VCLKStartFreq 25
-
-#define SIS_Glamour 0x0300
-#define SIS_Trojan 0x6300
-#define SIS_Spartan 0x5300
-
-/* heap stuff */
-#define OH_ALLOC_SIZE 4000
-#define SENTINEL 0x7fffffff
-
-#define TURBO_QUEUE_AREA_SIZE 0x80000 /* 512K */
-#define HW_CURSOR_AREA_SIZE 0x1000 /* 4K */
-
-/* video connection status */
-#define VB_COMPOSITE 0x01
-#define VB_SVIDEO 0x02
-#define VB_SCART 0x04
-#define VB_LCD 0x08
-#define VB_CRT2 0x10
-#define CRT1 0x20
-#define VB_HDTV 0x40
-
-/* ------------------- Global Variables ----------------------------- */
-
-struct video_info ivideo;
-
-struct GlyInfo {
- unsigned char ch;
- int fontwidth;
- int fontheight;
- u8 gmask[72];
- int ngmask;
-};
-
-/* Supported SiS Chips list */
-static struct board {
- u16 vendor, device;
- const char *name;
-} dev_list[] = {
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
- {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
- {0, 0, NULL}
-};
-
-/* card parameters */
-unsigned long rom_base;
-unsigned long rom_vbase;
-
-/* mode */
-static int video_type = FB_TYPE_PACKED_PIXELS;
-static int video_linelength;
-static int video_cmap_len;
-static int sisfb_off = 0;
-
-static struct fb_var_screeninfo default_var = {
- 0, 0, 0, 0,
- 0, 0,
- 0,
- 0,
- {0, 8, 0},
- {0, 8, 0},
- {0, 8, 0},
- {0, 0, 0},
- 0,
- FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- FB_VMODE_NONINTERLACED,
- {0, 0, 0, 0, 0, 0}
-};
-
-static struct display disp;
-static struct fb_info fb_info;
-
-static struct {
- u16 blue, green, red, pad;
-} palette[256];
-
-static union {
-#ifdef FBCON_HAS_CFB16
- u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
- u32 cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cfb32[16];
-#endif
-} fbcon_cmap;
-
-static int inverse = 0;
-static int currcon = 0;
-
-static struct display_switch sisfb_sw;
-
-u8 caps = 0;
-
-/* ModeSet stuff */
-
-u16 P3c4, P3d4, P3c0, P3ce, P3c2, P3ca, P3c6, P3c7, P3c8, P3c9, P3da;
-u16 CRT1VCLKLen;
-u16 flag_clearbuffer;
-u16 CRT1VCLKLen;
-int ModeIDOffset, StandTable, CRT1Table, ScreenOffset;
-int REFIndex, ModeType;
-int VCLKData;
-int RAMType;
-
-int mode_idx = -1;
-u8 mode_no = 0;
-u8 rate_idx = 0;
-
-static const struct _sisbios_mode {
- char name[15];
- u8 mode_no;
- u16 xres;
- u16 yres;
- u16 bpp;
- u16 rate_idx;
- u16 cols;
- u16 rows;
-} sisbios_mode[] = {
- {"640x480x8", 0x2E, 640, 480, 8, 1, 80, 30},
- {"640x480x16", 0x44, 640, 480, 16, 1, 80, 30},
- {"640x480x32", 0x62, 640, 480, 32, 1, 80, 30},
- {"800x600x8", 0x30, 800, 600, 8, 2, 100, 37},
- {"800x600x16", 0x47, 800, 600, 16, 2, 100, 37},
- {"800x600x32", 0x63, 800, 600, 32, 2, 100, 37},
- {"1024x768x8", 0x38, 1024, 768, 8, 2, 128, 48},
- {"1024x768x16", 0x4A, 1024, 768, 16, 2, 128, 48},
- {"1024x768x32", 0x64, 1024, 768, 32, 2, 128, 48},
- {"1280x1024x8", 0x3A, 1280, 1024, 8, 2, 160, 64},
- {"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
- {"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
- {"1600x1200x8", 0x3C, 1600, 1200, 8, 1, 200, 75},
- {"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
- {"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
- {"1920x1440x8", 0x68, 1920, 1440, 8, 1, 240, 75},
- {"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
- {"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
- {"\0", 0x00, 0, 0, 0, 0, 0, 0}
-};
-
-static struct _vrate {
- u16 idx;
- u16 xres;
- u16 yres;
- u16 refresh;
-} vrate[] = {
- {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
- {5, 640, 480, 100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
- {1, 800, 600, 56}, {2, 800, 600, 60}, {3, 800, 600, 72}, {4, 800, 600, 75},
- {5, 800, 600, 85}, {6, 800, 600, 100}, {7, 800, 600, 120}, {8, 800, 600, 160},
- {1, 1024, 768, 43}, {2, 1024, 768, 60}, {3, 1024, 768, 70}, {4, 1024, 768, 75},
- {5, 1024, 768, 85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
- {1, 1280, 1024, 43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
- {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
- {5, 1600, 1200, 85},
- {1, 1920, 1440, 60},
- {0, 0, 0, 0}
-};
-
-u16 DRAMType[17][5] = {
- {0x0C, 0x0A, 0x02, 0x40, 0x39}, {0x0D, 0x0A, 0x01, 0x40, 0x48},
- {0x0C, 0x09, 0x02, 0x20, 0x35}, {0x0D, 0x09, 0x01, 0x20, 0x44},
- {0x0C, 0x08, 0x02, 0x10, 0x31}, {0x0D, 0x08, 0x01, 0x10, 0x40},
- {0x0C, 0x0A, 0x01, 0x20, 0x34}, {0x0C, 0x09, 0x01, 0x08, 0x32},
- {0x0B, 0x08, 0x02, 0x08, 0x21}, {0x0C, 0x08, 0x01, 0x08, 0x30},
- {0x0A, 0x08, 0x02, 0x04, 0x11}, {0x0B, 0x0A, 0x01, 0x10, 0x28},
- {0x09, 0x08, 0x02, 0x02, 0x01}, {0x0B, 0x09, 0x01, 0x08, 0x24},
- {0x0B, 0x08, 0x01, 0x04, 0x20}, {0x0A, 0x08, 0x01, 0x02, 0x10},
- {0x09, 0x08, 0x01, 0x01, 0x00}
-};
-
-u16 MDA_DAC[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
-};
-
-u16 CGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
-};
-
-u16 EGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
- 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
- 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
- 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
- 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
- 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
- 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
-};
-
-u16 VGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
- 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
- 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
- 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
- 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
- 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
- 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
- 0x0B, 0x0C, 0x0D, 0x0F, 0x10
-};
-
-#define Monitor1Sense 0x20
-
-unsigned char SRegsInit[] = {
- 0x03, 0x00, 0x03, 0x00, 0x02, 0xa1, 0x00, 0x13,
- 0x2f, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xa1, 0x76, 0xb2, 0xf6, 0x0d, 0x00, 0x00, 0x00,
- 0x37, 0x61, 0x80, 0x1b, 0xe1, 0x01, 0x55, 0x43,
- 0x80, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff,
- 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff
-};
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
-
-unsigned char SRegs[] = {
- 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13,
- 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
- 0x0B, 0x0F, 0x00, 0x00, 0x4F, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x40, 0x00,
- 0xA1, 0xB6, 0xB2, 0xF6, 0x0D, 0x00, 0xF8, 0xF0,
- 0x37, 0x61, 0x80, 0x1B, 0xE1, 0x80, 0x55, 0x43,
- 0x80, 0x00, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF,
- 0x8E, 0x40, 0x00, 0x00, 0x08, 0x00, 0xFF, 0xFF
-};
-
-unsigned char CRegs[] = {
- 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x0b, 0xdf, 0x50, 0x40, 0xe7, 0x04, 0xa3,
- 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff
-}; // clear CR11[7]
-
-unsigned char GRegs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, 0x00
-};
-
-unsigned char ARegs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char MReg = 0x6f;
-
-#endif
-
-
-/* HEAP stuff */
-
-struct OH {
- struct OH *pohNext;
- struct OH *pohPrev;
- unsigned long ulOffset;
- unsigned long ulSize;
-};
-
-struct OHALLOC {
- struct OHALLOC *pohaNext;
- struct OH aoh[1];
-};
-
-struct HEAP {
- struct OH ohFree;
- struct OH ohUsed;
- struct OH *pohFreeList;
- struct OHALLOC *pohaChain;
-
- unsigned long ulMaxFreeSize;
-};
-
-struct HEAP heap;
-unsigned long heap_start;
-unsigned long heap_end;
-unsigned long heap_size;
-
-unsigned int tqueue_pos;
-unsigned long hwcursor_vbase;
-
-/* Draw Function stuff */
-u32 command_reg;
-
-/* -------------------- Macro definitions --------------------------- */
-
-#ifdef SISFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#define vgawb(reg,data) \
- (outb(data, ivideo.vga_base+reg))
-#define vgaww(reg,data) \
- (outw(data, ivideo.vga_base+reg))
-#define vgawl(reg,data) \
- (outl(data, ivideo.vga_base+reg))
-#define vgarb(reg) \
- (inb(ivideo.vga_base+reg))
-
-/* ---------------------- Routine Prototype ------------------------- */
-
-/* Interface used by the world */
-int sisfb_setup(char *options);
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
-
-/* Interface to the low level console driver */
-int sisfb_init(void);
-static int sisfb_update_var(int con, struct fb_info *info);
-static int sisfb_switch(int con, struct fb_info *info);
-static void sisfb_blank(int blank, struct fb_info *info);
-
-/* Internal routines */
-static void crtc_to_var(struct fb_var_screeninfo *var);
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *fb_info);
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *fb_info);
-static void do_install_cmap(int con, struct fb_info *info);
-static int do_set_var(struct fb_var_screeninfo *var, int isactive,
- struct fb_info *info);
-
-/* set-mode routines */
-static void set_reg1(u16 port, u16 index, u16 data);
-static void set_reg3(u16 port, u16 data);
-static void set_reg4(u16 port, unsigned long data);
-static u8 get_reg1(u16 port, u16 index);
-static u8 get_reg2(u16 port);
-//#ifndef CONFIG_FB_SIS_LINUXBIOS
-static u32 get_reg3(u16 port);
-static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo);
-static int search_modeID(unsigned long ROMAddr, u16 ModeNo);
-static int check_memory_size(unsigned long ROMAddr);
-static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo);
-static void set_seq_regs(unsigned long ROMAddr);
-static void set_misc_regs(unsigned long ROMAddr);
-static void set_crtc_regs(unsigned long ROMAddr);
-static void set_attregs(unsigned long ROMAddr);
-static void set_grc_regs(unsigned long ROMAddr);
-static void ClearExt1Regs(void);
-static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo);
-static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo);
-static void set_sync(unsigned long ROMAddr);
-static void set_crt1_crtc(unsigned long ROMAddr);
-static void set_crt1_offset(unsigned long ROMAddr);
-static u16 get_vclk_len(unsigned long ROMAddr);
-static void set_crt1_vclk(unsigned long ROMAddr);
-static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo);
-static u16 calc_delay2(unsigned long ROMAddr, u16 key);
-static u16 calc_delay(unsigned long ROMAddr, u16 key);
-static void set_crt1_FIFO(unsigned long ROMAddr);
-static void set_crt1_FIFO2(unsigned long ROMAddr);
-static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo);
-static void set_interlace(unsigned long ROMAddr, u16 ModeNo);
-//#endif
-static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh);
-static void load_DAC(unsigned long ROMAddr);
-static void display_on(void);
-
-static int SiSSetMode(u16 ModeNo);
-static void pre_setmode(void);
-static void post_setmode(void);
-static void search_mode(const char *name);
-static u8 search_refresh_rate(unsigned int rate);
-
-/* heap routines */
-static int sisfb_heap_init(void);
-static struct OH *poh_new_node(void);
-static struct OH *poh_allocate(unsigned long size);
-static struct OH *poh_free(unsigned long base);
-static void delete_node(struct OH *poh);
-static void insert_node(struct OH *pohList, struct OH *poh);
-static void free_node(struct OH *poh);
-
-/* ---------------------- Internal Routines ------------------------- */
-
-inline static u32 RD32(unsigned char *base, s32 off)
-{
- return readl(base + off);
-}
-
-inline static void WR32(unsigned char *base, s32 off, u32 v)
-{
- writel(v, base + off);
-}
-
-inline static void WR16(unsigned char *base, s32 off, u16 v)
-{
- writew(v, base + off);
-}
-
-inline static void WR8(unsigned char *base, s32 off, u8 v)
-{
- writeb(v, base + off);
-}
-
-inline static u32 regrl(s32 off)
-{
- return RD32(ivideo.mmio_vbase, off);
-}
-
-inline static void regwl(s32 off, u32 v)
-{
- WR32(ivideo.mmio_vbase, off, v);
-}
-
-inline static void regww(s32 off, u16 v)
-{
- WR16(ivideo.mmio_vbase, off, v);
-}
-
-inline static void regwb(s32 off, u8 v)
-{
- WR8(ivideo.mmio_vbase, off, v);
-}
-
-/*
- * Get CRTC registers to set var
- */
-static void crtc_to_var(struct fb_var_screeninfo *var)
-{
- u16 VRE, VBE, VRS, VBS, VDE, VT;
- u16 HRE, HBE, HRS, HBS, HDE, HT;
- u8 uSRdata, uCRdata, uCRdata2, uCRdata3, uMRdata;
- int A, B, C, D, E, F, temp;
- double hrate, drate;
-
- vgawb(SEQ_ADR, 0x6);
- uSRdata = vgarb(SEQ_DATA);
-
- if (uSRdata & 0x20)
- var->vmode = FB_VMODE_INTERLACED;
- else
- var->vmode = FB_VMODE_NONINTERLACED;
-
- switch ((uSRdata & 0x1c) >> 2) {
- case 0:
- var->bits_per_pixel = 8;
- break;
- case 2:
- var->bits_per_pixel = 16;
- break;
- case 4:
- var->bits_per_pixel = 32;
- break;
- }
-
- switch (var->bits_per_pixel) {
- case 8:
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- video_cmap_len = 256;
- break;
- case 16: /* RGB 565 */
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- video_cmap_len = 16;
-
- break;
- case 24: /* RGB 888 */
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- video_cmap_len = 16;
- break;
- case 32:
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- video_cmap_len = 16;
- break;
- }
-
- vgawb(SEQ_ADR, 0xa);
- uSRdata = vgarb(SEQ_DATA);
-
- vgawb(CRTC_ADR, 0x6);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x7);
- uCRdata2 = vgarb(CRTC_DATA);
- VT =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x01) << 8) |
- ((u16) (uCRdata2 & 0x20) << 4) | ((u16) (uSRdata & 0x01) <<
- 10);
- A = VT + 2;
-
- vgawb(CRTC_ADR, 0x12);
- uCRdata = vgarb(CRTC_DATA);
- VDE =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x02) << 7) |
- ((u16) (uCRdata2 & 0x40) << 3) | ((u16) (uSRdata & 0x02) << 9);
- E = VDE + 1;
-
- vgawb(CRTC_ADR, 0x10);
- uCRdata = vgarb(CRTC_DATA);
- VRS =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x04) << 6) |
- ((u16) (uCRdata2 & 0x80) << 2) | ((u16) (uSRdata & 0x08) << 7);
- F = VRS + 1 - E;
-
- vgawb(CRTC_ADR, 0x15);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x9);
- uCRdata3 = vgarb(CRTC_DATA);
- VBS =
- (uCRdata & 0xff) | ((u16) (uCRdata2 & 0x08) << 5) |
- ((u16) (uCRdata3 & 0x20) << 4) | ((u16) (uSRdata & 0x04) << 8);
-
- vgawb(CRTC_ADR, 0x16);
- uCRdata = vgarb(CRTC_DATA);
- VBE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x10) << 4);
- temp = VBE - ((E - 1) & 511);
- B = (temp > 0) ? temp : (temp + 512);
-
- vgawb(CRTC_ADR, 0x11);
- uCRdata = vgarb(CRTC_DATA);
- VRE = (uCRdata & 0x0f) | ((uSRdata & 0x20) >> 1);
- temp = VRE - ((E + F - 1) & 31);
- C = (temp > 0) ? temp : (temp + 32);
-
- D = B - F - C;
-
- var->yres = var->yres_virtual = E;
- var->upper_margin = D;
- var->lower_margin = F;
- var->vsync_len = C;
-
- vgawb(SEQ_ADR, 0xb);
- uSRdata = vgarb(SEQ_DATA);
-
- vgawb(CRTC_ADR, 0x0);
- uCRdata = vgarb(CRTC_DATA);
- HT = (uCRdata & 0xff) | ((u16) (uSRdata & 0x03) << 8);
- A = HT + 5;
-
- vgawb(CRTC_ADR, 0x1);
- uCRdata = vgarb(CRTC_DATA);
- HDE = (uCRdata & 0xff) | ((u16) (uSRdata & 0x0C) << 6);
- E = HDE + 1;
-
- vgawb(CRTC_ADR, 0x4);
- uCRdata = vgarb(CRTC_DATA);
- HRS = (uCRdata & 0xff) | ((u16) (uSRdata & 0xC0) << 2);
- F = HRS - E - 3;
-
- vgawb(CRTC_ADR, 0x2);
- uCRdata = vgarb(CRTC_DATA);
- HBS = (uCRdata & 0xff) | ((u16) (uSRdata & 0x30) << 4);
-
- vgawb(SEQ_ADR, 0xc);
- uSRdata = vgarb(SEQ_DATA);
- vgawb(CRTC_ADR, 0x3);
- uCRdata = vgarb(CRTC_DATA);
- vgawb(CRTC_ADR, 0x5);
- uCRdata2 = vgarb(CRTC_DATA);
- HBE =
- (uCRdata & 0x1f) | ((u16) (uCRdata2 & 0x80) >> 2) |
- ((u16) (uSRdata & 0x03) << 6);
- HRE = (uCRdata2 & 0x1f) | ((uSRdata & 0x04) << 3);
-
- temp = HBE - ((E - 1) & 255);
- B = (temp > 0) ? temp : (temp + 256);
-
- temp = HRE - ((E + F + 3) & 63);
- C = (temp > 0) ? temp : (temp + 64);
-
- D = B - F - C;
-
- var->xres = var->xres_virtual = E * 8;
- var->left_margin = D * 8;
- var->right_margin = F * 8;
- var->hsync_len = C * 8;
-
- var->activate = FB_ACTIVATE_NOW;
-
- var->sync = 0;
-
- uMRdata = vgarb(0x1C);
- if (uMRdata & 0x80)
- var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
- else
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
-
- if (uMRdata & 0x40)
- var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
- else
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
-
- VT += 2;
- VT <<= 1;
- HT = (HT + 5) * 8;
-
- hrate = (double) ivideo.refresh_rate * (double) VT / 2;
- drate = hrate * HT;
- var->pixclock = (u32) (1E12 / drate);
-}
-
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
-{
- struct fb_fix_screeninfo fix;
- struct display *display;
- struct display_switch *sw;
- u32 flags;
-
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
-
- sisfb_get_fix(&fix, con, 0);
-
- display->screen_base = ivideo.video_vbase;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->next_line = fix.line_length;
- /*display->can_soft_blank = 1; */
- display->can_soft_blank = 0;
- display->inverse = inverse;
- display->var = *var;
-
- save_flags(flags);
- switch (ivideo.video_bpp) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- sw = &fbcon_cfb8;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- sw = &fbcon_cfb16;
- display->dispsw_data = fbcon_cmap.cfb16;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB24
- case 24:
- sw = &fbcon_cfb24;
- display->dispsw_data = fbcon_cmap.cfb24;
- break;
-#endif
-
-#ifdef FBCON_HAS_CFB32
- case 32:
- sw = &fbcon_cfb32;
- display->dispsw_data = fbcon_cmap.cfb32;
- break;
-#endif
-
- default:
- sw = &fbcon_dummy;
- return;
- }
- memcpy(&sisfb_sw, sw, sizeof(*sw));
- display->dispsw = &sisfb_sw;
- restore_flags(flags);
-
- display->scrollmode = SCROLL_YREDRAW;
- sisfb_sw.bmove = fbcon_redraw_bmove;
-}
-
-/*
- * Read a single color register and split it into colors/transparent.
- * Return != 0 for invalid regno.
- */
-
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *fb_info)
-{
- if (regno >= video_cmap_len)
- return 1;
-
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
- *transp = 0;
- return 0;
-}
-
-/*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
-
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
- unsigned transp, struct fb_info *fb_info)
-{
-
- if (regno >= video_cmap_len)
- return 1;
-
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
-
- switch (ivideo.video_bpp) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- vgawb(DAC_ADR, regno);
- vgawb(DAC_DATA, red >> 10);
- vgawb(DAC_DATA, green >> 10);
- vgawb(DAC_DATA, blue >> 10);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- fbcon_cmap.cfb16[regno] =
- ((red & 0xf800)) |
- ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
- break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fbcon_cmap.cfb24[regno] =
- (red << 16) | (green << 8) | (blue);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fbcon_cmap.cfb32[regno] =
- (red << 16) | (green << 8) | (blue);
- break;
-#endif
- }
- return 0;
-}
-
-static void do_install_cmap(int con, struct fb_info *info)
-{
- if (con != currcon)
- return;
-
- if (fb_display[con].cmap.len)
- fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
- else
- fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
- sis_setcolreg, info);
-}
-
-static int do_set_var(struct fb_var_screeninfo *var, int isactive,
- struct fb_info *info)
-{
- unsigned int htotal =
- var->left_margin + var->xres + var->right_margin +
- var->hsync_len;
- unsigned int vtotal =
- var->upper_margin + var->yres + var->lower_margin +
- var->vsync_len;
- double drate = 0, hrate = 0;
- int found_mode = 0;
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
- vtotal <<= 1;
- else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
- vtotal <<= 2;
- else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
- var->yres <<= 1;
-
-
- if (!htotal || !vtotal) {
- DPRINTK("Invalid 'var' Information!\n");
- return 1;
- }
-
- drate = 1E12 / var->pixclock;
- hrate = drate / htotal;
- ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
-
- mode_idx = 0;
- while ((sisbios_mode[mode_idx].mode_no != 0)
- && (sisbios_mode[mode_idx].xres <= var->xres)) {
- if ((sisbios_mode[mode_idx].xres == var->xres)
- && (sisbios_mode[mode_idx].yres == var->yres)
- && (sisbios_mode[mode_idx].bpp == var->bits_per_pixel)) {
- mode_no = sisbios_mode[mode_idx].mode_no;
- found_mode = 1;
- break;
- }
- mode_idx++;
- }
-
- if (!found_mode) {
- printk("sisfb does not support mode %dx%d-%d\n", var->xres,
- var->yres, var->bits_per_pixel);
- return 1;
- }
-
- if (search_refresh_rate(ivideo.refresh_rate) == 0) {
- /* not supported rate */
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- ivideo.refresh_rate = 60;
- }
-
- if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
- pre_setmode();
-
- if (SiSSetMode(mode_no)) {
- DPRINTK("sisfb: set mode[0x%x]: failed\n",
- mode_no);
- return 1;
- }
-
- post_setmode();
-
- ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
- ivideo.video_width = sisbios_mode[mode_idx].xres;
- ivideo.video_height = sisbios_mode[mode_idx].yres;
- video_linelength =
- ivideo.video_width * (ivideo.video_bpp >> 3);
-
- DPRINTK("Current Mode: %dx%d-%d line_length=%d\n",
- ivideo.video_width, ivideo.video_height,
- ivideo.video_bpp, video_linelength);
- }
-
- return 0;
-}
-
-/* ---------------------- Draw Funtions ----------------------------- */
-
-static void sis_get_glyph(struct GlyInfo *gly)
-{
- struct display *p = &fb_display[currcon];
- u16 c;
- u8 *cdat;
- int widthb;
- u8 *gbuf = gly->gmask;
- int size;
-
-
- gly->fontheight = fontheight(p);
- gly->fontwidth = fontwidth(p);
- widthb = (fontwidth(p) + 7) / 8;
-
- c = gly->ch & p->charmask;
- if (fontwidth(p) <= 8)
- cdat = p->fontdata + c * fontheight(p);
- else
- cdat = p->fontdata + (c * fontheight(p) << 1);
-
- size = fontheight(p) * widthb;
- memcpy(gbuf, cdat, size);
- gly->ngmask = size;
-}
-
-
-/* ---------------------- HEAP Routines ----------------------------- */
-
-/*
- * Heap Initialization
- */
-
-static int sisfb_heap_init(void)
-{
- struct OH *poh;
- u8 jTemp, tq_state;
-
- if (ivideo.video_size > 0x800000)
- /* video ram is large than 8M */
- heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_8M;
- else
- heap_start = (unsigned long) ivideo.video_vbase + RESERVED_MEM_SIZE_4M;
-
- heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
- heap_size = heap_end - heap_start;
-
-
- /* Setting for Turbo Queue */
- if (heap_size >= TURBO_QUEUE_AREA_SIZE) {
- tqueue_pos =
- (ivideo.video_size -
- TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
- jTemp = (u8) (tqueue_pos & 0xff);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
- tq_state = vgarb(SEQ_DATA);
- tq_state |= 0xf0;
- tq_state &= 0xfc;
- tq_state |= (u8) (tqueue_pos >> 8);
- vgawb(SEQ_DATA, tq_state);
- vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
- vgawb(SEQ_DATA, jTemp);
-
- caps |= TURBO_QUEUE_CAP;
-
- heap_end -= TURBO_QUEUE_AREA_SIZE;
- heap_size -= TURBO_QUEUE_AREA_SIZE;
- }
-
- /* Setting for HW cursor(4K) */
- if (heap_size >= HW_CURSOR_AREA_SIZE) {
- heap_end -= HW_CURSOR_AREA_SIZE;
- heap_size -= HW_CURSOR_AREA_SIZE;
- hwcursor_vbase = heap_end;
-
- caps |= HW_CURSOR_CAP;
- }
-
- heap.pohaChain = NULL;
- heap.pohFreeList = NULL;
-
- poh = poh_new_node();
-
- if (poh == NULL)
- return 1;
-
- /* The first node describles the entire heap size */
- poh->pohNext = &heap.ohFree;
- poh->pohPrev = &heap.ohFree;
- poh->ulSize = heap_end - heap_start + 1;
- poh->ulOffset = heap_start - (unsigned long) ivideo.video_vbase;
-
- DPRINTK("sisfb:Heap start:0x%p, end:0x%p, len=%dk\n",
- (char *) heap_start, (char *) heap_end,
- (unsigned int) poh->ulSize / 1024);
-
- DPRINTK("sisfb:First Node offset:0x%x, size:%dk\n",
- (unsigned int) poh->ulOffset, (unsigned int) poh->ulSize / 1024);
-
- /* The second node in our free list sentinel */
- heap.ohFree.pohNext = poh;
- heap.ohFree.pohPrev = poh;
- heap.ohFree.ulSize = 0;
- heap.ulMaxFreeSize = poh->ulSize;
-
- /* Initialize the discardable list */
- heap.ohUsed.pohNext = &heap.ohUsed;
- heap.ohUsed.pohPrev = &heap.ohUsed;
- heap.ohUsed.ulSize = SENTINEL;
-
- return 0;
-}
-
-/*
- * Allocates a basic memory unit in which we'll pack our data structures.
- */
-
-static struct OH *poh_new_node(void)
-{
- int i;
- unsigned long cOhs;
- struct OHALLOC *poha;
- struct OH *poh;
-
- if (heap.pohFreeList == NULL) {
- poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
-
- poha->pohaNext = heap.pohaChain;
- heap.pohaChain = poha;
-
- cOhs =
- (OH_ALLOC_SIZE -
- sizeof(struct OHALLOC)) / sizeof(struct OH) + 1;
-
- poh = &poha->aoh[0];
- for (i = cOhs - 1; i != 0; i--) {
- poh->pohNext = poh + 1;
- poh = poh + 1;
- }
-
- poh->pohNext = NULL;
- heap.pohFreeList = &poha->aoh[0];
- }
-
- poh = heap.pohFreeList;
- heap.pohFreeList = poh->pohNext;
-
- return (poh);
-}
-
-/*
- * Allocates space, return NULL when failed
- */
-
-static struct OH *poh_allocate(unsigned long size)
-{
- struct OH *pohThis;
- struct OH *pohRoot;
- int bAllocated = 0;
-
- if (size > heap.ulMaxFreeSize) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
-
- pohThis = heap.ohFree.pohNext;
-
- while (pohThis != &heap.ohFree) {
- if (size <= pohThis->ulSize) {
- bAllocated = 1;
- break;
- }
- pohThis = pohThis->pohNext;
- }
-
- if (!bAllocated) {
- DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
- (unsigned int) size / 1024);
- return (NULL);
- }
-
- if (size == pohThis->ulSize) {
- pohRoot = pohThis;
- delete_node(pohThis);
- } else {
- pohRoot = poh_new_node();
-
- if (pohRoot == NULL) {
- return (NULL);
- }
-
- pohRoot->ulOffset = pohThis->ulOffset;
- pohRoot->ulSize = size;
-
- pohThis->ulOffset += size;
- pohThis->ulSize -= size;
- }
-
- heap.ulMaxFreeSize -= size;
-
- pohThis = &heap.ohUsed;
- insert_node(pohThis, pohRoot);
-
- return (pohRoot);
-}
-
-/*
- * To remove a node from a list.
- */
-
-static void delete_node(struct OH *poh)
-{
- struct OH *pohPrev;
- struct OH *pohNext;
-
-
- pohPrev = poh->pohPrev;
- pohNext = poh->pohNext;
-
- pohPrev->pohNext = pohNext;
- pohNext->pohPrev = pohPrev;
-
- return;
-}
-
-/*
- * To insert a node into a list.
- */
-
-static void insert_node(struct OH *pohList, struct OH *poh)
-{
- struct OH *pohTemp;
-
- pohTemp = pohList->pohNext;
-
- pohList->pohNext = poh;
- pohTemp->pohPrev = poh;
-
- poh->pohPrev = pohList;
- poh->pohNext = pohTemp;
-}
-
-/*
- * Frees an off-screen heap allocation.
- */
-
-static struct OH *poh_free(unsigned long base)
-{
-
- struct OH *pohThis;
- struct OH *pohFreed;
- struct OH *pohPrev;
- struct OH *pohNext;
- unsigned long ulUpper;
- unsigned long ulLower;
- int foundNode = 0;
-
- pohFreed = heap.ohUsed.pohNext;
-
- while (pohFreed != &heap.ohUsed) {
- if (pohFreed->ulOffset == base) {
- foundNode = 1;
- break;
- }
-
- pohFreed = pohFreed->pohNext;
- }
-
- if (!foundNode)
- return (NULL);
-
- heap.ulMaxFreeSize += pohFreed->ulSize;
-
- pohPrev = pohNext = NULL;
- ulUpper = pohFreed->ulOffset + pohFreed->ulSize;
- ulLower = pohFreed->ulOffset;
-
- pohThis = heap.ohFree.pohNext;
-
- while (pohThis != &heap.ohFree) {
- if (pohThis->ulOffset == ulUpper) {
- pohNext = pohThis;
- }
- else if ((pohThis->ulOffset + pohThis->ulSize) ==
- ulLower) {
- pohPrev = pohThis;
- }
- pohThis = pohThis->pohNext;
- }
-
- delete_node(pohFreed);
-
- if (pohPrev && pohNext) {
- pohPrev->ulSize += (pohFreed->ulSize + pohNext->ulSize);
- delete_node(pohNext);
- free_node(pohFreed);
- free_node(pohNext);
- return (pohPrev);
- }
-
- if (pohPrev) {
- pohPrev->ulSize += pohFreed->ulSize;
- free_node(pohFreed);
- return (pohPrev);
- }
-
- if (pohNext) {
- pohNext->ulSize += pohFreed->ulSize;
- pohNext->ulOffset = pohFreed->ulOffset;
- free_node(pohFreed);
- return (pohNext);
- }
-
- insert_node(&heap.ohFree, pohFreed);
-
- return (pohFreed);
-}
-
-/*
- * Frees our basic data structure allocation unit by adding it to a free
- * list.
- */
-
-static void free_node(struct OH *poh)
-{
- if (poh == NULL) {
- return;
- }
-
- poh->pohNext = heap.pohFreeList;
- heap.pohFreeList = poh;
-
- return;
-}
-
-void sis_malloc(struct sis_memreq *req)
-{
- struct OH *poh;
-
- poh = poh_allocate(req->size);
-
- if (poh == NULL) {
- req->offset = 0;
- req->size = 0;
- DPRINTK("sisfb: VMEM Allocation Failed\n");
- } else {
- DPRINTK("sisfb: VMEM Allocation Successed : 0x%p\n",
- (char *) (poh->ulOffset +
- (unsigned long) ivideo.video_vbase));
-
- req->offset = poh->ulOffset;
- req->size = poh->ulSize;
- }
-
-}
-
-void sis_free(unsigned long base)
-{
- struct OH *poh;
-
- poh = poh_free(base);
-
- if (poh == NULL) {
- DPRINTK("sisfb: poh_free() failed at base 0x%x\n",
- (unsigned int) base);
- }
-
-}
-
-
-
-/* ---------------------- SetMode Routines -------------------------- */
-
-static void set_reg1(u16 port, u16 index, u16 data)
-{
- outb((u8) (index & 0xff), port);
- port++;
- outb((u8) (data & 0xff), port);
-}
-
-static void set_reg3(u16 port, u16 data)
-{
- outb((u8) (data & 0xff), port);
-}
-
-static void set_reg4(u16 port, unsigned long data)
-{
- outl((u32) (data & 0xffffffff), port);
-}
-
-static u8 get_reg1(u16 port, u16 index)
-{
- u8 data;
-
- outb((u8) (index & 0xff), port);
- port += 1;
- data = inb(port);
- return (data);
-}
-
-static u8 get_reg2(u16 port)
-{
- u8 data;
-
- data = inb(port);
-
- return (data);
-}
-
-static u32 get_reg3(u16 port)
-{
- u32 data;
-
- data = inl(port);
- return (data);
-}
-
-static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo)
-{
- u16 modeidlength;
- u16 usModeIDOffset;
- unsigned short PreviousWord,CurrentWord;
-
- return(10);
-
- modeidlength=0;
- usModeIDOffset=*((unsigned short *)(ROMAddr+0x20A)); // Get EModeIDTable
-
- CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset)); // Offset 0x20A
- PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2)); // Offset 0x20A
- while((CurrentWord!=0x2E07)||(PreviousWord!=0x0801))
- {
- modeidlength++;
- usModeIDOffset=usModeIDOffset+1; // 10 <= ExtStructSize
- CurrentWord=*((unsigned short *)(ROMAddr+usModeIDOffset));
- PreviousWord=*((unsigned short *)(ROMAddr+usModeIDOffset-2));
- }
- modeidlength++;
-
- return(modeidlength);
-}
-
-static int search_modeID(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char ModeID;
- u16 usIDLength;
- unsigned int count = 0;
-
- ModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
- ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
- usIDLength = get_modeID_length(ROMAddr, ModeNo);
- while (ModeID != 0xff && ModeID != ModeNo) {
- ModeIDOffset = ModeIDOffset + usIDLength;
- ModeID = *((unsigned char *) (ROMAddr + ModeIDOffset));
- if (count++ >= 0xff)
- break;
- }
- if (ModeID == 0xff)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static int check_memory_size(unsigned long ROMAddr)
-{
- u16 memorysize;
- u16 modeflag;
- u16 temp;
-
- modeflag = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- ModeType = modeflag & ModeInfoFlag;
-
- memorysize = modeflag & MemoryInfoFlag;
- memorysize = memorysize >> MemorySizeShift;
- memorysize++;
-
- temp = get_reg1(P3c4, 0x14);
- temp = temp & 0x3F;
- temp++;
-
- if (temp < memorysize)
- return (FALSE);
- else
- return (TRUE);
-}
-
-static void get_mode_ptr(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char index;
-
- StandTable = *((u16 *) (ROMAddr + 0x202));
-
- if (ModeNo <= 13)
- index = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
- else {
- if (ModeType <= 0x02)
- index = 0x1B;
- else
- index = 0x0F;
- }
-
- StandTable = StandTable + 64 * index;
-
-}
-
-static void set_seq_regs(unsigned long ROMAddr)
-{
- unsigned char SRdata;
- u16 i;
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- SRdata = SRegs[0x01];
-#else
- set_reg1(P3c4, 0x00, 0x03);
- StandTable = StandTable + 0x05;
- SRdata = *((unsigned char *) (ROMAddr + StandTable));
-#endif
-
- SRdata = SRdata | 0x20;
- set_reg1(P3c4, 0x01, SRdata);
-
-
- for (i = 02; i <= 04; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- SRdata = SRegs[i];
-#else
- StandTable++;
- SRdata = *((unsigned char *) (ROMAddr + StandTable));
-#endif
- set_reg1(P3c4, i, SRdata);
- }
-}
-
-static void set_misc_regs(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg3(P3c2, 0x23);
-#else
- unsigned char Miscdata;
-
- StandTable++;
- Miscdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg3(P3c2, Miscdata);
-#endif
-}
-
-static void set_crtc_regs(unsigned long ROMAddr)
-{
- unsigned char CRTCdata;
- u16 i;
-
- CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- CRTCdata = CRTCdata & 0x7f;
-#endif
- set_reg1(P3d4, 0x11, CRTCdata);
-
- for (i = 0; i <= 0x18; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3d4, i, CRegs[i]);
-#else
- StandTable++;
- CRTCdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg1(P3d4, i, CRTCdata);
-#endif
- }
-}
-
-static void set_attregs(unsigned long ROMAddr)
-{
- unsigned char ARdata;
- u16 i;
-
- for (i = 0; i <= 0x13; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARegs[i]);
-#else
- StandTable++;
- ARdata = *((unsigned char *) (ROMAddr + StandTable));
-
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARdata);
-#endif
- }
-
- get_reg2(P3da);
- set_reg3(P3c0, 0x14);
- set_reg3(P3c0, 0x00);
- get_reg2(P3da);
- set_reg3(P3c0, 0x20);
-}
-
-static void set_grc_regs(unsigned long ROMAddr)
-{
- unsigned char GRdata;
- u16 i;
-
- for (i = 0; i <= 0x08; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3ce, i, GRegs[i]);
-#else
- StandTable++;
- GRdata = *((unsigned char *) (ROMAddr + StandTable));
- set_reg1(P3ce, i, GRdata);
-#endif
- }
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- if (ModeType > ModeVGA) {
- GRdata = (unsigned char) get_reg1(P3ce, 0x05);
- GRdata = GRdata & 0xBF;
- set_reg1(P3ce, 0x05, GRdata);
- }
-#endif
-}
-
-static void ClearExt1Regs(void)
-{
- u16 i;
-
- for (i = 0x0A; i <= 0x0E; i++)
- set_reg1(P3c4, i, 0x00);
-}
-
-static u16 GetRefindexLength(unsigned long ROMAddr, u16 ModeNo)
-{
- unsigned char ModeID;
- unsigned char temp;
- u16 refindexlength;
- u16 usModeIDOffset;
- u16 usREFIndex;
- u16 usIDLength;
-
- usModeIDOffset = *((u16 *) (ROMAddr + 0x20A));
- ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
- usIDLength = get_modeID_length(ROMAddr, ModeNo);
- while (ModeID != 0x40) {
- usModeIDOffset = usModeIDOffset + usIDLength;
- ModeID = *((unsigned char *) (ROMAddr + usModeIDOffset));
- }
-
- refindexlength = 1;
- usREFIndex = *((u16 *) (ROMAddr + usModeIDOffset + 0x04));
- usREFIndex++;
- temp = *((unsigned char *) (ROMAddr + usREFIndex));
- while (temp != 0xFF) {
- refindexlength++;
- usREFIndex++;
- temp = *((unsigned char *) (ROMAddr + usREFIndex));
- }
- return (refindexlength);
-}
-
-static int get_rate_ptr(unsigned long ROMAddr, u16 ModeNo)
-{
- short index;
- u16 temp;
- u16 ulRefIndexLength;
-
- if (ModeNo < 0x14)
- return (FALSE);
-
- index = get_reg1(P3d4, 0x33);
- index = index & 0x0F;
- if (index != 0)
- index--;
-
- REFIndex = *((u16 *) (ROMAddr + ModeIDOffset + 0x04));
-
- ulRefIndexLength = GetRefindexLength(ROMAddr, ModeNo);
-
- do {
- temp = *((u16 *) (ROMAddr + REFIndex));
- if (temp == 0xFFFF)
- break;
- temp = temp & ModeInfoFlag;
- if (temp < ModeType)
- break;
-
- REFIndex = REFIndex + ulRefIndexLength;
- index--;
- } while (index >= 0);
-
- REFIndex = REFIndex - ulRefIndexLength;
- return (TRUE);
-}
-
-static void set_sync(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg3(P3c2, MReg);
-#else
- u16 sync;
- u16 temp;
-
- sync = *((u16 *) (ROMAddr + REFIndex));
- sync = sync & 0xC0;
- temp = 0x2F;
- temp = temp | sync;
- set_reg3(P3c2, temp);
-#endif
-}
-
-static void set_crt1_crtc(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- unsigned char data;
- u16 i;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- for (i = 0; i <= 0x07; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x10; i <= 0x12; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x15; i <= 0x16; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x0A; i <= 0x0C; i++)
- set_reg1(P3c4, i, SRegs[i]);
-
- data = SRegs[0x0E] & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- set_reg1(P3d4, 0x09, CRegs[0x09]);
-#else
- unsigned char index;
- unsigned char data;
- u16 i;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x02));
- CRT1Table = *((u16 *) (ROMAddr + 0x204));
- CRT1Table = CRT1Table + index * CRT1Len;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- CRT1Table--;
- for (i = 0; i <= 0x05; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x06; i <= 0x07; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x10; i <= 0x12; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x15; i <= 0x16; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3d4, i, data);
- }
- for (i = 0x0A; i <= 0x0C; i++) {
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- set_reg1(P3c4, i, data);
- }
-
- CRT1Table++;
- data = *((unsigned char *) (ROMAddr + CRT1Table));
- data = data & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- data = (unsigned char) get_reg1(P3d4, 0x09);
- data = data & 0xDF;
- i = *((unsigned char *) (ROMAddr + CRT1Table));
- i = i & 0x01;
- i = i << 5;
- data = data | i;
- i = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- i = i & DoubleScanMode;
- if (i)
- data = data | 0x80;
- set_reg1(P3d4, 0x09, data);
-
- if (ModeType > 0x03)
- set_reg1(P3d4, 0x14, 0x4F);
-#endif
-}
-
-
-static void set_crt1_offset(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x0E, SRegs[0x0E]);
- set_reg1(P3c4, 0x10, SRegs[0x10]);
-#else
- u16 temp, ah, al;
- u16 temp2, i;
- u16 DisplayUnit;
-
- temp = *((unsigned char *) (ROMAddr + ModeIDOffset + 0x03));
- temp = temp >> 4;
- ScreenOffset = *((u16 *) (ROMAddr + 0x206));
- temp = *((unsigned char *) (ROMAddr + ScreenOffset + temp));
-
- temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- temp2 = temp2 & InterlaceMode;
- if (temp2)
- temp = temp << 1;
- temp2 = ModeType - ModeEGA;
- switch (temp2) {
- case 0:
- temp2 = 1;
- break;
- case 1:
- temp2 = 2;
- break;
- case 2:
- temp2 = 4;
- break;
- case 3:
- temp2 = 4;
- break;
- case 4:
- temp2 = 6;
- break;
- case 5:
- temp2 = 8;
- break;
- }
- temp = temp * temp2;
- DisplayUnit = temp;
-
- temp2 = temp;
- temp = temp >> 8;
- temp = temp & 0x0F;
- i = get_reg1(P3c4, 0x0E);
- i = i & 0xF0;
- i = i | temp;
- set_reg1(P3c4, 0x0E, i);
-
- temp = (unsigned char) temp2;
- temp = temp & 0xFF;
- set_reg1(P3d4, 0x13, temp);
-
- temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- temp2 = temp2 & InterlaceMode;
- if (temp2)
- DisplayUnit >>= 1;
-
- DisplayUnit = DisplayUnit << 5;
- ah = (DisplayUnit & 0xff00) >> 8;
- al = DisplayUnit & 0x00ff;
- if (al == 0)
- ah = ah + 1;
- else
- ah = ah + 2;
- set_reg1(P3c4, 0x10, ah);
-#endif
-}
-
-static u16 get_vclk_len(unsigned long ROMAddr)
-{
- u16 VCLKDataStart, vclklabel, temp;
- VCLKDataStart = *((u16 *) (ROMAddr + 0x208));
- for (temp = 0;; temp++) {
- vclklabel = *((u16 *) (ROMAddr + VCLKDataStart + temp));
- if (vclklabel == VCLKStartFreq) {
- temp = temp + 2;
- return (temp);
- }
- }
- return (0);
-}
-
-static void set_crt1_vclk(unsigned long ROMAddr)
-{
- u16 i;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- unsigned char index, data;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x03F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data;
-#endif
-
- set_reg1(P3c4, 0x31, 0);
-
- for (i = 0x2B; i <= 0x2C; i++) {
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, i, SRegs[i]);
-#else
- data = *((unsigned char *) (ROMAddr + VCLKData));
- set_reg1(P3c4, i, data);
- VCLKData++;
-#endif
- }
- set_reg1(P3c4, 0x2D, 0x80);
-}
-static void set_vclk_state(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x32, SRegs[0x32]);
- set_reg1(P3c4, 0x07, SRegs[0x07]);
-#else
-
- u16 data, data2;
- u16 VCLK;
- unsigned char index;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
-
- VCLK = *((u16 *) (ROMAddr + VCLKData));
- if (ModeNo <= 0x13)
- VCLK = 0;
-
- data = get_reg1(P3c4, 0x07);
- data = data & 0x7B;
- if (VCLK >= 150)
- data = data | 0x80;
- set_reg1(P3c4, 0x07, data);
-
- data = get_reg1(P3c4, 0x32);
- data = data & 0xD7;
- if (VCLK >= 150)
- data = data | 0x08;
- set_reg1(P3c4, 0x32, data);
-
- data2 = 0x03;
- if (VCLK > 135)
- data2 = 0x02;
- if (VCLK > 160)
- data2 = 0x01;
- if (VCLK > 260)
- data2 = 0x00;
- data = get_reg1(P3c4, 0x07);
- data = data & 0xFC;
- data = data | data2;
- set_reg1(P3c4, 0x07, data);
-#endif
-}
-
-static u16 calc_delay2(unsigned long ROMAddr, u16 key)
-{
- u16 data, index;
- unsigned char LatencyFactor[] = {
- 88, 80, 78, 72, 70, 00,
- 00, 79, 77, 71, 69, 49,
- 88, 80, 78, 72, 70, 00,
- 00, 72, 70, 64, 62, 44
- };
- index = 0;
- data = get_reg1(P3c4, 0x14);
- if (data & 0x80)
- index = index + 12;
-
- data = get_reg1(P3c4, 0x15);
- data = (data & 0xf0) >> 4;
- if (data & 0x01)
- index = index + 6;
-
- data = data >> 1;
- index = index + data;
- data = LatencyFactor[index];
-
- return (data);
-}
-
-static u16 calc_delay(unsigned long ROMAddr, u16 key)
-{
- u16 data, data2, temp0, temp1;
- unsigned char ThLowA[] = {
- 61, 3, 52, 5, 68, 7, 100, 11,
- 43, 3, 42, 5, 54, 7, 78, 11,
- 34, 3, 37, 5, 47, 7, 67, 11
- };
- unsigned char ThLowB[] = {
- 81, 4, 72, 6, 88, 8, 120, 12,
- 55, 4, 54, 6, 66, 8, 90, 12,
- 42, 4, 45, 6, 55, 8, 75, 12
- };
- unsigned char ThTiming[] = { 1, 2, 2, 3, 0, 1, 1, 2 };
-
- data = get_reg1(P3c4, 0x16);
- data = data >> 6;
- data2 = get_reg1(P3c4, 0x14);
- data2 = (data2 >> 4) & 0x0C;
- data = data | data2;
- data = data < 1;
- if (key == 0) {
- temp0 = (u16) ThLowA[data];
- temp1 = (u16) ThLowA[data + 1];
- } else {
- temp0 = (u16) ThLowB[data];
- temp1 = (u16) ThLowB[data + 1];
- }
-
- data2 = 0;
- data = get_reg1(P3c4, 0x18);
- if (data & 0x02)
- data2 = data2 | 0x01;
- if (data & 0x20)
- data2 = data2 | 0x02;
- if (data & 0x40)
- data2 = data2 | 0x04;
-
- data = temp1 * ThTiming[data2] + temp0;
- return (data);
-}
-
-
-static void set_crt1_FIFO(unsigned long ROMAddr)
-{
- u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
- u16 ah, bl, A, B;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
- VCLK = *((u16 *) (ROMAddr + VCLKData));
-
- MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
- index = get_reg1(P3c4, 0x3A);
- index = index & 07;
- MCLKOffset = MCLKOffset + index * 5;
- MCLK = *((unsigned char *) (ROMAddr + MCLKOffset + 0x03));
-
- data2 = ModeType - 0x02;
- switch (data2) {
- case 0:
- colorth = 1;
- break;
- case 1:
- colorth = 2;
- break;
- case 2:
- colorth = 4;
- break;
- case 3:
- colorth = 4;
- break;
- case 4:
- colorth = 6;
- break;
- case 5:
- colorth = 8;
- break;
- }
-
- do {
- B = (calc_delay(ROMAddr, 0) * VCLK * colorth);
- B = B / (16 * MCLK);
- B++;
-
- A = (calc_delay(ROMAddr, 1) * VCLK * colorth);
- A = A / (16 * MCLK);
- A++;
-
- if (A < 4)
- A = 0;
- else
- A = A - 4;
-
- if (A > B)
- bl = A;
- else
- bl = B;
-
- bl++;
- if (bl > 0x13) {
- data = get_reg1(P3c4, 0x16);
- data = data >> 6;
- if (data != 0) {
- data--;
- data = data << 6;
- data2 = get_reg1(P3c4, 0x16);
- data2 = (data2 & 0x3f) | data;
- set_reg1(P3c4, 0x16, data2);
- } else
- bl = 0x13;
- }
- } while (bl > 0x13);
-
- ah = bl;
- ah = ah << 4;
- ah = ah | 0x0f;
- set_reg1(P3c4, 0x08, ah);
-
- data = bl;
- data = data & 0x10;
- data = data << 1;
- data2 = get_reg1(P3c4, 0x0F);
- data2 = data2 & 0x9f;
- data2 = data2 | data;
- set_reg1(P3c4, 0x0F, data2);
-
- data = bl + 3;
- if (data > 0x0f)
- data = 0x0f;
- set_reg1(P3c4, 0x3b, 0x00);
- data2 = get_reg1(P3c4, 0x09);
- data2 = data2 & 0xF0;
- data2 = data2 | data;
- set_reg1(P3c4, 0x09, data2);
-}
-
-static void set_crt1_FIFO2(unsigned long ROMAddr)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x15, SRegs[0x15]);
-
- set_reg4(0xcf8, 0x80000050);
- set_reg4(0xcfc, 0xc5041e04);
-
- set_reg1(P3c4, 0x08, SRegs[0x08]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x3b, 0x00);
- set_reg1(P3c4, 0x09, SRegs[0x09]);
-#else
-
- u16 index, data, VCLK, data2, MCLKOffset, MCLK, colorth = 1;
- u16 ah, bl, B;
- unsigned long eax;
-
- index = *((unsigned char *) (ROMAddr + REFIndex + 0x03));
- index &= 0x3F;
- CRT1VCLKLen = get_vclk_len(ROMAddr);
- data = index * CRT1VCLKLen;
- VCLKData = *((u16 *) (ROMAddr + 0x208));
- VCLKData = VCLKData + data + (CRT1VCLKLen - 2);
- VCLK = *((u16 *) (ROMAddr + VCLKData));
-
- MCLKOffset = *((u16 *) (ROMAddr + 0x20C));
- index = get_reg1(P3c4, 0x1A);
- index = index & 07;
- MCLKOffset = MCLKOffset + index * 5;
- MCLK = *((u16 *) (ROMAddr + MCLKOffset + 0x03));
-
- data2 = ModeType - 0x02;
- switch (data2) {
- case 0:
- colorth = 1;
- break;
- case 1:
- colorth = 1;
- break;
- case 2:
- colorth = 2;
- break;
- case 3:
- colorth = 2;
- break;
- case 4:
- colorth = 3;
- break;
- case 5:
- colorth = 4;
- break;
- }
-
- do {
- B = (calc_delay2(ROMAddr, 0) * VCLK * colorth);
- if (B % (16 * MCLK) == 0) {
- B = B / (16 * MCLK);
- bl = B + 1;
- } else {
- B = B / (16 * MCLK);
- bl = B + 2;
- }
-
- if (bl > 0x13) {
- data = get_reg1(P3c4, 0x15);
- data = data & 0xf0;
- if (data != 0xb0) {
- data = data + 0x20;
- if (data == 0xa0)
- data = 0x30;
- data2 = get_reg1(P3c4, 0x15);
- data2 = (data2 & 0x0f) | data;
- set_reg1(P3c4, 0x15, data2);
- } else
- bl = 0x13;
- }
- } while (bl > 0x13);
-
- data2 = get_reg1(P3c4, 0x15);
- data2 = (data2 & 0xf0) >> 4;
- data2 = data2 << 24;
-
- set_reg4(0xcf8, 0x80000050);
- eax = get_reg3(0xcfc);
- eax = eax & 0x0f0ffffff;
- eax = eax | data2;
- set_reg4(0xcfc, eax);
-
- ah = bl;
- ah = ah << 4;
- ah = ah | 0x0f;
- set_reg1(P3c4, 0x08, ah);
-
- data = bl;
- data = data & 0x10;
- data = data << 1;
- data2 = get_reg1(P3c4, 0x0F);
- data2 = data2 & 0x9f;
- data2 = data2 | data;
- set_reg1(P3c4, 0x0F, data2);
-
- data = bl + 3;
- if (data > 0x0f)
- data = 0x0f;
- set_reg1(P3c4, 0x3b, 0x00);
- data2 = get_reg1(P3c4, 0x09);
- data2 = data2 & 0xF0;
- data2 = data2 | data;
- set_reg1(P3c4, 0x09, data2);
-#endif
-}
-
-static void set_crt1_mode_regs(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3c4, 0x06, SRegs[0x06]);
- set_reg1(P3c4, 0x01, SRegs[0x01]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x21, SRegs[0x21]);
-#else
-
- u16 data, data2, data3;
-
- if (ModeNo > 0x13)
- data = *((u16 *) (ROMAddr + REFIndex + 0x00));
- else
- data = 0;
-
- data2 = 0;
- if (ModeNo > 0x13)
- if (ModeType > 0x02) {
- data2 = data2 | 0x02;
- data3 = ModeType - ModeVGA;
- data3 = data3 << 2;
- data2 = data2 | data3;
- }
-
- data = data & InterlaceMode;
- if (data)
- data2 = data2 | 0x20;
- set_reg1(P3c4, 0x06, data2);
-
- data = get_reg1(P3c4, 0x01);
- data = data & 0xF7;
- data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data2 = data2 & HalfDCLK;
- if (data2)
- data = data | 0x08;
- set_reg1(P3c4, 0x01, data);
-
- data = get_reg1(P3c4, 0x0F);
- data = data & 0xF7;
- data2 = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data2 = data2 & LineCompareOff;
- if (data2)
- data = data | 0x08;
- set_reg1(P3c4, 0x0F, data);
-
- data = get_reg1(P3c4, 0x21);
- data = data & 0x1F;
- if (ModeType == 0x00)
- data = data | 0x60;
- else if (ModeType <= 0x02)
- data = data | 0x00;
- else
- data = data | 0xA0;
- set_reg1(P3c4, 0x21, data);
-#endif
-}
-
-static void set_interlace(unsigned long ROMAddr, u16 ModeNo)
-{
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- set_reg1(P3d4, 0x19, CRegs[0x19]);
- set_reg1(P3d4, 0x1A, CRegs[0x1A]);
-#else
-
- unsigned long Temp;
- u16 data, Temp2;
-
- Temp = (unsigned long) get_reg1(P3d4, 0x01);
- Temp++;
- Temp = Temp * 8;
-
- if (Temp == 1024)
- data = 0x0035;
- else if (Temp == 1280)
- data = 0x0048;
- else
- data = 0x0000;
-
- Temp2 = *((u16 *) (ROMAddr + REFIndex + 0x00));
- Temp2 &= InterlaceMode;
- if (Temp2 == 0)
- data = 0x0000;
-
- set_reg1(P3d4, 0x19, data);
-
- Temp = (unsigned long) get_reg1(P3d4, 0x1A);
- Temp2 = (u16) (Temp & 0xFC);
- set_reg1(P3d4, 0x1A, (u16) Temp);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x0f);
- Temp2 = (u16) Temp & 0xBF;
- if (ModeNo == 0x37)
- Temp2 = Temp2 | 0x40;
- set_reg1(P3d4, 0x1A, (u16) Temp2);
-#endif
-}
-
-static void write_DAC(u16 dl, u16 ah, u16 al, u16 dh)
-{
- u16 temp;
- u16 bh, bl;
-
- bh = ah;
- bl = al;
- if (dl != 0) {
- temp = bh;
- bh = dh;
- dh = temp;
- if (dl == 1) {
- temp = bl;
- bl = dh;
- dh = temp;
- } else {
- temp = bl;
- bl = bh;
- bh = temp;
- }
- }
- set_reg3(P3c9, (u16) dh);
- set_reg3(P3c9, (u16) bh);
- set_reg3(P3c9, (u16) bl);
-}
-
-
-static void load_DAC(unsigned long ROMAddr)
-{
- u16 data, data2;
- u16 time, i, j, k;
- u16 m, n, o;
- u16 si, di, bx, dl;
- u16 al, ah, dh;
- u16 *table = VGA_DAC;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- data = *((u16 *) (ROMAddr + ModeIDOffset + 0x01));
- data = data & DACInfoFlag;
- time = 64;
- if (data == 0x00)
- table = MDA_DAC;
- if (data == 0x08)
- table = CGA_DAC;
- if (data == 0x10)
- table = EGA_DAC;
- if (data == 0x18) {
- time = 256;
- table = VGA_DAC;
- }
-#else
- time = 256;
- table = VGA_DAC;
-#endif
-
- if (time == 256)
- j = 16;
- else
- j = time;
-
- set_reg3(P3c6, 0xFF);
- set_reg3(P3c8, 0x00);
-
- for (i = 0; i < j; i++) {
- data = table[i];
- for (k = 0; k < 3; k++) {
- data2 = 0;
- if (data & 0x01)
- data2 = 0x2A;
- if (data & 0x02)
- data2 = data2 + 0x15;
- set_reg3(P3c9, data2);
- data = data >> 2;
- }
- }
-
- if (time == 256) {
- for (i = 16; i < 32; i++) {
- data = table[i];
- for (k = 0; k < 3; k++)
- set_reg3(P3c9, data);
- }
- si = 32;
- for (m = 0; m < 9; m++) {
- di = si;
- bx = si + 0x04;
- dl = 0;
- for (n = 0; n < 3; n++) {
- for (o = 0; o < 5; o++) {
- dh = table[si];
- ah = table[di];
- al = table[bx];
- si++;
- write_DAC(dl, ah, al, dh);
- }
- si = si - 2;
- for (o = 0; o < 3; o++) {
- dh = table[bx];
- ah = table[di];
- al = table[si];
- si--;
- write_DAC(dl, ah, al, dh);
- }
- dl++;
- }
- si = si + 5;
- }
- }
-}
-
-static void display_on(void)
-{
- u16 data;
-
- data = get_reg1(P3c4, 0x01);
- data = data & 0xDF;
- set_reg1(P3c4, 0x01, data);
-}
-
-void SetMemoryClock(void)
-{
- unsigned char i;
- int idx;
-
- u8 MCLK[] = {
- 0x5A, 0x64, 0x80, 0x66, 0x00, // SDRAM
- 0xB3, 0x45, 0x80, 0x83, 0x00, // SGRAM
- 0x37, 0x61, 0x80, 0x00, 0x01, // ESDRAM
- 0x37, 0x22, 0x80, 0x33, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01,
- 0x37, 0x61, 0x80, 0x00, 0x01
- };
-
- u8 ECLK[] = {
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x53, 0x43, 0x80, 0x00, 0x01,
- 0x55, 0x43, 0x80, 0x00, 0x01,
- 0x52, 0x43, 0x80, 0x00, 0x01,
- 0x3f, 0x42, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01,
- 0x54, 0x43, 0x80, 0x00, 0x01
- };
-
- idx = RAMType * 5;
-
- for (i = 0x28; i <= 0x2A; i++) { // Set MCLK
- set_reg1(P3c4, i, MCLK[idx]);
- idx++;
- }
-
- idx = RAMType * 5;
- for (i = 0x2E; i <= 0x30; i++) { // Set ECLK
- set_reg1(P3c4, i, ECLK[idx]);
- idx++;
- }
-}
-
-void ClearDAC(u16 port)
-{
- int i;
-
- set_reg3(P3c8, 0x00);
- for (i = 0; i < (256 * 3); i++)
- set_reg3(P3c9, 0x00);
-}
-
-void ClearALLBuffer(void)
-{
- unsigned long AdapterMemorySize;
-
- AdapterMemorySize = get_reg1(P3c4, 0x14);
- AdapterMemorySize = AdapterMemorySize & 0x3F;
- AdapterMemorySize++;
-
- memset((char *) ivideo.video_vbase, 0, AdapterMemorySize);
-}
-
-void LongWait(void)
-{
- unsigned long temp;
-
- for (temp = 1; temp > 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x08;
- }
- for (; temp == 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x08;
- }
-}
-
-void WaitDisplay(void)
-{
- unsigned short temp;
-
- for (temp = 0; temp == 0;) {
- temp = get_reg2(P3da);
- temp = temp & 0x01;
- }
- for (; temp == 1;) {
- temp = get_reg2(P3da);
- temp = temp & 0x01;
- }
-}
-
-int TestMonitorType(unsigned short d1, unsigned short d2, unsigned short d3)
-{
- unsigned short temp;
- set_reg3(P3c6, 0xFF);
- set_reg3(P3c8, 0x00);
- set_reg3(P3c9, d1);
- set_reg3(P3c9, d2);
- set_reg3(P3c9, d3);
- WaitDisplay(); //wait horizontal retrace
- temp = get_reg2(P3c2);
- if (temp & 0x10)
- return 1;
- else
- return 0;
-}
-
-void SetRegANDOR(unsigned short Port, unsigned short Index,
- unsigned short DataAND, unsigned short DataOR)
-{
- unsigned short temp1;
- temp1 = get_reg1(Port, Index); //part1port index 02
- temp1 = (temp1 & (DataAND)) | DataOR;
- set_reg1(Port, Index, temp1);
-}
-
-
-int DetectMonitor(void)
-{
- unsigned short flag1;
- unsigned short DAC_TEST_PARMS[3] = { 0x0F, 0x0F, 0x0F };
- unsigned short DAC_CLR_PARMS[3] = { 0x00, 0x00, 0x00 };
-
- flag1 = get_reg1(P3c4, 0x38); //call BridgeisOn
- if ((flag1 & 0x20)) {
- set_reg1(P3d4, 0x30, 0x41);
- }
-
- SiSSetMode(0x2E); //set mode to 0x2E instead of 0x3
-
- ClearDAC(P3c8);
- ClearALLBuffer();
-
- LongWait();
- LongWait();
-
- flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
- DAC_TEST_PARMS[2]);
- if (flag1 == 0) {
- flag1 = TestMonitorType(DAC_TEST_PARMS[0], DAC_TEST_PARMS[1],
- DAC_TEST_PARMS[2]);
- }
-
- if (flag1 == 1) {
- SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, Monitor1Sense);
- } else {
- SetRegANDOR(P3d4, 0x32, ~Monitor1Sense, 0x0);
- }
-
- TestMonitorType(DAC_CLR_PARMS[0], DAC_CLR_PARMS[1],
- DAC_CLR_PARMS[2]);
-
- set_reg1(P3d4, 0x34, 0x4A);
-
- return 1;
-}
-
-int SiSInit300(void)
-{
- //unsigned long ROMAddr = rom_vbase;
- u16 BaseAddr = (u16) ivideo.vga_base;
- unsigned char i, temp, AGP;
- unsigned long j, k, ulTemp;
- unsigned char SR11, SR19, SR1A, SR21, SR22;
- unsigned char SR14;
- unsigned long Temp;
-
- P3c4 = BaseAddr + 0x14;
- P3d4 = BaseAddr + 0x24;
- P3c0 = BaseAddr + 0x10;
- P3ce = BaseAddr + 0x1e;
- P3c2 = BaseAddr + 0x12;
- P3ca = BaseAddr + 0x1a;
- P3c6 = BaseAddr + 0x16;
- P3c7 = BaseAddr + 0x17;
- P3c8 = BaseAddr + 0x18;
- P3c9 = BaseAddr + 0x19;
- P3da = BaseAddr + 0x2A;
-
- set_reg1(P3c4, 0x05, 0x86); // 1.Openkey
-
- SR14 = (unsigned char) get_reg1(P3c4, 0x14);
- SR19 = (unsigned char) get_reg1(P3c4, 0x19);
- SR1A = (unsigned char) get_reg1(P3c4, 0x1A);
-
- for (i = 0x06; i < 0x20; i++)
- set_reg1(P3c4, i, 0); // 2.Reset Extended register
- for (i = 0x21; i <= 0x27; i++)
- set_reg1(P3c4, i, 0); // Reset Extended register
- for (i = 0x31; i <= 0x3D; i++)
- set_reg1(P3c4, i, 0);
- for (i = 0x30; i <= 0x37; i++)
- set_reg1(P3d4, i, 0);
-
-#if 0
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- // 3.Set Define Extended register
- temp = (unsigned char) SR1A;
- else {
- temp = *((unsigned char *) (ROMAddr + SoftSettingAddr));
- if ((temp & SoftDRAMType) == 0) {
- // 3.Set Define Extended register
- temp = (unsigned char) get_reg1(P3c4, 0x3A);
- }
- }
-#endif
-
- // 3.Set Define Extended register
- temp = (unsigned char) SR1A;
-
- RAMType = temp & 0x07;
- SetMemoryClock();
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- ulTemp = (unsigned long) get_reg1(P3c4, 0x05);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x3C);
- Temp = Temp | 0x01;
- set_reg1(P3c4, 0x3C, (unsigned short) Temp);
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- Temp = (unsigned long) get_reg1(P3c4, 0x05);
-
- Temp = (unsigned long) get_reg1(P3c4, 0x3C);
- Temp = Temp & 0xFE;
- set_reg1(P3c4, 0x3C, (unsigned short) Temp);
- for (k = 0; k < 5; k++)
- for (j = 0; j < 0xffff; j++)
- Temp = (unsigned long) get_reg1(P3c4, 0x05);
-
- //SR07=*((unsigned char *)(ROMAddr+0xA4)); // todo
- set_reg1(P3c4, 0x07, SRegsInit[0x07]);
-#if 0
- if (HwDeviceExtension->jChipID == SIS_Glamour)
- for (i = 0x15; i <= 0x1C; i++) {
- temp = *((unsigned char *) (ROMAddr + 0xA5 + ((i - 0x15) * 8) + RAMType));
- set_reg1(P3c4, i, temp);
- }
-#endif
-
- //SR1F=*((unsigned char *)(ROMAddr+0xE5));
- set_reg1(P3c4, 0x1F, SRegsInit[0x1F]);
-
- // Get AGP
- AGP = 1;
- temp = (unsigned char) get_reg1(P3c4, 0x3A);
- temp = temp & 0x30;
- if (temp == 0x30)
- // PCI
- AGP = 0;
-
- //SR21=*((unsigned char *)(ROMAddr+0xE6));
- SR21 = SRegsInit[0x21];
- if (AGP == 0)
- SR21 = SR21 & 0xEF; // PCI
- set_reg1(P3c4, 0x21, SR21);
-
- //SR22=*((unsigned char *)(ROMAddr+0xE7));
- SR22 = SRegsInit[0x22];
- if (AGP == 1)
- SR22 = SR22 & 0x20; // AGP
- set_reg1(P3c4, 0x22, SR22);
-
- //SR23=*((unsigned char *)(ROMAddr+0xE8));
- set_reg1(P3c4, 0x23, SRegsInit[0x23]);
-
- //SR24=*((unsigned char *)(ROMAddr+0xE9));
- set_reg1(P3c4, 0x24, SRegsInit[0x24]);
-
- //SR25=*((unsigned char *)(ROMAddr+0xEA));
- set_reg1(P3c4, 0x25, SRegsInit[0x25]);
-
- //SR32=*((unsigned char *)(ROMAddr+0xEB));
- set_reg1(P3c4, 0x32, SRegsInit[0x32]);
-
- SR11 = 0x0F;
- set_reg1(P3c4, 0x11, SR11);
-
-#if 0
- if (IF_DEF_LVDS == 1) {
- //LVDS
- temp = ExtChipLVDS;
- } else if (IF_DEF_TRUMPION == 1) {
- //Trumpion
- temp = ExtChipTrumpion;
- } else {
- //301
- temp = ExtChip301;
- }
-#endif
-
- // 301;
- temp = 0x02;
- set_reg1(P3d4, 0x37, temp);
-
-#if 0
- //09/07/99 modify by domao for 630/540 MM
- if (HwDeviceExtension->jChipID == SIS_Glamour) {
- //For SiS 300 Chip
- SetDRAMSize(HwDeviceExtension);
- SetDRAMSize(HwDeviceExtension);
- } else {
- //For SiS 630/540 Chip
- //Restore SR14, SR19 and SR1A
- set_reg1(P3c4, 0x14, SR14);
- set_reg1(P3c4, 0x19, SR19);
- set_reg1(P3c4, 0x1A, SR1A);
- }
-#endif
-
- set_reg1(P3c4, 0x14, SR14);
- set_reg1(P3c4, 0x19, SR19);
- set_reg1(P3c4, 0x1A, SR1A);
- set_reg3(P3c6, 0xff);
- ClearDAC(P3c8);
- DetectMonitor();
-
-#if 0
- //sense CRT2
- GetSenseStatus(HwDeviceExtension, BaseAddr, ROMAddr);
-#endif
-
- return (TRUE);
-}
-
-static int SiSSetMode(u16 ModeNo)
-{
- //#ifndef CONFIG_FB_SIS_LINUXBIOS
- unsigned long temp;
- //#endif
-
- u16 cr30flag, cr31flag;
- unsigned long ROMAddr = rom_vbase;
- u16 BaseAddr = (u16) ivideo.vga_base;
-
- P3c4 = BaseAddr + 0x14;
- P3d4 = BaseAddr + 0x24;
- P3c0 = BaseAddr + 0x10;
- P3ce = BaseAddr + 0x1e;
- P3c2 = BaseAddr + 0x12;
- P3ca = BaseAddr + 0x1a;
- P3c6 = BaseAddr + 0x16;
- P3c7 = BaseAddr + 0x17;
- P3c8 = BaseAddr + 0x18;
- P3c9 = BaseAddr + 0x19;
- P3da = BaseAddr + 0x2A;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- temp = search_modeID(ROMAddr, ModeNo);
-
- if (temp == 0)
- return (0);
-
- temp = check_memory_size(ROMAddr);
- if (temp == 0)
- return (0);
-#endif
-
-#if 1
- cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
- if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- get_mode_ptr(ROMAddr, ModeNo);
-#endif
- set_seq_regs(ROMAddr);
- set_misc_regs(ROMAddr);
- set_crtc_regs(ROMAddr);
- set_attregs(ROMAddr);
- set_grc_regs(ROMAddr);
- ClearExt1Regs();
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- temp = get_rate_ptr(ROMAddr, ModeNo);
- if (temp) {
-#endif
- set_sync(ROMAddr);
- set_crt1_crtc(ROMAddr);
- set_crt1_offset(ROMAddr);
- set_crt1_vclk(ROMAddr);
- set_vclk_state(ROMAddr, ModeNo);
-
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- set_crt1_FIFO2(ROMAddr);
- else /* SiS 300 */
- set_crt1_FIFO(ROMAddr);
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- }
-#endif
- set_crt1_mode_regs(ROMAddr, ModeNo);
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan))
- set_interlace(ROMAddr, ModeNo);
- load_DAC(ROMAddr);
-
- /* clear OnScreen */
- memset((char *) ivideo.video_vbase, 0,
- video_linelength * ivideo.video_height);
- }
-#else
- cr30flag = (unsigned char) get_reg1(P3d4, 0x30);
- if (((cr30flag & 0x01) == 1) || ((cr30flag & 0x02) == 0)) {
- //set_seq_regs(ROMAddr);
- {
- unsigned char SRdata;
- SRdata = SRegs[0x01] | 0x20;
- set_reg1(P3c4, 0x01, SRdata);
-
- for (i = 02; i <= 04; i++)
- set_reg1(P3c4, i, SRegs[i]);
- }
-
- //set_misc_regs(ROMAddr);
- {
- set_reg3(P3c2, 0x23);
- }
-
- //set_crtc_regs(ROMAddr);
- {
- unsigned char CRTCdata;
-
- CRTCdata = (unsigned char) get_reg1(P3d4, 0x11);
- set_reg1(P3d4, 0x11, CRTCdata);
-
- for (i = 0; i <= 0x18; i++)
- set_reg1(P3d4, i, CRegs[i]);
- }
-
- //set_attregs(ROMAddr);
- {
- for (i = 0; i <= 0x13; i++) {
- get_reg2(P3da);
- set_reg3(P3c0, i);
- set_reg3(P3c0, ARegs[i]);
- }
- get_reg2(P3da);
- set_reg3(P3c0, 0x14);
- set_reg3(P3c0, 0x00);
- get_reg2(P3da);
- set_reg3(P3c0, 0x20);
- }
-
- //set_grc_regs(ROMAddr);
- {
- for (i = 0; i <= 0x08; i++)
- set_reg1(P3ce, i, GRegs[i]);
- }
-
- //ClearExt1Regs();
- {
- for (i = 0x0A; i <= 0x0E; i++)
- set_reg1(P3c4, i, 0x00);
- }
-
- //set_sync(ROMAddr);
- {
- set_reg3(P3c2, MReg);
- }
-
- //set_crt1_crtc(ROMAddr);
- {
- unsigned char data;
-
- data = (unsigned char) get_reg1(P3d4, 0x11);
- data = data & 0x7F;
- set_reg1(P3d4, 0x11, data);
-
- for (i = 0; i <= 0x07; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x10; i <= 0x12; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x15; i <= 0x16; i++)
- set_reg1(P3d4, i, CRegs[i]);
- for (i = 0x0A; i <= 0x0C; i++)
- set_reg1(P3c4, i, SRegs[i]);
-
- data = SRegs[0x0E] & 0xE0;
- set_reg1(P3c4, 0x0E, data);
-
- set_reg1(P3d4, 0x09, CRegs[0x09]);
-
- }
-
- //set_crt1_offset(ROMAddr);
- {
- set_reg1(P3c4, 0x0E, SRegs[0x0E]);
- set_reg1(P3c4, 0x10, SRegs[0x10]);
- }
-
- //set_crt1_vclk(ROMAddr);
- {
- set_reg1(P3c4, 0x31, 0);
-
- for (i = 0x2B; i <= 0x2C; i++)
- set_reg1(P3c4, i, SRegs[i]);
- set_reg1(P3c4, 0x2D, 0x80);
- }
-
- //set_vclk_state(ROMAddr, ModeNo);
- {
- set_reg1(P3c4, 0x32, SRegs[0x32]);
- set_reg1(P3c4, 0x07, SRegs[0x07]);
- }
-
- if ((ivideo.chip_id == SIS_Trojan)
- || (ivideo.chip_id == SIS_Spartan)) {
- //set_crt1_FIFO2(ROMAddr);
- set_reg1(P3c4, 0x15, SRegs[0x15]);
-
- set_reg4(0xcf8, 0x80000050);
- set_reg4(0xcfc, 0xc5041e04);
-
- set_reg1(P3c4, 0x08, SRegs[0x08]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x3b, 0x00);
- set_reg1(P3c4, 0x09, SRegs[0x09]);
- }
-
- //set_crt1_mode_regs(ROMAddr, ModeNo);
- {
- set_reg1(P3c4, 0x06, SRegs[0x06]);
- set_reg1(P3c4, 0x01, SRegs[0x01]);
- set_reg1(P3c4, 0x0F, SRegs[0x0F]);
- set_reg1(P3c4, 0x21, SRegs[0x21]);
- }
-
- if ((ivideo.chip_id == SIS_Trojan) || (ivideo.chip_id == SIS_Spartan)) {
- //set_interlace(ROMAddr, ModeNo);
- set_reg1(P3d4, 0x19, CRegs[0x19]);
- set_reg1(P3d4, 0x1A, CRegs[0x1A]);
- }
- load_DAC(ROMAddr);
-
- /* clear OnScreen */
- memset((char *) ivideo.video_vbase, 0,
- video_linelength * ivideo.video_height);
- }
-#endif
- cr31flag = (unsigned char) get_reg1(P3d4, 0x31);
-
- display_on();
-
- return (0);
-}
-
-static void pre_setmode(void)
-{
- vgawb(CRTC_ADR, 0x30);
- vgawb(CRTC_DATA, 0x00);
-
- vgawb(CRTC_ADR, 0x31);
- vgawb(CRTC_DATA, 0x60);
-
- DPRINTK("Setting CR33 = 0x%x\n", rate_idx & 0x0f);
-
- /* set CRT1 refresh rate */
- vgawb(CRTC_ADR, 0x33);
- vgawb(CRTC_DATA, rate_idx & 0x0f);
-}
-
-static void post_setmode(void)
-{
- u8 uTemp;
-
- /* turn on CRT1 */
- vgawb(CRTC_ADR, 0x17);
- uTemp = vgarb(CRTC_DATA);
- uTemp |= 0x80;
- vgawb(CRTC_DATA, uTemp);
-
- /* disable 24-bit palette RAM and Gamma correction */
- vgawb(SEQ_ADR, 0x07);
- uTemp = vgarb(SEQ_DATA);
- uTemp &= ~0x04;
- vgawb(SEQ_DATA, uTemp);
-}
-
-static void search_mode(const char *name)
-{
- int i = 0;
-
- if (name == NULL)
- return;
-
- while (sisbios_mode[i].mode_no != 0) {
- if (!strcmp(name, sisbios_mode[i].name)) {
- mode_idx = i;
- break;
- }
- i++;
- }
- if (mode_idx < 0)
- DPRINTK("Invalid user mode : %s\n", name);
-}
-
-static u8 search_refresh_rate(unsigned int rate)
-{
- u16 xres, yres;
- int i = 0;
-
- xres = sisbios_mode[mode_idx].xres;
- yres = sisbios_mode[mode_idx].yres;
-
- while ((vrate[i].idx != 0) && (vrate[i].xres <= xres)) {
- if ((vrate[i].xres == xres) && (vrate[i].yres == yres)
- && (vrate[i].refresh == rate)) {
- rate_idx = vrate[i].idx;
- return rate_idx;
- }
- i++;
- }
-
- DPRINTK("sisfb: Unsupported rate %d in %dx%d mode\n", rate, xres,
- yres);
-
- return 0;
-}
-
-
-
-/* ------------------ Public Routines ------------------------------- */
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_fix:[%d]\n", con);
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, fb_info.modename);
-
- fix->smem_start = ivideo.video_base;
- if(ivideo.video_size > 0x800000)
- fix->smem_len = RESERVED_MEM_SIZE_8M; /* reserved for Xserver */
- else
- fix->smem_len = RESERVED_MEM_SIZE_4M; /* reserved for Xserver */
-
- fix->type = video_type;
- fix->type_aux = 0;
- if (ivideo.video_bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_TRUECOLOR;
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = video_linelength;
- fix->mmio_start = ivideo.mmio_base;
- fix->mmio_len = MMIO_SIZE;
- fix->accel = FB_ACCEL_SIS_GLAMOUR;
- fix->reserved[0] = ivideo.video_size & 0xFFFF;
- fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
- fix->reserved[2] = caps; /* capabilities */
-
- return 0;
-}
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_var:[%d]\n", con);
-
- if (con == -1)
- memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
- else
- *var = fb_display[con].var;
- return 0;
-}
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err;
- unsigned int cols, rows;
-
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
-
- /* Set mode */
- if (do_set_var(var, con == currcon, info)) {
- crtc_to_var(var); /* return current mode to user */
- return -EINVAL;
- }
-
- /* get actual setting value */
- crtc_to_var(var);
-
- /* update display of current console */
- sisfb_set_disp(con, var);
-
- if (info->changevar)
- (*info->changevar) (con);
-
- if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
- return err;
-
- do_install_cmap(con, info);
-
- /* inform console to update struct display */
- cols = sisbios_mode[mode_idx].cols;
- rows = sisbios_mode[mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
-
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- DPRINTK("sisfb: sisfb_get_cmap:[%d]\n", con);
-
- if (con == currcon)
- return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
-
- return 0;
-}
-
-/*
- * Set the Colormap
- */
-
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
-
- if (!fb_display[con].cmap.len) { /* no colormap allocated */
- err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
- if (err)
- return err;
- }
- if (con == currcon) /* current console */
- return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
- else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
-{
- switch (cmd) {
- case FBIO_ALLOC:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_malloc((struct sis_memreq *) arg);
- break;
- case FBIO_FREE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- sis_free(*(unsigned long *) arg);
- break;
- case FBIOGET_GLYPH:
- sis_get_glyph((struct GlyInfo *) arg);
- break;
- case FBIOGET_HWCINFO:
- {
- unsigned long *hwc_offset = (unsigned long *) arg;
-
- if (caps | HW_CURSOR_CAP)
- *hwc_offset = hwcursor_vbase -
- (unsigned long) ivideo.video_vbase;
- else
- *hwc_offset = 0;
-
- break;
- }
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int sisfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
-{
- struct fb_var_screeninfo var;
- unsigned long start;
- unsigned long off;
- u32 len;
-
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- /* frame buffer memory */
- start = (unsigned long) ivideo.video_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
-
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- sisfb_get_var(&var, currcon, info);
- if (var.accel_flags)
- return -EINVAL;
- start = (unsigned long) ivideo.mmio_base;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + MMIO_SIZE);
- }
-
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
-
-#if defined(__i386__)
- if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
- if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
- return 0;
-}
-
-static struct fb_ops sisfb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: sisfb_get_fix,
- fb_get_var: sisfb_get_var,
- fb_set_var: sisfb_set_var,
- fb_get_cmap: sisfb_get_cmap,
- fb_set_cmap: sisfb_set_cmap,
- fb_ioctl: sisfb_ioctl,
- fb_mmap: sisfb_mmap,
-};
-
-int __init sisfb_setup(char *options)
-{
- char *this_opt;
-
- fb_info.fontname[0] = '\0';
- ivideo.refresh_rate = 0;
-
- if (!options || !*options)
- return 0;
-
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
- if (!*this_opt)
- continue;
-
- if (!strcmp(this_opt, "inverse")) {
- inverse = 1;
- fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5)) {
- strcpy(fb_info.fontname, this_opt + 5);
- } else if (!strncmp(this_opt, "mode:", 5)) {
- search_mode(this_opt + 5);
- } else if (!strncmp(this_opt, "vrate:", 6)) {
- ivideo.refresh_rate =
- simple_strtoul(this_opt + 6, NULL, 0);
- } else if (!strncmp(this_opt, "off", 3)) {
- sisfb_off = 1;
- } else
- DPRINTK("invalid parameter %s\n", this_opt);
- }
- return 0;
-}
-
-static int sisfb_update_var(int con, struct fb_info *info)
-{
- return 0;
-}
-
-/*
- * Switch Console (called by fbcon.c)
- */
-
-static int sisfb_switch(int con, struct fb_info *info)
-{
- int cols, rows;
-
- DPRINTK("sisfb: switch console from [%d] to [%d]\n", currcon, con);
-
- /* update colormap of current console */
- if (fb_display[currcon].cmap.len)
- fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
-
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
-
- /* same mode, needn't change mode actually */
-
- if (!memcmp(&fb_display[con].var, &fb_display[currcon].var, sizeof(struct fb_var_screeninfo)))
- {
- currcon = con;
- return 1;
- }
-
- currcon = con;
-
- do_set_var(&fb_display[con].var, 1, info);
-
- sisfb_set_disp(con, &fb_display[con].var);
-
- /* Install new colormap */
- do_install_cmap(con, info);
-
- cols = sisbios_mode[mode_idx].cols;
- rows = sisbios_mode[mode_idx].rows;
- vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
-
- sisfb_update_var(con, info);
-
- return 1;
-
-}
-
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void sisfb_blank(int blank, struct fb_info *info)
-{
- u8 CRData;
-
- vgawb(CRTC_ADR, 0x17);
- CRData = vgarb(CRTC_DATA);
-
- if (blank > 0) /* turn off CRT1 */
- CRData &= 0x7f;
- else /* turn on CRT1 */
- CRData |= 0x80;
-
- vgawb(CRTC_ADR, 0x17);
- vgawb(CRTC_DATA, CRData);
-}
-
-int __init sisfb_init(void)
-{
- struct pci_dev *pdev = NULL;
- struct board *b;
- int pdev_valid = 0;
- unsigned char jTemp;
-
- outb(0x77, 0x80);
-
- if (sisfb_off)
- return -ENXIO;
-
- pci_for_each_dev(pdev) {
- for (b = dev_list; b->vendor; b++)
- {
- if ((b->vendor == pdev->vendor)
- && (b->device == pdev->device))
- {
- pdev_valid = 1;
- strcpy(fb_info.modename, b->name);
- ivideo.chip_id = pdev->device;
- break;
- }
- }
-
- if (pdev_valid)
- break;
- }
-
- if (!pdev_valid)
- return -1;
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- if (pci_enable_device(pdev))
- return -EIO;
-#endif
-
- ivideo.video_base = pci_resource_start(pdev, 0);
- if (!request_mem_region(ivideo.video_base, pci_resource_len(pdev, 0),
- "sisfb FB")) {
- printk(KERN_ERR "sisfb: cannot reserve frame buffer memory\n");
- return -ENODEV;
- }
- ivideo.mmio_base = pci_resource_start(pdev, 1);
- if (!request_mem_region(ivideo.mmio_base, pci_resource_len(pdev, 1),
- "sisfb MMIO")) {
- printk(KERN_ERR "sisfb: cannot reserve MMIO region\n");
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- return -ENODEV;
- }
- ivideo.vga_base = pci_resource_start(pdev, 2);
- if (!request_region(ivideo.vga_base, pci_resource_len(pdev, 2),
- "sisfb IO")) {
- printk(KERN_ERR "sisfb: cannot reserve I/O ports\n");
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- return -ENODEV;
- }
- ivideo.vga_base += 0x30;
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- rom_base = 0x000C0000;
- request_region(rom_base, 32, "sisfb");
-#else
- rom_base = 0x0;
-#endif
-
- /* set passwd */
- vgawb(SEQ_ADR, IND_SIS_PASSWORD);
- vgawb(SEQ_DATA, SIS_PASSWORD);
-
- /* Enable MMIO & PCI linear address */
- vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
- jTemp = vgarb(SEQ_DATA);
- jTemp |= SIS_PCI_ADDR_ENABLE;
- jTemp |= SIS_MEM_MAP_IO_ENABLE;
- vgawb(SEQ_DATA, jTemp);
-
- /* get video ram size by SR14 */
- vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
- ivideo.video_size = ((int) ((vgarb(SEQ_DATA) & 0x3f) + 1) << 20);
-
- if (mode_idx < 0)
- mode_idx = DEFAULT_MODE; /* 0:640x480x8 */
-
-#ifdef CONFIG_FB_SIS_LINUXBIOS
- mode_idx = DEFAULT_MODE;
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- /* set to default refresh rate 60MHz */
- ivideo.refresh_rate = 60;
-#endif
-
- mode_no = sisbios_mode[mode_idx].mode_no;
-
- if (ivideo.refresh_rate != 0)
- search_refresh_rate(ivideo.refresh_rate);
-
- if (rate_idx == 0) {
- rate_idx = sisbios_mode[mode_idx].rate_idx;
- /* set to default refresh rate 60MHz */
- ivideo.refresh_rate = 60;
- }
-
- ivideo.video_bpp = sisbios_mode[mode_idx].bpp;
- ivideo.video_width = sisbios_mode[mode_idx].xres;
- ivideo.video_height = sisbios_mode[mode_idx].yres;
- video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
-
- ivideo.video_vbase = ioremap(ivideo.video_base, ivideo.video_size);
- ivideo.mmio_vbase = ioremap(ivideo.mmio_base, MMIO_SIZE);
-
-#ifndef CONFIG_FB_SIS_LINUXBIOS
- rom_vbase = (unsigned long) ioremap(rom_base, MAX_ROM_SCAN);
-#endif
-
- SiSInit300();
-
- printk(KERN_INFO
- "sisfb: framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
- ivideo.video_base, ivideo.video_vbase,
- ivideo.video_size / 1024);
- printk(KERN_INFO "sisfb: mode is %dx%dx%d, linelength=%d\n",
- ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
- video_linelength);
-
- /* enable 2D engine */
- vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
- jTemp = vgarb(SEQ_DATA);
- jTemp |= SIS_2D_ENABLE;
- vgawb(SEQ_DATA, jTemp);
-
- pre_setmode();
-
- if (SiSSetMode(mode_no)) {
- DPRINTK("sisfb: set mode[0x%x]: failed\n", 0x30);
- return -1;
- }
-
- post_setmode();
-
- crtc_to_var(&default_var);
-
- fb_info.changevar = NULL;
- fb_info.node = -1;
- fb_info.fbops = &sisfb_ops;
- fb_info.disp = &disp;
- fb_info.switch_con = &sisfb_switch;
- fb_info.updatevar = &sisfb_update_var;
- fb_info.blank = &sisfb_blank;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
-
- sisfb_set_disp(-1, &default_var);
-
- if (sisfb_heap_init()) {
- DPRINTK("sisfb: Failed to enable offscreen heap\n");
- }
-
- /* to avoid the inversed bgcolor bug of the initial state */
- vc_resize_con(1, 1, 0);
-
- if (register_framebuffer(&fb_info) < 0)
- return -EINVAL;
-
- ivideo.status = CRT1;
-
- printk(KERN_INFO "fb%d: %s frame buffer device\n",
- GET_FB_IDX(fb_info.node), fb_info.modename);
-
- return 0;
-}
-
-#ifdef MODULE
-
-static char *mode = NULL;
-static unsigned int rate = 0;
-
-MODULE_PARM(mode, "s");
-MODULE_PARM(rate, "i");
-
-int init_module(void)
-{
- if (mode)
- search_mode(mode);
-
- ivideo.refresh_rate = rate;
-
- sisfb_init();
-
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_framebuffer(&fb_info);
-}
-#endif /* MODULE */
-
-
-EXPORT_SYMBOL(sis_malloc);
-EXPORT_SYMBOL(sis_free);
-
-EXPORT_SYMBOL(ivideo);
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 7572891d6..880f1d1db 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -66,8 +66,6 @@ static int default_var_valid = 0;
static int currcon = 0;
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
static struct { u_char red, green, blue, pad; } palette[256];
#ifdef FBCON_HAS_CFB32
static u32 fbcon_cfb32_cmap[16];
@@ -259,7 +257,7 @@ static struct {
}}
};
-#define NUM_TOTAL_MODES arraysize(tgafb_predefined)
+#define NUM_TOTAL_MODES ARRAY_SIZE(tgafb_predefined)
/*
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index c51d33bed..8833cbeac 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -32,9 +32,6 @@
#include <video/fbcon-cfb32.h>
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
-
/*
* RAM we reserve for the frame buffer. This defines the maximum screen
* size
diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c
index 8a7e0a0ff..e48c0f458 100644
--- a/drivers/video/vgacon.c
+++ b/drivers/video/vgacon.c
@@ -46,11 +46,13 @@
#include <linux/malloc.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
+#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
+static spinlock_t vga_lock = SPIN_LOCK_UNLOCKED;
#define BLANK 0x0020
@@ -152,8 +154,7 @@ static inline void write_vga(unsigned char reg, unsigned int val)
* ddprintk might set the console position from interrupt
* handlers, thus the write has to be IRQ-atomic.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&vga_lock, flags);
#ifndef SLOW_VGA
v1 = reg + (val & 0xff00);
@@ -166,7 +167,7 @@ static inline void write_vga(unsigned char reg, unsigned int val)
outb_p(reg+1, vga_video_port_reg);
outb_p(val & 0xff, vga_video_port_val);
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&vga_lock, flags);
}
static const char __init *vgacon_startup(void)
@@ -415,7 +416,7 @@ static void vgacon_set_cursor_size(int xpos, int from, int to)
if ((from == lastfrom) && (to == lastto)) return;
lastfrom = from; lastto = to;
- save_flags(flags); cli();
+ spin_lock_irqsave(&vga_lock, flags);
outb_p(0x0a, vga_video_port_reg); /* Cursor start */
curs = inb_p(vga_video_port_val);
outb_p(0x0b, vga_video_port_reg); /* Cursor end */
@@ -428,7 +429,7 @@ static void vgacon_set_cursor_size(int xpos, int from, int to)
outb_p(curs, vga_video_port_val);
outb_p(0x0b, vga_video_port_reg); /* Cursor end */
outb_p(cure, vga_video_port_val);
- restore_flags(flags);
+ spin_unlock_irqrestore(&vga_lock, flags);
}
static void vgacon_cursor(struct vc_data *c, int mode)
@@ -533,11 +534,11 @@ static void vga_vesa_blank(int mode)
{
/* save original values of VGA controller registers */
if(!vga_vesa_blanked) {
- cli();
+ spin_lock_irq(&vga_lock);
vga_state.SeqCtrlIndex = inb_p(seq_port_reg);
vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
vga_state.CrtMiscIO = inb_p(video_misc_rd);
- sti();
+ spin_unlock_irq(&vga_lock);
outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
vga_state.HorizontalTotal = inb_p(vga_video_port_val);
@@ -561,7 +562,7 @@ static void vga_vesa_blank(int mode)
/* assure that video is enabled */
/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
- cli();
+ spin_lock_irq(&vga_lock);
outb_p(0x01,seq_port_reg);
outb_p(vga_state.ClockingMode | 0x20,seq_port_val);
@@ -598,13 +599,13 @@ static void vga_vesa_blank(int mode)
/* restore both index registers */
outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
- sti();
+ spin_unlock_irq(&vga_lock);
}
static void vga_vesa_unblank(void)
{
/* restore original values of VGA controller registers */
- cli();
+ spin_lock_irq(&vga_lock);
outb_p(vga_state.CrtMiscIO,video_misc_wr);
outb_p(0x00,vga_video_port_reg); /* HorizontalTotal */
@@ -629,7 +630,7 @@ static void vga_vesa_unblank(void)
/* restore index/control registers */
outb_p(vga_state.SeqCtrlIndex,seq_port_reg);
outb_p(vga_state.CrtCtrlIndex,vga_video_port_reg);
- sti();
+ spin_unlock_irq(&vga_lock);
}
static void vga_pal_blank(void)
@@ -750,7 +751,7 @@ vgacon_do_font_op(char *arg, int set, int ch512)
charmap += 4*cmapsz;
#endif
- cli();
+ spin_lock_irq(&vga_lock);
outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
outb_p( 0x01, seq_port_val ); /* Synchronous reset */
outb_p( 0x02, seq_port_reg );
@@ -766,7 +767,7 @@ vgacon_do_font_op(char *arg, int set, int ch512)
outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
outb_p( 0x06, gr_port_reg );
outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
- sti();
+ spin_unlock_irq(&vga_lock);
if (arg) {
if (set)
@@ -793,7 +794,7 @@ vgacon_do_font_op(char *arg, int set, int ch512)
}
}
- cli();
+ spin_lock_irq(&vga_lock);
outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
outb_p( 0x01, seq_port_val ); /* Synchronous reset */
outb_p( 0x02, seq_port_reg );
@@ -833,8 +834,7 @@ vgacon_do_font_op(char *arg, int set, int ch512)
inb_p( video_port_status );
outb_p ( 0x20, attrib_port );
}
- sti();
-
+ spin_unlock_irq(&vga_lock);
return 0;
}
@@ -865,12 +865,12 @@ vgacon_adjust_height(unsigned fontheight)
registers; they are write-only on EGA, but it appears that they
are all don't care bits on EGA, so I guess it doesn't matter. */
- cli();
+ spin_lock_irq(&vga_lock);
outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
ovr = inb_p(vga_video_port_val);
outb_p( 0x09, vga_video_port_reg ); /* Font size register */
fsr = inb_p(vga_video_port_val);
- sti();
+ spin_unlock_irq(&vga_lock);
vde = maxscan & 0xff; /* Vertical display end reg */
ovr = (ovr & 0xbd) + /* Overflow register */
@@ -878,14 +878,14 @@ vgacon_adjust_height(unsigned fontheight)
((maxscan & 0x200) >> 3);
fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
- cli();
+ spin_lock_irq(&vga_lock);
outb_p( 0x07, vga_video_port_reg ); /* CRTC overflow register */
outb_p( ovr, vga_video_port_val );
outb_p( 0x09, vga_video_port_reg ); /* Font size */
outb_p( fsr, vga_video_port_val );
outb_p( 0x12, vga_video_port_reg ); /* Vertical display limit */
outb_p( vde, vga_video_port_val );
- sti();
+ spin_unlock_irq(&vga_lock);
vc_resize_all(rows, 0); /* Adjust console size */
return 0;
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index ed7bad2b1..047482699 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -46,8 +46,6 @@
#define DPRINTK(fmt, args...)
#endif
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-
#if 1
#define vgawb_3d(reg,dat) \
if (cv3d_on_zorro2) { \
@@ -277,7 +275,7 @@ static struct {
};
-#define NUM_TOTAL_MODES arraysize(virgefb_predefined)
+#define NUM_TOTAL_MODES ARRAY_SIZE(virgefb_predefined)
static int Cyberfb_inverse = 0;
diff --git a/fs/Config.in b/fs/Config.in
index d728d2166..53380d067 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -117,6 +117,7 @@ if [ "$CONFIG_NET" = "y" ]; then
else
# for fs/nls/Config.in
define_bool CONFIG_NCPFS_NLS n
+ define_bool CONFIG_SMB_FS n
fi
mainmenu_option next_comment
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index c1c621179..42f19e292 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -245,13 +245,11 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
{
struct inode *inode;
- inode = get_empty_inode();
+ inode = new_inode(sb);
if (!inode)
goto out;
inode->i_version = ++event;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_uid = sb->u.adfs_sb.s_uid;
inode->i_gid = sb->u.adfs_sb.s_gid;
inode->i_ino = obj->file_id;
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 2f8c36aa5..fcb7e103a 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -306,18 +306,19 @@ affs_new_inode(const struct inode *dir)
struct super_block *sb;
s32 block;
- if (!dir || !(inode = get_empty_inode()))
+ if (!dir)
return NULL;
sb = dir->i_sb;
- inode->i_sb = sb;
+ inode = new_inode(sb);
+ if (!inode)
+ return NULL;
if (!(block = affs_new_header((struct inode *)dir))) {
iput(inode);
return NULL;
}
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_ino = block;
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index f7e78a75d..b125dee4e 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -20,7 +20,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
{
struct buffer_head *bh;
struct inode *inode = (struct inode*)page->mapping->host;
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct slink_front *lf;
int err;
int i, j;
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index ae157d1ac..0eb91f3c2 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -211,7 +211,6 @@ static void autofs_read_inode(struct inode *inode)
inode->i_fop = &autofs_dir_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_nlink = 2;
- inode->i_size = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
inode->i_blksize = 1024;
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 077df4c2b..dd7dd07ac 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -292,14 +292,12 @@ static int autofs4_statfs(struct super_block *sb, struct statfs *buf)
struct inode *autofs4_get_inode(struct super_block *sb,
struct autofs_info *inf)
{
- struct inode *inode = get_empty_inode();
+ struct inode *inode = new_inode(sb);
if (inode == NULL)
return NULL;
inf->inode = inode;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_mode = inf->mode;
if (sb->s_root) {
inode->i_uid = sb->s_root->d_inode->i_uid;
@@ -308,13 +306,9 @@ struct inode *autofs4_get_inode(struct super_block *sb,
inode->i_uid = 0;
inode->i_gid = 0;
}
- inode->i_size = 0;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_rdev = 0;
- inode->i_nlink = 1;
- inode->i_op = NULL;
- inode->i_fop = NULL;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
if (S_ISDIR(inf->mode)) {
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 1a0532420..5caf04a7b 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -80,10 +80,9 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
struct super_block * s = dir->i_sb;
unsigned long ino;
- inode = get_empty_inode();
+ inode = new_inode(s);
if (!inode)
return -ENOSPC;
- inode->i_sb = s;
ino = find_first_zero_bit(s->su_imap, s->su_lasti);
if (ino > s->su_lasti) {
iput(inode);
@@ -91,7 +90,6 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
}
set_bit(ino, s->su_imap);
s->su_freei--;
- inode->i_dev = s->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/buffer.c b/fs/buffer.c
index 4de38a0e4..9f9fbbfbd 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -707,11 +707,8 @@ void set_blocksize(kdev_t dev, int size)
*/
static void refill_freelist(int size)
{
- if (!grow_buffers(size)) {
+ if (!grow_buffers(size))
wakeup_bdflush(1); /* Sets task->state to TASK_RUNNING */
- current->policy |= SCHED_YIELD;
- schedule();
- }
}
void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
@@ -1470,7 +1467,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
int err = 0;
unsigned blocksize, bbits;
struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
- char *kaddr = (char *)kmap(page);
+ char *kaddr = kmap(page);
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
@@ -1585,7 +1582,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
- unsigned long kaddr = 0;
+ char *kaddr = NULL;
int nr, i;
if (!PageLocked(page))
@@ -1614,7 +1611,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
if (!buffer_mapped(bh)) {
if (!kaddr)
kaddr = kmap(page);
- memset((char *)(kaddr + i*blocksize), 0, blocksize);
+ memset(kaddr + i*blocksize, 0, blocksize);
flush_dcache_page(page);
set_bit(BH_Uptodate, &bh->b_state);
continue;
@@ -1818,7 +1815,7 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t
goto unlock;
}
- memset((char *) kmap(page) + offset, 0, length);
+ memset(kmap(page) + offset, 0, length);
flush_dcache_page(page);
kunmap(page);
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index dbdc946f4..2df6cf719 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -28,7 +28,7 @@ static int coda_symlink_filler(struct file *file, struct page *page)
int error;
struct coda_inode_info *cnp;
unsigned int len = PAGE_SIZE;
- char *p = (char*)kmap(page);
+ char *p = kmap(page);
lock_kernel();
cnp = ITOC(inode);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 4b34da094..51eff1caa 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -34,7 +34,7 @@ static struct address_space_operations cramfs_aops;
static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
{
- struct inode * inode = get_empty_inode();
+ struct inode * inode = new_inode(sb);
if (inode) {
inode->i_mode = cramfs_inode->mode;
@@ -42,14 +42,10 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
inode->i_size = cramfs_inode->size;
inode->i_gid = cramfs_inode->gid;
inode->i_ino = CRAMINO(cramfs_inode);
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_nlink = 1; /* arguably wrong for directories,
- but it's the best we can do
- without reading the directory
- contents. 1 yields the right
- result in GNU find, even
- without -noleaf option. */
+ /* inode->i_nlink is left 1 - arguably wrong for directories,
+ but it's the best we can do without reading the directory
+ contents. 1 yields the right result in GNU find, even
+ without -noleaf option. */
insert_inode_hash(inode);
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index 264992d3f..5c412e301 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -2250,7 +2250,6 @@ static void devfs_read_inode (struct inode *inode)
printk ("%s: read_inode(%d): VFS inode: %p devfs_entry: %p\n",
DEVFS_NAME, (int) inode->i_ino, inode, de);
#endif
- inode->i_size = 0;
inode->i_blocks = 0;
inode->i_blksize = 1024;
inode->i_op = &devfs_iops;
@@ -2416,11 +2415,6 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir)
struct devfs_entry *parent, *de;
struct inode *inode = file->f_dentry->d_inode;
- if (inode == NULL)
- {
- printk ("%s: readdir(): NULL inode\n", DEVFS_NAME);
- return -EBADF;
- }
if ( !S_ISDIR (inode->i_mode) )
{
printk ("%s: readdir(): inode is not a directory\n", DEVFS_NAME);
@@ -3185,6 +3179,7 @@ static ssize_t devfsd_read (struct file *file, char *buf, size_t len,
current->state = TASK_RUNNING;
return -EINTR;
}
+ set_current_state(TASK_INTERRUPTIBLE);
}
remove_wait_queue (&fs_info->devfsd_wait_queue, &wait);
current->state = TASK_RUNNING;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index c3667b208..0bb8826d8 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -140,14 +140,11 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
goto fail_free;
}
- inode = get_empty_inode();
+ inode = new_inode(s);
if (!inode)
goto fail_free;
- inode->i_sb = s;
- inode->i_dev = s->s_dev;
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_size = 0;
inode->i_blocks = 0;
inode->i_blksize = 1024;
inode->i_uid = inode->i_gid = 0;
@@ -192,11 +189,9 @@ void devpts_pty_new(int number, kdev_t device)
if ( sbi->inodes[number] )
return; /* Already registered, this does happen */
- inode = get_empty_inode();
+ inode = new_inode(sb);
if (!inode)
return;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_ino = number+2;
inode->i_blocks = 0;
inode->i_blksize = 1024;
diff --git a/fs/dnotify.c b/fs/dnotify.c
index 90fd86b06..5711e6b41 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -103,14 +103,14 @@ void __inode_dir_notify(struct inode *inode, unsigned long event)
write_lock(&dn_lock);
prev = &inode->i_dnotify;
while ((dn = *prev) != NULL) {
- if ((dn->dn_mask & event) == 0) {
- prev = &dn->dn_next;
- continue;
- }
if (dn->dn_magic != DNOTIFY_MAGIC) {
printk(KERN_ERR "__inode_dir_notify: bad magic "
"number in dnotify_struct!\n");
- return;
+ goto out;
+ }
+ if ((dn->dn_mask & event) == 0) {
+ prev = &dn->dn_next;
+ continue;
}
fown = &dn->dn_filp->f_owner;
if (fown->pid)
@@ -125,6 +125,7 @@ void __inode_dir_notify(struct inode *inode, unsigned long event)
}
if (changed)
redo_inode_mask(inode);
+out:
write_unlock(&dn_lock);
}
diff --git a/fs/dquot.c b/fs/dquot.c
index ef1f15016..1bcd12ceb 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -679,8 +679,6 @@ restart:
if (!filp->f_dentry)
continue;
inode = filp->f_dentry->d_inode;
- if (!inode)
- continue;
if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
file_list_unlock();
sb->dq_op->initialize(inode, type);
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index ac64b8aeb..9bba7a2cb 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -28,9 +28,6 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
int slot, namelen;
char *nameptr;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
if (inode->i_size & (EFS_DIRBSIZE-1))
printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 20840409d..d1c788cc2 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -13,7 +13,7 @@
static int efs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct buffer_head * bh;
struct inode * inode = (struct inode*)page->mapping->host;
efs_block_t size = inode->i_size;
diff --git a/fs/exec.c b/fs/exec.c
index 203100d33..1e24a4ace 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -212,7 +212,7 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
@@ -748,7 +748,7 @@ void remove_arg_zero(struct linux_binprm *bprm)
kunmap(page);
inside:
page = bprm->page[bprm->p/PAGE_SIZE];
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
}
kunmap(page);
bprm->argc--;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index adaab9c74..cf8fa5154 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -274,15 +274,13 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
return NULL;
}
- inode = get_empty_inode ();
+ sb = dir->i_sb;
+ inode = new_inode(sb);
if (!inode) {
*err = -ENOMEM;
return NULL;
}
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = 0;
lock_super (sb);
es = sb->u.ext2_sb.s_es;
repeat:
@@ -430,9 +428,6 @@ repeat:
mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
sb->s_dirt = 1;
inode->i_mode = mode;
- inode->i_sb = sb;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index d1e8557f7..7537ee569 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -138,13 +138,11 @@ struct inode *fat_build_inode(struct super_block *sb,
inode = fat_iget(sb, ino);
if (inode)
goto out;
- inode = get_empty_inode();
+ inode = new_inode(sb);
*res = -ENOMEM;
if (!inode)
goto out;
*res = 0;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
fat_fill_inode(inode, de);
fat_attach(inode, ino);
@@ -658,11 +656,9 @@ fat_read_super(struct super_block *sb, void *data, int silent,
if (! sbi->nls_io)
sbi->nls_io = load_nls_default();
- root_inode=get_empty_inode();
+ root_inode=new_inode(sb);
if (!root_inode)
goto out_unload_nls;
- root_inode->i_sb = sb;
- root_inode->i_dev = sb->s_dev;
root_inode->i_ino = MSDOS_ROOT_INO;
fat_read_root(root_inode);
insert_inode_hash(root_inode);
@@ -798,7 +794,6 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_nlink = 1;
}
#endif
- inode->i_size = 0;
if ((nr = MSDOS_I(inode)->i_start) != 0)
while (nr != -1) {
inode->i_size += SECTOR_SIZE*sbi->cluster_size;
@@ -822,7 +817,6 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
(CF_LE_W(de->starthi) << 16);
}
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
- inode->i_nlink = 1;
inode->i_size = CF_LE_L(de->size);
inode->i_op = &fat_file_inode_operations;
inode->i_fop = &fat_file_operations;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index d075c5c4e..9c9fcafbc 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -391,13 +391,13 @@ static void send_sigio_to_task(struct task_struct *p,
back to SIGIO in that case. --sct */
si.si_signo = fown->signum;
si.si_errno = 0;
- si.si_code = reason;
+ si.si_code = reason & ~__SI_MASK;
/* Make sure we are called with one of the POLL_*
reasons, otherwise we could leak kernel stack into
userspace. */
if ((reason & __SI_MASK) != __SI_POLL)
BUG();
- if (reason - POLL_IN > NSIGPOLL)
+ if (reason - POLL_IN >= NSIGPOLL)
si.si_band = ~0L;
else
si.si_band = band_table[reason - POLL_IN];
diff --git a/fs/file_table.c b/fs/file_table.c
index 931314661..09b28574d 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -176,10 +176,13 @@ int fs_may_remount_ro(struct super_block *sb)
file_list_lock();
for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
struct file *file = list_entry(p, struct file, f_list);
- struct inode *inode = file->f_dentry->d_inode;
- if (!inode)
+ struct inode *inode;
+
+ if (!file->f_dentry)
continue;
+ inode = file->f_dentry->d_inode;
+
/* File with pending delete? */
if (inode->i_nlink == 0)
goto too_bad;
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 3438cdb85..0d38b408c 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -401,7 +401,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
int hpfs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
struct inode *i = (struct inode*)page->mapping->host;
struct fnode *fnode;
struct buffer_head *bh;
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 41b201767..c9915cf80 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -40,14 +40,17 @@ struct inode_operations isofs_dir_inode_operations =
lookup: isofs_lookup,
};
-static int isofs_name_translate(char * old, int len, char * new)
+int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
{
- int i, c;
+ char * old = de->name;
+ int len = de->name_len[0];
+ int i;
for (i = 0; i < len; i++) {
- c = old[i];
+ unsigned char c = old[i];
if (!c)
break;
+
if (c >= 'A' && c <= 'Z')
c |= 0x20; /* lower case */
@@ -74,8 +77,7 @@ int get_acorn_filename(struct iso_directory_record * de,
{
int std;
unsigned char * chr;
- int retnamlen = isofs_name_translate(de->name,
- de->name_len[0], retname);
+ int retnamlen = isofs_name_translate(de, retname, inode);
if (retnamlen == 0) return 0;
std = sizeof(struct iso_directory_record) + de->name_len[0];
if (std & 1) std++;
@@ -105,7 +107,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
unsigned int block, offset;
int inode_number = 0; /* Quiet GCC */
- struct buffer_head *bh;
+ struct buffer_head *bh = NULL;
int len;
int map;
int high_sierra;
@@ -117,46 +119,22 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
return 0;
offset = filp->f_pos & (bufsize - 1);
- block = isofs_bmap(inode, filp->f_pos >> bufbits);
+ block = filp->f_pos >> bufbits;
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
- if (!block)
- return 0;
-
- if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
- return 0;
-
while (filp->f_pos < inode->i_size) {
int de_len;
-#ifdef DEBUG
- printk("Block, offset, f_pos: %x %x %x\n",
- block, offset, filp->f_pos);
- printk("inode->i_size = %x\n",inode->i_size);
-#endif
- /* Next directory_record on next CDROM sector */
- if (offset >= bufsize) {
-#ifdef DEBUG
- printk("offset >= bufsize\n");
-#endif
- brelse(bh);
- offset = 0;
- block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
- if (!block)
- return 0;
- bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
+
+ if (!bh) {
+ bh = isofs_bread(inode, bufsize, block);
if (!bh)
return 0;
- continue;
}
de = (struct iso_directory_record *) (bh->b_data + offset);
- if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
+ if (first_de) inode_number = (bh->b_blocknr << bufbits) + offset;
de_len = *(unsigned char *) de;
-#ifdef DEBUG
- printk("de_len = %d\n", de_len);
-#endif
-
/* If the length byte is zero, we should move on to the next
CDROM sector. If we are at the end of the directory, we
@@ -164,36 +142,33 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (de_len == 0) {
brelse(bh);
- filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
- + ISOFS_BLOCK_SIZE);
+ bh = NULL;
+ filp->f_pos = (filp->f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
+ block = filp->f_pos >> bufbits;
offset = 0;
-
- if (filp->f_pos >= inode->i_size)
- return 0;
-
- block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
- if (!block)
- return 0;
- bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
- if (!bh)
- return 0;
continue;
}
- offset += de_len;
- if (offset > bufsize) {
- /*
- * This would only normally happen if we had
- * a buggy cdrom image. All directory
- * entries should terminate with a null size
- * or end exactly at the end of the sector.
- */
- printk("next_offset (%x) > bufsize (%lx)\n",
- offset,bufsize);
- break;
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= bufsize) {
+ int slop = bufsize - offset + de_len;
+ memcpy(tmpde, de, slop);
+ offset &= bufsize - 1;
+ block++;
+ brelse(bh);
+ bh = NULL;
+ if (offset) {
+ bh = isofs_bread(inode, bufsize, block);
+ if (!bh)
+ return 0;
+ memcpy((void *) tmpde + slop, bh->b_data, offset);
+ }
+ de = tmpde;
}
- if(de->flags[-high_sierra] & 0x80) {
+ if (de->flags[-high_sierra] & 0x80) {
first_de = 0;
filp->f_pos += de_len;
continue;
@@ -240,7 +215,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (map) {
#ifdef CONFIG_JOLIET
if (inode->i_sb->u.isofs_sb.s_joliet_level) {
- len = get_joliet_filename(de, inode, tmpname);
+ len = get_joliet_filename(de, tmpname, inode);
p = tmpname;
} else
#endif
@@ -249,8 +224,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
p = tmpname;
} else
if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
- len = isofs_name_translate(de->name,
- de->name_len[0], tmpname);
+ len = isofs_name_translate(de, tmpname, inode);
p = tmpname;
} else {
p = de->name;
@@ -265,7 +239,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
continue;
}
- brelse(bh);
+ if (bh) brelse(bh);
return 0;
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 157b8ebba..453e4a456 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -972,14 +972,24 @@ int isofs_bmap(struct inode *inode, int block)
return 0;
}
+struct buffer_head *isofs_bread(struct inode *inode, unsigned int bufsize, unsigned int block)
+{
+ unsigned int blknr = isofs_bmap(inode, block);
+ if (!blknr)
+ return NULL;
+ return bread(inode->i_dev, blknr, bufsize);
+}
+
static int isofs_readpage(struct file *file, struct page *page)
{
return block_read_full_page(page,isofs_get_block);
}
+
static int _isofs_bmap(struct address_space *mapping, long block)
{
return generic_block_bmap(mapping,block,isofs_get_block);
}
+
static struct address_space_operations isofs_aops = {
readpage: isofs_readpage,
sync_page: block_sync_page,
@@ -1002,93 +1012,89 @@ static inline void test_and_set_gid(gid_t *p, gid_t value)
static int isofs_read_level3_size(struct inode * inode)
{
- unsigned long ino = inode->i_ino;
+ unsigned long f_pos = inode->i_ino;
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
int high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
struct buffer_head * bh = NULL;
- int block = 0;
+ unsigned long block, offset;
int i = 0;
int more_entries = 0;
- void *cpnt;
- struct iso_directory_record * raw_inode;
+ struct iso_directory_record * tmpde = kmalloc(256, GFP_KERNEL);
+
+ if (!tmpde)
+ return -ENOMEM;
inode->i_size = 0;
inode->u.isofs_i.i_next_section_ino = 0;
+
+ block = f_pos >> ISOFS_BUFFER_BITS(inode);
+ offset = f_pos & (bufsize-1);
+
do {
- unsigned char *pnt;
- unsigned int reclen;
- int offset = (ino & (bufsize - 1));
-
- cpnt = NULL;
- /* Check whether to update our buffer */
- if (block != ino >> ISOFS_BUFFER_BITS(inode)) {
- block = ino >> ISOFS_BUFFER_BITS(inode);
- brelse(bh);
+ struct iso_directory_record * de;
+ unsigned int de_len;
+
+ if (!bh) {
bh = bread(inode->i_dev, block, bufsize);
if (!bh)
goto out_noread;
}
- pnt = ((unsigned char *) bh->b_data + offset);
- /*
- * Note: this is invariant even if the record
- * spans buffers and must be copied ...
- */
- reclen = *pnt;
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ de_len = *(unsigned char *) de;
- /* N.B. this test doesn't trigger the i++ code ... */
- if(reclen == 0) {
- ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
+ if (de_len == 0) {
+ brelse(bh);
+ bh = NULL;
+ f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
+ block = f_pos >> ISOFS_BUFFER_BITS(inode);
+ offset = 0;
continue;
}
- raw_inode = ((struct iso_directory_record *) pnt);
-
- /* Check whether the raw inode spans the buffer ... */
- if (offset + reclen > bufsize){
- int frag1 = bufsize - offset;
-
- cpnt = kmalloc(reclen, GFP_KERNEL);
- if (cpnt == NULL)
- goto out_nomem;
- memcpy(cpnt, pnt, frag1);
+
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= bufsize) {
+ int slop = bufsize - offset + de_len;
+ memcpy(tmpde, de, slop);
+ offset &= bufsize - 1;
+ block++;
brelse(bh);
- bh = bread(inode->i_dev, ++block, bufsize);
- if (!bh)
- goto out_noread;
- offset += reclen - bufsize;
- memcpy((char *)cpnt+frag1, bh->b_data, offset);
- raw_inode = ((struct iso_directory_record *) cpnt);
+ bh = NULL;
+ if (offset) {
+ bh = bread(inode->i_dev, block, bufsize);
+ if (!bh)
+ goto out_noread;
+ memcpy((void *) tmpde + slop, bh->b_data, offset);
+ }
+ de = tmpde;
}
- inode->i_size += isonum_733 (raw_inode->size);
- if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
+ inode->i_size += isonum_733(de->size);
+ if (i == 1)
+ inode->u.isofs_i.i_next_section_ino = f_pos;
- more_entries = raw_inode->flags[-high_sierra] & 0x80;
+ more_entries = de->flags[-high_sierra] & 0x80;
- ino += reclen;
- if (cpnt)
- kfree (cpnt);
+ f_pos += de_len;
i++;
if(i > 100)
goto out_toomany;
} while(more_entries);
out:
- brelse(bh);
+ kfree(tmpde);
+ if (bh) brelse(bh);
return 0;
-out_nomem:
- printk(KERN_INFO "ISOFS: NoMem ISO inode %lu\n", inode->i_ino);
- brelse(bh);
- return 1;
out_noread:
- printk(KERN_INFO "ISOFS: unable to read i-node block %d\n", block);
- if (cpnt)
- kfree(cpnt);
+ printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
+ kfree(tmpde);
return 1;
out_toomany:
printk(KERN_INFO "isofs_read_level3_size: "
"More than 100 file sections ?!?, aborting...\n"
"isofs_read_level3_size: inode=%lu ino=%lu\n",
- inode->i_ino, ino);
+ inode->i_ino, f_pos);
goto out;
}
@@ -1259,143 +1265,6 @@ static void isofs_read_inode(struct inode * inode)
return;
}
-/* There are times when we need to know the inode number of a parent of
- a particular directory. When control passes through a routine that
- has access to the parent information, it fills it into the inode structure,
- but sometimes the inode gets flushed out of the queue, and someone
- remembers the number. When they try to open up again, we have lost
- the information. The '..' entry on the disc points to the data area
- for a particular inode, so we can follow these links back up, but since
- we do not know the inode number, we do not actually know how large the
- directory is. The disc is almost always correct, and there is
- enough error checking on the drive itself, but an open ended search
- makes me a little nervous.
-
- The BSD iso filesystem uses the extent number for an inode, and this
- would work really nicely for us except that the read_inode function
- would not have any clean way of finding the actual directory record
- that goes with the file. If we had such info, then it would pay
- to change the inode numbers and eliminate this function.
-*/
-
-int isofs_lookup_grandparent(struct inode * parent, int extent)
-{
- unsigned long bufsize = ISOFS_BUFFER_SIZE(parent);
- unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
- unsigned int block,offset;
- int parent_dir, inode_number;
- int result;
- int directory_size;
- struct buffer_head * bh;
- struct iso_directory_record * de;
-
- offset = 0;
- block = extent << (ISOFS_ZONE_BITS(parent) - bufbits);
- if (!(bh = bread(parent->i_dev, block, bufsize))) return -1;
-
- while (1 == 1) {
- de = (struct iso_directory_record *) (bh->b_data + offset);
- if (*((unsigned char *) de) == 0)
- {
- brelse(bh);
- printk("Directory .. not found\n");
- return -1;
- }
-
- offset += *((unsigned char *) de);
-
- if (offset >= bufsize)
- {
- printk(".. Directory not in first block"
- " of directory.\n");
- brelse(bh);
- return -1;
- }
-
- if (de->name_len[0] == 1 && de->name[0] == 1)
- {
- parent_dir = find_rock_ridge_relocation(de, parent);
- directory_size = isonum_733 (de->size);
- brelse(bh);
- break;
- }
- }
-#ifdef DEBUG
- printk("Parent dir:%x\n",parent_dir);
-#endif
- /* Now we know the extent where the parent dir starts on. */
-
- result = -1;
-
- offset = 0;
- block = parent_dir << (ISOFS_ZONE_BITS(parent) - bufbits);
- if (!block || !(bh = bread(parent->i_dev,block, bufsize)))
- {
- return -1;
- }
-
- for(;;)
- {
- de = (struct iso_directory_record *) (bh->b_data + offset);
- inode_number = (block << bufbits)+(offset & (bufsize - 1));
-
- /* If the length byte is zero, we should move on to the next
- CDROM sector. If we are at the end of the directory, we
- kick out of the while loop. */
-
- if ((*((unsigned char *) de) == 0) || (offset == bufsize) )
- {
- brelse(bh);
- offset = 0;
- block++;
- directory_size -= bufsize;
- if(directory_size < 0) return -1;
- if((block & 1) && (ISOFS_ZONE_BITS(parent) - bufbits) == 1)
- {
- return -1;
- }
- if((block & 3) && (ISOFS_ZONE_BITS(parent) - bufbits) == 2)
- {
- return -1;
- }
- if (!block
- || !(bh = bread(parent->i_dev,block, bufsize)))
- {
- return -1;
- }
- continue;
- }
-
- /* Make sure that the entire directory record is in the current
- bh block. If not, we malloc a buffer, and put the two
- halves together, so that we can cleanly read the block. */
-
- offset += *((unsigned char *) de);
-
- if (offset > bufsize)
- {
- printk("Directory overrun\n");
- goto out;
- }
-
- if (find_rock_ridge_relocation(de, parent) == extent){
- result = inode_number;
- goto out;
- }
-
- }
-
- /* We go here for any condition we cannot handle.
- We also drop through to here at the end of the directory. */
-
- out:
- brelse(bh);
-#ifdef DEBUG
- printk("Resultant Inode %d\n",result);
-#endif
- return result;
-}
-
#ifdef LEAK_CHECK
#undef malloc
#undef free_s
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index 009314a82..5b93f4581 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -70,8 +70,7 @@ wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
}
int
-get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
- unsigned char *outname)
+get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode)
{
unsigned char utf8;
struct nls_table *nls;
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 7d4ca4e98..4473f7c0d 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -57,147 +57,87 @@ isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
* itself (as an inode number). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
-static struct buffer_head *
-isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
+static unsigned long
+isofs_find_entry(struct inode *dir, struct dentry *dentry,
+ char * tmpname, struct iso_directory_record * tmpde)
{
+ unsigned long inode_number;
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
- unsigned int block, i, f_pos, offset,
- inode_number = 0; /* shut gcc up */
- struct buffer_head * bh , * retval = NULL;
- unsigned int old_offset;
- int dlen, match;
- char * dpnt;
- unsigned char *page = NULL;
- struct iso_directory_record * de = NULL; /* shut gcc up */
- char de_not_in_buf = 0; /* true if de is in kmalloc'd memory */
- char c;
-
- *ino = 0;
-
- if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
+ unsigned int block, f_pos, offset;
+ struct buffer_head * bh = NULL;
+
+ if (!dir->u.isofs_i.i_first_extent)
+ return 0;
f_pos = 0;
-
- offset = f_pos & (bufsize - 1);
- block = isofs_bmap(dir,f_pos >> bufbits);
-
- if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
+ offset = 0;
+ block = 0;
while (f_pos < dir->i_size) {
+ struct iso_directory_record * de;
+ int de_len, match, i, dlen;
+ char *dpnt;
- /* if de is in kmalloc'd memory, do not point to the
- next de, instead we will move to the next sector */
- if(!de_not_in_buf) {
- de = (struct iso_directory_record *)
- (bh->b_data + offset);
+ if (!bh) {
+ bh = isofs_bread(dir, bufsize, block);
+ if (!bh)
+ return 0;
}
- inode_number = (block << bufbits) + (offset & (bufsize - 1));
-
- /* If byte is zero, or we had to fetch this de past
- the end of the buffer, this is the end of file, or
- time to move to the next sector. Usually 2048 byte
- boundaries. */
-
- if (*((unsigned char *) de) == 0 || de_not_in_buf) {
- if(de_not_in_buf) {
- /* james@bpgc.com: Since we slopped
- past the end of the last buffer, we
- must start some way into the new
- one */
- de_not_in_buf = 0;
- kfree(de);
- f_pos += offset;
- }
- else {
- offset = 0;
- f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
- + ISOFS_BLOCK_SIZE);
- }
- brelse(bh);
- bh = NULL;
-
- if (f_pos >= dir->i_size)
- break;
- block = isofs_bmap(dir,f_pos>>bufbits);
- if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
- break;
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ inode_number = (bh->b_blocknr << bufbits) + offset;
- continue; /* Will kick out if past end of directory */
+ de_len = *(unsigned char *) de;
+ if (!de_len) {
+ brelse(bh);
+ bh = NULL;
+ f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
+ block = f_pos >> bufbits;
+ offset = 0;
+ continue;
}
- old_offset = offset;
- offset += *((unsigned char *) de);
- f_pos += *((unsigned char *) de);
+ offset += de_len;
+ f_pos += de_len;
- /* james@bpgc.com: new code to handle case where the
- directory entry spans two blocks. Usually 1024
- byte boundaries */
+ /* Make sure we have a full directory entry */
if (offset >= bufsize) {
- struct buffer_head *bh_next;
-
- /* james@bpgc.com: read the next block, and
- copy the split de into a newly kmalloc'd
- buffer */
- block = isofs_bmap(dir,f_pos>>bufbits);
- if (!block ||
- !(bh_next = bread(dir->i_dev,block,bufsize)))
- break;
-
- de = (struct iso_directory_record *)
- kmalloc(offset - old_offset, GFP_KERNEL);
- memcpy((char *)de, bh->b_data + old_offset,
- bufsize - old_offset);
- memcpy((char *)de + bufsize - old_offset,
- bh_next->b_data, offset - bufsize);
- brelse(bh_next);
- de_not_in_buf = 1;
- offset -= bufsize;
+ int slop = bufsize - offset + de_len;
+ memcpy(tmpde, de, slop);
+ offset &= bufsize - 1;
+ block++;
+ brelse(bh);
+ bh = NULL;
+ if (offset) {
+ bh = isofs_bread(dir, bufsize, block);
+ if (!bh)
+ return 0;
+ memcpy((void *) tmpde + slop, bh->b_data, offset);
+ }
+ de = tmpde;
}
+
dlen = de->name_len[0];
dpnt = de->name;
- if (dir->i_sb->u.isofs_sb.s_rock ||
- dir->i_sb->u.isofs_sb.s_joliet_level ||
- dir->i_sb->u.isofs_sb.s_mapping == 'n' ||
- dir->i_sb->u.isofs_sb.s_mapping == 'a') {
- if (! page) {
- page = (unsigned char *)
- __get_free_page(GFP_KERNEL);
- if (!page) break;
- }
- }
if (dir->i_sb->u.isofs_sb.s_rock &&
- ((i = get_rock_ridge_filename(de, page, dir)))) {
+ ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
dlen = i;
- dpnt = page;
+ dpnt = tmpname;
#ifdef CONFIG_JOLIET
} else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
- dlen = get_joliet_filename(de, dir, page);
- dpnt = page;
+ dlen = get_joliet_filename(de, tmpname, dir);
+ dpnt = tmpname;
#endif
} else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') {
- dlen = get_acorn_filename(de, page, dir);
- dpnt = page;
+ dlen = get_acorn_filename(de, tmpname, dir);
+ dpnt = tmpname;
} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
- for (i = 0; i < dlen; i++) {
- c = dpnt[i];
- /* lower case */
- if (c >= 'A' && c <= 'Z') c |= 0x20;
- if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
- dlen -= 2;
- break;
- }
- if (c == ';') c = '.';
- page[i] = c;
- }
- /* This allows us to match with and without
- * a trailing period. */
- if(page[dlen-1] == '.' && dentry->d_name.len == dlen-1)
- dlen--;
- dpnt = page;
+ dlen = isofs_name_translate(de, tmpname, dir);
+ dpnt = tmpname;
}
+
/*
* Skip hidden or associated files unless unhide is set
*/
@@ -208,43 +148,32 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
match = (isofs_cmp(dentry,dpnt,dlen) == 0);
}
if (match) {
- if(inode_number == -1) {
- /* Should only happen for the '..' entry */
- inode_number =
- isofs_lookup_grandparent(dir,
- find_rock_ridge_relocation(de,dir));
- }
- *ino = inode_number;
- retval = bh;
- bh = NULL;
- break;
+ if (bh) brelse(bh);
+ return inode_number;
}
}
- if (page) free_page((unsigned long) page);
if (bh) brelse(bh);
- if(de_not_in_buf)
- kfree(de);
- return retval;
+ return 0;
}
struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
{
unsigned long ino;
- struct buffer_head * bh;
struct inode *inode;
+ struct page *page;
#ifdef DEBUG
printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
#endif
dentry->d_op = dir->i_sb->s_root->d_op;
- bh = isofs_find_entry(dir, dentry, &ino);
+ page = alloc_page(GFP_USER);
+ ino = isofs_find_entry(dir, dentry, page_address(page), 1024 + page_address(page));
+ __free_page(page);
inode = NULL;
- if (bh) {
- brelse(bh);
-
- inode = iget(dir->i_sb,ino);
+ if (ino) {
+ inode = iget(dir->i_sb, ino);
if (!inode)
return ERR_PTR(-EACCES);
}
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 1a7cbe374..b2eff877f 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -449,7 +449,7 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
{
struct inode *inode = (struct inode*)page->mapping->host;
- char *link = (char*)kmap(page);
+ char *link = kmap(page);
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head *bh;
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 3ac27df92..f61005aac 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -327,17 +327,15 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
struct inode * inode;
struct jffs_control *c;
- inode = get_empty_inode();
+ sb = dir->i_sb;
+ inode = new_inode(sb);
if (!inode) {
*err = -ENOMEM;
return NULL;
}
- sb = dir->i_sb;
c = (struct jffs_control *)sb->u.generic_sbp;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_ino = raw_inode->ino;
inode->i_mode = raw_inode->mode;
inode->i_nlink = raw_inode->nlink;
@@ -351,7 +349,6 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
inode->i_blksize = PAGE_SIZE;
inode->i_blocks = (inode->i_size + 511) >> 9;
inode->i_version = 0;
- inode->i_flags = sb->s_flags;
inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino);
insert_inode_hash(inode);
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index 5cf82f468..09e88d7ba 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -10,7 +10,8 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * $Id: intrep.c,v 1.69 2000/08/24 09:35:47 dwmw2 Exp $
+ * - Based on Id: intrep.c,v 1.71 2000/10/27 16:51:29 dwmw2 Exp
+ * - With the ctype() changes from v1.77.
*
* Ported to Linux 2.3.x and MTD:
* Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -68,15 +69,11 @@
#include <linux/version.h>
#include <linux/smp_lock.h>
#include <linux/sched.h>
-
+#include <linux/ctype.h>
#include "intrep.h"
#include "jffs_fm.h"
-#if LINUX_VERSION_CODE < 0x20300
-#define set_current_state(x) do{current->state = x;} while (0)
-#endif
-
#if defined(JFFS_MEMORY_DEBUG) && JFFS_MEMORY_DEBUG
long no_jffs_file = 0;
long no_jffs_node = 0;
@@ -94,48 +91,7 @@ static int jffs_update_file(struct jffs_file *f, struct jffs_node *node);
static __u8 flash_read_u8(struct mtd_info *mtd, loff_t from);
#if 1
-#define _U 01
-#define _L 02
-#define _N 04
-#define _S 010
-#define _P 020
-#define _C 040
-#define _X 0100
-#define _B 0200
-
-const unsigned char jffs_ctype_[1 + 256] = {
- 0,
- _C, _C, _C, _C, _C, _C, _C, _C,
- _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C,
- _C, _C, _C, _C, _C, _C, _C, _C,
- _C, _C, _C, _C, _C, _C, _C, _C,
- _S|_B, _P, _P, _P, _P, _P, _P, _P,
- _P, _P, _P, _P, _P, _P, _P, _P,
- _N, _N, _N, _N, _N, _N, _N, _N,
- _N, _N, _P, _P, _P, _P, _P, _P,
- _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U,
- _U, _U, _U, _U, _U, _U, _U, _U,
- _U, _U, _U, _U, _U, _U, _U, _U,
- _U, _U, _U, _P, _P, _P, _P, _P,
- _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L,
- _L, _L, _L, _L, _L, _L, _L, _L,
- _L, _L, _L, _L, _L, _L, _L, _L,
- _L, _L, _L, _P, _P, _P, _P, _C
-};
-
-#define jffs_isalpha(c) ((jffs_ctype_+1)[(int)c]&(_U|_L))
-#define jffs_isupper(c) ((jffs_ctype_+1)[(int)c]&_U)
-#define jffs_islower(c) ((jffs_ctype_+1)[(int)c]&_L)
-#define jffs_isdigit(c) ((jffs_ctype_+1)[(int)c]&_N)
-#define jffs_isxdigit(c) ((jffs_ctype_+1)[(int)c]&(_X|_N))
-#define jffs_isspace(c) ((jffs_ctype_+1)[(int)c]&_S)
-#define jffs_ispunct(c) ((jffs_ctype_+1)[(int)c]&_P)
-#define jffs_isalnum(c) ((jffs_ctype_+1)[(int)c]&(_U|_L|_N))
-#define jffs_isprint(c) ((jffs_ctype_+1)[(int)c]&(_P|_U|_L|_N|_B))
-#define jffs_isgraph(c) ((jffs_ctype_+1)[(int)c]&(_P|_U|_L|_N))
-#define jffs_iscntrl(c) ((jffs_ctype_+1)[(int)c]&_C)
-
-void
+static void
jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
{
char line[16];
@@ -169,7 +125,7 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
printk(" ");
for (i = 0; i < j; i++) {
- if (jffs_isgraph(line[i])) {
+ if (isgraph(line[i])) {
printk("%c", line[i]);
}
else {
@@ -193,9 +149,12 @@ flash_safe_read(struct mtd_info *mtd, loff_t from,
size_t retlen;
int res;
+ D3(printk(KERN_NOTICE "flash_safe_read(%p, %08x, %p, %08x)\n",
+ mtd, from, buf, count));
+
res = MTD_READ(mtd, from, count, &retlen, buf);
if (retlen != count) {
- printk("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
+ panic("Didn't read all bytes in flash_safe_read(). Returned %d\n", res);
}
return res?res:retlen;
}
@@ -367,9 +326,37 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size)
{
__u32 sum = 0;
loff_t ptr = start;
- while (size-- > 0) {
- sum += flash_read_u8(mtd, ptr++);
+ __u8 *read_buf;
+ int i, length;
+
+ /* Allocate read buffer */
+ read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+
+ /* Loop until checksum done */
+ while (size) {
+ /* Get amount of data to read */
+ if (size < 4096)
+ length = size;
+ else
+ length = 4096;
+
+ /* Perform flash read */
+ D3(printk(KERN_NOTICE "jffs_checksum_flash\n"));
+ flash_safe_read(mtd, ptr, &read_buf[0], length);
+
+ /* Compute checksum */
+ for (i=0; i < length ; i++)
+ sum += read_buf[i];
+
+ /* Update pointer and size */
+ size -= length;
+ ptr += length;
}
+
+ /* Free read buffer */
+ kfree (read_buf);
+
+ /* Return result */
D3(printk("checksum result: 0x%08x\n", sum));
return sum;
}
@@ -609,12 +596,17 @@ jffs_scan_flash(struct jffs_control *c)
loff_t pos = fmc->flash_start;
loff_t start;
loff_t end = fmc->flash_start + fmc->flash_size;
+ __u8 *read_buf;
+ int i, len, retlen;
D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n",
(long)pos, (long)end));
flash_safe_acquire(fmc->mtd);
+ /* Allocate read buffer */
+ read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL);
+
/* Start the scan. */
while (pos < end) {
deleted_file = 0;
@@ -629,9 +621,22 @@ jffs_scan_flash(struct jffs_control *c)
something else than 0xff is found. */
D1(printk("jffs_scan_flash(): 0xff at pos 0x%lx.\n",
(long)pos));
- for (; pos < end
- && JFFS_EMPTY_BITMASK == flash_read_u32(fmc->mtd, pos);
- pos += 4);
+
+ len = end - pos < 4096 ? end - pos : 4096;
+
+ retlen = flash_safe_read(fmc->mtd, pos,
+ &read_buf[0], len);
+
+ retlen &= ~3;
+
+ for (i=0 ; i < retlen ; i+=4, pos += 4) {
+ if(*((__u32 *) &read_buf[i]) !=
+ JFFS_EMPTY_BITMASK)
+ break;
+ }
+ if (i == retlen)
+ continue;
+
D1(printk("jffs_scan_flash(): 0xff ended at "
"pos 0x%lx.\n", (long)pos));
@@ -748,7 +753,12 @@ jffs_scan_flash(struct jffs_control *c)
if (!(node = (struct jffs_node *)
kmalloc(sizeof(struct jffs_node),
GFP_KERNEL))) {
+ /* Free read buffer */
+ kfree (read_buf);
+
+ /* Release the flash device */
flash_safe_release(fmc->mtd);
+
return -ENOMEM;
}
DJM(no_jffs_node++);
@@ -893,7 +903,13 @@ jffs_scan_flash(struct jffs_control *c)
D(printk("jffs_scan_flash(): !node->fm\n"));
kfree(node);
DJM(no_jffs_node--);
+
+ /* Free read buffer */
+ kfree (read_buf);
+
+ /* Release the flash device */
flash_safe_release(fmc->mtd);
+
return -ENOMEM;
}
if ((err = jffs_insert_node(c, 0, &raw_inode,
@@ -911,7 +927,13 @@ jffs_scan_flash(struct jffs_control *c)
D(printk("jffs_scan_flash: !dl\n"));
kfree(node);
DJM(no_jffs_node--);
+
+ /* Release the flash device */
flash_safe_release(fmc->flash_part);
+
+ /* Free read buffer */
+ kfree (read_buf);
+
return -ENOMEM;
}
dl->ino = deleted_file;
@@ -936,6 +958,11 @@ jffs_scan_flash(struct jffs_control *c)
DJM(no_jffs_node--);
}
jffs_build_end(fmc);
+
+ /* Free read buffer */
+ kfree (read_buf);
+
+ /* Return happy */
D3(printk("jffs_scan_flash(): Leaving...\n"));
flash_safe_release(fmc->mtd);
return 0;
@@ -1598,6 +1625,7 @@ jffs_get_node_data(struct jffs_file *f, struct jffs_node *node,
f->name, node->ino, node->version, node_offset));
r = jffs_min(avail, max_size);
+ D3(printk(KERN_NOTICE "jffs_get_node_data\n"));
flash_safe_read(fmc->mtd, pos, buf, r);
D3(printk(" jffs_get_node_data(): Read %u byte%s.\n",
@@ -3026,9 +3054,8 @@ jffs_garbage_collect_thread(void *ptr)
case SIGKILL:
D1(printk("jffs_garbage_collect_thread(): SIGKILL received.\n"));
c->gc_task = NULL;
- up(&c->gc_thread_sem);
unlock_kernel();
- return(0);
+ up_and_exit(&c->gc_thread_sem, 0);
}
}
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 249e7514d..b5194b561 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -168,7 +168,6 @@ reclaimer(void *ptr)
* reclaim is in progress */
lock_kernel();
lockd_up();
- down(&file_lock_sem);
/* First, reclaim all locks that have been granted previously. */
restart:
@@ -181,12 +180,11 @@ restart:
fl->fl_u.nfs_fl.state != host->h_state &&
(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) {
fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED;
- nlmclnt_reclaim(host, fl);
+ nlmclnt_reclaim(host, fl); /* This sleeps */
goto restart;
}
tmp = tmp->next;
}
- up(&file_lock_sem);
host->h_reclaiming = 0;
wake_up(&host->h_gracewait);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index dbe3f69b5..211b01530 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -407,19 +407,15 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
static
void nlmclnt_insert_lock_callback(struct file_lock *fl)
{
- lock_kernel();
nlm_get_host(fl->fl_u.nfs_fl.host);
- unlock_kernel();
}
static
void nlmclnt_remove_lock_callback(struct file_lock *fl)
{
- lock_kernel();
if (fl->fl_u.nfs_fl.host) {
nlm_release_host(fl->fl_u.nfs_fl.host);
fl->fl_u.nfs_fl.host = NULL;
}
- unlock_kernel();
}
/*
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 5460e8c9f..078f568b7 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -468,7 +468,6 @@ nlmsvc_notify_blocked(struct file_lock *fl)
dprintk("lockd: VFS unblock notification for block %p\n", fl);
posix_unblock_lock(fl);
- lock_kernel();
for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
nlmsvc_insert_block(block, 0);
@@ -476,7 +475,6 @@ nlmsvc_notify_blocked(struct file_lock *fl)
return;
}
}
- unlock_kernel();
printk(KERN_WARNING "lockd: notification for unknown block!\n");
}
diff --git a/fs/locks.c b/fs/locks.c
index 0e92b740f..7da293a31 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -125,11 +125,6 @@
#include <asm/semaphore.h>
#include <asm/uaccess.h>
-DECLARE_MUTEX(file_lock_sem);
-
-#define acquire_fl_sem() down(&file_lock_sem)
-#define release_fl_sem() up(&file_lock_sem)
-
int leases_enable = 1;
int lease_break_time = 45;
@@ -428,6 +423,15 @@ static void locks_insert_block(struct file_lock *blocker,
list_add(&waiter->fl_link, &blocked_list);
}
+static inline
+void locks_notify_blocked(struct file_lock *waiter)
+{
+ if (waiter->fl_notify)
+ waiter->fl_notify(waiter);
+ else
+ wake_up(&waiter->fl_wait);
+}
+
/* Wake up processes blocked waiting for blocker.
* If told to wait then schedule the processes until the block list
* is empty, otherwise empty the block list ourselves.
@@ -436,11 +440,9 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
{
while (!list_empty(&blocker->fl_block)) {
struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block);
- /* N.B. Is it possible for the notify function to block?? */
- if (waiter->fl_notify)
- waiter->fl_notify(waiter);
- wake_up(&waiter->fl_wait);
+
if (wait) {
+ locks_notify_blocked(waiter);
/* Let the blocked process remove waiter from the
* block list when it gets scheduled.
*/
@@ -451,6 +453,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
* time it wakes up blocker won't exist any more.
*/
locks_delete_block(waiter);
+ locks_notify_blocked(waiter);
}
}
}
@@ -477,7 +480,6 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
*/
static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
{
- int (*lock)(struct file *, int, struct file_lock *);
struct file_lock *fl = *thisfl_p;
*thisfl_p = fl->fl_next;
@@ -488,7 +490,7 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
if (fl->fl_fasync != NULL){
- printk("locks_delete_lock: fasync == %p\n", fl->fl_fasync);
+ printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
fl->fl_fasync = NULL;
}
@@ -496,12 +498,24 @@ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
fl->fl_remove(fl);
locks_wake_up_blocks(fl, wait);
- lock = fl->fl_file->f_op->lock;
- if (lock) {
+ locks_free_lock(fl);
+}
+
+/*
+ * Call back client filesystem in order to get it to unregister a lock,
+ * then delete lock. Essentially useful only in locks_remove_*().
+ * Note: this must be called with the semaphore already held!
+ */
+static inline void locks_unlock_delete(struct file_lock **thisfl_p)
+{
+ struct file_lock *fl = *thisfl_p;
+ int (*lock)(struct file *, int, struct file_lock *);
+
+ if ((lock = fl->fl_file->f_op->lock) != NULL) {
fl->fl_type = F_UNLCK;
lock(fl->fl_file, F_SETLK, fl);
}
- locks_free_lock(fl);
+ locks_delete_lock(thisfl_p, 0);
}
/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -562,22 +576,19 @@ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
return (locks_conflict(caller_fl, sys_fl));
}
-int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, struct semaphore *sem, int timeout)
+static int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, int timeout)
{
int result = 0;
- wait_queue_t wait;
- init_waitqueue_entry(&wait, current);
+ DECLARE_WAITQUEUE(wait, current);
- __add_wait_queue(fl_wait, &wait);
current->state = TASK_INTERRUPTIBLE;
- up(sem);
+ add_wait_queue(fl_wait, &wait);
if (timeout == 0)
schedule();
else
result = schedule_timeout(timeout);
if (signal_pending(current))
result = -ERESTARTSYS;
- down(sem);
remove_wait_queue(fl_wait, &wait);
current->state = TASK_RUNNING;
return result;
@@ -587,7 +598,7 @@ static int locks_block_on(struct file_lock *blocker, struct file_lock *waiter)
{
int result;
locks_insert_block(blocker, waiter);
- result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, 0);
+ result = interruptible_sleep_on_locked(&waiter->fl_wait, 0);
locks_delete_block(waiter);
return result;
}
@@ -596,7 +607,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
{
int result;
locks_insert_block(blocker, waiter);
- result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, time);
+ result = interruptible_sleep_on_locked(&waiter->fl_wait, time);
locks_delete_block(waiter);
return result;
}
@@ -606,14 +617,14 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
- acquire_fl_sem();
+ lock_kernel();
for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!(cfl->fl_flags & FL_POSIX))
continue;
if (posix_locks_conflict(cfl, fl))
break;
}
- release_fl_sem();
+ unlock_kernel();
return (cfl);
}
@@ -668,14 +679,14 @@ int locks_mandatory_locked(struct inode *inode)
/*
* Search the lock list for this inode for any POSIX locks.
*/
- acquire_fl_sem();
+ lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
if (fl->fl_owner != owner)
break;
}
- release_fl_sem();
+ unlock_kernel();
return fl ? -EAGAIN : 0;
}
@@ -696,7 +707,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
new_fl->fl_end = offset + count - 1;
error = 0;
- acquire_fl_sem();
+ lock_kernel();
repeat:
/* Search the lock list for this inode for locks that conflict with
@@ -729,7 +740,7 @@ repeat:
}
}
locks_free_lock(new_fl);
- release_fl_sem();
+ unlock_kernel();
return error;
}
@@ -847,7 +858,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if (!(new_fl && new_fl2))
goto out;
- acquire_fl_sem();
+ lock_kernel();
if (caller->fl_type != F_UNLCK) {
repeat:
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -951,7 +962,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
* as the change in lock type might satisfy
* their needs.
*/
- locks_wake_up_blocks(fl, 0);
+ locks_wake_up_blocks(fl, 0); /* This cannot schedule()! */
fl->fl_start = caller->fl_start;
fl->fl_end = caller->fl_end;
fl->fl_type = caller->fl_type;
@@ -992,7 +1003,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
locks_wake_up_blocks(left, 0);
}
out:
- release_fl_sem();
+ unlock_kernel();
/*
* Free any unused locks.
*/
@@ -1038,7 +1049,7 @@ int __get_lease(struct inode *inode, unsigned int mode)
alloc_err = lease_alloc(NULL, 0, &new_fl);
- acquire_fl_sem();
+ lock_kernel();
flock = inode->i_flock;
if (flock->fl_type & F_INPROGRESS) {
if ((mode & O_NONBLOCK)
@@ -1107,7 +1118,7 @@ restart:
}
out:
- release_fl_sem();
+ unlock_kernel();
if (!alloc_err)
locks_free_lock(new_fl);
return error;
@@ -1210,7 +1221,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
before = &inode->i_flock;
- acquire_fl_sem();
+ lock_kernel();
while ((fl = *before) != NULL) {
if (fl->fl_flags != FL_LEASE)
@@ -1261,7 +1272,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
filp->f_owner.uid = current->uid;
filp->f_owner.euid = current->euid;
out_unlock:
- release_fl_sem();
+ unlock_kernel();
return error;
}
@@ -1307,10 +1318,10 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
&& !(filp->f_mode & 3))
goto out_putf;
- acquire_fl_sem();
+ lock_kernel();
error = flock_lock_file(filp, type,
(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
- release_fl_sem();
+ unlock_kernel();
out_putf:
fput(filp);
@@ -1643,16 +1654,16 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
*/
return;
}
- acquire_fl_sem();
+ lock_kernel();
before = &inode->i_flock;
while ((fl = *before) != NULL) {
if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
- locks_delete_lock(before, 0);
+ locks_unlock_delete(before);
continue;
}
before = &fl->fl_next;
}
- release_fl_sem();
+ unlock_kernel();
}
/*
@@ -1667,7 +1678,7 @@ void locks_remove_flock(struct file *filp)
if (!inode->i_flock)
return;
- acquire_fl_sem();
+ lock_kernel();
before = &inode->i_flock;
while ((fl = *before) != NULL) {
@@ -1678,7 +1689,7 @@ void locks_remove_flock(struct file *filp)
}
before = &fl->fl_next;
}
- release_fl_sem();
+ unlock_kernel();
}
/**
@@ -1691,9 +1702,7 @@ void locks_remove_flock(struct file *filp)
void
posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
{
- acquire_fl_sem();
locks_insert_block(blocker, waiter);
- release_fl_sem();
}
/**
@@ -1705,12 +1714,8 @@ posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
void
posix_unblock_lock(struct file_lock *waiter)
{
- acquire_fl_sem();
- if (!list_empty(&waiter->fl_block)) {
+ if (!list_empty(&waiter->fl_block))
locks_delete_block(waiter);
- wake_up(&waiter->fl_wait);
- }
- release_fl_sem();
}
static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
@@ -1801,7 +1806,7 @@ int get_locks_status(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
int i = 0;
- acquire_fl_sem();
+ lock_kernel();
list_for_each(tmp, &file_lock_list) {
struct list_head *btmp;
struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
@@ -1822,7 +1827,7 @@ int get_locks_status(char *buffer, char **start, off_t offset, int length)
}
}
done:
- release_fl_sem();
+ unlock_kernel();
*start = buffer;
if(q-buffer < length)
return (q-buffer);
@@ -1847,7 +1852,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
- acquire_fl_sem();
+ lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (fl->fl_flags == FL_POSIX) {
if (fl->fl_type == F_RDLCK)
@@ -1864,7 +1869,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
result = 0;
break;
}
- release_fl_sem();
+ unlock_kernel();
return result;
}
@@ -1885,7 +1890,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
- acquire_fl_sem();
+ lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (fl->fl_flags == FL_POSIX) {
if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
@@ -1900,7 +1905,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
result = 0;
break;
}
- release_fl_sem();
+ unlock_kernel();
return result;
}
#endif
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index dce2687ee..49f757e80 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -224,14 +224,12 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
struct buffer_head * bh;
int i,j;
- inode = get_empty_inode();
+ sb = dir->i_sb;
+ inode = new_inode(sb);
if (!inode) {
*error = -ENOMEM;
return NULL;
}
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = 0;
j = 8192;
bh = NULL;
*error = -ENOSPC;
@@ -259,8 +257,6 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
unlock_super(sb);
return NULL;
}
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = j;
diff --git a/fs/namei.c b/fs/namei.c
index c22fc2ec3..c0d1abc36 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1381,7 +1381,10 @@ asmlinkage long sys_rmdir(const char * pathname)
case LAST_DOTDOT:
error = -ENOTEMPTY;
goto exit1;
- case LAST_ROOT: case LAST_DOT:
+ case LAST_DOT:
+ error = -EINVAL;
+ goto exit1;
+ case LAST_ROOT:
error = -EBUSY;
goto exit1;
}
@@ -1949,7 +1952,7 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage)
if (!Page_Uptodate(page))
goto async_fail;
*ppage = page;
- return (char*) kmap(page);
+ return kmap(page);
async_fail:
page_cache_release(page);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index eda3fe6af..a187b1199 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -462,7 +462,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (!page)
goto read_really;
- ctl.cache = cache = (union ncp_dir_cache *) kmap(page);
+ ctl.cache = cache = kmap(page);
ctl.head = cache->head;
if (!Page_Uptodate(page) || !ctl.head.eof)
@@ -490,7 +490,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
if (!ctl.page)
goto invalid_cache;
- ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
+ ctl.cache = kmap(ctl.page);
if (!Page_Uptodate(ctl.page))
goto invalid_cache;
}
@@ -635,7 +635,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
ctl.ofs += 1;
ctl.page = grab_cache_page(&inode->i_data, ctl.ofs);
if (ctl.page)
- ctl.cache = (union ncp_dir_cache *) kmap(ctl.page);
+ ctl.cache = kmap(ctl.page);
}
if (ctl.cache) {
ctl.cache->dentry[ctl.idx] = newdent;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 139c9262d..ac4de2b83 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -120,11 +120,6 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
DPRINTK("ncp_file_read: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- error = -EINVAL;
- if (inode == NULL) {
- DPRINTK("ncp_file_read: inode = NULL\n");
- goto out;
- }
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(inode)))
goto out;
@@ -210,10 +205,6 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
DPRINTK("ncp_file_write: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- if (inode == NULL) {
- DPRINTK("ncp_file_write: inode = NULL\n");
- return -EINVAL;
- }
errno = -EIO;
if (!ncp_conn_valid(NCP_SERVER(inode)))
goto out;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index ff0c1fd03..badfc7817 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -214,13 +214,11 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
return NULL;
}
- inode = get_empty_inode();
+ inode = new_inode(sb);
if (inode) {
init_MUTEX(&NCP_FINFO(inode)->open_sem);
atomic_set(&NCP_FINFO(inode)->opened, info->opened);
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_ino = info->ino;
ncp_set_attr(inode, info);
if (S_ISREG(inode->i_mode)) {
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 4df91abe3..4b6afe2e9 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -86,10 +86,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_CONN_LOGGED_IN:
- if ((permission(inode, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid)) {
+ if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- }
if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
return -EINVAL;
if (server->root_setuped)
@@ -207,8 +205,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
struct nw_info_struct i;
struct dentry* dentry;
- if ( (permission(inode, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
+ if (!capable(CAP_SYS_ADMIN))
{
return -EACCES;
}
@@ -513,8 +510,7 @@ outrel:
* Thanks Petr Vandrovec for idea and many hints.
*/
case NCP_IOC_SETCHARSETS:
- if ((permission(inode, MAY_WRITE) != 0) &&
- (current->uid != server->m.mounted_uid))
+ if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (server->root_setuped)
return -EBUSY;
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 041dd0785..9261eb453 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -37,7 +37,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
struct page* page;
- unsigned long pg_addr;
+ char *pg_addr;
unsigned int already_read;
unsigned int count;
int bufsize;
@@ -71,7 +71,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
if (ncp_read_kernel(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle,
pos, to_read,
- (char *) (pg_addr + already_read),
+ pg_addr + already_read,
&read_this_time) != 0) {
read_this_time = 0;
}
@@ -87,8 +87,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
}
if (already_read < PAGE_SIZE)
- memset((char*)(pg_addr + already_read), 0,
- PAGE_SIZE - already_read);
+ memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
flush_dcache_page(page);
kunmap(page);
return page;
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 9272822a4..6e09c8bf2 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -1005,6 +1005,8 @@ ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
/* this is wrong! */
vname_cc = kmalloc(vlen, GFP_KERNEL);
+ if (!vname_cc)
+ return -ENOMEM;
for (i = 0; i < vlen; i++)
vname_cc[i] = ncp_tolower(in, vname[i]);
vname = vname_cc;
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 0962593da..022cbce78 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -48,7 +48,7 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
struct inode *inode = (struct inode*)page->mapping->host;
int error, length, len, cnt;
char *link;
- char *buf = (char*)kmap(page);
+ char *buf = kmap(page);
error = -ENOMEM;
for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 3f6b770aa..c66d870d9 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -97,7 +97,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct file *file = desc->file;
struct inode *inode = file->f_dentry->d_inode;
- void *buffer = (void *)kmap(page);
+ void *buffer = kmap(page);
int plus = NFS_USE_READDIRPLUS(inode);
int error;
@@ -145,7 +145,7 @@ static inline
int find_dirent(nfs_readdir_descriptor_t *desc, struct page *page)
{
struct nfs_entry *entry = desc->entry;
- char *start = (char *)kmap(page),
+ char *start = kmap(page),
*p = start;
int loop_count = 0,
status = 0;
@@ -251,7 +251,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
{
struct file *file = desc->file;
struct nfs_entry *entry = desc->entry;
- char *start = (char *)kmap(desc->page),
+ char *start = kmap(desc->page),
*p = start + desc->page_offset;
unsigned long fileid;
int loop_count = 0,
@@ -323,7 +323,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
status = -ENOMEM;
goto out;
}
- p = (u32 *)kmap(page);
+ p = kmap(page);
status = NFS_PROTO(inode)->readdir(file, desc->target, p,
NFS_SERVER(inode)->dtsize, 0);
if (status >= 0) {
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index b21592528..5b582024e 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -720,12 +720,9 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
(dentry->d_name.len == 9 &&
memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
- struct inode *inode = get_empty_inode();
+ struct inode *inode = new_inode(sb);
if (!inode)
- goto out;
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_flags = 0;
+ goto out;
inode->i_ino = nfs_fattr_to_ino_t(fattr);
nfs_read_inode(inode);
nfs_fill_inode(inode, fattr);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 7c1aad253..76fc2f437 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -101,7 +101,7 @@ nfs_readpage_sync(struct file *file, struct page *page)
* This works now because the socket layer never tries to DMA
* into this buffer directly.
*/
- buffer = (char *) kmap(page);
+ buffer = kmap(page);
do {
if (count < rsize)
rsize = count;
@@ -257,7 +257,7 @@ nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
struct nfs_page *req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_base = kmap(req->wb_page) + req->wb_offset;
iov->iov_len = req->wb_bytes;
count += req->wb_bytes;
iov++;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 4c9c45e2a..4960526b4 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -30,7 +30,7 @@
static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
{
struct inode *inode = dentry->d_inode;
- void *buffer = (void *)kmap(page);
+ void *buffer = kmap(page);
int error;
/* We place the length at the beginning of the page,
@@ -69,7 +69,7 @@ static char *nfs_getlink(struct dentry *dentry, struct page **ppage)
if (!Page_Uptodate(page))
goto getlink_read_error;
*ppage = page;
- p = (u32 *) kmap(page);
+ p = kmap(page);
return (char*)(p+1);
getlink_read_error:
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 5346e6302..230954993 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -184,7 +184,7 @@ nfs_writepage_sync(struct file *file, struct page *page,
dentry->d_parent->d_name.name, dentry->d_name.name,
count, (long long)(page_offset(page) + offset));
- buffer = (u8 *) kmap(page) + offset;
+ buffer = kmap(page) + offset;
base = page_offset(page) + offset;
flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
@@ -601,14 +601,10 @@ nfs_wait_on_request(struct nfs_page *req)
{
struct inode *inode = req->wb_dentry->d_inode;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
- int retval;
if (!NFS_WBACK_BUSY(req))
return 0;
- req->wb_count++;
- retval = nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
- nfs_release_request(req);
- return retval;
+ return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
}
/*
@@ -1065,7 +1061,7 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
struct nfs_page *req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
- iov->iov_base = (void *)(kmap(req->wb_page) + req->wb_offset);
+ iov->iov_base = kmap(req->wb_page) + req->wb_offset;
iov->iov_len = req->wb_bytes;
count += req->wb_bytes;
iov++;
@@ -1239,6 +1235,13 @@ nfs_writeback_done(struct rpc_task *task)
}
#endif
+ /*
+ * Update attributes as result of writeback.
+ * FIXME: There is an inherent race with invalidate_inode_pages and
+ * writebacks since the page->count is kept > 1 for as long
+ * as the page has a write request pending.
+ */
+ nfs_write_attributes(inode, resp->fattr);
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
@@ -1278,9 +1281,6 @@ nfs_writeback_done(struct rpc_task *task)
next:
nfs_unlock_request(req);
}
- /* Update attributes as result of writeback. */
- nfs_write_attributes(inode, resp->fattr);
-
}
@@ -1395,6 +1395,7 @@ nfs_commit_done(struct rpc_task *task)
dprintk("NFS: %4d nfs_commit_done (status %d)\n",
task->tk_pid, task->tk_status);
+ nfs_write_attributes(inode, resp->fattr);
while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req);
@@ -1426,8 +1427,6 @@ nfs_commit_done(struct rpc_task *task)
next:
nfs_unlock_request(req);
}
-
- nfs_write_attributes(inode, resp->fattr);
}
#endif
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index f01f1de86..b57b85ca1 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1538,6 +1538,8 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
inode->i_uid == current->fsuid)
return 0;
+ acc &= ~ MAY_OWNER_OVERRIDE; /* This bit is no longer needed,
+ and gets in the way later */
err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC));
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index f9ffb0a40..49d2160a6 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -428,7 +428,7 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
int error=0;
ntfs_attribute *si;
- r=get_empty_inode();
+ r=new_inode(dir->i_sb);
if(!r){
error=ENOMEM;
goto fail;
@@ -456,8 +456,6 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
r->i_uid=vol->uid;
r->i_gid=vol->gid;
- r->i_nlink=1;
- r->i_sb=dir->i_sb;
/* FIXME: dirty? dev? */
/* get the file modification times from the standard information */
si=ntfs_find_attr(ino,vol->at_standard_information,NULL);
@@ -502,7 +500,7 @@ _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
goto out;
error = EIO;
- r = get_empty_inode();
+ r = new_inode(dir->i_sb);
if (!r)
goto out;
@@ -522,8 +520,6 @@ _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
goto out;
r->i_uid = vol->uid;
r->i_gid = vol->gid;
- r->i_nlink = 1;
- r->i_sb = dir->i_sb;
si = ntfs_find_attr(ino,vol->at_standard_information,NULL);
if(si){
char *attr = si->d.data;
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 910ffe095..3fdc84ed1 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1050,7 +1050,7 @@ ntfs_clear_bit (unsigned char *byte, int bit)
/* We have to skip the 16 metafiles and the 8 reserved entries */
static int
-new_inode (ntfs_volume* vol,int* result)
+ntfs_new_inode (ntfs_volume* vol,int* result)
{
int byte,error;
int bit;
@@ -1236,11 +1236,11 @@ int ntfs_alloc_inode (ntfs_inode *dir, ntfs_inode *result,
ntfs_volume* vol=dir->vol;
int byte,bit;
- error=new_inode (vol,&(result->i_number));
+ error=ntfs_new_inode (vol,&(result->i_number));
if(error==ENOSPC){
error=ntfs_extend_mft(vol);
if(error)return error;
- error=new_inode(vol,&(result->i_number));
+ error=ntfs_new_inode(vol,&(result->i_number));
}
if(error){
ntfs_error ("ntfs_get_empty_inode: no free inodes\n");
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 3b7b5b2af..1e6f1c854 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -125,7 +125,7 @@ ntfs_init_upcase(ntfs_inode *upcase)
io.param=(char*)upcase->vol->upcase;
io.size=2*UPCASE_LENGTH;
ntfs_read_attr(upcase,upcase->vol->at_data,0,0,&io);
- upcase->vol->upcase_length = io.size;
+ upcase->vol->upcase_length = io.size / 2;
}
static int
diff --git a/fs/pipe.c b/fs/pipe.c
index 1856d54d3..c7f27a520 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -608,14 +608,12 @@ static struct super_operations pipefs_ops = {
static struct super_block * pipefs_read_super(struct super_block *sb, void *data, int silent)
{
- struct inode *root = get_empty_inode();
+ struct inode *root = new_inode(sb);
if (!root)
return NULL;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
- root->i_sb = sb;
- root->i_dev = sb->s_dev;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = PIPEFS_MAGIC;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index d12a577fa..e98061fa8 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -372,7 +372,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
task->start_time,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
- task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0,
+ task->rlim[RLIMIT_RSS].rlim_cur,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
mm ? mm->start_stack : 0,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a1f7efe0f..c1a960c5d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -207,15 +207,12 @@ static int standard_permission(struct inode *inode, int mask)
return -EACCES;
}
-static int proc_permission(struct inode *inode, int mask)
+static int proc_check_root(struct inode *inode)
{
struct dentry *de, *base, *root;
struct vfsmount *our_vfsmnt, *vfsmnt, *mnt;
int res = 0;
- if (standard_permission(inode, mask) != 0)
- return -EACCES;
-
if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
return -ENOENT;
read_lock(&current->fs->lock);
@@ -250,6 +247,13 @@ out:
goto exit;
}
+static int proc_permission(struct inode *inode, int mask)
+{
+ if (standard_permission(inode, mask) != 0)
+ return -EACCES;
+ return proc_check_root(inode);
+}
+
static ssize_t pid_maps_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
@@ -403,12 +407,14 @@ static struct inode_operations proc_mem_inode_operations = {
static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
- int error;
+ int error = -EACCES;
/* We don't need a base pointer in the /proc filesystem */
path_release(nd);
- error = proc_permission(inode, MAY_EXEC);
+ if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+ goto out;
+ error = proc_check_root(inode);
if (error)
goto out;
@@ -441,12 +447,14 @@ static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
{
- int error;
+ int error = -EACCES;
struct inode *inode = dentry->d_inode;
struct dentry *de;
struct vfsmount *mnt = NULL;
- error = proc_permission(inode, MAY_EXEC);
+ if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
+ goto out;
+ error = proc_check_root(inode);
if (error)
goto out;
@@ -618,14 +626,12 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
/* We need a new inode */
- inode = get_empty_inode();
+ inode = new_inode(sb);
if (!inode)
goto out;
/* Common stuff */
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_ino = fake_ino(task->pid, ino);
@@ -910,11 +916,9 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
name = dentry->d_name.name;
len = dentry->d_name.len;
if (len == 4 && !memcmp(name, "self", 4)) {
- inode = get_empty_inode();
+ inode = new_inode(dir->i_sb);
if (!inode)
return ERR_PTR(-ENOMEM);
- inode->i_sb = dir->i_sb;
- inode->i_dev = dir->i_sb->s_dev;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_ino = fake_ino(0, PROC_PID_INO);
inode->u.proc_i.file = NULL;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 0dd6e6063..e58b04e02 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -215,7 +215,7 @@ static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
static struct inode_operations proc_link_inode_operations = {
readlink: proc_readlink,
- follow_link: proc_follow_link
+ follow_link: proc_follow_link,
};
/*
@@ -396,8 +396,6 @@ static void proc_kill_inodes(struct proc_dir_entry *de)
if (dentry->d_op != &proc_dentry_operations)
continue;
inode = dentry->d_inode;
- if (!inode)
- continue;
if (inode->u.generic_ip != de)
continue;
fops_put(filp->f_op);
@@ -573,12 +571,12 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
(void *) proc_alloc_map);
proc_kill_inodes(de);
de->nlink = 0;
- de->deleted = 1;
- if (!de->count)
+ if (!atomic_read(&de->count))
free_proc_entry(de);
else {
+ de->deleted = 1;
printk("remove_proc_entry: %s/%s busy, count=%d\n",
- parent->name, de->name, de->count);
+ parent->name, de->name, atomic_read(&de->count));
}
break;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 7b571398a..3453bf88b 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -25,7 +25,7 @@ extern void free_proc_entry(struct proc_dir_entry *);
struct proc_dir_entry * de_get(struct proc_dir_entry *de)
{
if (de)
- de->count++;
+ atomic_inc(&de->count);
return de;
}
@@ -34,20 +34,21 @@ struct proc_dir_entry * de_get(struct proc_dir_entry *de)
*/
void de_put(struct proc_dir_entry *de)
{
- if (de) {
- lock_kernel(); /* FIXME: count should be atomic_t */
- if (!de->count) {
+ if (de) {
+ lock_kernel();
+ if (!atomic_read(&de->count)) {
printk("de_put: entry %s already free!\n", de->name);
+ unlock_kernel();
return;
}
- if (!--de->count) {
+ if (atomic_dec_and_test(&de->count)) {
if (de->deleted) {
printk("de_put: deferred delete of %s\n",
de->name);
free_proc_entry(de);
}
- }
+ }
unlock_kernel();
}
}
@@ -139,7 +140,7 @@ struct inode * proc_get_inode(struct super_block * sb, int ino,
#if 1
/* shouldn't ever happen */
if (de && de->deleted)
-printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
+printk("proc_iget: using deleted entry %s, count=%d\n", de->name, atomic_read(&de->count));
#endif
inode = iget(sb, ino);
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 5e94c6aa5..d24f65b50 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -9,6 +9,10 @@
* there. I took this into a separate file and switched the thing to generic
* proc_file_inode_operations, leaving in array.c only per-process stuff.
* Inumbers allocation made dynamic (via create_proc_entry()). AV, May 1999.
+ *
+ * Changes:
+ * Fulton Green : Encapsulated position metric calculations.
+ * <kernel@FultonGreen.com>
*/
#include <linux/types.h>
@@ -68,6 +72,17 @@ extern int get_swaparea_info (char *);
extern int get_ds1286_status(char *);
#endif
+static int proc_calc_metrics(char *page, char **start, off_t off,
+ int count, int *eof, int len)
+{
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
static int loadavg_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -82,12 +97,7 @@ static int loadavg_read_proc(char *page, char **start, off_t off,
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
nr_running, nr_threads, last_pid);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int uptime_read_proc(char *page, char **start, off_t off,
@@ -122,12 +132,7 @@ static int uptime_read_proc(char *page, char **start, off_t off,
idle / HZ,
idle % HZ);
#endif
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int meminfo_read_proc(char *page, char **start, off_t off,
@@ -187,12 +192,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
K(i.totalswap),
K(i.freeswap));
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
#undef B
#undef K
}
@@ -205,20 +205,14 @@ static int version_read_proc(char *page, char **start, off_t off,
strcpy(page, linux_banner);
len = strlen(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int cpuinfo_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_cpuinfo(page, start, off, count);
- if (len < count) *eof = 1;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#ifdef CONFIG_PROC_HARDWARE
@@ -226,12 +220,7 @@ static int hardware_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_hardware_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif
@@ -240,12 +229,7 @@ static int stram_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_stram_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif
@@ -254,12 +238,7 @@ static int malloc_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_malloc(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif
@@ -268,12 +247,7 @@ static int modules_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_module_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int ksyms_read_proc(char *page, char **start, off_t off,
@@ -356,24 +330,14 @@ static int kstat_read_proc(char *page, char **start, off_t off,
xtime.tv_sec - jif / HZ,
total_forks);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int devices_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_device_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int partitions_read_proc(char *page, char **start, off_t off,
@@ -389,12 +353,7 @@ static int interrupts_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_irq_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif
@@ -402,36 +361,21 @@ static int filesystems_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_filesystem_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int dma_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_dma_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int ioports_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_ioport_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int cmdline_read_proc(char *page, char **start, off_t off,
@@ -442,12 +386,7 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
len = sprintf(page, "%s\n", saved_command_line);
len = strlen(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#ifdef CONFIG_SGI_DS1286
@@ -455,12 +394,7 @@ static int ds1286_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_ds1286_status(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
#endif
@@ -479,48 +413,28 @@ static int mounts_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_filesystem_info(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_exec_domain_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int swaps_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_swaparea_info(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
static int memory_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len = get_mem_list(page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
+ return proc_calc_metrics(page, start, off, count, eof, len);
}
/*
@@ -631,9 +545,9 @@ void __init proc_misc_init(void)
{"swaps", swaps_read_proc},
{"iomem", memory_read_proc},
{"execdomains", execdomains_read_proc},
- {NULL,NULL}
+ {NULL,}
};
- for(p=simple_ones;p->name;p++)
+ for (p = simple_ones; p->name; p++)
create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
/* And now for trickier ones */
@@ -661,12 +575,8 @@ void __init proc_misc_init(void)
entry->proc_fops = &ppc_htab_operations;
}
#endif
- {
- struct proc_dir_entry *res = create_proc_entry("slabinfo",
- S_IWUSR | S_IRUGO, NULL);
- if (res) {
- res->read_proc = slabinfo_read_proc;
- res->write_proc = slabinfo_write_proc;
- }
- }
+ entry = create_proc_read_entry("slabinfo", S_IWUSR | S_IRUGO, NULL,
+ slabinfo_read_proc, NULL);
+ if (entry)
+ entry->write_proc = slabinfo_write_proc;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 075a5843d..cae861960 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -96,10 +96,12 @@ static struct inode_operations proc_root_inode_operations = {
* This is the root "inode" in the /proc tree..
*/
struct proc_dir_entry proc_root = {
- PROC_ROOT_INO, 5, "/proc",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_root_inode_operations, &proc_root_operations,
- NULL, NULL,
- NULL,
- &proc_root, NULL
+ low_ino: PROC_ROOT_INO,
+ namelen: 5,
+ name: "/proc",
+ mode: S_IFDIR | S_IRUGO | S_IXUGO,
+ nlink: 2,
+ proc_iops: &proc_root_inode_operations,
+ proc_fops: &proc_root_operations,
+ parent: &proc_root,
};
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index f13ba4f3d..31461669c 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -65,7 +65,8 @@ static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry)
static int ramfs_readpage(struct file *file, struct page * page)
{
if (!Page_Uptodate(page)) {
- memset(page_address(page), 0, PAGE_CACHE_SIZE);
+ memset(kmap(page), 0, PAGE_CACHE_SIZE);
+ kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
@@ -85,9 +86,7 @@ static int ramfs_writepage(struct file *file, struct page *page)
static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
- void *addr;
-
- addr = (void *) kmap(page);
+ void *addr = kmap(page);
if (!Page_Uptodate(page)) {
memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
@@ -110,21 +109,15 @@ static int ramfs_commit_write(struct file *file, struct page *page, unsigned off
struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
{
- struct inode * inode = get_empty_inode();
+ struct inode * inode = new_inode(sb);
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 = to_kdev_t(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) {
diff --git a/fs/select.c b/fs/select.c
index a49213ecb..975013e7f 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -382,13 +382,14 @@ static void do_pollfd(unsigned int num, struct pollfd * fdpage,
static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
struct pollfd *fds[], poll_table *wait, long timeout)
{
- int count = 0;
+ int count;
poll_table* pt = wait;
for (;;) {
unsigned int i;
set_current_state(TASK_INTERRUPTIBLE);
+ count = 0;
for (i=0; i < nchunks; i++)
do_pollfd(POLLFD_PER_PAGE, fds[i], &pt, &count);
if (nleft)
@@ -396,9 +397,9 @@ static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
pt = NULL;
if (count || !timeout || signal_pending(current))
break;
- if(wait->error) {
- return wait->error;
- }
+ count = wait->error;
+ if (count)
+ break;
timeout = schedule_timeout(timeout);
}
current->state = TASK_RUNNING;
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index 0b42c2387..aa85680ac 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -47,11 +47,11 @@ smb_get_dircache(struct dentry * dentry)
page = grab_cache_page(mapping, 0);
if (!page)
goto out;
- cachep = (struct cache_head *)kmap(page);
+ cachep = kmap(page);
memset((char*)cachep, 0, PAGE_SIZE);
goto out;
}
- cachep = (struct cache_head *)kmap(page);
+ cachep = kmap(page);
if (cachep->valid) {
/*
* OK, at least the page 0 survived and seems to be promising.
@@ -69,7 +69,7 @@ smb_get_dircache(struct dentry * dentry)
cachep->valid = 0;
goto out;
}
- index->block = (struct cache_block *) kmap(page);
+ index->block = kmap(page);
}
}
out:
@@ -188,7 +188,7 @@ get_block:
page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
page = grab_cache_page(mapping, page_off>>PAGE_CACHE_SHIFT);
if (page) {
- block = (struct cache_block *)kmap(page);
+ block = kmap(page);
index->block = block;
index->space = PAGE_SIZE;
goto add_entry;
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 0406f72cb..bcc900626 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -78,11 +78,9 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
DEBUG1("smb_iget: %p\n", fattr);
- result = get_empty_inode();
+ result = new_inode(sb);
if (!result)
return result;
- result->i_sb = sb;
- result->i_dev = sb->s_dev;
result->i_ino = fattr->f_ino;
memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
smb_set_inode_attr(result, fattr);
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 8469366cf..7709ade8d 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -91,10 +91,12 @@ struct inode * sysv_new_inode(const struct inode * dir)
struct sysv_inode * raw_inode;
int i,j,ino,block;
- if (!dir || !(inode = get_empty_inode()))
+ if (!dir)
return NULL;
sb = dir->i_sb;
- inode->i_sb = sb;
+ inode = new_inode(sb);
+ if (!inode)
+ return NULL;
lock_super(sb); /* protect against task switches */
if ((*sb->sv_sb_fic_count == 0)
|| (*sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)-1) == 0) /* Applies only to SystemV2 FS */
@@ -131,7 +133,6 @@ struct inode * sysv_new_inode(const struct inode * dir)
mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
sb->s_dirt = 1; /* and needs time stamp */
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = ino;
@@ -141,7 +142,6 @@ struct inode * sysv_new_inode(const struct inode * dir)
mark_inode_dirty(inode);
/* Change directory entry: */
inode->i_mode = 0; /* for sysv_write_inode() */
- inode->i_size = 0; /* ditto */
sysv_write_inode(inode, 0); /* ensure inode not allocated again */
/* FIXME: caller may call this too. */
mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 9f093c536..9ec279e47 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -86,12 +86,6 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *dir = filp->f_dentry->d_inode;
int result;
- if (!dir)
- return -EBADF;
-
- if (!S_ISDIR(dir->i_mode))
- return -ENOTDIR;
-
if ( filp->f_pos == 0 )
{
if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR))
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 9ba4a6641..7e8ac9b7d 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -54,7 +54,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page)
if (!PageLocked(page))
PAGE_BUG(page);
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
memset(kaddr, 0, PAGE_CACHE_SIZE);
block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
@@ -78,7 +78,7 @@ static int udf_adinicb_writepage(struct file *file, struct page *page)
if (!PageLocked(page))
PAGE_BUG(page);
- kaddr = (char *)kmap(page);
+ kaddr = kmap(page);
block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize);
memcpy(bh->b_data + udf_ext0_offset(inode), kaddr, inode->i_size);
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 5377773ce..5a2e7a1dc 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -77,15 +77,13 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
int block;
Uint32 start = UDF_I_LOCATION(dir).logicalBlockNum;
- inode = get_empty_inode();
+ sb = dir->i_sb;
+ inode = new_inode(sb);
if (!inode)
{
*err = -ENOMEM;
return NULL;
}
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = 0;
*err = -ENOSPC;
block = udf_new_block(dir, UDF_I_LOCATION(dir).partitionReferenceNum,
@@ -115,9 +113,6 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
inode->i_mode = mode;
- inode->i_sb = sb;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
@@ -132,7 +127,6 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0;
- inode->i_size = 0;
UDF_I_LENEATTR(inode) = 0;
UDF_I_LENALLOC(inode) = 0;
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE))
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 4219c505f..83a34f258 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -158,7 +158,6 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
{
struct buffer_head *bh = NULL;
struct page *page;
- unsigned long kaddr = 0;
int block;
/* from now on we have normal address_space methods */
@@ -183,10 +182,10 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
PAGE_BUG(page);
if (!Page_Uptodate(page))
{
- kaddr = kmap(page);
- memset((char *)kaddr + UDF_I_LENALLOC(inode), 0x00,
+ char *kaddr = kmap(page);
+ memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
- memcpy((char *)kaddr, bh->b_data + udf_file_entry_alloc_offset(inode),
+ memcpy(kaddr, bh->b_data + udf_file_entry_alloc_offset(inode),
UDF_I_LENALLOC(inode));
flush_dcache_page(page);
SetPageUptodate(page);
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 8a0dde5e4..547fc784b 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -83,7 +83,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
struct buffer_head *bh = NULL;
char *symlink;
int err = -EIO;
- char *p = (char *)kmap(page);
+ char *p = kmap(page);
lock_kernel();
if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 1a97daf7c..d7fef19cd 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -161,19 +161,16 @@ struct inode * ufs_new_inode (const struct inode * dir, int mode, int * err )
*err = -EPERM;
return NULL;
}
- inode = get_empty_inode ();
+ sb = dir->i_sb;
+ inode = new_inode(sb);
if (!inode) {
*err = -ENOMEM;
return NULL;
}
- sb = dir->i_sb;
swab = sb->u.ufs_sb.s_swab;
uspi = sb->u.ufs_sb.s_uspi;
usb1 = ubh_get_usb_first(USPI_UBH);
- inode->i_sb = sb;
- inode->i_flags = 0;
-
lock_super (sb);
*err = -ENOSPC;
@@ -261,9 +258,6 @@ cg_found:
sb->s_dirt = 1;
inode->i_mode = mode;
- inode->i_sb = sb;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 63ee81b16..2e0b7bb14 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -700,7 +700,7 @@ struct dentry *umsdos_solve_hlink (struct dentry *hlink)
path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
if (path == NULL)
goto out_release;
- memcpy(path, (char*)kmap(page), hlink->d_inode->i_size);
+ memcpy(path, kmap(page), hlink->d_inode->i_size);
kunmap(page);
page_cache_release(page);
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 551c9662f..93c6af317 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -129,7 +129,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
wait_on_page(page);
if (!Page_Uptodate(page))
goto async_fail;
- p = (struct umsdos_dirent*)((char*)kmap(page)+offs);
+ p = (struct umsdos_dirent*)(kmap(page)+offs);
/* if this is an invalid entry (invalid name length), ignore it */
if( p->name_len > UMSDOS_MAXNAME )
@@ -158,7 +158,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
goto async_fail;
}
memcpy(entry->spare,p->spare,part);
- memcpy(entry->spare+part,(char*)kmap(page2),
+ memcpy(entry->spare+part,kmap(page2),
recsize+offs-PAGE_CACHE_SIZE);
kunmap(page2);
page_cache_release(page2);
@@ -399,7 +399,7 @@ static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
wait_on_page(page);
if (!Page_Uptodate(page))
goto async_fail;
- p = (char*)kmap(page);
+ p = kmap(page);
}
rentry = (struct umsdos_dirent *)(p+offs);
@@ -451,7 +451,7 @@ static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
page = next_page;
goto async_fail;
}
- q = (char*)kmap(next_page);
+ q = kmap(next_page);
if (memcmp(entry->name, rentry->name, len) ||
memcmp(entry->name+len, q, entry->name_len-len)) {
kunmap(next_page);
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index 4e8d0c410..a509f6c74 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -66,8 +66,8 @@ static __inline__ long atomic_add_return(int i, atomic_t * v)
long temp, result;
__asm__ __volatile__(
"1: ldl_l %0,%1\n"
+ " addl %0,%3,%2\n"
" addl %0,%3,%0\n"
- " mov %0,%2\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
@@ -84,8 +84,8 @@ static __inline__ long atomic_sub_return(int i, atomic_t * v)
long temp, result;
__asm__ __volatile__(
"1: ldl_l %0,%1\n"
+ " subl %0,%3,%2\n"
" subl %0,%3,%0\n"
- " mov %0,%2\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
diff --git a/include/asm-alpha/compiler.h b/include/asm-alpha/compiler.h
index 70d6ce775..7714bf2df 100644
--- a/include/asm-alpha/compiler.h
+++ b/include/asm-alpha/compiler.h
@@ -72,4 +72,13 @@
__asm__("stw %1,%0" : "=m"(mem) : "r"(val))
#endif
+/* Somewhere in the middle of the GCC 2.96 development cycle, we implemented
+ a mechanism by which the user can annotate likely branch directions and
+ expect the blocks to be reordered appropriately. Define __builtin_expect
+ to nothing for earlier compilers. */
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
+#define __builtin_expect(x, expected_value) (x)
+#endif
+
#endif /* __ALPHA_COMPILER_H */
diff --git a/include/asm-alpha/module.h b/include/asm-alpha/module.h
new file mode 100644
index 000000000..6e0efe9ac
--- /dev/null
+++ b/include/asm-alpha/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_ALPHA_MODULE_H
+#define _ASM_ALPHA_MODULE_H
+/*
+ * This file contains the alpha architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_ALPHA_MODULE_H */
diff --git a/include/asm-alpha/param.h b/include/asm-alpha/param.h
index 768c92e02..a398a3009 100644
--- a/include/asm-alpha/param.h
+++ b/include/asm-alpha/param.h
@@ -30,4 +30,8 @@
#define MAXHOSTNAMELEN 64 /* max length of hostname */
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC HZ /* frequency at which times() counts */
+#endif
+
#endif /* _ASM_ALPHA_PARAM_H */
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 5c4373d3b..54341fff1 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -301,9 +301,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define PageSkip(page) (0)
#define kern_addr_valid(addr) (1)
diff --git a/include/asm-alpha/semaphore-helper.h b/include/asm-alpha/semaphore-helper.h
deleted file mode 100644
index 52d8fb5f4..000000000
--- a/include/asm-alpha/semaphore-helper.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef _ALPHA_SEMAPHORE_HELPER_H
-#define _ALPHA_SEMAPHORE_HELPER_H
-
-/*
- * SMP- and interrupt-safe semaphores helper functions.
- *
- * (C) Copyright 1996 Linus Torvalds
- * (C) Copyright 1999 Richard Henderson
- */
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * which we have. Let the rest of the losers suck eggs.
- */
-
-static inline void
-wake_one_more(struct semaphore * sem)
-{
- atomic_inc(&sem->waking);
-}
-
-static inline int
-waking_non_zero(struct semaphore *sem)
-{
- long ret, tmp;
-
- /* An atomic conditional decrement. */
- __asm__ __volatile__(
- "1: ldl_l %1,%2\n"
- " blt %1,2f\n"
- " subl %1,1,%0\n"
- " stl_c %0,%2\n"
- " beq %0,3f\n"
- "2:\n"
- ".subsection 2\n"
- "3: br 1b\n"
- ".previous"
- : "=r"(ret), "=r"(tmp), "=m"(sem->waking.counter)
- : "0"(0));
-
- return ret > 0;
-}
-
-
-/*
- * waking_non_zero_interruptible:
- * 1 got the lock
- * 0 go to sleep
- * -EINTR interrupted
- *
- * We must undo the sem->count down_interruptible decrement
- * simultaneously and atomicly with the sem->waking adjustment,
- * otherwise we can race with wake_one_more.
- *
- * This is accomplished by doing a 64-bit ll/sc on the 2 32-bit words.
- */
-
-static inline int
-waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
-{
- long ret, tmp, tmp2, tmp3;
-
- /* "Equivalent" C. Note that we have to do this all without
- (taken) branches in order to be a valid ll/sc sequence.
-
- do {
- tmp = ldq_l;
- ret = 0;
- if (tmp >= 0) {
- tmp += 0xffffffff00000000;
- ret = 1;
- }
- else if (pending) {
- // Since -1 + 1 carries into the high word, we have
- // to be more careful adding 1 here.
- tmp = (tmp & 0xffffffff00000000)
- | ((tmp + 1) & 0x00000000ffffffff;
- ret = -EINTR;
- }
- else {
- break; // ideally. we don't actually break
- // since this is a predicate we don't
- // have, and is more trouble to build
- // than to elide the noop stq_c.
- }
- tmp = stq_c = tmp;
- } while (tmp == 0);
- */
-
- __asm__ __volatile__(
- "1: ldq_l %1,%4\n"
- " lda %0,0\n"
- " cmovne %5,%6,%0\n"
- " addq %1,1,%2\n"
- " and %1,%7,%3\n"
- " andnot %2,%7,%2\n"
- " cmovge %1,1,%0\n"
- " or %3,%2,%2\n"
- " addq %1,%7,%3\n"
- " cmovne %5,%2,%1\n"
- " cmovge %2,%3,%1\n"
- " stq_c %1,%4\n"
- " beq %1,3f\n"
- "2:\n"
- ".subsection 2\n"
- "3: br 1b\n"
- ".previous"
- : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(tmp3), "=m"(*sem)
- : "r"(signal_pending(tsk)), "r"(-EINTR),
- "r"(0xffffffff00000000));
-
- return ret;
-}
-
-/*
- * waking_non_zero_trylock is unused. we do everything in
- * down_trylock and let non-ll/sc hosts bounce around.
- */
-
-static inline int
-waking_non_zero_trylock(struct semaphore *sem)
-{
- return 0;
-}
-
-#endif
diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h
index 38bc05c6e..0e4a1e3a6 100644
--- a/include/asm-alpha/semaphore.h
+++ b/include/asm-alpha/semaphore.h
@@ -11,11 +11,16 @@
#include <asm/current.h>
#include <asm/system.h>
#include <asm/atomic.h>
+#include <asm/compiler.h> /* __builtin_expect */
+
+#define DEBUG_SEMAPHORE 0
+#define DEBUG_RW_SEMAPHORE 0
struct semaphore {
/* Careful, inline assembly knows about the position of these two. */
- atomic_t count;
+ atomic_t count __attribute__((aligned(8)));
atomic_t waking; /* biased by -1 */
+
wait_queue_head_t wait;
#if WAITQUEUE_DEBUG
long __magic;
@@ -42,7 +47,7 @@ struct semaphore {
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
-extern inline void sema_init(struct semaphore *sem, int val)
+static inline void sema_init(struct semaphore *sem, int val)
{
/*
* Logically,
@@ -68,103 +73,33 @@ static inline void init_MUTEX_LOCKED (struct semaphore *sem)
sema_init(sem, 0);
}
-
-extern void __down(struct semaphore * sem);
-extern int __down_interruptible(struct semaphore * sem);
-extern int __down_trylock(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
-
-/* All have custom assembly linkages. */
-extern void __down_failed(struct semaphore * sem);
-extern void __down_failed_interruptible(struct semaphore * sem);
-extern void __down_failed_trylock(struct semaphore * sem);
-extern void __up_wakeup(struct semaphore * sem);
+extern void down(struct semaphore *);
+extern void __down_failed(struct semaphore *);
+extern int down_interruptible(struct semaphore *);
+extern int __down_failed_interruptible(struct semaphore *);
+extern int down_trylock(struct semaphore *);
+extern void up(struct semaphore *);
+extern void __up_wakeup(struct semaphore *);
/*
- * Whee. Hidden out of line code is fun. The contention cases are
- * handled out of line in kernel/sched.c; arch/alpha/lib/semaphore.S
- * takes care of making sure we can call it without clobbering regs.
+ * Hidden out of line code is fun, but extremely messy. Rely on newer
+ * compilers to do a respectable job with this. The contention cases
+ * are handled out of line in arch/alpha/kernel/semaphore.c.
*/
-extern inline void down(struct semaphore * sem)
+static inline void __down(struct semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __down_failed anyway, reuse them in
- the atomic operation as well.
-
- __down_failed takes the semaphore address in $24, and
- it's return address in $28. The pv is loaded as usual.
- The gp is clobbered (in the module case) as usual. */
-
- /* This little bit of silliness is to get the GP loaded for
- a function that ordinarily wouldn't. Otherwise we could
- have it done by the macro directly, which can be optimized
- the linker. */
- register void *pv __asm__("$27");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- pv = __down_failed;
- __asm__ __volatile__ (
- "/* semaphore down operation */\n"
- "1: ldl_l $24,%1\n"
- " subl $24,1,$28\n"
- " subl $24,1,$24\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " blt $24,3f\n"
- "4: mb\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%1\n"
- " jsr $28,($27),__down_failed\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv)
- : "$24", "$28", "memory");
+ long count = atomic_dec_return(&sem->count);
+ if (__builtin_expect(count < 0, 0))
+ __down_failed(sem);
}
-extern inline int down_interruptible(struct semaphore * sem)
+static inline int __down_interruptible(struct semaphore *sem)
{
- /* __down_failed_interruptible takes the semaphore address in $24,
- and it's return address in $28. The pv is loaded as usual.
- The gp is clobbered (in the module case) as usual. The return
- value is in $24. */
-
- register int ret __asm__("$24");
- register void *pv __asm__("$27");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- pv = __down_failed_interruptible;
- __asm__ __volatile__ (
- "/* semaphore down interruptible operation */\n"
- "1: ldl_l $24,%2\n"
- " subl $24,1,$28\n"
- " subl $24,1,$24\n"
- " stl_c $28,%2\n"
- " beq $28,2f\n"
- " blt $24,3f\n"
- " mov $31,%0\n"
- "4: mb\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%2\n"
- " jsr $28,($27),__down_failed_interruptible\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(ret), "=r"(pv)
- : "m"(sem->count), "r"(pv)
- : "$28", "memory");
-
- return ret;
+ long count = atomic_dec_return(&sem->count);
+ if (__builtin_expect(count < 0, 0))
+ return __down_failed_interruptible(sem);
+ return 0;
}
/*
@@ -174,7 +109,7 @@ extern inline int down_interruptible(struct semaphore * sem)
* Do this by using ll/sc on the pair of 32-bit words.
*/
-extern inline int down_trylock(struct semaphore * sem)
+static inline int __down_trylock(struct semaphore * sem)
{
long ret, tmp, tmp2, sub;
@@ -182,25 +117,21 @@ extern inline int down_trylock(struct semaphore * sem)
(taken) branches in order to be a valid ll/sc sequence.
do {
- tmp = ldq_l;
- sub = 0x0000000100000000;
- ret = ((int)tmp <= 0); // count =< 0 ?
- if ((int)tmp >= 0) sub = 0; // count >= 0 ?
- // note that if count=0 subq overflows to the high
- // longword (i.e waking)
- ret &= ((long)tmp < 0); // waking < 0 ?
- sub += 1;
- if (ret)
- break;
- tmp -= sub;
- tmp = stq_c = tmp;
+ tmp = ldq_l;
+ sub = 0x0000000100000000;
+ ret = ((int)tmp <= 0); // count <= 0 ?
+ // Note that if count=0, the decrement overflows into
+ // waking, so cancel the 1 loaded above. Also cancel
+ // it if the lock was already free.
+ if ((int)tmp >= 0) sub = 0; // count >= 0 ?
+ ret &= ((long)tmp < 0); // waking < 0 ?
+ sub += 1;
+ if (ret) break;
+ tmp -= sub;
+ tmp = stq_c = tmp;
} while (tmp == 0);
*/
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
__asm__ __volatile__(
"1: ldq_l %1,%4\n"
" lda %3,1\n"
@@ -215,7 +146,7 @@ extern inline int down_trylock(struct semaphore * sem)
" subq %1,%3,%1\n"
" stq_c %1,%4\n"
" beq %1,3f\n"
- "2:\n"
+ "2: mb\n"
".subsection 2\n"
"3: br 1b\n"
".previous"
@@ -226,45 +157,70 @@ extern inline int down_trylock(struct semaphore * sem)
return ret;
}
-extern inline void up(struct semaphore * sem)
+static inline void __up(struct semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __up_wakeup anyway, reuse them in
- the atomic operation as well.
+ long ret, tmp, tmp2, tmp3;
- __up_wakeup takes the semaphore address in $24, and
- it's return address in $28. The pv is loaded as usual.
- The gp is clobbered (in the module case) as usual. */
+ /* We must manipulate count and waking simultaneously and atomically.
+ Otherwise we have races between up and __down_failed_interruptible
+ waking up on a signal.
- register void *pv __asm__("$27");
+ "Equivalent" C. Note that we have to do this all without
+ (taken) branches in order to be a valid ll/sc sequence.
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- pv = __up_wakeup;
- __asm__ __volatile__ (
- "/* semaphore up operation */\n"
+ do {
+ tmp = ldq_l;
+ ret = (int)tmp + 1; // count += 1;
+ tmp2 = tmp & 0xffffffff00000000; // extract waking
+ if (ret <= 0) // still sleepers?
+ tmp2 += 0x0000000100000000; // waking += 1;
+ tmp = ret & 0x00000000ffffffff; // insert count
+ tmp |= tmp2; // insert waking;
+ tmp = stq_c = tmp;
+ } while (tmp == 0);
+ */
+
+ __asm__ __volatile__(
" mb\n"
- "1: ldl_l $24,%1\n"
- " addl $24,1,$28\n"
- " addl $24,1,$24\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " ble $24,3f\n"
- "4:\n"
+ "1: ldq_l %1,%4\n"
+ " addl %1,1,%0\n"
+ " zapnot %1,0xf0,%2\n"
+ " addq %2,%5,%3\n"
+ " cmovle %0,%3,%2\n"
+ " zapnot %0,0x0f,%1\n"
+ " bis %1,%2,%1\n"
+ " stq_c %1,%4\n"
+ " beq %1,3f\n"
+ "2:\n"
".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%1\n"
- " jsr $28,($27),__up_wakeup\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
+ "3: br 1b\n"
".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv)
- : "$24", "$28", "memory");
+ : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(tmp3)
+ : "m"(*sem), "r"(0x0000000100000000)
+ : "memory");
+
+ if (__builtin_expect(ret <= 0, 0))
+ __up_wakeup(sem);
}
+#if !WAITQUEUE_DEBUG && !DEBUG_SEMAPHORE
+extern inline void down(struct semaphore *sem)
+{
+ __down(sem);
+}
+extern inline int down_interruptible(struct semaphore *sem)
+{
+ return __down_interruptible(sem);
+}
+extern inline int down_trylock(struct semaphore *sem)
+{
+ return __down_trylock(sem);
+}
+extern inline void up(struct semaphore *sem)
+{
+ __up(sem);
+}
+#endif
/* rw mutexes (should that be mutices? =) -- throw rw
* spinlocks and semaphores together, and this is what we
@@ -297,7 +253,7 @@ extern inline void up(struct semaphore * sem)
#define RW_LOCK_BIAS 0x01000000
struct rw_semaphore {
- int count;
+ atomic_t count;
/* bit 0 means read bias granted;
bit 1 means write bias granted. */
unsigned granted;
@@ -317,7 +273,7 @@ struct rw_semaphore {
#endif
#define __RWSEM_INITIALIZER(name,count) \
- { (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+ { ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
@@ -331,9 +287,9 @@ struct rw_semaphore {
#define DECLARE_RWSEM_WRITE_LOCKED(name) \
__DECLARE_RWSEM_GENERIC(name, 0)
-extern inline void init_rwsem(struct rw_semaphore *sem)
+static inline void init_rwsem(struct rw_semaphore *sem)
{
- sem->count = RW_LOCK_BIAS;
+ atomic_set (&sem->count, RW_LOCK_BIAS);
sem->granted = 0;
init_waitqueue_head(&sem->wait);
init_waitqueue_head(&sem->write_bias_wait);
@@ -344,213 +300,73 @@ extern inline void init_rwsem(struct rw_semaphore *sem)
#endif
}
-/* All have custom assembly linkages. */
-extern void __down_read_failed(struct rw_semaphore *sem);
-extern void __down_write_failed(struct rw_semaphore *sem);
-extern void __rwsem_wake(struct rw_semaphore *sem, unsigned long readers);
+extern void down_read(struct rw_semaphore *);
+extern void down_write(struct rw_semaphore *);
+extern void up_read(struct rw_semaphore *);
+extern void up_write(struct rw_semaphore *);
+extern void __down_read_failed(struct rw_semaphore *, int);
+extern void __down_write_failed(struct rw_semaphore *, int);
+extern void __rwsem_wake(struct rw_semaphore *, int);
-extern inline void down_read(struct rw_semaphore *sem)
+static inline void __down_read(struct rw_semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __down_read_failed anyway, reuse them in
- the atomic operation as well.
+ long count = atomic_dec_return(&sem->count);
+ if (__builtin_expect(count < 0, 0))
+ __down_read_failed(sem, count);
+}
- __down_read_failed takes the semaphore address in $24, the count
- we read in $25, and it's return address in $28. The pv is loaded
- as usual. The gp is clobbered (in the module case) as usual. */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ long count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
+ if (__builtin_expect(count != 0, 0))
+ __down_write_failed(sem, count);
+}
- /* This little bit of silliness is to get the GP loaded for
- a function that ordinarily wouldn't. Otherwise we could
- have it done by the macro directly, which can be optimized
- the linker. */
- register void *pv __asm__("$27");
+/* When a reader does a release, the only significant case is when there
+ was a writer waiting, and we've bumped the count to 0, then we must
+ wake the writer up. */
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
+static inline void __up_read(struct rw_semaphore *sem)
+{
+ long count;
+ mb();
+ count = atomic_inc_return(&sem->count);
+ if (__builtin_expect(count == 0, 0))
+ __rwsem_wake(sem, 0);
+}
- pv = __down_read_failed;
- __asm__ __volatile__(
- "/* semaphore down_read operation */\n"
- "1: ldl_l $24,%1\n"
- " subl $24,1,$28\n"
- " subl $24,1,$25\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " blt $25,3f\n"
- "4: mb\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%1\n"
- " jsr $28,($27),__down_read_failed\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv)
- : "$24", "$25", "$28", "memory");
+/* Releasing the writer is easy -- just release it and wake up
+ any sleepers. */
-#if WAITQUEUE_DEBUG
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_inc(&sem->readers);
-#endif
+static inline void __up_write(struct rw_semaphore *sem)
+{
+ long count, wake;
+ mb();
+ count = atomic_add_return(RW_LOCK_BIAS, &sem->count);
+
+ /* Only do the wake if we were, but are no longer, negative. */
+ wake = ((int)(count - RW_LOCK_BIAS) < 0) && count >= 0;
+ if (__builtin_expect(wake, 0))
+ __rwsem_wake(sem, count);
}
+#if !WAITQUEUE_DEBUG && !DEBUG_RW_SEMAPHORE
+extern inline void down_read(struct rw_semaphore *sem)
+{
+ __down_read(sem);
+}
extern inline void down_write(struct rw_semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __down_write_failed anyway, reuse them in
- the atomic operation as well.
-
- __down_write_failed takes the semaphore address in $24, the count
- we read in $25, and it's return address in $28. The pv is loaded
- as usual. The gp is clobbered (in the module case) as usual. */
-
- /* This little bit of silliness is to get the GP loaded for
- a function that ordinarily wouldn't. Otherwise we could
- have it done by the macro directly, which can be optimized
- the linker. */
- register void *pv __asm__("$27");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
-#endif
-
- pv = __down_write_failed;
- __asm__ __volatile__(
- "/* semaphore down_write operation */\n"
- "1: ldl_l $24,%1\n"
- " ldah $28,%3($24)\n"
- " ldah $25,%3($24)\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " bne $25,3f\n"
- "4: mb\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%1\n"
- " jsr $28,($27),__down_write_failed\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv), "i"(-(RW_LOCK_BIAS >> 16))
- : "$24", "$25", "$28", "memory");
-
-#if WAITQUEUE_DEBUG
- if (atomic_read(&sem->writers))
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (sem->granted & 3)
- BUG();
- atomic_inc(&sem->writers);
-#endif
+ __down_write(sem);
}
-
-/* When a reader does a release, the only significant case is when
- there was a writer waiting, and we've * bumped the count to 0: we must
-wake the writer up. */
-
extern inline void up_read(struct rw_semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __rwsem_wake anyway, reuse them in
- the atomic operation as well.
-
- __rwsem_wake takes the semaphore address in $24, the
- number of waiting readers in $25, and it's return address
- in $28. The pv is loaded as usual. The gp is clobbered
- (in the module case) as usual. */
-
- register void *pv __asm__("$27");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 2)
- BUG();
- if (atomic_read(&sem->writers))
- BUG();
- atomic_dec(&sem->readers);
-#endif
-
- pv = __rwsem_wake;
- __asm__ __volatile__(
- "/* semaphore up_read operation */\n"
- " mb\n"
- "1: ldl_l $24,%1\n"
- " addl $24,1,$28\n"
- " addl $24,1,$24\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " beq $24,3f\n"
- "4:\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: lda $24,%1\n"
- " mov 0,$25\n"
- " jsr $28,($27),__rwsem_wake\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv)
- : "$24", "$25", "$28", "memory");
+ __up_read(sem);
}
-
-/* releasing the writer is easy -- just release it and
- * wake up any sleepers.
- */
extern inline void up_write(struct rw_semaphore *sem)
{
- /* Given that we have to use particular hard registers to
- communicate with __rwsem_wake anyway, reuse them in
- the atomic operation as well.
-
- __rwsem_wake takes the semaphore address in $24, the
- number of waiting readers in $25, and it's return address
- in $28. The pv is loaded as usual. The gp is clobbered
- (in the module case) as usual. */
-
- register void *pv __asm__("$27");
-
-#if WAITQUEUE_DEBUG
- CHECK_MAGIC(sem->__magic);
- if (sem->granted & 3)
- BUG();
- if (atomic_read(&sem->readers))
- BUG();
- if (atomic_read(&sem->writers) != 1)
- BUG();
- atomic_dec(&sem->writers);
-#endif
-
- pv = __rwsem_wake;
- __asm__ __volatile__(
- "/* semaphore up_write operation */\n"
- " mb\n"
- "1: ldl_l $24,%1\n"
- " ldah $28,%3($24)\n"
- " stl_c $28,%1\n"
- " beq $28,2f\n"
- " blt $24,3f\n"
- "4:\n"
- ".subsection 2\n"
- "2: br 1b\n"
- "3: ldah $25,%3($24)\n"
- /* Only do the wake if we're no longer negative. */
- " blt $25,4b\n"
- " lda $24,%1\n"
- " jsr $28,($27),__rwsem_wake\n"
- " ldgp $29,0($28)\n"
- " br 4b\n"
- ".previous"
- : "=r"(pv)
- : "m"(sem->count), "r"(pv), "i"(RW_LOCK_BIAS >> 16)
- : "$24", "$25", "$28", "memory");
+ __up_write(sem);
}
+#endif
#endif
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
index 64e05d17b..e1d809880 100644
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -80,7 +80,7 @@ static inline void spin_lock(spinlock_t * lock)
" blbs %0,2b\n"
" br 1b\n"
".previous"
- : "=r" (tmp), "=m" (lock->lock)
+ : "=&r" (tmp), "=m" (lock->lock)
: "m"(lock->lock) : "memory");
}
diff --git a/include/asm-alpha/xor.h b/include/asm-alpha/xor.h
new file mode 100644
index 000000000..e11477f33
--- /dev/null
+++ b/include/asm-alpha/xor.h
@@ -0,0 +1,855 @@
+/*
+ * include/asm-alpha/xor.h
+ *
+ * Optimized RAID-5 checksumming functions for alpha EV5 and EV6
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+extern void xor_alpha_2(unsigned long, unsigned long *, unsigned long *);
+extern void xor_alpha_3(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *);
+extern void xor_alpha_4(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+extern void xor_alpha_5(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *, unsigned long *);
+
+extern void xor_alpha_prefetch_2(unsigned long, unsigned long *,
+ unsigned long *);
+extern void xor_alpha_prefetch_3(unsigned long, unsigned long *,
+ unsigned long *, unsigned long *);
+extern void xor_alpha_prefetch_4(unsigned long, unsigned long *,
+ unsigned long *, unsigned long *,
+ unsigned long *);
+extern void xor_alpha_prefetch_5(unsigned long, unsigned long *,
+ unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+
+asm("
+ .text
+ .align 3
+ .ent xor_alpha_2
+xor_alpha_2:
+ .prologue 0
+ srl $16, 6, $16
+ .align 4
+2:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,8($17)
+ ldq $3,8($18)
+
+ ldq $4,16($17)
+ ldq $5,16($18)
+ ldq $6,24($17)
+ ldq $7,24($18)
+
+ ldq $19,32($17)
+ ldq $20,32($18)
+ ldq $21,40($17)
+ ldq $22,40($18)
+
+ ldq $23,48($17)
+ ldq $24,48($18)
+ ldq $25,56($17)
+ xor $0,$1,$0 # 7 cycles from $1 load
+
+ ldq $27,56($18)
+ xor $2,$3,$2
+ stq $0,0($17)
+ xor $4,$5,$4
+
+ stq $2,8($17)
+ xor $6,$7,$6
+ stq $4,16($17)
+ xor $19,$20,$19
+
+ stq $6,24($17)
+ xor $21,$22,$21
+ stq $19,32($17)
+ xor $23,$24,$23
+
+ stq $21,40($17)
+ xor $25,$27,$25
+ stq $23,48($17)
+ subq $16,1,$16
+
+ stq $25,56($17)
+ addq $17,64,$17
+ addq $18,64,$18
+ bgt $16,2b
+
+ ret
+ .end xor_alpha_2
+
+ .align 3
+ .ent xor_alpha_3
+xor_alpha_3:
+ .prologue 0
+ srl $16, 6, $16
+ .align 4
+3:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,8($17)
+
+ ldq $4,8($18)
+ ldq $6,16($17)
+ ldq $7,16($18)
+ ldq $21,24($17)
+
+ ldq $22,24($18)
+ ldq $24,32($17)
+ ldq $25,32($18)
+ ldq $5,8($19)
+
+ ldq $20,16($19)
+ ldq $23,24($19)
+ ldq $27,32($19)
+ nop
+
+ xor $0,$1,$1 # 8 cycles from $0 load
+ xor $3,$4,$4 # 6 cycles from $4 load
+ xor $6,$7,$7 # 6 cycles from $7 load
+ xor $21,$22,$22 # 5 cycles from $22 load
+
+ xor $1,$2,$2 # 9 cycles from $2 load
+ xor $24,$25,$25 # 5 cycles from $25 load
+ stq $2,0($17)
+ xor $4,$5,$5 # 6 cycles from $5 load
+
+ stq $5,8($17)
+ xor $7,$20,$20 # 7 cycles from $20 load
+ stq $20,16($17)
+ xor $22,$23,$23 # 7 cycles from $23 load
+
+ stq $23,24($17)
+ xor $25,$27,$27 # 7 cycles from $27 load
+ stq $27,32($17)
+ nop
+
+ ldq $0,40($17)
+ ldq $1,40($18)
+ ldq $3,48($17)
+ ldq $4,48($18)
+
+ ldq $6,56($17)
+ ldq $7,56($18)
+ ldq $2,40($19)
+ ldq $5,48($19)
+
+ ldq $20,56($19)
+ xor $0,$1,$1 # 4 cycles from $1 load
+ xor $3,$4,$4 # 5 cycles from $4 load
+ xor $6,$7,$7 # 5 cycles from $7 load
+
+ xor $1,$2,$2 # 4 cycles from $2 load
+ xor $4,$5,$5 # 5 cycles from $5 load
+ stq $2,40($17)
+ xor $7,$20,$20 # 4 cycles from $20 load
+
+ stq $5,48($17)
+ subq $16,1,$16
+ stq $20,56($17)
+ addq $19,64,$19
+
+ addq $18,64,$18
+ addq $17,64,$17
+ bgt $16,3b
+ ret
+ .end xor_alpha_3
+
+ .align 3
+ .ent xor_alpha_4
+xor_alpha_4:
+ .prologue 0
+ srl $16, 6, $16
+ .align 4
+4:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,0($20)
+
+ ldq $4,8($17)
+ ldq $5,8($18)
+ ldq $6,8($19)
+ ldq $7,8($20)
+
+ ldq $21,16($17)
+ ldq $22,16($18)
+ ldq $23,16($19)
+ ldq $24,16($20)
+
+ ldq $25,24($17)
+ xor $0,$1,$1 # 6 cycles from $1 load
+ ldq $27,24($18)
+ xor $2,$3,$3 # 6 cycles from $3 load
+
+ ldq $0,24($19)
+ xor $1,$3,$3
+ ldq $1,24($20)
+ xor $4,$5,$5 # 7 cycles from $5 load
+
+ stq $3,0($17)
+ xor $6,$7,$7
+ xor $21,$22,$22 # 7 cycles from $22 load
+ xor $5,$7,$7
+
+ stq $7,8($17)
+ xor $23,$24,$24 # 7 cycles from $24 load
+ ldq $2,32($17)
+ xor $22,$24,$24
+
+ ldq $3,32($18)
+ ldq $4,32($19)
+ ldq $5,32($20)
+ xor $25,$27,$27 # 8 cycles from $27 load
+
+ ldq $6,40($17)
+ ldq $7,40($18)
+ ldq $21,40($19)
+ ldq $22,40($20)
+
+ stq $24,16($17)
+ xor $0,$1,$1 # 9 cycles from $1 load
+ xor $2,$3,$3 # 5 cycles from $3 load
+ xor $27,$1,$1
+
+ stq $1,24($17)
+ xor $4,$5,$5 # 5 cycles from $5 load
+ ldq $23,48($17)
+ ldq $24,48($18)
+
+ ldq $25,48($19)
+ xor $3,$5,$5
+ ldq $27,48($20)
+ ldq $0,56($17)
+
+ ldq $1,56($18)
+ ldq $2,56($19)
+ xor $6,$7,$7 # 8 cycles from $6 load
+ ldq $3,56($20)
+
+ stq $5,32($17)
+ xor $21,$22,$22 # 8 cycles from $22 load
+ xor $7,$22,$22
+ xor $23,$24,$24 # 5 cycles from $24 load
+
+ stq $22,40($17)
+ xor $25,$27,$27 # 5 cycles from $27 load
+ xor $24,$27,$27
+ xor $0,$1,$1 # 5 cycles from $1 load
+
+ stq $27,48($17)
+ xor $2,$3,$3 # 4 cycles from $3 load
+ xor $1,$3,$3
+ subq $16,1,$16
+
+ stq $3,56($17)
+ addq $20,64,$20
+ addq $19,64,$19
+ addq $18,64,$18
+
+ addq $17,64,$17
+ bgt $16,4b
+ ret
+ .end xor_alpha_4
+
+ .align 3
+ .ent xor_alpha_5
+xor_alpha_5:
+ .prologue 0
+ srl $16, 6, $16
+ .align 4
+5:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,0($20)
+
+ ldq $4,0($21)
+ ldq $5,8($17)
+ ldq $6,8($18)
+ ldq $7,8($19)
+
+ ldq $22,8($20)
+ ldq $23,8($21)
+ ldq $24,16($17)
+ ldq $25,16($18)
+
+ ldq $27,16($19)
+ xor $0,$1,$1 # 6 cycles from $1 load
+ ldq $28,16($20)
+ xor $2,$3,$3 # 6 cycles from $3 load
+
+ ldq $0,16($21)
+ xor $1,$3,$3
+ ldq $1,24($17)
+ xor $3,$4,$4 # 7 cycles from $4 load
+
+ stq $4,0($17)
+ xor $5,$6,$6 # 7 cycles from $6 load
+ xor $7,$22,$22 # 7 cycles from $22 load
+ xor $6,$23,$23 # 7 cycles from $23 load
+
+ ldq $2,24($18)
+ xor $22,$23,$23
+ ldq $3,24($19)
+ xor $24,$25,$25 # 8 cycles from $25 load
+
+ stq $23,8($17)
+ xor $25,$27,$27 # 8 cycles from $27 load
+ ldq $4,24($20)
+ xor $28,$0,$0 # 7 cycles from $0 load
+
+ ldq $5,24($21)
+ xor $27,$0,$0
+ ldq $6,32($17)
+ ldq $7,32($18)
+
+ stq $0,16($17)
+ xor $1,$2,$2 # 6 cycles from $2 load
+ ldq $22,32($19)
+ xor $3,$4,$4 # 4 cycles from $4 load
+
+ ldq $23,32($20)
+ xor $2,$4,$4
+ ldq $24,32($21)
+ ldq $25,40($17)
+
+ ldq $27,40($18)
+ ldq $28,40($19)
+ ldq $0,40($20)
+ xor $4,$5,$5 # 7 cycles from $5 load
+
+ stq $5,24($17)
+ xor $6,$7,$7 # 7 cycles from $7 load
+ ldq $1,40($21)
+ ldq $2,48($17)
+
+ ldq $3,48($18)
+ xor $7,$22,$22 # 7 cycles from $22 load
+ ldq $4,48($19)
+ xor $23,$24,$24 # 6 cycles from $24 load
+
+ ldq $5,48($20)
+ xor $22,$24,$24
+ ldq $6,48($21)
+ xor $25,$27,$27 # 7 cycles from $27 load
+
+ stq $24,32($17)
+ xor $27,$28,$28 # 8 cycles from $28 load
+ ldq $7,56($17)
+ xor $0,$1,$1 # 6 cycles from $1 load
+
+ ldq $22,56($18)
+ ldq $23,56($19)
+ ldq $24,56($20)
+ ldq $25,56($21)
+
+ xor $28,$1,$1
+ xor $2,$3,$3 # 9 cycles from $3 load
+ xor $3,$4,$4 # 9 cycles from $4 load
+ xor $5,$6,$6 # 8 cycles from $6 load
+
+ stq $1,40($17)
+ xor $4,$6,$6
+ xor $7,$22,$22 # 7 cycles from $22 load
+ xor $23,$24,$24 # 6 cycles from $24 load
+
+ stq $6,48($17)
+ xor $22,$24,$24
+ subq $16,1,$16
+ xor $24,$25,$25 # 8 cycles from $25 load
+
+ stq $25,56($17)
+ addq $21,64,$21
+ addq $20,64,$20
+ addq $19,64,$19
+
+ addq $18,64,$18
+ addq $17,64,$17
+ bgt $16,5b
+ ret
+ .end xor_alpha_5
+
+ .align 3
+ .ent xor_alpha_prefetch_2
+xor_alpha_prefetch_2:
+ .prologue 0
+ srl $16, 6, $16
+
+ ldq $31, 0($17)
+ ldq $31, 0($18)
+
+ ldq $31, 64($17)
+ ldq $31, 64($18)
+
+ ldq $31, 128($17)
+ ldq $31, 128($18)
+
+ ldq $31, 192($17)
+ ldq $31, 192($18)
+ .align 4
+2:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,8($17)
+ ldq $3,8($18)
+
+ ldq $4,16($17)
+ ldq $5,16($18)
+ ldq $6,24($17)
+ ldq $7,24($18)
+
+ ldq $19,32($17)
+ ldq $20,32($18)
+ ldq $21,40($17)
+ ldq $22,40($18)
+
+ ldq $23,48($17)
+ ldq $24,48($18)
+ ldq $25,56($17)
+ ldq $27,56($18)
+
+ ldq $31,256($17)
+ xor $0,$1,$0 # 8 cycles from $1 load
+ ldq $31,256($18)
+ xor $2,$3,$2
+
+ stq $0,0($17)
+ xor $4,$5,$4
+ stq $2,8($17)
+ xor $6,$7,$6
+
+ stq $4,16($17)
+ xor $19,$20,$19
+ stq $6,24($17)
+ xor $21,$22,$21
+
+ stq $19,32($17)
+ xor $23,$24,$23
+ stq $21,40($17)
+ xor $25,$27,$25
+
+ stq $23,48($17)
+ subq $16,1,$16
+ stq $25,56($17)
+ addq $17,64,$17
+
+ addq $18,64,$18
+ bgt $16,2b
+ ret
+ .end xor_alpha_prefetch_2
+
+ .align 3
+ .ent xor_alpha_prefetch_3
+xor_alpha_prefetch_3:
+ .prologue 0
+ srl $16, 6, $16
+
+ ldq $31, 0($17)
+ ldq $31, 0($18)
+ ldq $31, 0($19)
+
+ ldq $31, 64($17)
+ ldq $31, 64($18)
+ ldq $31, 64($19)
+
+ ldq $31, 128($17)
+ ldq $31, 128($18)
+ ldq $31, 128($19)
+
+ ldq $31, 192($17)
+ ldq $31, 192($18)
+ ldq $31, 192($19)
+ .align 4
+3:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,8($17)
+
+ ldq $4,8($18)
+ ldq $6,16($17)
+ ldq $7,16($18)
+ ldq $21,24($17)
+
+ ldq $22,24($18)
+ ldq $24,32($17)
+ ldq $25,32($18)
+ ldq $5,8($19)
+
+ ldq $20,16($19)
+ ldq $23,24($19)
+ ldq $27,32($19)
+ nop
+
+ xor $0,$1,$1 # 8 cycles from $0 load
+ xor $3,$4,$4 # 7 cycles from $4 load
+ xor $6,$7,$7 # 6 cycles from $7 load
+ xor $21,$22,$22 # 5 cycles from $22 load
+
+ xor $1,$2,$2 # 9 cycles from $2 load
+ xor $24,$25,$25 # 5 cycles from $25 load
+ stq $2,0($17)
+ xor $4,$5,$5 # 6 cycles from $5 load
+
+ stq $5,8($17)
+ xor $7,$20,$20 # 7 cycles from $20 load
+ stq $20,16($17)
+ xor $22,$23,$23 # 7 cycles from $23 load
+
+ stq $23,24($17)
+ xor $25,$27,$27 # 7 cycles from $27 load
+ stq $27,32($17)
+ nop
+
+ ldq $0,40($17)
+ ldq $1,40($18)
+ ldq $3,48($17)
+ ldq $4,48($18)
+
+ ldq $6,56($17)
+ ldq $7,56($18)
+ ldq $2,40($19)
+ ldq $5,48($19)
+
+ ldq $20,56($19)
+ ldq $31,256($17)
+ ldq $31,256($18)
+ ldq $31,256($19)
+
+ xor $0,$1,$1 # 6 cycles from $1 load
+ xor $3,$4,$4 # 5 cycles from $4 load
+ xor $6,$7,$7 # 5 cycles from $7 load
+ xor $1,$2,$2 # 4 cycles from $2 load
+
+ xor $4,$5,$5 # 5 cycles from $5 load
+ xor $7,$20,$20 # 4 cycles from $20 load
+ stq $2,40($17)
+ subq $16,1,$16
+
+ stq $5,48($17)
+ addq $19,64,$19
+ stq $20,56($17)
+ addq $18,64,$18
+
+ addq $17,64,$17
+ bgt $16,3b
+ ret
+ .end xor_alpha_prefetch_3
+
+ .align 3
+ .ent xor_alpha_prefetch_4
+xor_alpha_prefetch_4:
+ .prologue 0
+ srl $16, 6, $16
+
+ ldq $31, 0($17)
+ ldq $31, 0($18)
+ ldq $31, 0($19)
+ ldq $31, 0($20)
+
+ ldq $31, 64($17)
+ ldq $31, 64($18)
+ ldq $31, 64($19)
+ ldq $31, 64($20)
+
+ ldq $31, 128($17)
+ ldq $31, 128($18)
+ ldq $31, 128($19)
+ ldq $31, 128($20)
+
+ ldq $31, 192($17)
+ ldq $31, 192($18)
+ ldq $31, 192($19)
+ ldq $31, 192($20)
+ .align 4
+4:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,0($20)
+
+ ldq $4,8($17)
+ ldq $5,8($18)
+ ldq $6,8($19)
+ ldq $7,8($20)
+
+ ldq $21,16($17)
+ ldq $22,16($18)
+ ldq $23,16($19)
+ ldq $24,16($20)
+
+ ldq $25,24($17)
+ xor $0,$1,$1 # 6 cycles from $1 load
+ ldq $27,24($18)
+ xor $2,$3,$3 # 6 cycles from $3 load
+
+ ldq $0,24($19)
+ xor $1,$3,$3
+ ldq $1,24($20)
+ xor $4,$5,$5 # 7 cycles from $5 load
+
+ stq $3,0($17)
+ xor $6,$7,$7
+ xor $21,$22,$22 # 7 cycles from $22 load
+ xor $5,$7,$7
+
+ stq $7,8($17)
+ xor $23,$24,$24 # 7 cycles from $24 load
+ ldq $2,32($17)
+ xor $22,$24,$24
+
+ ldq $3,32($18)
+ ldq $4,32($19)
+ ldq $5,32($20)
+ xor $25,$27,$27 # 8 cycles from $27 load
+
+ ldq $6,40($17)
+ ldq $7,40($18)
+ ldq $21,40($19)
+ ldq $22,40($20)
+
+ stq $24,16($17)
+ xor $0,$1,$1 # 9 cycles from $1 load
+ xor $2,$3,$3 # 5 cycles from $3 load
+ xor $27,$1,$1
+
+ stq $1,24($17)
+ xor $4,$5,$5 # 5 cycles from $5 load
+ ldq $23,48($17)
+ xor $3,$5,$5
+
+ ldq $24,48($18)
+ ldq $25,48($19)
+ ldq $27,48($20)
+ ldq $0,56($17)
+
+ ldq $1,56($18)
+ ldq $2,56($19)
+ ldq $3,56($20)
+ xor $6,$7,$7 # 8 cycles from $6 load
+
+ ldq $31,256($17)
+ xor $21,$22,$22 # 8 cycles from $22 load
+ ldq $31,256($18)
+ xor $7,$22,$22
+
+ ldq $31,256($19)
+ xor $23,$24,$24 # 6 cycles from $24 load
+ ldq $31,256($20)
+ xor $25,$27,$27 # 6 cycles from $27 load
+
+ stq $5,32($17)
+ xor $24,$27,$27
+ xor $0,$1,$1 # 7 cycles from $1 load
+ xor $2,$3,$3 # 6 cycles from $3 load
+
+ stq $22,40($17)
+ xor $1,$3,$3
+ stq $27,48($17)
+ subq $16,1,$16
+
+ stq $3,56($17)
+ addq $20,64,$20
+ addq $19,64,$19
+ addq $18,64,$18
+
+ addq $17,64,$17
+ bgt $16,4b
+ ret
+ .end xor_alpha_prefetch_4
+
+ .align 3
+ .ent xor_alpha_prefetch_5
+xor_alpha_prefetch_5:
+ .prologue 0
+ srl $16, 6, $16
+
+ ldq $31, 0($17)
+ ldq $31, 0($18)
+ ldq $31, 0($19)
+ ldq $31, 0($20)
+ ldq $31, 0($21)
+
+ ldq $31, 64($17)
+ ldq $31, 64($18)
+ ldq $31, 64($19)
+ ldq $31, 64($20)
+ ldq $31, 64($21)
+
+ ldq $31, 128($17)
+ ldq $31, 128($18)
+ ldq $31, 128($19)
+ ldq $31, 128($20)
+ ldq $31, 128($21)
+
+ ldq $31, 192($17)
+ ldq $31, 192($18)
+ ldq $31, 192($19)
+ ldq $31, 192($20)
+ ldq $31, 192($21)
+ .align 4
+5:
+ ldq $0,0($17)
+ ldq $1,0($18)
+ ldq $2,0($19)
+ ldq $3,0($20)
+
+ ldq $4,0($21)
+ ldq $5,8($17)
+ ldq $6,8($18)
+ ldq $7,8($19)
+
+ ldq $22,8($20)
+ ldq $23,8($21)
+ ldq $24,16($17)
+ ldq $25,16($18)
+
+ ldq $27,16($19)
+ xor $0,$1,$1 # 6 cycles from $1 load
+ ldq $28,16($20)
+ xor $2,$3,$3 # 6 cycles from $3 load
+
+ ldq $0,16($21)
+ xor $1,$3,$3
+ ldq $1,24($17)
+ xor $3,$4,$4 # 7 cycles from $4 load
+
+ stq $4,0($17)
+ xor $5,$6,$6 # 7 cycles from $6 load
+ xor $7,$22,$22 # 7 cycles from $22 load
+ xor $6,$23,$23 # 7 cycles from $23 load
+
+ ldq $2,24($18)
+ xor $22,$23,$23
+ ldq $3,24($19)
+ xor $24,$25,$25 # 8 cycles from $25 load
+
+ stq $23,8($17)
+ xor $25,$27,$27 # 8 cycles from $27 load
+ ldq $4,24($20)
+ xor $28,$0,$0 # 7 cycles from $0 load
+
+ ldq $5,24($21)
+ xor $27,$0,$0
+ ldq $6,32($17)
+ ldq $7,32($18)
+
+ stq $0,16($17)
+ xor $1,$2,$2 # 6 cycles from $2 load
+ ldq $22,32($19)
+ xor $3,$4,$4 # 4 cycles from $4 load
+
+ ldq $23,32($20)
+ xor $2,$4,$4
+ ldq $24,32($21)
+ ldq $25,40($17)
+
+ ldq $27,40($18)
+ ldq $28,40($19)
+ ldq $0,40($20)
+ xor $4,$5,$5 # 7 cycles from $5 load
+
+ stq $5,24($17)
+ xor $6,$7,$7 # 7 cycles from $7 load
+ ldq $1,40($21)
+ ldq $2,48($17)
+
+ ldq $3,48($18)
+ xor $7,$22,$22 # 7 cycles from $22 load
+ ldq $4,48($19)
+ xor $23,$24,$24 # 6 cycles from $24 load
+
+ ldq $5,48($20)
+ xor $22,$24,$24
+ ldq $6,48($21)
+ xor $25,$27,$27 # 7 cycles from $27 load
+
+ stq $24,32($17)
+ xor $27,$28,$28 # 8 cycles from $28 load
+ ldq $7,56($17)
+ xor $0,$1,$1 # 6 cycles from $1 load
+
+ ldq $22,56($18)
+ ldq $23,56($19)
+ ldq $24,56($20)
+ ldq $25,56($21)
+
+ ldq $31,256($17)
+ xor $28,$1,$1
+ ldq $31,256($18)
+ xor $2,$3,$3 # 9 cycles from $3 load
+
+ ldq $31,256($19)
+ xor $3,$4,$4 # 9 cycles from $4 load
+ ldq $31,256($20)
+ xor $5,$6,$6 # 8 cycles from $6 load
+
+ stq $1,40($17)
+ xor $4,$6,$6
+ xor $7,$22,$22 # 7 cycles from $22 load
+ xor $23,$24,$24 # 6 cycles from $24 load
+
+ stq $6,48($17)
+ xor $22,$24,$24
+ ldq $31,256($21)
+ xor $24,$25,$25 # 8 cycles from $25 load
+
+ stq $25,56($17)
+ subq $16,1,$16
+ addq $21,64,$21
+ addq $20,64,$20
+
+ addq $19,64,$19
+ addq $18,64,$18
+ addq $17,64,$17
+ bgt $16,5b
+
+ ret
+ .end xor_alpha_prefetch_5
+");
+
+static struct xor_block_template xor_block_alpha = {
+ name: "alpha",
+ do_2: xor_alpha_2,
+ do_3: xor_alpha_3,
+ do_4: xor_alpha_4,
+ do_5: xor_alpha_5,
+};
+
+static struct xor_block_template xor_block_alpha_prefetch = {
+ name: "alpha prefetch",
+ do_2: xor_alpha_prefetch_2,
+ do_3: xor_alpha_prefetch_3,
+ do_4: xor_alpha_prefetch_4,
+ do_5: xor_alpha_prefetch_5,
+};
+
+/* For grins, also test the generic routines. */
+#include <asm-generic/xor.h>
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES \
+ do { \
+ xor_speed(&xor_block_8regs); \
+ xor_speed(&xor_block_32regs); \
+ xor_speed(&xor_block_alpha); \
+ xor_speed(&xor_block_alpha_prefetch); \
+ } while (0)
+
+/* Force the use of alpha_prefetch if EV6, as it is significantly
+ faster in the cold cache case. */
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+ (implver() == IMPLVER_EV6 ? &xor_block_alpha_prefetch : FASTEST)
diff --git a/include/asm-arm/module.h b/include/asm-arm/module.h
new file mode 100644
index 000000000..3199b3bc5
--- /dev/null
+++ b/include/asm-arm/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_ARM_MODULE_H
+#define _ASM_ARM_MODULE_H
+/*
+ * This file contains the arm architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_ARM_MODULE_H */
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 09c7421cc..008fdde99 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -176,9 +176,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(swp) ((pte_t) { (swp).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
/* FIXME: this is not correct */
#define kern_addr_valid(addr) (1)
diff --git a/include/asm-arm/xor.h b/include/asm-arm/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-arm/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-generic/xor.h b/include/asm-generic/xor.h
new file mode 100644
index 000000000..ebda0f96c
--- /dev/null
+++ b/include/asm-generic/xor.h
@@ -0,0 +1,322 @@
+/*
+ * include/asm-generic/xor.h
+ *
+ * Generic optimized RAID-5 checksumming functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static void
+xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ p1[0] ^= p2[0];
+ p1[1] ^= p2[1];
+ p1[2] ^= p2[2];
+ p1[3] ^= p2[3];
+ p1[4] ^= p2[4];
+ p1[5] ^= p2[5];
+ p1[6] ^= p2[6];
+ p1[7] ^= p2[7];
+ p1 += 8;
+ p2 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_8regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ p1[0] ^= p2[0] ^ p3[0];
+ p1[1] ^= p2[1] ^ p3[1];
+ p1[2] ^= p2[2] ^ p3[2];
+ p1[3] ^= p2[3] ^ p3[3];
+ p1[4] ^= p2[4] ^ p3[4];
+ p1[5] ^= p2[5] ^ p3[5];
+ p1[6] ^= p2[6] ^ p3[6];
+ p1[7] ^= p2[7] ^ p3[7];
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_8regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ p1[0] ^= p2[0] ^ p3[0] ^ p4[0];
+ p1[1] ^= p2[1] ^ p3[1] ^ p4[1];
+ p1[2] ^= p2[2] ^ p3[2] ^ p4[2];
+ p1[3] ^= p2[3] ^ p3[3] ^ p4[3];
+ p1[4] ^= p2[4] ^ p3[4] ^ p4[4];
+ p1[5] ^= p2[5] ^ p3[5] ^ p4[5];
+ p1[6] ^= p2[6] ^ p3[6] ^ p4[6];
+ p1[7] ^= p2[7] ^ p3[7] ^ p4[7];
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_8regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0];
+ p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1];
+ p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2];
+ p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3];
+ p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4];
+ p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5];
+ p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6];
+ p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7];
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ p5 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_32regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ register long d0, d1, d2, d3, d4, d5, d6, d7;
+ d0 = p1[0]; /* Pull the stuff into registers */
+ d1 = p1[1]; /* ... in bursts, if possible. */
+ d2 = p1[2];
+ d3 = p1[3];
+ d4 = p1[4];
+ d5 = p1[5];
+ d6 = p1[6];
+ d7 = p1[7];
+ d0 ^= p2[0];
+ d1 ^= p2[1];
+ d2 ^= p2[2];
+ d3 ^= p2[3];
+ d4 ^= p2[4];
+ d5 ^= p2[5];
+ d6 ^= p2[6];
+ d7 ^= p2[7];
+ p1[0] = d0; /* Store the result (in burts) */
+ p1[1] = d1;
+ p1[2] = d2;
+ p1[3] = d3;
+ p1[4] = d4;
+ p1[5] = d5;
+ p1[6] = d6;
+ p1[7] = d7;
+ p1 += 8;
+ p2 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_32regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ register long d0, d1, d2, d3, d4, d5, d6, d7;
+ d0 = p1[0]; /* Pull the stuff into registers */
+ d1 = p1[1]; /* ... in bursts, if possible. */
+ d2 = p1[2];
+ d3 = p1[3];
+ d4 = p1[4];
+ d5 = p1[5];
+ d6 = p1[6];
+ d7 = p1[7];
+ d0 ^= p2[0];
+ d1 ^= p2[1];
+ d2 ^= p2[2];
+ d3 ^= p2[3];
+ d4 ^= p2[4];
+ d5 ^= p2[5];
+ d6 ^= p2[6];
+ d7 ^= p2[7];
+ d0 ^= p3[0];
+ d1 ^= p3[1];
+ d2 ^= p3[2];
+ d3 ^= p3[3];
+ d4 ^= p3[4];
+ d5 ^= p3[5];
+ d6 ^= p3[6];
+ d7 ^= p3[7];
+ p1[0] = d0; /* Store the result (in burts) */
+ p1[1] = d1;
+ p1[2] = d2;
+ p1[3] = d3;
+ p1[4] = d4;
+ p1[5] = d5;
+ p1[6] = d6;
+ p1[7] = d7;
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_32regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ register long d0, d1, d2, d3, d4, d5, d6, d7;
+ d0 = p1[0]; /* Pull the stuff into registers */
+ d1 = p1[1]; /* ... in bursts, if possible. */
+ d2 = p1[2];
+ d3 = p1[3];
+ d4 = p1[4];
+ d5 = p1[5];
+ d6 = p1[6];
+ d7 = p1[7];
+ d0 ^= p2[0];
+ d1 ^= p2[1];
+ d2 ^= p2[2];
+ d3 ^= p2[3];
+ d4 ^= p2[4];
+ d5 ^= p2[5];
+ d6 ^= p2[6];
+ d7 ^= p2[7];
+ d0 ^= p3[0];
+ d1 ^= p3[1];
+ d2 ^= p3[2];
+ d3 ^= p3[3];
+ d4 ^= p3[4];
+ d5 ^= p3[5];
+ d6 ^= p3[6];
+ d7 ^= p3[7];
+ d0 ^= p4[0];
+ d1 ^= p4[1];
+ d2 ^= p4[2];
+ d3 ^= p4[3];
+ d4 ^= p4[4];
+ d5 ^= p4[5];
+ d6 ^= p4[6];
+ d7 ^= p4[7];
+ p1[0] = d0; /* Store the result (in burts) */
+ p1[1] = d1;
+ p1[2] = d2;
+ p1[3] = d3;
+ p1[4] = d4;
+ p1[5] = d5;
+ p1[6] = d6;
+ p1[7] = d7;
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ } while (--lines > 0);
+}
+
+static void
+xor_32regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ long lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ register long d0, d1, d2, d3, d4, d5, d6, d7;
+ d0 = p1[0]; /* Pull the stuff into registers */
+ d1 = p1[1]; /* ... in bursts, if possible. */
+ d2 = p1[2];
+ d3 = p1[3];
+ d4 = p1[4];
+ d5 = p1[5];
+ d6 = p1[6];
+ d7 = p1[7];
+ d0 ^= p2[0];
+ d1 ^= p2[1];
+ d2 ^= p2[2];
+ d3 ^= p2[3];
+ d4 ^= p2[4];
+ d5 ^= p2[5];
+ d6 ^= p2[6];
+ d7 ^= p2[7];
+ d0 ^= p3[0];
+ d1 ^= p3[1];
+ d2 ^= p3[2];
+ d3 ^= p3[3];
+ d4 ^= p3[4];
+ d5 ^= p3[5];
+ d6 ^= p3[6];
+ d7 ^= p3[7];
+ d0 ^= p4[0];
+ d1 ^= p4[1];
+ d2 ^= p4[2];
+ d3 ^= p4[3];
+ d4 ^= p4[4];
+ d5 ^= p4[5];
+ d6 ^= p4[6];
+ d7 ^= p4[7];
+ d0 ^= p5[0];
+ d1 ^= p5[1];
+ d2 ^= p5[2];
+ d3 ^= p5[3];
+ d4 ^= p5[4];
+ d5 ^= p5[5];
+ d6 ^= p5[6];
+ d7 ^= p5[7];
+ p1[0] = d0; /* Store the result (in burts) */
+ p1[1] = d1;
+ p1[2] = d2;
+ p1[3] = d3;
+ p1[4] = d4;
+ p1[5] = d5;
+ p1[6] = d6;
+ p1[7] = d7;
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ p5 += 8;
+ } while (--lines > 0);
+}
+
+static struct xor_block_template xor_block_8regs = {
+ name: "8regs",
+ do_2: xor_8regs_2,
+ do_3: xor_8regs_3,
+ do_4: xor_8regs_4,
+ do_5: xor_8regs_5,
+};
+
+static struct xor_block_template xor_block_32regs = {
+ name: "32regs",
+ do_2: xor_32regs_2,
+ do_3: xor_32regs_3,
+ do_4: xor_32regs_4,
+ do_5: xor_32regs_5,
+};
+
+#define XOR_TRY_TEMPLATES \
+ do { \
+ xor_speed(&xor_block_8regs); \
+ xor_speed(&xor_block_32regs); \
+ } while (0)
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index 4b95d09cd..4e77e5d8a 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -147,200 +147,6 @@ static void __init check_popad(void)
}
/*
- * B step AMD K6 before B 9730xxxx have hardware bugs that can cause
- * misexecution of code under Linux. Owners of such processors should
- * contact AMD for precise details and a CPU swap.
- *
- * See http://www.mygale.com/~poulot/k6bug.html
- * http://www.amd.com/K6/k6docs/revgd.html
- *
- * The following test is erm.. interesting. AMD neglected to up
- * the chip setting when fixing the bug but they also tweaked some
- * performance at the same time..
- */
-
-extern void vide(void);
-__asm__(".align 4\nvide: ret");
-
-static void __init check_amd_k6(void)
-{
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
- boot_cpu_data.x86 == 5 &&
- boot_cpu_data.x86_model == 6 &&
- boot_cpu_data.x86_mask == 1)
- {
- int n;
- void (*f_vide)(void);
- unsigned long d, d2;
-
- printk(KERN_INFO "AMD K6 stepping B detected - ");
-
-#define K6_BUG_LOOP 1000000
-
- /*
- * It looks like AMD fixed the 2.6.2 bug and improved indirect
- * calls at the same time.
- */
-
- n = K6_BUG_LOOP;
- f_vide = vide;
- rdtscl(d);
- while (n--)
- f_vide();
- rdtscl(d2);
- d = d2-d;
-
- /* Knock these two lines out if it debugs out ok */
- printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
- printk(KERN_INFO "AMD K6 stepping B detected - ");
- /* -- cut here -- */
- if (d > 20*K6_BUG_LOOP)
- printk("system stability may be impaired when more than 32 MB are used.\n");
- else
- printk("probably OK (after B9730xxxx).\n");
- printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
- }
-}
-
-/*
- * All current models of Pentium and Pentium with MMX technology CPUs
- * have the F0 0F bug, which lets nonpriviledged users lock up the system:
- */
-
-#ifndef CONFIG_M686
-extern void trap_init_f00f_bug(void);
-
-static void __init check_pentium_f00f(void)
-{
- /*
- * Pentium and Pentium MMX
- */
- boot_cpu_data.f00f_bug = 0;
- if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
- printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
- boot_cpu_data.f00f_bug = 1;
- trap_init_f00f_bug();
- }
-}
-#endif
-
-/*
- * Perform the Cyrix 5/2 test. A Cyrix won't change
- * the flags, while other 486 chips will.
- */
-
-static inline int test_cyrix_52div(void)
-{
- unsigned int test;
-
- __asm__ __volatile__(
- "sahf\n\t" /* clear flags (%eax = 0x0005) */
- "div %b2\n\t" /* divide 5 by 2 */
- "lahf" /* store flags into %ah */
- : "=a" (test)
- : "0" (5), "q" (2)
- : "cc");
-
- /* AH is 0x02 on Cyrix after the divide.. */
- return (unsigned char) (test >> 8) == 0x02;
-}
-
-/*
- * Fix cpuid problems with Cyrix CPU's:
- * -- on the Cx686(L) the cpuid is disabled on power up.
- * -- braindamaged BIOS disable cpuid on the Cx686MX.
- */
-
-extern unsigned char Cx86_dir0_msb; /* exported HACK from cyrix_model() */
-
-static void __init check_cx686_cpuid(void)
-{
- if (boot_cpu_data.cpuid_level == -1 &&
- ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
- int eax, dummy;
- unsigned char ccr3, ccr4;
- __u32 old_cap;
-
- cli();
- ccr3 = getCx86(CX86_CCR3);
- setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
- ccr4 = getCx86(CX86_CCR4);
- setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */
- setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
- sti();
-
- /* we have up to level 1 available on the Cx6x86(L|MX) */
- boot_cpu_data.cpuid_level = 1;
- /* Need to preserve some externally computed capabilities */
- old_cap = boot_cpu_data.x86_capability & X86_FEATURE_MTRR;
- cpuid(1, &eax, &dummy, &dummy,
- &boot_cpu_data.x86_capability);
- boot_cpu_data.x86_capability |= old_cap;
-
- boot_cpu_data.x86 = (eax >> 8) & 15;
- /*
- * we already have a cooked step/rev number from DIR1
- * so we don't use the cpuid-provided ones.
- */
- }
-}
-
-/*
- * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
- * BIOSes for compatability with DOS games. This makes the udelay loop
- * work correctly, and improves performance.
- */
-
-extern void calibrate_delay(void) __init;
-
-static void __init check_cx686_slop(void)
-{
- if (Cx86_dir0_msb == 3) {
- unsigned char ccr3, ccr5;
-
- cli();
- ccr3 = getCx86(CX86_CCR3);
- setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
- ccr5 = getCx86(CX86_CCR5);
- if (ccr5 & 2)
- setCx86(CX86_CCR5, ccr5 & 0xfd); /* reset SLOP */
- setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
- sti();
-
- if (ccr5 & 2) { /* possible wrong calibration done */
- printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
- calibrate_delay();
- boot_cpu_data.loops_per_sec = loops_per_sec;
- }
- }
-}
-
-/*
- * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
- * by the fact that they preserve the flags across the division of 5/2.
- * PII and PPro exhibit this behavior too, but they have cpuid available.
- */
-
-static void __init check_cyrix_cpu(void)
-{
- if ((boot_cpu_data.cpuid_level == -1) && (boot_cpu_data.x86 == 4)
- && test_cyrix_52div()) {
-
- strcpy(boot_cpu_data.x86_vendor_id, "CyrixInstead");
- }
-}
-
-/*
- * In setup.c's cyrix_model() we have set the boot_cpu_data.coma_bug
- * on certain processors that we know contain this bug and now we
- * enable the workaround for it.
- */
-
-static void __init check_cyrix_coma(void)
-{
-}
-
-/*
* Check whether we are able to run this kernel safely on SMP.
*
* - In order to run on a i386, we need to be compiled for i386
@@ -391,7 +197,7 @@ static void __init check_config(void)
*/
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
- && boot_cpu_data.x86_capability & X86_FEATURE_APIC
+ && test_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability)
&& boot_cpu_data.x86 == 5
&& boot_cpu_data.x86_model == 2
&& (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
@@ -409,10 +215,7 @@ static void __init check_config(void)
static void __init check_bugs(void)
{
- check_cyrix_cpu();
identify_cpu(&boot_cpu_data);
- check_cx686_cpuid();
- check_cx686_slop();
#ifndef CONFIG_SMP
printk("CPU: ");
print_cpu_info(&boot_cpu_data);
@@ -421,10 +224,5 @@ static void __init check_bugs(void)
check_fpu();
check_hlt();
check_popad();
- check_amd_k6();
-#ifndef CONFIG_M686
- check_pentium_f00f();
-#endif
- check_cyrix_coma();
system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
}
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
new file mode 100644
index 000000000..598edbdaf
--- /dev/null
+++ b/include/asm-i386/cpufeature.h
@@ -0,0 +1,73 @@
+/*
+ * cpufeature.h
+ *
+ * Defines x86 CPU feature bits
+ */
+
+#ifndef __ASM_I386_CPUFEATURE_H
+#define __ASM_I386_CPUFEATURE_H
+
+/* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
+#define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT)
+
+#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */
+
+/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
+#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
+#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
+#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
+#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
+#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
+#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
+#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
+#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */
+#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
+#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
+#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
+#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
+#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
+#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
+#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
+#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
+#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
+#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
+#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */
+#define X86_FEATURE_DTES (0*32+21) /* Debug Trace Store */
+#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
+#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
+#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
+ /* of FPU context), and CR4.OSFXSR available */
+#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
+#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */
+#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */
+#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */
+
+/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
+/* Don't duplicate feature flags which are redundant with Intel! */
+#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
+#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
+#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
+#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
+
+/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
+#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */
+#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */
+#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */
+
+/* Other features, Linux-defined mapping, word 3 */
+/* This range is used for feature bits which conflict or are synthesized */
+#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */
+#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
+#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
+
+#endif /* __ASM_I386_CPUFEATURE_H */
+
+/*
+ * Local Variables:
+ * mode:c
+ * comment-column:42
+ * End:
+ */
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 55ffacff1..c8d826232 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -8,6 +8,8 @@
#include <asm/ptrace.h>
#include <asm/user.h>
+#include <linux/utsname.h>
+
typedef unsigned long elf_greg_t;
#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
@@ -84,7 +86,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
instruction set this CPU supports. This could be done in user space,
but it's not easy, and we've already done it here. */
-#define ELF_HWCAP (boot_cpu_data.x86_capability)
+#define ELF_HWCAP (boot_cpu_data.x86_capability[0])
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
@@ -93,7 +95,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
For the moment, we have only optimizations for the Intel generations,
but that could change... */
-#define ELF_PLATFORM ("i386\0i486\0i586\0i686"+(((boot_cpu_data.x86>6?6:boot_cpu_data.x86)-3)*5))
+#define ELF_PLATFORM (system_utsname.machine)
#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
index 8370b7eb6..dfff7fad0 100644
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -53,19 +53,19 @@ extern void kmap_init(void) __init;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-extern unsigned long FASTCALL(kmap_high(struct page *page));
+extern void * FASTCALL(kmap_high(struct page *page));
extern void FASTCALL(kunmap_high(struct page *page));
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
@@ -80,13 +80,13 @@ extern inline void kunmap(struct page *page)
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
enum fixed_addresses idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
@@ -97,12 +97,13 @@ extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
__flush_tlb_one(vaddr);
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
if (vaddr < FIXADDR_START) // FIXME
diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h
index f8ebabe1b..04ba635e5 100644
--- a/include/asm-i386/i387.h
+++ b/include/asm-i386/i387.h
@@ -30,6 +30,7 @@ extern void restore_fpu( struct task_struct *tsk );
#define clear_fpu( tsk ) do { \
if ( tsk->flags & PF_USEDFPU ) { \
+ asm volatile("fwait"); \
tsk->flags &= ~PF_USEDFPU; \
stts(); \
} \
diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h
new file mode 100644
index 000000000..61e2fd50e
--- /dev/null
+++ b/include/asm-i386/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_I386_MODULE_H
+#define _ASM_I386_MODULE_H
+/*
+ * This file contains the i386 architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_I386_MODULE_H */
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 5460e6ccc..1fc0a0b9a 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -340,9 +340,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
#endif /* !__ASSEMBLY__ */
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 76ac26cae..9e8e8c5ef 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -13,6 +13,7 @@
#include <asm/page.h>
#include <asm/types.h>
#include <asm/sigcontext.h>
+#include <asm/cpufeature.h>
#include <linux/config.h>
#include <linux/threads.h>
@@ -37,8 +38,8 @@ struct cpuinfo_x86 {
char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
char hard_math;
char rfu;
- int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
- __u32 x86_capability;
+ int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
+ __u32 x86_capability[NCAPINTS];
char x86_vendor_id[16];
char x86_model_id[64];
int x86_cache_size; /* in KB - valid for CPUS which support this
@@ -67,39 +68,6 @@ struct cpuinfo_x86 {
* capabilities of CPUs
*/
-#define X86_FEATURE_FPU 0x00000001 /* onboard FPU */
-#define X86_FEATURE_VME 0x00000002 /* Virtual Mode Extensions */
-#define X86_FEATURE_DE 0x00000004 /* Debugging Extensions */
-#define X86_FEATURE_PSE 0x00000008 /* Page Size Extensions */
-#define X86_FEATURE_TSC 0x00000010 /* Time Stamp Counter */
-#define X86_FEATURE_MSR 0x00000020 /* Model-Specific Registers, RDMSR, WRMSR */
-#define X86_FEATURE_PAE 0x00000040 /* Physical Address Extensions */
-#define X86_FEATURE_MCE 0x00000080 /* Machine Check Exceptions */
-#define X86_FEATURE_CX8 0x00000100 /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC 0x00000200 /* onboard APIC */
-#define X86_FEATURE_10 0x00000400
-#define X86_FEATURE_SEP 0x00000800 /* Fast System Call */
-#define X86_FEATURE_MTRR 0x00001000 /* Memory Type Range Registers */
-#define X86_FEATURE_PGE 0x00002000 /* Page Global Enable */
-#define X86_FEATURE_MCA 0x00004000 /* Machine Check Architecture */
-#define X86_FEATURE_CMOV 0x00008000 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
-#define X86_FEATURE_PAT 0x00010000 /* Page Attribute Table */
-#define X86_FEATURE_PSE36 0x00020000 /* 36-bit PSEs */
-#define X86_FEATURE_PN 0x00040000
-#define X86_FEATURE_19 0x00080000
-#define X86_FEATURE_20 0x00100000
-#define X86_FEATURE_21 0x00200000
-#define X86_FEATURE_22 0x00400000
-#define X86_FEATURE_MMX 0x00800000 /* Multimedia Extensions */
-#define X86_FEATURE_FXSR 0x01000000 /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR (OS uses these instructions) available */
-#define X86_FEATURE_XMM 0x02000000 /* Streaming SIMD Extensions */
-#define X86_FEATURE_26 0x04000000
-#define X86_FEATURE_27 0x08000000
-#define X86_FEATURE_28 0x10000000
-#define X86_FEATURE_29 0x20000000
-#define X86_FEATURE_30 0x40000000
-#define X86_FEATURE_AMD3D 0x80000000
-
extern struct cpuinfo_x86 boot_cpu_data;
extern struct tss_struct init_tss[NR_CPUS];
@@ -111,22 +79,15 @@ extern struct cpuinfo_x86 cpu_data[];
#define current_cpu_data boot_cpu_data
#endif
-#define cpu_has_pge \
- (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
-#define cpu_has_pse \
- (boot_cpu_data.x86_capability & X86_FEATURE_PSE)
-#define cpu_has_pae \
- (boot_cpu_data.x86_capability & X86_FEATURE_PAE)
-#define cpu_has_tsc \
- (boot_cpu_data.x86_capability & X86_FEATURE_TSC)
-#define cpu_has_de \
- (boot_cpu_data.x86_capability & X86_FEATURE_DE)
-#define cpu_has_vme \
- (boot_cpu_data.x86_capability & X86_FEATURE_VME)
-#define cpu_has_fxsr \
- (boot_cpu_data.x86_capability & X86_FEATURE_FXSR)
-#define cpu_has_xmm \
- (boot_cpu_data.x86_capability & X86_FEATURE_XMM)
+#define cpu_has_pge (test_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability))
+#define cpu_has_pse (test_bit(X86_FEATURE_PSE, boot_cpu_data.x86_capability))
+#define cpu_has_pae (test_bit(X86_FEATURE_PAE, boot_cpu_data.x86_capability))
+#define cpu_has_tsc (test_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability))
+#define cpu_has_de (test_bit(X86_FEATURE_DE, boot_cpu_data.x86_capability))
+#define cpu_has_vme (test_bit(X86_FEATURE_VME, boot_cpu_data.x86_capability))
+#define cpu_has_fxsr (test_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability))
+#define cpu_has_xmm (test_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability))
+#define cpu_has_fpu (test_bit(X86_FEATURE_FPU, boot_cpu_data.x86_capability))
extern char ignore_irq13;
@@ -135,7 +96,28 @@ extern void print_cpu_info(struct cpuinfo_x86 *);
extern void dodgy_tsc(void);
/*
- * Generic CPUID function
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+/*
+ * Generic CPUID function
*/
extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
{
@@ -147,6 +129,45 @@ extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
: "a" (op));
}
+/*
+ * CPUID functions returning a single datum
+ */
+extern inline unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ return eax;
+}
+extern inline unsigned int cpuid_ebx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ return ebx;
+}
+extern inline unsigned int cpuid_ecx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ return ecx;
+}
+extern inline unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ __asm__("cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op));
+ return edx;
+}
/*
* Intel CPU features in CR4
@@ -220,7 +241,11 @@ static inline void clear_in_cr4 (unsigned long mask)
/*
* Bus types (default is ISA, but people can check others with these..)
*/
+#ifdef CONFIG_EISA
extern int EISA_bus;
+#else
+#define EISA_bus (0)
+#endif
extern int MCA_bus;
/* from system description table in BIOS. Mostly for MCA use, but
@@ -441,4 +466,10 @@ struct microcode {
#define MICROCODE_IOCFREE _IO('6',0) /* because it is for P6 */
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+extern inline void rep_nop(void)
+{
+ __asm__ __volatile__("rep;nop");
+}
+
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/xor.h b/include/asm-i386/xor.h
new file mode 100644
index 000000000..6a2230b8f
--- /dev/null
+++ b/include/asm-i386/xor.h
@@ -0,0 +1,858 @@
+/*
+ * include/asm-i386/xor.h
+ *
+ * Optimized RAID-5 checksumming functions for MMX and SSE.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * High-speed RAID5 checksumming functions utilizing MMX instructions.
+ * Copyright (C) 1998 Ingo Molnar.
+ */
+
+#define FPU_SAVE \
+ do { \
+ if (!(current->flags & PF_USEDFPU)) \
+ __asm__ __volatile__ (" clts;\n"); \
+ __asm__ __volatile__ ("fsave %0; fwait": "=m"(fpu_save[0])); \
+ } while (0)
+
+#define FPU_RESTORE \
+ do { \
+ __asm__ __volatile__ ("frstor %0": : "m"(fpu_save[0])); \
+ if (!(current->flags & PF_USEDFPU)) \
+ stts(); \
+ } while (0)
+
+#define LD(x,y) " movq 8*("#x")(%1), %%mm"#y" ;\n"
+#define ST(x,y) " movq %%mm"#y", 8*("#x")(%1) ;\n"
+#define XO1(x,y) " pxor 8*("#x")(%2), %%mm"#y" ;\n"
+#define XO2(x,y) " pxor 8*("#x")(%3), %%mm"#y" ;\n"
+#define XO3(x,y) " pxor 8*("#x")(%4), %%mm"#y" ;\n"
+#define XO4(x,y) " pxor 8*("#x")(%5), %%mm"#y" ;\n"
+
+
+static void
+xor_pII_mmx_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ unsigned long lines = bytes >> 7;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ XO1(i,0) \
+ ST(i,0) \
+ XO1(i+1,1) \
+ ST(i+1,1) \
+ XO1(i+2,2) \
+ ST(i+2,2) \
+ XO1(i+3,3) \
+ ST(i+3,3)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $128, %1 ;\n"
+ " addl $128, %2 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static void
+xor_pII_mmx_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ unsigned long lines = bytes >> 7;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ XO2(i,0) \
+ ST(i,0) \
+ XO2(i+1,1) \
+ ST(i+1,1) \
+ XO2(i+2,2) \
+ ST(i+2,2) \
+ XO2(i+3,3) \
+ ST(i+3,3)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $128, %1 ;\n"
+ " addl $128, %2 ;\n"
+ " addl $128, %3 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static void
+xor_pII_mmx_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ unsigned long lines = bytes >> 7;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ XO2(i,0) \
+ XO2(i+1,1) \
+ XO2(i+2,2) \
+ XO2(i+3,3) \
+ XO3(i,0) \
+ ST(i,0) \
+ XO3(i+1,1) \
+ ST(i+1,1) \
+ XO3(i+2,2) \
+ ST(i+2,2) \
+ XO3(i+3,3) \
+ ST(i+3,3)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $128, %1 ;\n"
+ " addl $128, %2 ;\n"
+ " addl $128, %3 ;\n"
+ " addl $128, %4 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static void
+xor_pII_mmx_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ unsigned long lines = bytes >> 7;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ XO2(i,0) \
+ XO2(i+1,1) \
+ XO2(i+2,2) \
+ XO2(i+3,3) \
+ XO3(i,0) \
+ XO3(i+1,1) \
+ XO3(i+2,2) \
+ XO3(i+3,3) \
+ XO4(i,0) \
+ ST(i,0) \
+ XO4(i+1,1) \
+ ST(i+1,1) \
+ XO4(i+2,2) \
+ ST(i+2,2) \
+ XO4(i+3,3) \
+ ST(i+3,3)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $128, %1 ;\n"
+ " addl $128, %2 ;\n"
+ " addl $128, %3 ;\n"
+ " addl $128, %4 ;\n"
+ " addl $128, %5 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "g" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4), "r" (p5)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+#undef LD
+#undef XO1
+#undef XO2
+#undef XO3
+#undef XO4
+#undef ST
+#undef BLOCK
+
+static void
+xor_p5_mmx_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ unsigned long lines = bytes >> 6;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+ " .align 32 ;\n"
+ " 1: ;\n"
+ " movq (%1), %%mm0 ;\n"
+ " movq 8(%1), %%mm1 ;\n"
+ " pxor (%2), %%mm0 ;\n"
+ " movq 16(%1), %%mm2 ;\n"
+ " movq %%mm0, (%1) ;\n"
+ " pxor 8(%2), %%mm1 ;\n"
+ " movq 24(%1), %%mm3 ;\n"
+ " movq %%mm1, 8(%1) ;\n"
+ " pxor 16(%2), %%mm2 ;\n"
+ " movq 32(%1), %%mm4 ;\n"
+ " movq %%mm2, 16(%1) ;\n"
+ " pxor 24(%2), %%mm3 ;\n"
+ " movq 40(%1), %%mm5 ;\n"
+ " movq %%mm3, 24(%1) ;\n"
+ " pxor 32(%2), %%mm4 ;\n"
+ " movq 48(%1), %%mm6 ;\n"
+ " movq %%mm4, 32(%1) ;\n"
+ " pxor 40(%2), %%mm5 ;\n"
+ " movq 56(%1), %%mm7 ;\n"
+ " movq %%mm5, 40(%1) ;\n"
+ " pxor 48(%2), %%mm6 ;\n"
+ " pxor 56(%2), %%mm7 ;\n"
+ " movq %%mm6, 48(%1) ;\n"
+ " movq %%mm7, 56(%1) ;\n"
+
+ " addl $64, %1 ;\n"
+ " addl $64, %2 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static void
+xor_p5_mmx_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ unsigned long lines = bytes >> 6;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+ " .align 32,0x90 ;\n"
+ " 1: ;\n"
+ " movq (%1), %%mm0 ;\n"
+ " movq 8(%1), %%mm1 ;\n"
+ " pxor (%2), %%mm0 ;\n"
+ " movq 16(%1), %%mm2 ;\n"
+ " pxor 8(%2), %%mm1 ;\n"
+ " pxor (%3), %%mm0 ;\n"
+ " pxor 16(%2), %%mm2 ;\n"
+ " movq %%mm0, (%1) ;\n"
+ " pxor 8(%3), %%mm1 ;\n"
+ " pxor 16(%3), %%mm2 ;\n"
+ " movq 24(%1), %%mm3 ;\n"
+ " movq %%mm1, 8(%1) ;\n"
+ " movq 32(%1), %%mm4 ;\n"
+ " movq 40(%1), %%mm5 ;\n"
+ " pxor 24(%2), %%mm3 ;\n"
+ " movq %%mm2, 16(%1) ;\n"
+ " pxor 32(%2), %%mm4 ;\n"
+ " pxor 24(%3), %%mm3 ;\n"
+ " pxor 40(%2), %%mm5 ;\n"
+ " movq %%mm3, 24(%1) ;\n"
+ " pxor 32(%3), %%mm4 ;\n"
+ " pxor 40(%3), %%mm5 ;\n"
+ " movq 48(%1), %%mm6 ;\n"
+ " movq %%mm4, 32(%1) ;\n"
+ " movq 56(%1), %%mm7 ;\n"
+ " pxor 48(%2), %%mm6 ;\n"
+ " movq %%mm5, 40(%1) ;\n"
+ " pxor 56(%2), %%mm7 ;\n"
+ " pxor 48(%3), %%mm6 ;\n"
+ " pxor 56(%3), %%mm7 ;\n"
+ " movq %%mm6, 48(%1) ;\n"
+ " movq %%mm7, 56(%1) ;\n"
+
+ " addl $64, %1 ;\n"
+ " addl $64, %2 ;\n"
+ " addl $64, %3 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3)
+ : "memory" );
+
+ FPU_RESTORE;
+}
+
+static void
+xor_p5_mmx_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ unsigned long lines = bytes >> 6;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+ " .align 32,0x90 ;\n"
+ " 1: ;\n"
+ " movq (%1), %%mm0 ;\n"
+ " movq 8(%1), %%mm1 ;\n"
+ " pxor (%2), %%mm0 ;\n"
+ " movq 16(%1), %%mm2 ;\n"
+ " pxor 8(%2), %%mm1 ;\n"
+ " pxor (%3), %%mm0 ;\n"
+ " pxor 16(%2), %%mm2 ;\n"
+ " pxor 8(%3), %%mm1 ;\n"
+ " pxor (%4), %%mm0 ;\n"
+ " movq 24(%1), %%mm3 ;\n"
+ " pxor 16(%3), %%mm2 ;\n"
+ " pxor 8(%4), %%mm1 ;\n"
+ " movq %%mm0, (%1) ;\n"
+ " movq 32(%1), %%mm4 ;\n"
+ " pxor 24(%2), %%mm3 ;\n"
+ " pxor 16(%4), %%mm2 ;\n"
+ " movq %%mm1, 8(%1) ;\n"
+ " movq 40(%1), %%mm5 ;\n"
+ " pxor 32(%2), %%mm4 ;\n"
+ " pxor 24(%3), %%mm3 ;\n"
+ " movq %%mm2, 16(%1) ;\n"
+ " pxor 40(%2), %%mm5 ;\n"
+ " pxor 32(%3), %%mm4 ;\n"
+ " pxor 24(%4), %%mm3 ;\n"
+ " movq %%mm3, 24(%1) ;\n"
+ " movq 56(%1), %%mm7 ;\n"
+ " movq 48(%1), %%mm6 ;\n"
+ " pxor 40(%3), %%mm5 ;\n"
+ " pxor 32(%4), %%mm4 ;\n"
+ " pxor 48(%2), %%mm6 ;\n"
+ " movq %%mm4, 32(%1) ;\n"
+ " pxor 56(%2), %%mm7 ;\n"
+ " pxor 40(%4), %%mm5 ;\n"
+ " pxor 48(%3), %%mm6 ;\n"
+ " pxor 56(%3), %%mm7 ;\n"
+ " movq %%mm5, 40(%1) ;\n"
+ " pxor 48(%4), %%mm6 ;\n"
+ " pxor 56(%4), %%mm7 ;\n"
+ " movq %%mm6, 48(%1) ;\n"
+ " movq %%mm7, 56(%1) ;\n"
+
+ " addl $64, %1 ;\n"
+ " addl $64, %2 ;\n"
+ " addl $64, %3 ;\n"
+ " addl $64, %4 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static void
+xor_p5_mmx_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ unsigned long lines = bytes >> 6;
+ char fpu_save[108];
+
+ FPU_SAVE;
+
+ __asm__ __volatile__ (
+ " .align 32,0x90 ;\n"
+ " 1: ;\n"
+ " movq (%1), %%mm0 ;\n"
+ " movq 8(%1), %%mm1 ;\n"
+ " pxor (%2), %%mm0 ;\n"
+ " pxor 8(%2), %%mm1 ;\n"
+ " movq 16(%1), %%mm2 ;\n"
+ " pxor (%3), %%mm0 ;\n"
+ " pxor 8(%3), %%mm1 ;\n"
+ " pxor 16(%2), %%mm2 ;\n"
+ " pxor (%4), %%mm0 ;\n"
+ " pxor 8(%4), %%mm1 ;\n"
+ " pxor 16(%3), %%mm2 ;\n"
+ " movq 24(%1), %%mm3 ;\n"
+ " pxor (%5), %%mm0 ;\n"
+ " pxor 8(%5), %%mm1 ;\n"
+ " movq %%mm0, (%1) ;\n"
+ " pxor 16(%4), %%mm2 ;\n"
+ " pxor 24(%2), %%mm3 ;\n"
+ " movq %%mm1, 8(%1) ;\n"
+ " pxor 16(%5), %%mm2 ;\n"
+ " pxor 24(%3), %%mm3 ;\n"
+ " movq 32(%1), %%mm4 ;\n"
+ " movq %%mm2, 16(%1) ;\n"
+ " pxor 24(%4), %%mm3 ;\n"
+ " pxor 32(%2), %%mm4 ;\n"
+ " movq 40(%1), %%mm5 ;\n"
+ " pxor 24(%5), %%mm3 ;\n"
+ " pxor 32(%3), %%mm4 ;\n"
+ " pxor 40(%2), %%mm5 ;\n"
+ " movq %%mm3, 24(%1) ;\n"
+ " pxor 32(%4), %%mm4 ;\n"
+ " pxor 40(%3), %%mm5 ;\n"
+ " movq 48(%1), %%mm6 ;\n"
+ " movq 56(%1), %%mm7 ;\n"
+ " pxor 32(%5), %%mm4 ;\n"
+ " pxor 40(%4), %%mm5 ;\n"
+ " pxor 48(%2), %%mm6 ;\n"
+ " pxor 56(%2), %%mm7 ;\n"
+ " movq %%mm4, 32(%1) ;\n"
+ " pxor 48(%3), %%mm6 ;\n"
+ " pxor 56(%3), %%mm7 ;\n"
+ " pxor 40(%5), %%mm5 ;\n"
+ " pxor 48(%4), %%mm6 ;\n"
+ " pxor 56(%4), %%mm7 ;\n"
+ " movq %%mm5, 40(%1) ;\n"
+ " pxor 48(%5), %%mm6 ;\n"
+ " pxor 56(%5), %%mm7 ;\n"
+ " movq %%mm6, 48(%1) ;\n"
+ " movq %%mm7, 56(%1) ;\n"
+
+ " addl $64, %1 ;\n"
+ " addl $64, %2 ;\n"
+ " addl $64, %3 ;\n"
+ " addl $64, %4 ;\n"
+ " addl $64, %5 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "g" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4), "r" (p5)
+ : "memory");
+
+ FPU_RESTORE;
+}
+
+static struct xor_block_template xor_block_pII_mmx = {
+ name: "pII_mmx",
+ do_2: xor_pII_mmx_2,
+ do_3: xor_pII_mmx_3,
+ do_4: xor_pII_mmx_4,
+ do_5: xor_pII_mmx_5,
+};
+
+static struct xor_block_template xor_block_p5_mmx = {
+ name: "p5_mmx",
+ do_2: xor_p5_mmx_2,
+ do_3: xor_p5_mmx_3,
+ do_4: xor_p5_mmx_4,
+ do_5: xor_p5_mmx_5,
+};
+
+#undef FPU_SAVE
+#undef FPU_RESTORE
+
+/*
+ * Cache avoiding checksumming functions utilizing KNI instructions
+ * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
+ */
+
+#define XMMS_SAVE \
+ __asm__ __volatile__ ( \
+ "movl %%cr0,%0 ;\n\t" \
+ "clts ;\n\t" \
+ "movups %%xmm0,(%1) ;\n\t" \
+ "movups %%xmm1,0x10(%1) ;\n\t" \
+ "movups %%xmm2,0x20(%1) ;\n\t" \
+ "movups %%xmm3,0x30(%1) ;\n\t" \
+ : "=r" (cr0) \
+ : "r" (xmm_save) \
+ : "memory")
+
+#define XMMS_RESTORE \
+ __asm__ __volatile__ ( \
+ "sfence ;\n\t" \
+ "movups (%1),%%xmm0 ;\n\t" \
+ "movups 0x10(%1),%%xmm1 ;\n\t" \
+ "movups 0x20(%1),%%xmm2 ;\n\t" \
+ "movups 0x30(%1),%%xmm3 ;\n\t" \
+ "movl %0,%%cr0 ;\n\t" \
+ : \
+ : "r" (cr0), "r" (xmm_save) \
+ : "memory")
+
+#define OFFS(x) "16*("#x")"
+#define PF0(x) " prefetcht0 "OFFS(x)"(%1) ;\n"
+#define LD(x,y) " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n"
+#define ST(x,y) " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n"
+#define PF1(x) " prefetchnta "OFFS(x)"(%2) ;\n"
+#define PF2(x) " prefetchnta "OFFS(x)"(%3) ;\n"
+#define PF3(x) " prefetchnta "OFFS(x)"(%4) ;\n"
+#define PF4(x) " prefetchnta "OFFS(x)"(%5) ;\n"
+#define PF5(x) " prefetchnta "OFFS(x)"(%6) ;\n"
+#define XO1(x,y) " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n"
+#define XO2(x,y) " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n"
+#define XO3(x,y) " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n"
+#define XO4(x,y) " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n"
+#define XO5(x,y) " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n"
+
+
+static void
+xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ unsigned long lines = bytes >> 8;
+ char xmm_save[16*4];
+ int cr0;
+
+ XMMS_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ LD(i,0) \
+ LD(i+1,1) \
+ PF1(i) \
+ PF1(i+2) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ PF0(i+4) \
+ PF0(i+6) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ ST(i,0) \
+ ST(i+1,1) \
+ ST(i+2,2) \
+ ST(i+3,3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $256, %1 ;\n"
+ " addl $256, %2 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2)
+ : "memory");
+
+ XMMS_RESTORE;
+}
+
+static void
+xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ unsigned long lines = bytes >> 8;
+ char xmm_save[16*4];
+ int cr0;
+
+ XMMS_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i+2) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ PF2(i) \
+ PF2(i+2) \
+ PF0(i+4) \
+ PF0(i+6) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ XO2(i,0) \
+ XO2(i+1,1) \
+ XO2(i+2,2) \
+ XO2(i+3,3) \
+ ST(i,0) \
+ ST(i+1,1) \
+ ST(i+2,2) \
+ ST(i+3,3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $256, %1 ;\n"
+ " addl $256, %2 ;\n"
+ " addl $256, %3 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r"(p2), "r"(p3)
+ : "memory" );
+
+ XMMS_RESTORE;
+}
+
+static void
+xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ unsigned long lines = bytes >> 8;
+ char xmm_save[16*4];
+ int cr0;
+
+ XMMS_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i+2) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ PF2(i) \
+ PF2(i+2) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ PF3(i) \
+ PF3(i+2) \
+ PF0(i+4) \
+ PF0(i+6) \
+ XO2(i,0) \
+ XO2(i+1,1) \
+ XO2(i+2,2) \
+ XO2(i+3,3) \
+ XO3(i,0) \
+ XO3(i+1,1) \
+ XO3(i+2,2) \
+ XO3(i+3,3) \
+ ST(i,0) \
+ ST(i+1,1) \
+ ST(i+2,2) \
+ ST(i+3,3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $256, %1 ;\n"
+ " addl $256, %2 ;\n"
+ " addl $256, %3 ;\n"
+ " addl $256, %4 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4)
+ : "memory" );
+
+ XMMS_RESTORE;
+}
+
+static void
+xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ unsigned long lines = bytes >> 8;
+ char xmm_save[16*4];
+ int cr0;
+
+ XMMS_SAVE;
+
+ __asm__ __volatile__ (
+#undef BLOCK
+#define BLOCK(i) \
+ PF1(i) \
+ PF1(i+2) \
+ LD(i,0) \
+ LD(i+1,1) \
+ LD(i+2,2) \
+ LD(i+3,3) \
+ PF2(i) \
+ PF2(i+2) \
+ XO1(i,0) \
+ XO1(i+1,1) \
+ XO1(i+2,2) \
+ XO1(i+3,3) \
+ PF3(i) \
+ PF3(i+2) \
+ XO2(i,0) \
+ XO2(i+1,1) \
+ XO2(i+2,2) \
+ XO2(i+3,3) \
+ PF4(i) \
+ PF4(i+2) \
+ PF0(i+4) \
+ PF0(i+6) \
+ XO3(i,0) \
+ XO3(i+1,1) \
+ XO3(i+2,2) \
+ XO3(i+3,3) \
+ XO4(i,0) \
+ XO4(i+1,1) \
+ XO4(i+2,2) \
+ XO4(i+3,3) \
+ ST(i,0) \
+ ST(i+1,1) \
+ ST(i+2,2) \
+ ST(i+3,3) \
+
+
+ PF0(0)
+ PF0(2)
+
+ " .align 32 ;\n"
+ " 1: ;\n"
+
+ BLOCK(0)
+ BLOCK(4)
+ BLOCK(8)
+ BLOCK(12)
+
+ " addl $256, %1 ;\n"
+ " addl $256, %2 ;\n"
+ " addl $256, %3 ;\n"
+ " addl $256, %4 ;\n"
+ " addl $256, %5 ;\n"
+ " decl %0 ;\n"
+ " jnz 1b ;\n"
+ :
+ : "r" (lines),
+ "r" (p1), "r" (p2), "r" (p3), "r" (p4), "r" (p5)
+ : "memory");
+
+ XMMS_RESTORE;
+}
+
+static struct xor_block_template xor_block_pIII_sse = {
+ name: "pIII_sse",
+ do_2: xor_sse_2,
+ do_3: xor_sse_3,
+ do_4: xor_sse_4,
+ do_5: xor_sse_5,
+};
+
+/* Also try the generic routines. */
+#include <asm-generic/xor.h>
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES \
+ do { \
+ xor_speed(&xor_block_8regs); \
+ xor_speed(&xor_block_32regs); \
+ if (cpu_has_xmm) \
+ xor_speed(&xor_block_pIII_sse); \
+ if (md_cpu_has_mmx()) { \
+ xor_speed(&xor_block_pII_mmx); \
+ xor_speed(&xor_block_p5_mmx); \
+ } \
+ } while (0)
+
+/* We force the use of the SSE xor block because it can write around L2.
+ We may also be able to load into the L1 only depending on how the cpu
+ deals with a load to a line that is being prefetched. */
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+ (cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
diff --git a/include/asm-ia64/xor.h b/include/asm-ia64/xor.h
new file mode 100644
index 000000000..28aca667c
--- /dev/null
+++ b/include/asm-ia64/xor.h
@@ -0,0 +1,283 @@
+/*
+ * include/asm-ia64/xor.h
+ *
+ * Optimized RAID-5 checksumming functions for IA-64.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+extern void xor_ia64_2(unsigned long, unsigned long *, unsigned long *);
+extern void xor_ia64_3(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *);
+extern void xor_ia64_4(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+extern void xor_ia64_5(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *, unsigned long *);
+
+asm ("
+ .text
+
+ // Assume L2 memory latency of 6 cycles.
+
+ .proc xor_ia64_2
+xor_ia64_2:
+ .prologue
+ .fframe 0
+ { .mii
+ .save ar.pfs, r31
+ alloc r31 = ar.pfs, 3, 0, 13, 16
+ .save ar.lc, r30
+ mov r30 = ar.lc
+ .save pr, r29
+ mov r29 = pr
+ ;;
+ }
+ .body
+ { .mii
+ mov r8 = in1
+ mov ar.ec = 6 + 2
+ shr in0 = in0, 3
+ ;;
+ }
+ { .mmi
+ adds in0 = -1, in0
+ mov r16 = in1
+ mov r17 = in2
+ ;;
+ }
+ { .mii
+ mov ar.lc = in0
+ mov pr.rot = 1 << 16
+ ;;
+ }
+ .rotr s1[6+1], s2[6+1], d[2]
+ .rotp p[6+2]
+0: { .mmi
+(p[0]) ld8.nta s1[0] = [r16], 8
+(p[0]) ld8.nta s2[0] = [r17], 8
+(p[6]) xor d[0] = s1[6], s2[6]
+ }
+ { .mfb
+(p[6+1]) st8.nta [r8] = d[1], 8
+ nop.f 0
+ br.ctop.dptk.few 0b
+ ;;
+ }
+ { .mii
+ mov ar.lc = r30
+ mov pr = r29, -1
+ }
+ { .bbb
+ br.ret.sptk.few rp
+ }
+ .endp xor_ia64_2
+
+ .proc xor_ia64_3
+xor_ia64_3:
+ .prologue
+ .fframe 0
+ { .mii
+ .save ar.pfs, r31
+ alloc r31 = ar.pfs, 4, 0, 20, 24
+ .save ar.lc, r30
+ mov r30 = ar.lc
+ .save pr, r29
+ mov r29 = pr
+ ;;
+ }
+ .body
+ { .mii
+ mov r8 = in1
+ mov ar.ec = 6 + 2
+ shr in0 = in0, 3
+ ;;
+ }
+ { .mmi
+ adds in0 = -1, in0
+ mov r16 = in1
+ mov r17 = in2
+ ;;
+ }
+ { .mii
+ mov r18 = in3
+ mov ar.lc = in0
+ mov pr.rot = 1 << 16
+ ;;
+ }
+ .rotr s1[6+1], s2[6+1], s3[6+1], d[2]
+ .rotp p[6+2]
+0: { .mmi
+(p[0]) ld8.nta s1[0] = [r16], 8
+(p[0]) ld8.nta s2[0] = [r17], 8
+(p[6]) xor d[0] = s1[6], s2[6]
+ ;;
+ }
+ { .mmi
+(p[0]) ld8.nta s3[0] = [r18], 8
+(p[6+1]) st8.nta [r8] = d[1], 8
+(p[6]) xor d[0] = d[0], s3[6]
+ }
+ { .bbb
+ br.ctop.dptk.few 0b
+ ;;
+ }
+ { .mii
+ mov ar.lc = r30
+ mov pr = r29, -1
+ }
+ { .bbb
+ br.ret.sptk.few rp
+ }
+ .endp xor_ia64_3
+
+ .proc xor_ia64_4
+xor_ia64_4:
+ .prologue
+ .fframe 0
+ { .mii
+ .save ar.pfs, r31
+ alloc r31 = ar.pfs, 5, 0, 27, 32
+ .save ar.lc, r30
+ mov r30 = ar.lc
+ .save pr, r29
+ mov r29 = pr
+ ;;
+ }
+ .body
+ { .mii
+ mov r8 = in1
+ mov ar.ec = 6 + 2
+ shr in0 = in0, 3
+ ;;
+ }
+ { .mmi
+ adds in0 = -1, in0
+ mov r16 = in1
+ mov r17 = in2
+ ;;
+ }
+ { .mii
+ mov r18 = in3
+ mov ar.lc = in0
+ mov pr.rot = 1 << 16
+ }
+ { .mfb
+ mov r19 = in4
+ ;;
+ }
+ .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], d[2]
+ .rotp p[6+2]
+0: { .mmi
+(p[0]) ld8.nta s1[0] = [r16], 8
+(p[0]) ld8.nta s2[0] = [r17], 8
+(p[6]) xor d[0] = s1[6], s2[6]
+ }
+ { .mmi
+(p[0]) ld8.nta s3[0] = [r18], 8
+(p[0]) ld8.nta s4[0] = [r19], 8
+(p[6]) xor r20 = s3[6], s4[6]
+ ;;
+ }
+ { .mib
+(p[6+1]) st8.nta [r8] = d[1], 8
+(p[6]) xor d[0] = d[0], r20
+ br.ctop.dptk.few 0b
+ ;;
+ }
+ { .mii
+ mov ar.lc = r30
+ mov pr = r29, -1
+ }
+ { .bbb
+ br.ret.sptk.few rp
+ }
+ .endp xor_ia64_4
+
+ .proc xor_ia64_5
+xor_ia64_5:
+ .prologue
+ .fframe 0
+ { .mii
+ .save ar.pfs, r31
+ alloc r31 = ar.pfs, 6, 0, 34, 40
+ .save ar.lc, r30
+ mov r30 = ar.lc
+ .save pr, r29
+ mov r29 = pr
+ ;;
+ }
+ .body
+ { .mii
+ mov r8 = in1
+ mov ar.ec = 6 + 2
+ shr in0 = in0, 3
+ ;;
+ }
+ { .mmi
+ adds in0 = -1, in0
+ mov r16 = in1
+ mov r17 = in2
+ ;;
+ }
+ { .mii
+ mov r18 = in3
+ mov ar.lc = in0
+ mov pr.rot = 1 << 16
+ }
+ { .mib
+ mov r19 = in4
+ mov r20 = in5
+ ;;
+ }
+ .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], s5[6+1], d[2]
+ .rotp p[6+2]
+0: { .mmi
+(p[0]) ld8.nta s1[0] = [r16], 8
+(p[0]) ld8.nta s2[0] = [r17], 8
+(p[6]) xor d[0] = s1[6], s2[6]
+ }
+ { .mmi
+(p[0]) ld8.nta s3[0] = [r18], 8
+(p[0]) ld8.nta s4[0] = [r19], 8
+(p[6]) xor r21 = s3[6], s4[6]
+ ;;
+ }
+ { .mmi
+(p[0]) ld8.nta s5[0] = [r20], 8
+(p[6+1]) st8.nta [r8] = d[1], 8
+(p[6]) xor d[0] = d[0], r21
+ ;;
+ }
+ { .mfb
+(p[6]) xor d[0] = d[0], s5[6]
+ nop.f 0
+ br.ctop.dptk.few 0b
+ ;;
+ }
+ { .mii
+ mov ar.lc = r30
+ mov pr = r29, -1
+ }
+ { .bbb
+ br.ret.sptk.few rp
+ }
+ .endp xor_ia64_5
+");
+
+static struct xor_block_template xor_block_ia64 = {
+ name: "ia64",
+ do_2: xor_ia64_2,
+ do_3: xor_ia64_3,
+ do_4: xor_ia64_4,
+ do_5: xor_ia64_5,
+};
+
+#define XOR_TRY_TEMPLATES xor_speed(&xor_block_ia64)
diff --git a/include/asm-m68k/module.h b/include/asm-m68k/module.h
new file mode 100644
index 000000000..85bf411d5
--- /dev/null
+++ b/include/asm-m68k/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_M68K_MODULE_H
+#define _ASM_M68K_MODULE_H
+/*
+ * This file contains the m68k architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_M68K_MODULE_H */
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index 2e128ff48..655d604d2 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -390,9 +390,6 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
#endif /* __ASSEMBLY__ */
-#define module_map vmalloc
-#define module_unmap vfree
-
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define PageSkip(page) (0)
#define kern_addr_valid(addr) (1)
diff --git a/include/asm-m68k/xor.h b/include/asm-m68k/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-m68k/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-mips/module.h b/include/asm-mips/module.h
new file mode 100644
index 000000000..272e05e60
--- /dev/null
+++ b/include/asm-mips/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_MIPS_MODULE_H
+#define _ASM_MIPS_MODULE_H
+/*
+ * This file contains the mips architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_MIPS_MODULE_H */
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index b1d1f1212..ffee96a42 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -456,9 +456,6 @@ extern void update_mmu_cache(struct vm_area_struct *vma,
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define PageSkip(page) (0)
#define kern_addr_valid(addr) (1)
diff --git a/include/asm-mips/resource.h b/include/asm-mips/resource.h
index 718e983e6..286b71b70 100644
--- a/include/asm-mips/resource.h
+++ b/include/asm-mips/resource.h
@@ -1,10 +1,9 @@
-/* $Id: resource.h,v 1.4 2000/01/27 23:45:30 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996, 1998 by Ralf Baechle
+ * Copyright (C) 1995, 96, 98, 2000 by Ralf Baechle
*/
#ifndef _ASM_RESOURCE_H
#define _ASM_RESOURCE_H
@@ -26,14 +25,14 @@
#define RLIM_NLIMITS 11 /* Number of limit flavors. */
+#ifdef __KERNEL__
+
/*
* SuS says limits have to be unsigned.
* Which makes a ton more sense anyway.
*/
#define RLIM_INFINITY 0x7fffffffUL
-#ifdef __KERNEL__
-
#define INIT_RLIMITS \
{ \
{ RLIM_INFINITY, RLIM_INFINITY }, \
diff --git a/include/asm-mips/xor.h b/include/asm-mips/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-mips/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-mips64/module.h b/include/asm-mips64/module.h
new file mode 100644
index 000000000..dbc894f7e
--- /dev/null
+++ b/include/asm-mips64/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_MIPS64_MODULE_H
+#define _ASM_MIPS64_MODULE_H
+/*
+ * This file contains the mips64 architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_MIPS64_MODULE_H */
diff --git a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h
index 4874a59e5..af0c7b4c9 100644
--- a/include/asm-mips64/pgtable.h
+++ b/include/asm-mips64/pgtable.h
@@ -525,9 +525,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define PageSkip(page) (0)
#ifndef CONFIG_DISCONTIGMEM
diff --git a/include/asm-mips64/sn/ioc3.h b/include/asm-mips64/sn/ioc3.h
index 57a2abbf2..f7d530f30 100644
--- a/include/asm-mips64/sn/ioc3.h
+++ b/include/asm-mips64/sn/ioc3.h
@@ -1,10 +1,9 @@
-/* $Id: ioc3.h,v 1.1 2000/01/13 00:17:02 ralf Exp $
- *
- * Copyright (C) 1999 Ralf Baechle
- * This file is part of the Linux driver for the SGI IOC3.
+/*
+ * Copyright (C) 1999, 2000 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
-#ifndef IOC3_H
-#define IOC3_H
+#ifndef _IOC3_H
+#define _IOC3_H
/* SUPERIO uart register map */
typedef volatile struct ioc3_uartregs {
@@ -659,4 +658,4 @@ typedef enum ioc3_subdevs_e {
#define IOC3_INTA_SUBDEVS IOC3_SDB_ETHER
#define IOC3_INTB_SUBDEVS (IOC3_SDB_GENERIC|IOC3_SDB_KBMS|IOC3_SDB_SERIAL|IOC3_SDB_ECPP|IOC3_SDB_RT)
-#endif /* IOC3_H */
+#endif /* _IOC3_H */
diff --git a/include/asm-mips64/xor.h b/include/asm-mips64/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-mips64/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-ppc/8xx_immap.h b/include/asm-ppc/8xx_immap.h
index 0223fe275..d470233e3 100644
--- a/include/asm-ppc/8xx_immap.h
+++ b/include/asm-ppc/8xx_immap.h
@@ -10,6 +10,7 @@
* a combination that I found difficult to separate into logical
* functional files.....but anyone else is welcome to try. -- Dan
*/
+#ifdef __KERNEL__
#ifndef __IMMAP_8XX__
#define __IMMAP_8XX__
@@ -453,3 +454,4 @@ typedef struct immap {
} immap_t;
#endif /* __IMMAP_8XX__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/amigahw.h b/include/asm-ppc/amigahw.h
index 491547376..8c98945e7 100644
--- a/include/asm-ppc/amigahw.h
+++ b/include/asm-ppc/amigahw.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASMPPC_AMIGAHW_H
#define __ASMPPC_AMIGAHW_H
@@ -13,3 +14,4 @@
#endif /* __ASMPPC_AMIGAHW_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/amigaints.h b/include/asm-ppc/amigaints.h
index c7a50189e..a5e1c4850 100644
--- a/include/asm-ppc/amigaints.h
+++ b/include/asm-ppc/amigaints.h
@@ -10,6 +10,7 @@
** Created 10/2/92 by Greg Harp
*/
+#ifdef __KERNEL__
#ifndef _ASMm68k_AMIGAINTS_H_
#define _ASMm68k_AMIGAINTS_H_
@@ -133,3 +134,4 @@ extern unsigned char cia_set_irq(unsigned int irq, int set);
extern unsigned char cia_able_irq(unsigned int irq, int enable);
#endif /* asm-m68k/amigaints.h */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/amigappc.h b/include/asm-ppc/amigappc.h
index 96e5e8f09..8750af77a 100644
--- a/include/asm-ppc/amigappc.h
+++ b/include/asm-ppc/amigappc.h
@@ -11,6 +11,7 @@
** Created: 7/22/97 by Jesper Skov
*/
+#ifdef __KERNEL__
#ifndef _M68K_AMIGAPPC_H
#define _M68K_AMIGAPPC_H
@@ -81,3 +82,4 @@ do { \
#define INTLVL_MASK (0x7f)
#endif /* _M68k_AMIGAPPC_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/backlight.h b/include/asm-ppc/backlight.h
index 79756eca3..2f070ef6f 100644
--- a/include/asm-ppc/backlight.h
+++ b/include/asm-ppc/backlight.h
@@ -4,6 +4,7 @@
* For now, implementation resides in arch/ppc/kernel/pmac_support.c
*
*/
+#ifdef __KERNEL__
#ifndef __ASM_PPC_BACKLIGHT_H
#define __ASM_PPC_BACKLIGHT_H
@@ -26,3 +27,4 @@ extern int set_backlight_level(int level);
extern int get_backlight_level(void);
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
index b82a9fc21..c31e5c5eb 100644
--- a/include/asm-ppc/bitops.h
+++ b/include/asm-ppc/bitops.h
@@ -3,6 +3,7 @@
* bitops.h: Bit string operations on the ppc
*/
+#ifdef __KERNEL__
#ifndef _PPC_BITOPS_H
#define _PPC_BITOPS_H
@@ -351,3 +352,4 @@ found_middle:
#endif /* __KERNEL__ */
#endif /* _PPC_BITOPS_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/board.h b/include/asm-ppc/board.h
index 1476a232a..d1d3ba68a 100644
--- a/include/asm-ppc/board.h
+++ b/include/asm-ppc/board.h
@@ -10,6 +10,7 @@
*
*/
+#ifdef __KERNEL__
#ifndef __BOARD_H__
#define __BOARD_H__
@@ -40,3 +41,4 @@ extern unsigned char __res[];
#endif
#endif /* __BOARD_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/bootinfo.h b/include/asm-ppc/bootinfo.h
index af614d798..84e7a7c8f 100644
--- a/include/asm-ppc/bootinfo.h
+++ b/include/asm-ppc/bootinfo.h
@@ -6,6 +6,7 @@
*/
+#ifdef __KERNEL__
#ifndef _PPC_BOOTINFO_H
#define _PPC_BOOTINFO_H
@@ -33,3 +34,4 @@ struct bi_record {
#endif /* _PPC_BOOTINFO_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h
index 02454f6cf..2da8cfd6c 100644
--- a/include/asm-ppc/byteorder.h
+++ b/include/asm-ppc/byteorder.h
@@ -7,6 +7,7 @@
#include <asm/types.h>
+#ifdef __KERNEL__
#ifdef __GNUC__
extern __inline__ unsigned ld_le16(const volatile unsigned short *addr)
@@ -72,11 +73,13 @@ static __inline__ __const__ __u32 ___arch__swab32(__u32 value)
#define __arch__swab16s(addr) st_le16(addr,*addr)
#define __arch__swab32s(addr) st_le32(addr,*addr)
-#endif /* __GNUC__ */
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#ifndef __STRICT_ANSI__
#define __BYTEORDER_HAS_U64__
#endif
+
+#endif /* __GNUC__ */
+#endif /* __KERNEL__ */
+
#include <linux/byteorder/big_endian.h>
#endif /* _PPC_BYTEORDER_H */
diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
index c45fd8409..e4bcdde00 100644
--- a/include/asm-ppc/cache.h
+++ b/include/asm-ppc/cache.h
@@ -1,6 +1,7 @@
/*
* include/asm-ppc/cache.h
*/
+#ifdef __KERNEL__
#ifndef __ARCH_PPC_CACHE_H
#define __ARCH_PPC_CACHE_H
@@ -83,3 +84,4 @@ extern void flush_dcache_range(unsigned long start, unsigned long stop);
#endif /* CONFIG_8xx */
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/checksum.h b/include/asm-ppc/checksum.h
index e635ff599..48c8ca7b5 100644
--- a/include/asm-ppc/checksum.h
+++ b/include/asm-ppc/checksum.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_CHECKSUM_H
#define _PPC_CHECKSUM_H
@@ -111,3 +112,4 @@ extern unsigned short csum_tcpudp_magic(unsigned long saddr,
unsigned int sum);
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h
index 427ec1884..b612cf02f 100644
--- a/include/asm-ppc/cpm_8260.h
+++ b/include/asm-ppc/cpm_8260.h
@@ -8,6 +8,7 @@
* All CPM control and status is available through the MPC8260 internal
* memory map. See immap.h for details.
*/
+#ifdef __KERNEL__
#ifndef __CPM_82XX__
#define __CPM_82XX__
@@ -697,3 +698,4 @@ typedef struct iic {
#define BD_IIC_START ((ushort)0x0400)
#endif /* __CPM_82XX__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/current.h b/include/asm-ppc/current.h
index 49415ce9f..8d41501ba 100644
--- a/include/asm-ppc/current.h
+++ b/include/asm-ppc/current.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_CURRENT_H
#define _PPC_CURRENT_H
@@ -7,3 +8,4 @@
register struct task_struct *current asm ("r2");
#endif /* !(_PPC_CURRENT_H) */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/dbdma.h b/include/asm-ppc/dbdma.h
index 38cd15803..0590cb454 100644
--- a/include/asm-ppc/dbdma.h
+++ b/include/asm-ppc/dbdma.h
@@ -5,6 +5,7 @@
* Copyright (C) 1996 Paul Mackerras.
*/
+#ifdef __KERNEL__
#ifndef _ASM_DBDMA_H_
#define _ASM_DBDMA_H_
/*
@@ -90,3 +91,4 @@ struct dbdma_cmd {
#define DBDMA_ALIGN(x) (((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \
& -sizeof(struct dbdma_cmd))
#endif /* _ASM_DBDMA_H_ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/delay.h b/include/asm-ppc/delay.h
index 239e0d3ac..2116a2f2c 100644
--- a/include/asm-ppc/delay.h
+++ b/include/asm-ppc/delay.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_DELAY_H
#define _PPC_DELAY_H
@@ -31,3 +32,4 @@ extern __inline__ void udelay(unsigned long usecs)
}
#endif /* defined(_PPC_DELAY_H) */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h
index 5cac2be5e..735d91d1f 100644
--- a/include/asm-ppc/dma.h
+++ b/include/asm-ppc/dma.h
@@ -6,6 +6,8 @@
* Changes for ppc sound by Christoph Nadig
*/
+#ifdef __KERNEL__
+
#include <linux/config.h>
#include <asm/io.h>
#include <linux/spinlock.h>
@@ -410,3 +412,4 @@ extern int isa_dma_bridge_buggy;
#define isa_dma_bridge_buggy (0)
#endif
#endif /* _ASM_DMA_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
index 75b515e18..6a0e2e874 100644
--- a/include/asm-ppc/elf.h
+++ b/include/asm-ppc/elf.h
@@ -11,38 +11,41 @@
#define ELF_NVRREG 33 /* includes vscr */
/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ((x)->e_machine == EM_PPC)
-
-/*
* These are used to set parameters in the core dumps.
*/
#define ELF_ARCH EM_PPC
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
- use of this is to invoke "./ld.so someprog" to test out a new version of
- the loader. We need to make sure that it is out of the way of the program
- that it will "exec", and that there is sufficient room for the brk. */
-
-#define ELF_ET_DYN_BASE (0x08000000)
-
+/* General registers */
typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+/* Floating point registers */
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-#ifdef __KERNEL__
/* Altivec registers */
-typedef vector128 elf_vrreg_t;
+typedef __vector128 elf_vrreg_t;
typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
-#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+
+#define elf_check_arch(x) ((x)->e_machine == EM_PPC)
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE (0x08000000)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
#define ELF_CORE_COPY_REGS(gregs, regs) \
memcpy(gregs, regs, \
@@ -65,8 +68,7 @@ typedef elf_vrreg_t elf_vrregset_t[ELF_NVRREG];
#define ELF_PLATFORM (NULL)
-#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
+#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-ppc/feature.h b/include/asm-ppc/feature.h
index ca4ca4692..7a33ea8d3 100644
--- a/include/asm-ppc/feature.h
+++ b/include/asm-ppc/feature.h
@@ -12,6 +12,7 @@
*
*
*/
+#ifdef __KERNEL__
#ifndef __ASM_PPC_FEATURE_H
#define __ASM_PPC_FEATURE_H
@@ -93,3 +94,4 @@ extern void feature_prepare_for_sleep(void);
extern void feature_wake_up(void);
#endif /* __ASM_PPC_FEATURE_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
index f12eae65f..f04178736 100644
--- a/include/asm-ppc/floppy.h
+++ b/include/asm-ppc/floppy.h
@@ -7,6 +7,7 @@
*
* Copyright (C) 1995
*/
+#ifdef __KERNEL__
#ifndef __ASM_PPC_FLOPPY_H
#define __ASM_PPC_FLOPPY_H
@@ -54,3 +55,4 @@ static int FDC2 = -1;
#define CROSS_64KB(a,s) (0)
#endif /* __ASM_PPC_FLOPPY_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/gemini.h b/include/asm-ppc/gemini.h
index 7e681e043..ebd01c9b6 100644
--- a/include/asm-ppc/gemini.h
+++ b/include/asm-ppc/gemini.h
@@ -6,6 +6,7 @@
* "Gemini" boards.
*
*/
+#ifdef __KERNEL__
#ifndef __PPC_GEMINI_H
#define __PPC_GEMINI_H
@@ -164,3 +165,4 @@ extern void gemini_prom_init(void);
extern void gemini_init_l2(void);
#endif /* __ASSEMBLY__ */
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/gemini_serial.h b/include/asm-ppc/gemini_serial.h
index 089a0ce60..e4e08467e 100644
--- a/include/asm-ppc/gemini_serial.h
+++ b/include/asm-ppc/gemini_serial.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASMPPC_GEMINI_SERIAL_H
#define __ASMPPC_GEMINI_SERIAL_H
@@ -37,3 +38,4 @@
PU32_SERIAL_PORT_DEFNS
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
index f7c12df77..8a270c8c1 100644
--- a/include/asm-ppc/hardirq.h
+++ b/include/asm-ppc/hardirq.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASM_HARDIRQ_H
#define __ASM_HARDIRQ_H
@@ -99,3 +100,4 @@ extern void synchronize_irq(void);
#endif /* CONFIG_SMP */
#endif /* __ASM_HARDIRQ_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h
index 428a59d1c..38114e564 100644
--- a/include/asm-ppc/highmem.h
+++ b/include/asm-ppc/highmem.h
@@ -49,19 +49,19 @@ extern void kmap_init(void) __init;
#define KMAP_FIX_BEGIN (0xfe400000UL)
-extern unsigned long kmap_high(struct page *page);
+extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
@@ -76,13 +76,13 @@ extern inline void kunmap(struct page *page)
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
unsigned int idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE;
@@ -93,12 +93,13 @@ extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
set_pte(kmap_pte+idx, mk_pte(page, kmap_prot));
flush_hash_page(0, vaddr);
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
unsigned int idx = type + KM_TYPE_NR*smp_processor_id();
if (vaddr < KMAP_FIX_BEGIN) // FIXME
diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h
index 28a47906c..7d4790171 100644
--- a/include/asm-ppc/hw_irq.h
+++ b/include/asm-ppc/hw_irq.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
*/
+#ifdef __KERNEL__
#ifndef _PPC_HW_IRQ_H
#define _PPC_HW_IRQ_H
@@ -40,3 +41,4 @@ extern atomic_t ppc_n_lost_interrupts;
#define mask_and_ack_irq(irq) ({if (irq_desc[irq].handler && irq_desc[irq].handler->ack) irq_desc[irq].handler->ack(irq);})
#endif /* _PPC_HW_IRQ_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
index 8b50f862b..179bdec67 100644
--- a/include/asm-ppc/ide.h
+++ b/include/asm-ppc/ide.h
@@ -10,6 +10,8 @@
#ifndef __ASMPPC_IDE_H
#define __ASMPPC_IDE_H
+#ifdef __KERNEL__
+
#include <linux/sched.h>
#include <asm/processor.h>
@@ -19,8 +21,6 @@
#include <asm/hdreg.h>
-#ifdef __KERNEL__
-
#include <linux/config.h>
#include <linux/hdreg.h>
#include <linux/ioport.h>
diff --git a/include/asm-ppc/immap_8260.h b/include/asm-ppc/immap_8260.h
index 298276363..32eb50b8c 100644
--- a/include/asm-ppc/immap_8260.h
+++ b/include/asm-ppc/immap_8260.h
@@ -7,6 +7,7 @@
* this will be, as I don't have any knowledge of the subsequent
* parts at this time. I copied this from the 8xx_immap.h.
*/
+#ifdef __KERNEL__
#ifndef __IMMAP_82XX__
#define __IMMAP_82XX__
@@ -433,3 +434,4 @@ typedef struct immap {
immap_t *immr;
#endif /* __IMMAP_82XX__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/init.h b/include/asm-ppc/init.h
index 00a1c79cc..d4976d863 100644
--- a/include/asm-ppc/init.h
+++ b/include/asm-ppc/init.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_INIT_H
#define _PPC_INIT_H
@@ -35,3 +36,4 @@
__argopenfirmware
#endif /* _PPC_INIT_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 45b2531a3..03f9db09a 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_IO_H
#define _PPC_IO_H
@@ -92,7 +93,7 @@ extern __inline__ unsigned int name(unsigned int port) \
"3: li %0,-1\n" \
" b 2b\n" \
".previous\n" \
- ".section __ex_table,\"ax\"\n" \
+ ".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,3b\n" \
".previous" \
@@ -108,7 +109,7 @@ extern __inline__ void name(unsigned int val, unsigned int port) \
op " %0,0,%1\n" \
"1: sync\n" \
"2:\n" \
- ".section __ex_table,\"ax\"\n" \
+ ".section __ex_table,\"a\"\n" \
" .align 2\n" \
" .long 1b,2b\n" \
".previous" \
@@ -347,7 +348,6 @@ extern inline void out_be32(volatile unsigned *addr, int val)
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
-#ifdef __KERNEL__
static inline int check_signature(unsigned long io_addr,
const unsigned char *signature, int length)
{
@@ -370,6 +370,5 @@ out:
#define dma_cache_wback(_start,_size) do { } while (0)
#define dma_cache_wback_inv(_start,_size) do { } while (0)
-#endif /* __KERNEL__ */
-
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ipcbuf.h b/include/asm-ppc/ipcbuf.h
index 98c75e646..fab6752c7 100644
--- a/include/asm-ppc/ipcbuf.h
+++ b/include/asm-ppc/ipcbuf.h
@@ -2,10 +2,28 @@
#define __PPC_IPCBUF_H__
/*
- * The ipc64_perm structure for the PPC is identical to kern_ipc_perm
- * as we have always had 32-bit UIDs and GIDs in the kernel.
+ * The ipc64_perm structure for PPC architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 1 32-bit value to fill up for 8-byte alignment
+ * - 2 miscellaneous 64-bit values (so that this structure matches
+ * PPC64 ipc64_perm)
*/
-#define ipc64_perm kern_ipc_perm
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_uid_t cuid;
+ __kernel_gid_t cgid;
+ __kernel_mode_t mode;
+ unsigned long seq;
+ unsigned int __pad2;
+ unsigned long long __unused1;
+ unsigned long long __unused2;
+};
#endif /* __PPC_IPCBUF_H__ */
diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
index 86647a0e6..c3ae15763 100644
--- a/include/asm-ppc/irq.h
+++ b/include/asm-ppc/irq.h
@@ -1,8 +1,8 @@
-#include <linux/config.h>
-
+#ifdef __KERNEL__
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
+#include <linux/config.h>
#include <asm/machdep.h> /* ppc_md */
extern void disable_irq(unsigned int);
@@ -217,3 +217,4 @@ static __inline__ int irq_cannonicalize(int irq)
extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
#endif /* _ASM_IRQ_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h
index 51c868b36..7337be058 100644
--- a/include/asm-ppc/kgdb.h
+++ b/include/asm-ppc/kgdb.h
@@ -6,6 +6,7 @@
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
+#ifdef __KERNEL__
#ifndef _PPC_KGDB_H
#define _PPC_KGDB_H
@@ -46,3 +47,4 @@ extern char getDebugChar(void); /* read and return a single char */
#endif /* !(__ASSEMBLY__) */
#endif /* !(_PPC_KGDB_H) */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h
index d92d81b20..a1483ed3b 100644
--- a/include/asm-ppc/kmap_types.h
+++ b/include/asm-ppc/kmap_types.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _ASM_KMAP_TYPES_H
#define _ASM_KMAP_TYPES_H
@@ -8,3 +9,4 @@ enum km_type {
};
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/linux_logo.h b/include/asm-ppc/linux_logo.h
index 33ad40f64..c35e6db5b 100644
--- a/include/asm-ppc/linux_logo.h
+++ b/include/asm-ppc/linux_logo.h
@@ -10,6 +10,7 @@
* values have to start from 0x20
* (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
*/
+#ifdef __KERNEL__
#include <linux/init.h>
@@ -39,3 +40,4 @@ extern unsigned char linux_logo16_blue[];
extern unsigned char linux_logo16[];
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index 709827f29..67111965f 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -1,4 +1,4 @@
-
+#ifdef __KERNEL__
#ifndef _PPC_MACHDEP_H
#define _PPC_MACHDEP_H
@@ -101,3 +101,4 @@ typedef enum sys_ctrler_kind {
extern sys_ctrler_t sys_ctrler;
#endif /* _PPC_MACHDEP_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mbx.h b/include/asm-ppc/mbx.h
index 6c84b8955..a3e8f9b32 100644
--- a/include/asm-ppc/mbx.h
+++ b/include/asm-ppc/mbx.h
@@ -1,4 +1,3 @@
-
/*
* A collection of structures, addresses, and values associated with
* the Motorola MBX boards. This was originally created for the
@@ -8,6 +7,7 @@
*
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
*/
+#ifdef __KERNEL__
#ifndef __MACH_MBX_DEFS
#define __MACH_MBX_DEFS
@@ -87,3 +87,4 @@ typedef struct bd_info {
*/
#define _MACH_8xx (_MACH_mbx)
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
index f7a479fff..227018b2f 100644
--- a/include/asm-ppc/mc146818rtc.h
+++ b/include/asm-ppc/mc146818rtc.h
@@ -1,6 +1,7 @@
/*
* Machine dependent access functions for RTC registers.
*/
+#ifdef __KERNEL__
#ifndef __ASM_PPC_MC146818RTC_H
#define __ASM_PPC_MC146818RTC_H
@@ -27,3 +28,4 @@ outb_p((val),RTC_PORT(1)); \
#define RTC_IRQ 8
#endif /* __ASM_PPC_MC146818RTC_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/md.h b/include/asm-ppc/md.h
index 0ff3e7e92..79c3a22c6 100644
--- a/include/asm-ppc/md.h
+++ b/include/asm-ppc/md.h
@@ -3,6 +3,7 @@
*
*/
+#ifdef __KERNEL__
#ifndef __ASM_MD_H
#define __ASM_MD_H
@@ -11,3 +12,4 @@
#define MD_XORBLOCK_ALIGNMENT sizeof(long)
#endif /* __ASM_MD_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h
index a634d7f20..963555776 100644
--- a/include/asm-ppc/mediabay.h
+++ b/include/asm-ppc/mediabay.h
@@ -7,13 +7,13 @@
#ifndef _PPC_MEDIABAY_H
#define _PPC_MEDIABAY_H
+#ifdef __KERNEL__
+
#define MB_FD 0 /* media bay contains floppy drive */
#define MB_FD1 1 /* media bay contains floppy drive */
#define MB_CD 3 /* media bay contains ATA drive such as CD */
#define MB_NO 7 /* media bay contains nothing */
-#ifdef __KERNEL__
-
void media_bay_init(void);
int check_media_bay(struct device_node *which_bay, int what);
int check_media_bay_by_base(unsigned long base, int what);
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index 4a3a42f26..2fe5cfe71 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -2,6 +2,7 @@
* PowerPC memory management structures
*/
+#ifdef __KERNEL__
#ifndef _PPC_MMU_H_
#define _PPC_MMU_H_
@@ -363,3 +364,4 @@ extern void _tlbia(void); /* invalidate all TLB entries */
#define TLB_G 0x00000001 /* Memory is guarded from prefetch */
#endif /* _PPC_MMU_H_ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 414dd1cdc..fed474d14 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -1,5 +1,6 @@
#include <linux/config.h>
+#ifdef __KERNEL__
#ifndef __PPC_MMU_CONTEXT_H
#define __PPC_MMU_CONTEXT_H
@@ -112,3 +113,4 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm
((segment < 8) ? ((segment) | (context)<<4) : (segment))
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/module.h b/include/asm-ppc/module.h
new file mode 100644
index 000000000..77133a1cf
--- /dev/null
+++ b/include/asm-ppc/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_PPC_MODULE_H
+#define _ASM_PPC_MODULE_H
+/*
+ * This file contains the PPC architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_PPC_MODULE_H */
diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
index 10d586cad..94a054b57 100644
--- a/include/asm-ppc/mpc8260.h
+++ b/include/asm-ppc/mpc8260.h
@@ -5,6 +5,7 @@
* file that has to include MPC8260 configuration, they all include
* this one and the configuration switching is done here.
*/
+#ifdef __KERNEL__
#ifndef __CONFIG_8260_DEFS
#define __CONFIG_8260_DEFS
@@ -40,3 +41,4 @@ extern int request_8xxirq(unsigned int irq,
#endif /* CONFIG_8260 */
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
index db327b76a..2476f7540 100644
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -5,6 +5,7 @@
* file that has to include MPC8xx configuration, they all include
* this one and the configuration switching is done here.
*/
+#ifdef __KERNEL__
#ifndef __CONFIG_8xx_DEFS
#define __CONFIG_8xx_DEFS
@@ -79,3 +80,4 @@ extern int request_8xxirq(unsigned int irq,
void *dev_id);
#endif /* CONFIG_8xx */
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/msgbuf.h b/include/asm-ppc/msgbuf.h
index ebfb950a2..3432b9b36 100644
--- a/include/asm-ppc/msgbuf.h
+++ b/include/asm-ppc/msgbuf.h
@@ -7,7 +7,6 @@
struct msqid64_ds {
struct ipc64_perm msg_perm;
- unsigned int __unused0;
unsigned int __unused1;
__kernel_time_t msg_stime; /* last msgsnd time */
unsigned int __unused2;
diff --git a/include/asm-ppc/namei.h b/include/asm-ppc/namei.h
index cd871903d..0bd54a034 100644
--- a/include/asm-ppc/namei.h
+++ b/include/asm-ppc/namei.h
@@ -5,6 +5,7 @@
* Included from linux/fs/namei.c
*/
+#ifdef __KERNEL__
#ifndef __PPC_NAMEI_H
#define __PPC_NAMEI_H
@@ -16,3 +17,4 @@
#define __emul_prefix() NULL
#endif /* __PPC_NAMEI_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h
index 144d518b9..7f6fc08b1 100644
--- a/include/asm-ppc/nvram.h
+++ b/include/asm-ppc/nvram.h
@@ -2,6 +2,7 @@
* PreP compliant NVRAM access
*/
+#ifdef __KERNEL__
#ifndef _PPC_NVRAM_H
#define _PPC_NVRAM_H
@@ -64,3 +65,4 @@ struct pmac_machine_location {
#define PMAC_NVRAM_GET_OFFSET _IOWR('p', 0x40, int) /* Get NVRAM partition offset */
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/oak.h b/include/asm-ppc/oak.h
index c906f5c4d..63f316401 100644
--- a/include/asm-ppc/oak.h
+++ b/include/asm-ppc/oak.h
@@ -11,6 +11,7 @@
*
*/
+#ifdef __KERNEL__
#ifndef __OAK_H__
#define __OAK_H__
@@ -66,3 +67,4 @@ typedef struct board_info {
#endif
#endif /* __OAK_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
index dee0ced3a..d4c104f8d 100644
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -1,8 +1,3 @@
-#include <linux/config.h>
-#ifndef __ASSEMBLY__
-#include <asm/system.h> /* for xmon definition */
-#endif /* ndef __ASSEMBLY__ */
-
#ifndef _PPC_PAGE_H
#define _PPC_PAGE_H
@@ -11,11 +6,14 @@
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
+#ifdef __KERNEL__
+#include <linux/config.h>
+
#define PAGE_OFFSET 0xc0000000
#define KERNELBASE PAGE_OFFSET
#ifndef __ASSEMBLY__
-#ifdef __KERNEL__
+#include <asm/system.h> /* for xmon definition */
#ifdef CONFIG_XMON
#define BUG() do { \
@@ -134,6 +132,6 @@ extern __inline__ int get_order(unsigned long size)
return order;
}
-#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc/param.h b/include/asm-ppc/param.h
index 93d6fc52c..923a3fe60 100644
--- a/include/asm-ppc/param.h
+++ b/include/asm-ppc/param.h
@@ -20,4 +20,8 @@
#define MAXHOSTNAMELEN 64 /* max length of hostname */
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */
+#endif
+
#endif
diff --git a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
index 5aa72d3a2..9e5385e51 100644
--- a/include/asm-ppc/pci-bridge.h
+++ b/include/asm-ppc/pci-bridge.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _ASM_PCI_BRIDGE_H
#define _ASM_PCI_BRIDGE_H
@@ -46,3 +47,4 @@ struct bridge_data {
};
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index a9da1b195..1a661f050 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -1,12 +1,12 @@
#ifndef __PPC_PCI_H
#define __PPC_PCI_H
+#ifdef __KERNEL__
/* Values for the `which' argument to sys_pciconfig_iobase syscall. */
#define IOBASE_BRIDGE_NUMBER 0
#define IOBASE_MEMORY 1
#define IOBASE_IO 2
-#ifdef __KERNEL__
/* Can be used to override the logic in pci_scan_bus for skipping
* already-configured bus numbers - to be used for buggy BIOSes
diff --git a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
index 6166a1bfb..7da57a6f2 100644
--- a/include/asm-ppc/pgalloc.h
+++ b/include/asm-ppc/pgalloc.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_PGALLOC_H
#define _PPC_PGALLOC_H
@@ -51,33 +52,6 @@ extern unsigned long get_zero_page_fast(void);
extern void __bad_pte(pmd_t *pmd);
-extern inline void set_pgdir(unsigned long address, pgd_t entry)
-{
- struct task_struct * p;
- pgd_t *pgd;
-#ifdef CONFIG_SMP
- int i;
-#endif
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (!p->mm)
- continue;
- *pgd_offset(p->mm,address) = entry;
- }
- read_unlock(&tasklist_lock);
-#ifndef CONFIG_SMP
- for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
- pgd[address >> PGDIR_SHIFT] = entry;
-#else
- /* To pgd_alloc/pgd_free, one holds master kernel lock and so does our callee, so we can
- modify pgd caches of other CPUs as well. -jj */
- for (i = 0; i < NR_CPUS; i++)
- for (pgd = (pgd_t *)cpu_data[i].pgd_cache; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
- pgd[address >> PGDIR_SHIFT] = entry;
-#endif
-}
-
/* We don't use pmd cache, so this is a dummy routine */
extern __inline__ pmd_t *get_pmd_fast(void)
{
@@ -200,3 +174,4 @@ extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
extern int do_check_pgt_cache(int, int);
#endif /* _PPC_PGALLOC_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index 27c89e13e..0f4579cd7 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
@@ -451,9 +452,6 @@ extern void flush_hash_page(unsigned context, unsigned long va);
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
/* CONFIG_APUS */
/* For virtual address to physical address conversion */
extern void cache_clear(__u32 addr, int length);
@@ -492,3 +490,4 @@ extern void kernel_set_cachemode (unsigned long address, unsigned long size,
#endif __ASSEMBLY__
#endif /* _PPC_PGTABLE_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/pnp.h b/include/asm-ppc/pnp.h
index 15335ff35..6f6760b30 100644
--- a/include/asm-ppc/pnp.h
+++ b/include/asm-ppc/pnp.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
/* 11/02/95 */
/*----------------------------------------------------------------------------*/
/* Plug and Play header definitions */
@@ -641,3 +642,4 @@ typedef union _PnP_TAG_PACKET {
#endif /* __ASSEMBLY__ */
#endif /* ndef _PNP_ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/prep_nvram.h b/include/asm-ppc/prep_nvram.h
index 2f0f80b5c..82ec21508 100644
--- a/include/asm-ppc/prep_nvram.h
+++ b/include/asm-ppc/prep_nvram.h
@@ -17,6 +17,7 @@
For enum's: if given in hex then they are bit significant, i.e. only
one bit is on for each enum.
*/
+#ifdef __KERNEL__
#ifndef _PPC_PREP_NVRAM_H
#define _PPC_PREP_NVRAM_H
@@ -144,3 +145,4 @@ void prep_nvram_write_val(int addr,
unsigned char val);
#endif /* _PPC_PREP_NVRAM_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
index f99eb4abe..cfd49807e 100644
--- a/include/asm-ppc/processor.h
+++ b/include/asm-ppc/processor.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASM_PPC_PROCESSOR_H
#define __ASM_PPC_PROCESSOR_H
@@ -727,3 +728,4 @@ void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
#endif /* CONFIG_MACH_SPECIFIC */
#endif /* __ASM_PPC_PROCESSOR_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index dc98c596d..0c57690ea 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -4,6 +4,7 @@
*
* Copyright (C) 1996 Paul Mackerras.
*/
+#ifdef __KERNEL__
#ifndef _PPC_PROM_H
#define _PPC_PROM_H
@@ -98,3 +99,4 @@ extern void map_bootx_text(void);
#endif /* _PPC_PROM_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
index 93a75bd87..b154187e6 100644
--- a/include/asm-ppc/ptrace.h
+++ b/include/asm-ppc/ptrace.h
@@ -17,32 +17,26 @@
* the PT_* values below. This simplifies arch/ppc/kernel/ptrace.c.
*/
-#include <linux/config.h>
-
#ifndef __ASSEMBLY__
-#ifdef CONFIG_PPC64BRIDGE
-#define PPC_REG unsigned long /*long*/
-#else
-#define PPC_REG unsigned long
-#endif
struct pt_regs {
- PPC_REG gpr[32];
- PPC_REG nip;
- PPC_REG msr;
- PPC_REG orig_gpr3; /* Used for restarting system calls */
- PPC_REG ctr;
- PPC_REG link;
- PPC_REG xer;
- PPC_REG ccr;
- PPC_REG mq; /* 601 only (not used at present) */
- /* Used on APUS to hold IPL value. */
- PPC_REG trap; /* Reason for being here */
- PPC_REG dar; /* Fault registers */
- PPC_REG dsisr;
- PPC_REG result; /* Result of a system call */
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ unsigned long trap; /* Reason for being here */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+ unsigned long result; /* Result of a system call */
};
#endif
+#ifdef __KERNEL__
#define STACK_FRAME_OVERHEAD 16 /* size of minimum stack frame */
/* Size of stack frame allocated when calling signal handler. */
@@ -51,6 +45,8 @@ struct pt_regs {
#define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
+#endif /* __KERNEL__ */
+
/*
* Offsets used by 'ptrace' system call interface.
* These can't be changed without breaking binary compatibility
diff --git a/include/asm-ppc/raven.h b/include/asm-ppc/raven.h
index 62f996f66..ee873ff82 100644
--- a/include/asm-ppc/raven.h
+++ b/include/asm-ppc/raven.h
@@ -8,6 +8,7 @@
* for more details.
*/
+#ifdef __KERNEL__
#ifndef _ASMPPC_RAVEN_H
#define _ASMPPC_RAVEN_H
@@ -31,3 +32,4 @@ extern struct hw_interrupt_type raven_pic;
extern int raven_init(void);
#endif _ASMPPC_RAVEN_H
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/residual.h b/include/asm-ppc/residual.h
index c037a4e4a..685c04502 100644
--- a/include/asm-ppc/residual.h
+++ b/include/asm-ppc/residual.h
@@ -10,6 +10,7 @@
/* i.e. only one bit is on for each enum */
/* Reserved fields must be filled with zeros. */
+#ifdef __KERNEL__
#ifndef _RESIDUAL_
#define _RESIDUAL_
@@ -330,3 +331,4 @@ extern PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p,
#endif /* __ASSEMBLY__ */
#endif /* ndef _RESIDUAL_ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/rpxclassic.h b/include/asm-ppc/rpxclassic.h
index b84a20d12..0583b60fb 100644
--- a/include/asm-ppc/rpxclassic.h
+++ b/include/asm-ppc/rpxclassic.h
@@ -5,6 +5,7 @@
*
* Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
*/
+#ifdef __KERNEL__
#ifndef __MACH_RPX_DEFS
#define __MACH_RPX_DEFS
@@ -82,3 +83,4 @@ extern bd_t m8xx_board_info;
#define _MACH_8xx (_MACH_classic)
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/rpxlite.h b/include/asm-ppc/rpxlite.h
index c0cc7e0a6..1d447082b 100644
--- a/include/asm-ppc/rpxlite.h
+++ b/include/asm-ppc/rpxlite.h
@@ -5,6 +5,7 @@
*
* Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
*/
+#ifdef __KERNEL__
#ifndef __MACH_RPX_DEFS
#define __MACH_RPX_DEFS
@@ -65,3 +66,4 @@ extern bd_t m8xx_board_info;
#define _MACH_8xx (_MACH_rpxlite)
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/scatterlist.h b/include/asm-ppc/scatterlist.h
index f81590716..5c6b01c99 100644
--- a/include/asm-ppc/scatterlist.h
+++ b/include/asm-ppc/scatterlist.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_SCATTERLIST_H
#define _PPC_SCATTERLIST_H
@@ -12,3 +13,4 @@ struct scatterlist {
#endif /* !(_PPC_SCATTERLIST_H) */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/semaphore-helper.h b/include/asm-ppc/semaphore-helper.h
index 3033272d9..14f2c0e2e 100644
--- a/include/asm-ppc/semaphore-helper.h
+++ b/include/asm-ppc/semaphore-helper.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_SEMAPHORE_HELPER_H
#define _PPC_SEMAPHORE_HELPER_H
@@ -105,3 +106,4 @@ static inline int waking_non_zero_trylock(struct semaphore *sem)
}
#endif /* _PPC_SEMAPHORE_HELPER_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/sembuf.h b/include/asm-ppc/sembuf.h
index 6b6a182a8..d0ab55833 100644
--- a/include/asm-ppc/sembuf.h
+++ b/include/asm-ppc/sembuf.h
@@ -7,7 +7,6 @@
struct semid64_ds {
struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
- unsigned int __unused0;
unsigned int __unused1;
__kernel_time_t sem_otime; /* last semop time */
unsigned int __unused2;
diff --git a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
index b6b89dc79..60c1a14ff 100644
--- a/include/asm-ppc/serial.h
+++ b/include/asm-ppc/serial.h
@@ -2,6 +2,7 @@
* include/asm-ppc/serial.h
*/
+#ifdef __KERNEL__
#include <linux/config.h>
#ifdef CONFIG_GEMINI
@@ -127,3 +128,4 @@
MCA_SERIAL_PORT_DFNS
#endif /* CONFIG_GEMINI */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/setup.h b/include/asm-ppc/setup.h
index 2f9164160..cd458c4f1 100644
--- a/include/asm-ppc/setup.h
+++ b/include/asm-ppc/setup.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_SETUP_H
#define _PPC_SETUP_H
@@ -7,3 +8,4 @@
#include <asm-m68k/setup.h>
#endif /* _PPC_SETUP_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/shmbuf.h b/include/asm-ppc/shmbuf.h
index df84f0b09..ec614e8c6 100644
--- a/include/asm-ppc/shmbuf.h
+++ b/include/asm-ppc/shmbuf.h
@@ -7,19 +7,19 @@
struct shmid64_ds {
struct ipc64_perm shm_perm; /* operation perms */
- unsigned int __unused0;
- size_t shm_segsz; /* size of segment (bytes) */
- unsigned long __unused1;
+ unsigned int __unused1;
__kernel_time_t shm_atime; /* last attach time */
- unsigned long __unused2;
+ unsigned int __unused2;
__kernel_time_t shm_dtime; /* last detach time */
- unsigned long __unused3;
+ unsigned int __unused3;
__kernel_time_t shm_ctime; /* last change time */
+ unsigned int __unused4;
+ size_t shm_segsz; /* size of segment (bytes) */
__kernel_pid_t shm_cpid; /* pid of creator */
__kernel_pid_t shm_lpid; /* pid of last operator */
unsigned long shm_nattch; /* no. of current attaches */
- unsigned long __unused4;
unsigned long __unused5;
+ unsigned long __unused6;
};
struct shminfo64 {
diff --git a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
index 3b0bd261d..74a16e0b2 100644
--- a/include/asm-ppc/siginfo.h
+++ b/include/asm-ppc/siginfo.h
@@ -3,8 +3,6 @@
/* Copied from i386 from alpha. */
-#include <linux/types.h>
-
typedef union sigval {
int sival_int;
void *sival_ptr;
diff --git a/include/asm-ppc/signal.h b/include/asm-ppc/signal.h
index f5025a161..4958b3f35 100644
--- a/include/asm-ppc/signal.h
+++ b/include/asm-ppc/signal.h
@@ -1,7 +1,9 @@
#ifndef _ASMPPC_SIGNAL_H
#define _ASMPPC_SIGNAL_H
+#ifdef __KERNEL__
#include <linux/types.h>
+#endif /* __KERNEL__ */
/* Avoid too many header ordering problems. */
struct siginfo;
diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
index abbd0ca0c..4851e13fd 100644
--- a/include/asm-ppc/smp.h
+++ b/include/asm-ppc/smp.h
@@ -3,6 +3,7 @@
* Taken from asm-sparc/smp.h
*/
+#ifdef __KERNEL__
#ifndef _PPC_SMP_H
#define _PPC_SMP_H
@@ -59,3 +60,4 @@ extern struct klock_info_struct klock_info;
#endif /* !(CONFIG_SMP) */
#endif /* !(_PPC_SMP_H) */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/smplock.h b/include/asm-ppc/smplock.h
index 96565069c..5fdd5733b 100644
--- a/include/asm-ppc/smplock.h
+++ b/include/asm-ppc/smplock.h
@@ -3,6 +3,7 @@
*
* Default SMP lock implementation
*/
+#ifdef __KERNEL__
#include <linux/interrupt.h>
#include <linux/spinlock.h>
@@ -49,3 +50,4 @@ extern __inline__ void unlock_kernel(void)
if (--current->lock_depth < 0)
spin_unlock(&kernel_flag);
}
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h
index 4eaed0be6..20898d818 100644
--- a/include/asm-ppc/softirq.h
+++ b/include/asm-ppc/softirq.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASM_SOFTIRQ_H
#define __ASM_SOFTIRQ_H
@@ -10,3 +11,4 @@
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif /* __ASM_SOFTIRQ_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
index 292406736..eae7df4a5 100644
--- a/include/asm-ppc/spinlock.h
+++ b/include/asm-ppc/spinlock.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __ASM_SPINLOCK_H
#define __ASM_SPINLOCK_H
@@ -54,3 +55,4 @@ extern void _write_unlock(rwlock_t *rw);
#define read_unlock(rw) _read_unlock(rw)
#endif /* __ASM_SPINLOCK_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/stat.h b/include/asm-ppc/stat.h
index 204b07e6e..ed382adc8 100644
--- a/include/asm-ppc/stat.h
+++ b/include/asm-ppc/stat.h
@@ -1,7 +1,9 @@
#ifndef _PPC_STAT_H
#define _PPC_STAT_H
+#ifdef __KERNEL__
#include <linux/types.h>
+#endif /* __KERNEL__ */
struct __old_kernel_stat {
unsigned short st_dev;
diff --git a/include/asm-ppc/string.h b/include/asm-ppc/string.h
index d912a6b5f..557e3ad0e 100644
--- a/include/asm-ppc/string.h
+++ b/include/asm-ppc/string.h
@@ -1,6 +1,8 @@
#ifndef _PPC_STRING_H_
#define _PPC_STRING_H_
+#ifdef __KERNEL__
+
#define __HAVE_ARCH_STRCPY
#define __HAVE_ARCH_STRNCPY
#define __HAVE_ARCH_STRLEN
@@ -26,4 +28,6 @@ extern void * memmove(void *,const void *,__kernel_size_t);
extern int memcmp(const void *,const void *,__kernel_size_t);
extern void * memchr(const void *,int,__kernel_size_t);
+#endif /* __KERNEL__ */
+
#endif
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 523a427a0..571d2c81f 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
*/
+#ifdef __KERNEL__
#ifndef __PPC_SYSTEM_H
#define __PPC_SYSTEM_H
@@ -224,3 +225,4 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
})
#endif /* __PPC_SYSTEM_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h
index 324b62600..52e6d2d52 100644
--- a/include/asm-ppc/termbits.h
+++ b/include/asm-ppc/termbits.h
@@ -1,8 +1,6 @@
#ifndef _PPC_TERMBITS_H
#define _PPC_TERMBITS_H
-#include <linux/posix_types.h>
-
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h
index 1eb0ae9f0..8f43219a8 100644
--- a/include/asm-ppc/time.h
+++ b/include/asm-ppc/time.h
@@ -6,6 +6,7 @@
* Paul Mackerras' version and mine for PReP and Pmac.
*/
+#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/mc146818rtc.h>
@@ -113,3 +114,4 @@ extern __inline__ unsigned binary_tbl(void) {
({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;})
unsigned mulhwu_scale_factor(unsigned, unsigned);
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/timex.h b/include/asm-ppc/timex.h
index df7a8749d..485ad0053 100644
--- a/include/asm-ppc/timex.h
+++ b/include/asm-ppc/timex.h
@@ -3,6 +3,7 @@
*
* ppc architecture timex specifications
*/
+#ifdef __KERNEL__
#ifndef _ASMppc_TIMEX_H
#define _ASMppc_TIMEX_H
@@ -39,3 +40,4 @@ static inline cycles_t get_cycles(void)
}
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/tqm860.h b/include/asm-ppc/tqm860.h
index a42b7b277..733dcccdb 100644
--- a/include/asm-ppc/tqm860.h
+++ b/include/asm-ppc/tqm860.h
@@ -10,6 +10,7 @@
*
* Copyright (c) 1999 Wolfgang Denk (wd@denx.de)
*/
+#ifdef __KERNEL__
#ifndef __MACH_TQM860_DEFS
#define __MACH_TQM860_DEFS
@@ -63,3 +64,4 @@ typedef struct bd_info {
#endif /* __MACH_TQM860_DEFS */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/tqm8xxL.h b/include/asm-ppc/tqm8xxL.h
index e51e98080..338396aa6 100644
--- a/include/asm-ppc/tqm8xxL.h
+++ b/include/asm-ppc/tqm8xxL.h
@@ -10,6 +10,7 @@
*
* Copyright (c) 1999 Wolfgang Denk (wd@denx.de)
*/
+#ifdef __KERNEL__
#ifndef __MACH_TQM8xxL_DEFS
#define __MACH_TQM8xxL_DEFS
@@ -64,3 +65,4 @@ typedef struct bd_info {
#endif /* __MACH_TQM8xxL_DEFS */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h
index 4ebbb9e02..6734fa276 100644
--- a/include/asm-ppc/types.h
+++ b/include/asm-ppc/types.h
@@ -3,8 +3,6 @@
#ifndef __ASSEMBLY__
-typedef unsigned short umode_t;
-
typedef __signed__ char __s8;
typedef unsigned char __u8;
@@ -21,7 +19,7 @@ typedef unsigned long long __u64;
typedef struct {
__u32 u[4];
-} __attribute((aligned(16))) vector128;
+} __attribute((aligned(16))) __vector128;
#ifdef __KERNEL__
/*
@@ -39,11 +37,15 @@ typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
+typedef __vector128 vector128;
+
#define BITS_PER_LONG 32
/* DMA addresses are 32-bits wide */
typedef u32 dma_addr_t;
+typedef unsigned short umode_t;
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
index 628373b15..cd87905b0 100644
--- a/include/asm-ppc/uaccess.h
+++ b/include/asm-ppc/uaccess.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_UACCESS_H
#define _PPC_UACCESS_H
@@ -274,3 +275,4 @@ extern __inline__ int strnlen_user(const char *str, long len)
#endif /* __ASSEMBLY__ */
#endif /* _PPC_UACCESS_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/unaligned.h b/include/asm-ppc/unaligned.h
index 90a54eae9..797ffd6e4 100644
--- a/include/asm-ppc/unaligned.h
+++ b/include/asm-ppc/unaligned.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef __PPC_UNALIGNED_H
#define __PPC_UNALIGNED_H
@@ -14,3 +15,4 @@
#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h
index eefe4389c..b21cc8931 100644
--- a/include/asm-ppc/uninorth.h
+++ b/include/asm-ppc/uninorth.h
@@ -3,6 +3,7 @@
* from Apple. This chip is used on "Core99" machines
*
*/
+#ifdef __KERNEL__
/*
@@ -79,5 +80,4 @@
*/
#define UNI_N_HWINIT_STATE_CPU1_FLAG 0x10000000
-
-
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/user.h b/include/asm-ppc/user.h
index e3bd611b3..d662b2151 100644
--- a/include/asm-ppc/user.h
+++ b/include/asm-ppc/user.h
@@ -1,3 +1,4 @@
+#ifdef __KERNEL__
#ifndef _PPC_USER_H
#define _PPC_USER_H
@@ -50,3 +51,4 @@ struct user {
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
#endif /* _PPC_USER_H */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/vga.h b/include/asm-ppc/vga.h
index 69e3d7f9a..c5864734e 100644
--- a/include/asm-ppc/vga.h
+++ b/include/asm-ppc/vga.h
@@ -4,6 +4,7 @@
* (c) 1998 Martin Mares <mj@ucw.cz>
*/
+#ifdef __KERNEL__
#ifndef _LINUX_ASM_VGA_H_
#define _LINUX_ASM_VGA_H_
@@ -42,3 +43,4 @@ extern unsigned long vgacon_remap_base;
#define vga_writeb(x,y) (*(y) = (x))
#endif
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/walnut.h b/include/asm-ppc/walnut.h
index 84499af8a..45a92bbb3 100644
--- a/include/asm-ppc/walnut.h
+++ b/include/asm-ppc/walnut.h
@@ -11,6 +11,7 @@
*
*/
+#ifdef __KERNEL__
#ifndef __WALNUT_H__
#define __WALNUT_H__
@@ -26,3 +27,4 @@ extern "C" {
#endif
#endif /* __WALNUT_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/xor.h b/include/asm-ppc/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-ppc/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-s390/module.h b/include/asm-s390/module.h
new file mode 100644
index 000000000..173869666
--- /dev/null
+++ b/include/asm-s390/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_S390_MODULE_H
+#define _ASM_S390_MODULE_H
+/*
+ * This file contains the s390 architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_S390_MODULE_H */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index ae4f3b505..6906a875a 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -405,9 +405,6 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
#include <asm-generic/pgtable.h>
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-s390/xor.h b/include/asm-s390/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-s390/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-sh/module.h b/include/asm-sh/module.h
new file mode 100644
index 000000000..62751b0fa
--- /dev/null
+++ b/include/asm-sh/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_SH_MODULE_H
+#define _ASM_SH_MODULE_H
+/*
+ * This file contains the SH architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_SH_MODULE_H */
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 323b7eb7c..2246e5c0d 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -254,9 +254,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define module_map vmalloc
-#define module_unmap vfree
-
#include <asm-generic/pgtable.h>
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-sh/xor.h b/include/asm-sh/xor.h
new file mode 100644
index 000000000..c82eb12a5
--- /dev/null
+++ b/include/asm-sh/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/include/asm-sparc/bpp.h b/include/asm-sparc/bpp.h
index d1b967a00..ad4a84571 100644
--- a/include/asm-sparc/bpp.h
+++ b/include/asm-sparc/bpp.h
@@ -70,13 +70,4 @@
# define BPP_GP_Select 0x0800
# define BPP_GP_nFault 0x1000
-
-/*
- * Prototype for the initialization routine.
- */
-
-#ifdef __KERNEL__
-extern int bpp_init(void);
-#endif
-
#endif
diff --git a/include/asm-sparc/ethtool.h b/include/asm-sparc/ethtool.h
deleted file mode 100644
index 572db24fb..000000000
--- a/include/asm-sparc/ethtool.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $Id: ethtool.h,v 1.2 2000/01/31 04:59:17 davem Exp $
- * ethtool.h: Defines for SparcLinux ethtool.
- *
- * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- */
-
-#ifndef _SPARC_ETHTOOL_H
-#define _SPARC_ETHTOOL_H
-
-/* We do things like this so it does not matter what kernel
- * headers you have on your system etc.
- */
-#undef SIOCETHTOOL
-#define SIOCETHTOOL (SIOCDEVPRIVATE + 0x0f)
-
-/* This should work for both 32 and 64 bit userland. */
-struct ethtool_cmd {
- u32 cmd;
- u32 supported;
- u16 speed;
- u8 duplex;
- u8 port;
- u8 phy_address;
- u8 transceiver;
- u8 autoneg;
-};
-
-/* CMDs currently supported */
-#define SPARC_ETH_GSET 0x00000001 /* Get settings, non-privileged. */
-#define SPARC_ETH_SSET 0x00000002 /* Set settings, privileged. */
-
-/* Indicates what features are supported by the interface. */
-#define SUPPORTED_10baseT_Half 0x00000001
-#define SUPPORTED_10baseT_Full 0x00000002
-#define SUPPORTED_100baseT_Half 0x00000004
-#define SUPPORTED_100baseT_Full 0x00000008
-#define SUPPORTED_1000baseT_Half 0x00000010
-#define SUPPORTED_1000baseT_Full 0x00000020
-#define SUPPORTED_Autoneg 0x00000040
-#define SUPPORTED_TP 0x00000080
-#define SUPPORTED_AUI 0x00000100
-#define SUPPORTED_MII 0x00000200
-#define SUPPORTED_FIBRE 0x00000400
-
-/* The following are all involved in forcing a particular link
- * mode for the device for setting things. When getting the
- * devices settings, these indicate the current mode and whether
- * it was foced up into this mode or autonegotiated.
- */
-
-/* The forced speec, 10Mb, 100Mb, gigabit. */
-#define SPEED_10 10
-#define SPEED_100 100
-#define SPEED_1000 1000
-
-/* Duplex, half or full. */
-#define DUPLEX_HALF 0x00
-#define DUPLEX_FULL 0x01
-
-/* Which connector port. */
-#define PORT_TP 0x00
-#define PORT_AUI 0x01
-#define PORT_MII 0x02
-#define PORT_FIBRE 0x03
-
-/* Which tranceiver to use. */
-#define XCVR_INTERNAL 0x00
-#define XCVR_EXTERNAL 0x01
-#define XCVR_DUMMY1 0x02
-#define XCVR_DUMMY2 0x03
-#define XCVR_DUMMY3 0x04
-
-/* Enable or disable autonegotiation. If this is set to enable,
- * the forced link modes above are completely ignored.
- */
-#define AUTONEG_DISABLE 0x00
-#define AUTONEG_ENABLE 0x01
-
-#endif /* _SPARC_ETHTOOL_H */
diff --git a/include/asm-sparc/highmem.h b/include/asm-sparc/highmem.h
index 0724061e4..179f1a3cb 100644
--- a/include/asm-sparc/highmem.h
+++ b/include/asm-sparc/highmem.h
@@ -49,19 +49,19 @@ extern void kmap_init(void) __init;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
-extern unsigned long kmap_high(struct page *page);
+extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-extern inline unsigned long kmap(struct page *page)
+static inline void *kmap(struct page *page)
{
if (in_interrupt())
BUG();
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
return kmap_high(page);
}
-extern inline void kunmap(struct page *page)
+static inline void kunmap(struct page *page)
{
if (in_interrupt())
BUG();
@@ -76,13 +76,13 @@ extern inline void kunmap(struct page *page)
* be used in IRQ contexts, so in some (very limited) cases we need
* it.
*/
-extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic(struct page *page, enum km_type type)
{
unsigned long idx;
unsigned long vaddr;
if (page < highmem_start_page)
- return (unsigned long) page_address(page);
+ return page_address(page);
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = FIX_KMAP_BEGIN + idx * PAGE_SIZE;
@@ -106,12 +106,13 @@ extern inline unsigned long kmap_atomic(struct page *page, enum km_type type)
flush_tlb_all();
#endif
- return vaddr;
+ return (void*) vaddr;
}
-extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type)
+static inline void kunmap_atomic(void *kvaddr, enum km_type type)
{
#if HIGHMEM_DEBUG
+ unsigned long vaddr = (unsigned long) kvaddr;
unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
#if 0
diff --git a/include/asm-sparc/module.h b/include/asm-sparc/module.h
new file mode 100644
index 000000000..45c02931c
--- /dev/null
+++ b/include/asm-sparc/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_SPARC_MODULE_H
+#define _ASM_SPARC_MODULE_H
+/*
+ * This file contains the sparc architecture specific module code.
+ */
+
+#define module_map(x) vmalloc(x)
+#define module_unmap(x) vfree(x)
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_SPARC_MODULE_H */
diff --git a/include/asm-sparc/openpromio.h b/include/asm-sparc/openpromio.h
index bebb788ac..6e32823ab 100644
--- a/include/asm-sparc/openpromio.h
+++ b/include/asm-sparc/openpromio.h
@@ -64,11 +64,5 @@ struct opiocdesc
#define OPIOCGETNEXT _IOWR('O', 5, int)
#define OPIOCGETCHILD _IOWR('O', 6, int)
-
-#ifdef __KERNEL__
-int openprom_init(void);
-#endif
-
-
#endif /* _SPARC_OPENPROMIO_H */
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 251ff01da..020b68fbb 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.105 2000/10/30 21:01:41 davem Exp $ */
+/* $Id: pgtable.h,v 1.106 2000/11/08 04:49:24 davem Exp $ */
#ifndef _SPARC_PGTABLE_H
#define _SPARC_PGTABLE_H
@@ -437,8 +437,6 @@ __get_iospace (unsigned long addr)
}
}
-#define module_map vmalloc
-#define module_unmap vfree
extern unsigned long *sparc_valid_addr_bitmap;
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff --git a/include/asm-sparc/xor.h b/include/asm-sparc/xor.h
new file mode 100644
index 000000000..f9af76af7
--- /dev/null
+++ b/include/asm-sparc/xor.h
@@ -0,0 +1,273 @@
+/*
+ * include/asm-sparc/xor.h
+ *
+ * Optimized RAID-5 checksumming functions for 32-bit Sparc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * High speed xor_block operation for RAID4/5 utilizing the
+ * ldd/std SPARC instructions.
+ *
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+static void
+sparc_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+ int lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ __asm__ __volatile__("
+ ldd [%0 + 0x00], %%g2
+ ldd [%0 + 0x08], %%g4
+ ldd [%0 + 0x10], %%o0
+ ldd [%0 + 0x18], %%o2
+ ldd [%1 + 0x00], %%o4
+ ldd [%1 + 0x08], %%l0
+ ldd [%1 + 0x10], %%l2
+ ldd [%1 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ std %%g2, [%0 + 0x00]
+ std %%g4, [%0 + 0x08]
+ std %%o0, [%0 + 0x10]
+ std %%o2, [%0 + 0x18]
+ "
+ :
+ : "r" (p1), "r" (p2)
+ : "g2", "g3", "g4", "g5",
+ "o0", "o1", "o2", "o3", "o4", "o5",
+ "l0", "l1", "l2", "l3", "l4", "l5");
+ p1 += 8;
+ p2 += 8;
+ } while (--lines > 0);
+}
+
+static void
+sparc_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3)
+{
+ int lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ __asm__ __volatile__("
+ ldd [%0 + 0x00], %%g2
+ ldd [%0 + 0x08], %%g4
+ ldd [%0 + 0x10], %%o0
+ ldd [%0 + 0x18], %%o2
+ ldd [%1 + 0x00], %%o4
+ ldd [%1 + 0x08], %%l0
+ ldd [%1 + 0x10], %%l2
+ ldd [%1 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%2 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%2 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%2 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%2 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ std %%g2, [%0 + 0x00]
+ std %%g4, [%0 + 0x08]
+ std %%o0, [%0 + 0x10]
+ std %%o2, [%0 + 0x18]
+ "
+ :
+ : "r" (p1), "r" (p2), "r" (p3)
+ : "g2", "g3", "g4", "g5",
+ "o0", "o1", "o2", "o3", "o4", "o5",
+ "l0", "l1", "l2", "l3", "l4", "l5");
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ } while (--lines > 0);
+}
+
+static void
+sparc_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4)
+{
+ int lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ __asm__ __volatile__("
+ ldd [%0 + 0x00], %%g2
+ ldd [%0 + 0x08], %%g4
+ ldd [%0 + 0x10], %%o0
+ ldd [%0 + 0x18], %%o2
+ ldd [%1 + 0x00], %%o4
+ ldd [%1 + 0x08], %%l0
+ ldd [%1 + 0x10], %%l2
+ ldd [%1 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%2 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%2 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%2 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%2 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%3 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%3 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%3 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%3 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ std %%g2, [%0 + 0x00]
+ std %%g4, [%0 + 0x08]
+ std %%o0, [%0 + 0x10]
+ std %%o2, [%0 + 0x18]
+ "
+ :
+ : "r" (p1), "r" (p2), "r" (p3), "r" (p4)
+ : "g2", "g3", "g4", "g5",
+ "o0", "o1", "o2", "o3", "o4", "o5",
+ "l0", "l1", "l2", "l3", "l4", "l5");
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ } while (--lines > 0);
+}
+
+static void
+sparc_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+ unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+ int lines = bytes / (sizeof (long)) / 8;
+
+ do {
+ __asm__ __volatile__("
+ ldd [%0 + 0x00], %%g2
+ ldd [%0 + 0x08], %%g4
+ ldd [%0 + 0x10], %%o0
+ ldd [%0 + 0x18], %%o2
+ ldd [%1 + 0x00], %%o4
+ ldd [%1 + 0x08], %%l0
+ ldd [%1 + 0x10], %%l2
+ ldd [%1 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%2 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%2 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%2 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%2 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%3 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%3 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%3 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%3 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ ldd [%4 + 0x00], %%o4
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ ldd [%4 + 0x08], %%l0
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ ldd [%4 + 0x10], %%l2
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ ldd [%4 + 0x18], %%l4
+ xor %%g2, %%o4, %%g2
+ xor %%g3, %%o5, %%g3
+ xor %%g4, %%l0, %%g4
+ xor %%g5, %%l1, %%g5
+ xor %%o0, %%l2, %%o0
+ xor %%o1, %%l3, %%o1
+ xor %%o2, %%l4, %%o2
+ xor %%o3, %%l5, %%o3
+ std %%g2, [%0 + 0x00]
+ std %%g4, [%0 + 0x08]
+ std %%o0, [%0 + 0x10]
+ std %%o2, [%0 + 0x18]
+ "
+ :
+ : "r" (p1), "r" (p2), "r" (p3), "r" (p4), "r" (p5)
+ : "g2", "g3", "g4", "g5",
+ "o0", "o1", "o2", "o3", "o4", "o5",
+ "l0", "l1", "l2", "l3", "l4", "l5");
+ p1 += 8;
+ p2 += 8;
+ p3 += 8;
+ p4 += 8;
+ p5 += 8;
+ } while (--lines > 0);
+}
+
+static struct xor_block_template xor_block_SPARC = {
+ name: "SPARC",
+ do_2: sparc_2,
+ do_3: sparc_3,
+ do_4: sparc_4,
+ do_5: sparc_5,
+};
+
+/* For grins, also test the generic routines. */
+#include <asm-generic/xor.h>
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES \
+ do { \
+ xor_speed(&xor_block_8regs); \
+ xor_speed(&xor_block_32regs); \
+ xor_speed(&xor_block_SPARC); \
+ } while (0)
diff --git a/include/asm-sparc64/bpp.h b/include/asm-sparc64/bpp.h
index 4b36c9209..eb86015ee 100644
--- a/include/asm-sparc64/bpp.h
+++ b/include/asm-sparc64/bpp.h
@@ -70,13 +70,4 @@
# define BPP_GP_Select 0x0800
# define BPP_GP_nFault 0x1000
-
-/*
- * Prototype for the initialization routine.
- */
-
-#ifdef __KERNEL__
-extern int bpp_init(void);
-#endif
-
#endif
diff --git a/include/asm-sparc64/envctrl.h b/include/asm-sparc64/envctrl.h
index e16de8fb2..53a665381 100644
--- a/include/asm-sparc64/envctrl.h
+++ b/include/asm-sparc64/envctrl.h
@@ -1,4 +1,4 @@
-/* $Id: envctrl.h,v 1.2 2000/10/17 16:20:36 davem Exp $
+/* $Id: envctrl.h,v 1.3 2000/11/03 00:37:40 davem Exp $
*
* envctrl.h: Definitions for access to the i2c environment
* monitoring on Ultrasparc systems.
@@ -54,6 +54,8 @@
#define ENVCTRL_RD_ETHERNET_TEMPERATURE _IOR('p', 0x47, int)
#define ENVCTRL_RD_MTHRBD_TEMPERATURE _IOR('p', 0x48, int)
+#define ENVCTRL_RD_GLOBALADDRESS _IOR('p', 0x49, int)
+
/* Read return values for a voltage status request. */
#define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD 0x01
#define ENVCTRL_VOLTAGE_BAD 0x02
diff --git a/include/asm-sparc64/ethtool.h b/include/asm-sparc64/ethtool.h
deleted file mode 100644
index 18d86c3de..000000000
--- a/include/asm-sparc64/ethtool.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* $Id: ethtool.h,v 1.2 2000/01/31 04:59:19 davem Exp $
- * ethtool.h: Defines for SparcLinux ethtool.
- *
- * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- */
-
-#ifndef _SPARC64_ETHTOOL_H
-#define _SPARC64_ETHTOOL_H
-
-/* We do things like this so it does not matter what kernel
- * headers you have on your system etc.
- */
-#undef SIOCETHTOOL
-#define SIOCETHTOOL (SIOCDEVPRIVATE + 0x0f)
-
-/* This should work for both 32 and 64 bit userland. */
-struct ethtool_cmd {
- u32 cmd;
- u32 supported;
- u16 speed;
- u8 duplex;
- u8 port;
- u8 phy_address;
- u8 transceiver;
- u8 autoneg;
-};
-
-/* CMDs currently supported */
-#define SPARC_ETH_GSET 0x00000001 /* Get settings, non-privileged. */
-#define SPARC_ETH_SSET 0x00000002 /* Set settings, privileged. */
-
-/* Indicates what features are supported by the interface. */
-#define SUPPORTED_10baseT_Half 0x00000001
-#define SUPPORTED_10baseT_Full 0x00000002
-#define SUPPORTED_100baseT_Half 0x00000004
-#define SUPPORTED_100baseT_Full 0x00000008
-#define SUPPORTED_1000baseT_Half 0x00000010
-#define SUPPORTED_1000baseT_Full 0x00000020
-#define SUPPORTED_Autoneg 0x00000040
-#define SUPPORTED_TP 0x00000080
-#define SUPPORTED_AUI 0x00000100
-#define SUPPORTED_MII 0x00000200
-#define SUPPORTED_FIBRE 0x00000400
-
-/* The following are all involved in forcing a particular link
- * mode for the device for setting things. When getting the
- * devices settings, these indicate the current mode and whether
- * it was foced up into this mode or autonegotiated.
- */
-
-/* The forced speec, 10Mb, 100Mb, gigabit. */
-#define SPEED_10 10
-#define SPEED_100 100
-#define SPEED_1000 1000
-
-/* Duplex, half or full. */
-#define DUPLEX_HALF 0x00
-#define DUPLEX_FULL 0x01
-
-/* Which connector port. */
-#define PORT_TP 0x00
-#define PORT_AUI 0x01
-#define PORT_MII 0x02
-#define PORT_FIBRE 0x03
-
-/* Which tranceiver to use. */
-#define XCVR_INTERNAL 0x00
-#define XCVR_EXTERNAL 0x01
-#define XCVR_DUMMY1 0x02
-#define XCVR_DUMMY2 0x03
-#define XCVR_DUMMY3 0x04
-
-/* Enable or disable autonegotiation. If this is set to enable,
- * the forced link modes above are completely ignored.
- */
-#define AUTONEG_DISABLE 0x00
-#define AUTONEG_ENABLE 0x01
-
-#endif /* _SPARC64_ETHTOOL_H */
diff --git a/include/asm-sparc64/module.h b/include/asm-sparc64/module.h
new file mode 100644
index 000000000..f44977ec8
--- /dev/null
+++ b/include/asm-sparc64/module.h
@@ -0,0 +1,11 @@
+#ifndef _ASM_SPARC64_MODULE_H
+#define _ASM_SPARC64_MODULE_H
+/*
+ * This file contains the sparc64 architecture specific module code.
+ */
+
+extern void * module_map (unsigned long size);
+extern void module_unmap (void *addr);
+#define module_arch_init(x) (0)
+
+#endif /* _ASM_SPARC64_MODULE_H */
diff --git a/include/asm-sparc64/openpromio.h b/include/asm-sparc64/openpromio.h
index 37420b761..555b3b5b1 100644
--- a/include/asm-sparc64/openpromio.h
+++ b/include/asm-sparc64/openpromio.h
@@ -64,11 +64,5 @@ struct opiocdesc
#define OPIOCGETNEXT _IOWR('O', 5, int)
#define OPIOCGETCHILD _IOWR('O', 6, int)
-
-#ifdef __KERNEL__
-int openprom_init(void);
-#endif
-
-
#endif /* _SPARC64_OPENPROMIO_H */
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index be3dde29c..23603f287 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -1,4 +1,4 @@
-/* $Id */
+/* $Id: pgalloc.h,v 1.13 2000/11/06 06:59:04 davem Exp $ */
#ifndef _SPARC64_PGALLOC_H
#define _SPARC64_PGALLOC_H
@@ -21,8 +21,15 @@
/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
#define flush_icache_range(start, end) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
-extern void __flush_dcache_page(void *addr);
-#define flush_dcache_page(page) __flush_dcache_page((page)->virtual)
+
+extern void __flush_dcache_page(void *addr, int flush_icache);
+#define flush_dcache_page(page) \
+do { if ((page)->mapping && !(page)->mapping->i_mmap && !(page)->mapping->i_mmap_shared) \
+ set_bit(PG_dcache_dirty, &(page)->flags); \
+ else \
+ __flush_dcache_page((page)->virtual, \
+ (page)->mapping != NULL); \
+} while(0)
extern void __flush_dcache_range(unsigned long start, unsigned long end);
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 62c4c4ef4..a01042346 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.132 2000/10/19 00:50:16 davem Exp $
+/* $Id: pgtable.h,v 1.135 2000/11/08 04:49:24 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -19,6 +19,8 @@
#ifndef __ASSEMBLY__
+#define PG_dcache_dirty PG_arch_1
+
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
* hook is made available.
@@ -233,7 +235,7 @@ extern pgd_t swapper_pg_dir[1];
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
-extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte);
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
#define flush_icache_page(vma, pg) do { } while(0)
@@ -284,8 +286,6 @@ __get_iospace (unsigned long addr)
return ((sun4u_get_pte (addr) & 0xf0000000) >> 28);
}
-extern void * module_map (unsigned long size);
-extern void module_unmap (void *addr);
extern unsigned long *sparc64_valid_addr_bitmap;
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
diff --git a/include/asm-sparc64/xor.h b/include/asm-sparc64/xor.h
new file mode 100644
index 000000000..0a3e1e876
--- /dev/null
+++ b/include/asm-sparc64/xor.h
@@ -0,0 +1,396 @@
+/*
+ * include/asm-sparc64/xor.h
+ *
+ * High speed xor_block operation for RAID4/5 utilizing the
+ * UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Requirements:
+ * !(((long)dest | (long)sourceN) & (64 - 1)) &&
+ * !(len & 127) && len >= 256
+ *
+ * It is done in pure assembly, as otherwise gcc makes it a non-leaf
+ * function, which is not what we want.
+ */
+
+#include <asm/pstate.h>
+#include <asm/asi.h>
+
+extern void xor_vis_2(unsigned long, unsigned long *, unsigned long *);
+extern void xor_vis_3(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *);
+extern void xor_vis_4(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+extern void xor_vis_5(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *, unsigned long *);
+
+#define _S(x) __S(x)
+#define __S(x) #x
+#define DEF(x) __asm__(#x " = " _S(x))
+
+DEF(FPRS_FEF);
+DEF(FPRS_DU);
+DEF(ASI_BLK_P);
+
+/* ??? We set and use %asi instead of using ASI_BLK_P directly because gas
+ currently does not accept symbolic constants for the ASI specifier. */
+
+__asm__ ("
+ .text
+ .globl xor_vis_2
+ .type xor_vis_2,@function
+xor_vis_2:
+ rd %fprs, %g1
+ andcc %g1, FPRS_FEF|FPRS_DU, %g0
+ be,pt %icc, 0f
+ sethi %hi(VISenter), %g1
+ jmpl %g1 + %lo(VISenter), %g7
+ add %g7, 8, %g7
+0: wr %g0, FPRS_FEF, %fprs
+ rd %asi, %g1
+ wr %g0, ASI_BLK_P, %asi
+ membar #LoadStore|#StoreLoad|#StoreStore
+ sub %o0, 128, %o0
+ ldda [%o1] %asi, %f0
+ ldda [%o2] %asi, %f16
+
+2: ldda [%o1 + 64] %asi, %f32
+ fxor %f0, %f16, %f16
+ fxor %f2, %f18, %f18
+ fxor %f4, %f20, %f20
+ fxor %f6, %f22, %f22
+ fxor %f8, %f24, %f24
+ fxor %f10, %f26, %f26
+ fxor %f12, %f28, %f28
+ fxor %f14, %f30, %f30
+ stda %f16, [%o1] %asi
+ ldda [%o2 + 64] %asi, %f48
+ ldda [%o1 + 128] %asi, %f0
+ fxor %f32, %f48, %f48
+ fxor %f34, %f50, %f50
+ add %o1, 128, %o1
+ fxor %f36, %f52, %f52
+ add %o2, 128, %o2
+ fxor %f38, %f54, %f54
+ subcc %o0, 128, %o0
+ fxor %f40, %f56, %f56
+ fxor %f42, %f58, %f58
+ fxor %f44, %f60, %f60
+ fxor %f46, %f62, %f62
+ stda %f48, [%o1 - 64] %asi
+ bne,pt %xcc, 2b
+ ldda [%o2] %asi, %f16
+
+ ldda [%o1 + 64] %asi, %f32
+ fxor %f0, %f16, %f16
+ fxor %f2, %f18, %f18
+ fxor %f4, %f20, %f20
+ fxor %f6, %f22, %f22
+ fxor %f8, %f24, %f24
+ fxor %f10, %f26, %f26
+ fxor %f12, %f28, %f28
+ fxor %f14, %f30, %f30
+ stda %f16, [%o1] %asi
+ ldda [%o2 + 64] %asi, %f48
+ membar #Sync
+ fxor %f32, %f48, %f48
+ fxor %f34, %f50, %f50
+ fxor %f36, %f52, %f52
+ fxor %f38, %f54, %f54
+ fxor %f40, %f56, %f56
+ fxor %f42, %f58, %f58
+ fxor %f44, %f60, %f60
+ fxor %f46, %f62, %f62
+ stda %f48, [%o1 + 64] %asi
+ membar #Sync|#StoreStore|#StoreLoad
+ wr %g1, %g0, %asi
+ retl
+ wr %g0, 0, %fprs
+ .size xor_vis_2, .-xor_vis_2
+
+
+ .globl xor_vis_3
+ .type xor_vis_3,@function
+xor_vis_3:
+ rd %fprs, %g1
+ andcc %g1, FPRS_FEF|FPRS_DU, %g0
+ be,pt %icc, 0f
+ sethi %hi(VISenter), %g1
+ jmpl %g1 + %lo(VISenter), %g7
+ add %g7, 8, %g7
+0: wr %g0, FPRS_FEF, %fprs
+ rd %asi, %g1
+ wr %g0, ASI_BLK_P, %asi
+ membar #LoadStore|#StoreLoad|#StoreStore
+ sub %o0, 64, %o0
+ ldda [%o1] %asi, %f0
+ ldda [%o2] %asi, %f16
+
+3: ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f48
+ fxor %f2, %f18, %f50
+ add %o1, 64, %o1
+ fxor %f4, %f20, %f52
+ fxor %f6, %f22, %f54
+ add %o2, 64, %o2
+ fxor %f8, %f24, %f56
+ fxor %f10, %f26, %f58
+ fxor %f12, %f28, %f60
+ fxor %f14, %f30, %f62
+ ldda [%o1] %asi, %f0
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ add %o3, 64, %o3
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ subcc %o0, 64, %o0
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ stda %f48, [%o1 - 64] %asi
+ bne,pt %xcc, 3b
+ ldda [%o2] %asi, %f16
+
+ ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f48
+ fxor %f2, %f18, %f50
+ fxor %f4, %f20, %f52
+ fxor %f6, %f22, %f54
+ fxor %f8, %f24, %f56
+ fxor %f10, %f26, %f58
+ fxor %f12, %f28, %f60
+ fxor %f14, %f30, %f62
+ membar #Sync
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ stda %f48, [%o1] %asi
+ membar #Sync|#StoreStore|#StoreLoad
+ wr %g1, %g0, %asi
+ retl
+ wr %g0, 0, %fprs
+ .size xor_vis_3, .-xor_vis_3
+
+
+ .globl xor_vis_4
+ .type xor_vis_4,@function
+xor_vis_4:
+ rd %fprs, %g1
+ andcc %g1, FPRS_FEF|FPRS_DU, %g0
+ be,pt %icc, 0f
+ sethi %hi(VISenter), %g1
+ jmpl %g1 + %lo(VISenter), %g7
+ add %g7, 8, %g7
+0: wr %g0, FPRS_FEF, %fprs
+ rd %asi, %g1
+ wr %g0, ASI_BLK_P, %asi
+ membar #LoadStore|#StoreLoad|#StoreStore
+ sub %o0, 64, %o0
+ ldda [%o1] %asi, %f0
+ ldda [%o2] %asi, %f16
+
+4: ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f16
+ fxor %f2, %f18, %f18
+ add %o1, 64, %o1
+ fxor %f4, %f20, %f20
+ fxor %f6, %f22, %f22
+ add %o2, 64, %o2
+ fxor %f8, %f24, %f24
+ fxor %f10, %f26, %f26
+ fxor %f12, %f28, %f28
+ fxor %f14, %f30, %f30
+ ldda [%o4] %asi, %f48
+ fxor %f16, %f32, %f32
+ fxor %f18, %f34, %f34
+ fxor %f20, %f36, %f36
+ fxor %f22, %f38, %f38
+ add %o3, 64, %o3
+ fxor %f24, %f40, %f40
+ fxor %f26, %f42, %f42
+ fxor %f28, %f44, %f44
+ fxor %f30, %f46, %f46
+ ldda [%o1] %asi, %f0
+ fxor %f32, %f48, %f48
+ fxor %f34, %f50, %f50
+ fxor %f36, %f52, %f52
+ add %o4, 64, %o4
+ fxor %f38, %f54, %f54
+ fxor %f40, %f56, %f56
+ fxor %f42, %f58, %f58
+ subcc %o0, 64, %o0
+ fxor %f44, %f60, %f60
+ fxor %f46, %f62, %f62
+ stda %f48, [%o1 - 64] %asi
+ bne,pt %xcc, 4b
+ ldda [%o2] %asi, %f16
+
+ ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f16
+ fxor %f2, %f18, %f18
+ fxor %f4, %f20, %f20
+ fxor %f6, %f22, %f22
+ fxor %f8, %f24, %f24
+ fxor %f10, %f26, %f26
+ fxor %f12, %f28, %f28
+ fxor %f14, %f30, %f30
+ ldda [%o4] %asi, %f48
+ fxor %f16, %f32, %f32
+ fxor %f18, %f34, %f34
+ fxor %f20, %f36, %f36
+ fxor %f22, %f38, %f38
+ fxor %f24, %f40, %f40
+ fxor %f26, %f42, %f42
+ fxor %f28, %f44, %f44
+ fxor %f30, %f46, %f46
+ membar #Sync
+ fxor %f32, %f48, %f48
+ fxor %f34, %f50, %f50
+ fxor %f36, %f52, %f52
+ fxor %f38, %f54, %f54
+ fxor %f40, %f56, %f56
+ fxor %f42, %f58, %f58
+ fxor %f44, %f60, %f60
+ fxor %f46, %f62, %f62
+ stda %f48, [%o1] %asi
+ membar #Sync|#StoreStore|#StoreLoad
+ wr %g1, %g0, %asi
+ retl
+ wr %g0, 0, %fprs
+ .size xor_vis_4, .-xor_vis_4
+
+
+ .globl xor_vis_5
+ .type xor_vis_5,@function
+xor_vis_5:
+ rd %fprs, %g1
+ andcc %g1, FPRS_FEF|FPRS_DU, %g0
+ be,pt %icc, 0f
+ sethi %hi(VISenter), %g1
+ jmpl %g1 + %lo(VISenter), %g7
+ add %g7, 8, %g7
+0: wr %g0, FPRS_FEF, %fprs
+ rd %asi, %g1
+ wr %g0, ASI_BLK_P, %asi
+ membar #LoadStore|#StoreLoad|#StoreStore
+ sub %o0, 64, %o0
+ ldda [%o1] %asi, %f0
+ ldda [%o2] %asi, %f16
+
+5: ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f48
+ fxor %f2, %f18, %f50
+ add %o1, 64, %o1
+ fxor %f4, %f20, %f52
+ fxor %f6, %f22, %f54
+ add %o2, 64, %o2
+ fxor %f8, %f24, %f56
+ fxor %f10, %f26, %f58
+ fxor %f12, %f28, %f60
+ fxor %f14, %f30, %f62
+ ldda [%o4] %asi, %f16
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ add %o3, 64, %o3
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ ldda [%o5] %asi, %f32
+ fxor %f48, %f16, %f48
+ fxor %f50, %f18, %f50
+ add %o4, 64, %o4
+ fxor %f52, %f20, %f52
+ fxor %f54, %f22, %f54
+ add %o5, 64, %o5
+ fxor %f56, %f24, %f56
+ fxor %f58, %f26, %f58
+ fxor %f60, %f28, %f60
+ fxor %f62, %f30, %f62
+ ldda [%o1] %asi, %f0
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ subcc %o0, 64, %o0
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ stda %f48, [%o1 - 64] %asi
+ bne,pt %xcc, 5b
+ ldda [%o2] %asi, %f16
+
+ ldda [%o3] %asi, %f32
+ fxor %f0, %f16, %f48
+ fxor %f2, %f18, %f50
+ fxor %f4, %f20, %f52
+ fxor %f6, %f22, %f54
+ fxor %f8, %f24, %f56
+ fxor %f10, %f26, %f58
+ fxor %f12, %f28, %f60
+ fxor %f14, %f30, %f62
+ ldda [%o4] %asi, %f16
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ ldda [%o5] %asi, %f32
+ fxor %f48, %f16, %f48
+ fxor %f50, %f18, %f50
+ fxor %f52, %f20, %f52
+ fxor %f54, %f22, %f54
+ fxor %f56, %f24, %f56
+ fxor %f58, %f26, %f58
+ fxor %f60, %f28, %f60
+ fxor %f62, %f30, %f62
+ membar #Sync
+ fxor %f48, %f32, %f48
+ fxor %f50, %f34, %f50
+ fxor %f52, %f36, %f52
+ fxor %f54, %f38, %f54
+ fxor %f56, %f40, %f56
+ fxor %f58, %f42, %f58
+ fxor %f60, %f44, %f60
+ fxor %f62, %f46, %f62
+ stda %f48, [%o1] %asi
+ membar #Sync|#StoreStore|#StoreLoad
+ wr %g1, %g0, %asi
+ retl
+ wr %g0, 0, %fprs
+ .size xor_vis_5, .-xor_vis_5
+");
+
+static struct xor_block_template xor_block_VIS = {
+ name: "VIS",
+ do_2: xor_vis_2,
+ do_3: xor_vis_3,
+ do_4: xor_vis_4,
+ do_5: xor_vis_5,
+};
+
+#define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 993fd93e7..7a045f033 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -215,6 +215,7 @@ enum
{
ACPI_FACP = 1,
ACPI_DSDT,
+ ACPI_FACS,
ACPI_PM1_ENABLE,
ACPI_GPE_ENABLE,
ACPI_GPE_LEVEL,
diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h
index 166fa085b..99df46b37 100644
--- a/include/linux/agp_backend.h
+++ b/include/linux/agp_backend.h
@@ -45,6 +45,7 @@ enum chipset_type {
INTEL_BX,
INTEL_GX,
INTEL_I810,
+ INTEL_I815,
INTEL_I840,
VIA_GENERIC,
VIA_VP3,
@@ -226,4 +227,23 @@ extern void agp_backend_release(void);
*
*/
+typedef struct {
+ void (*free_memory)(agp_memory *);
+ agp_memory *(*allocate_memory)(size_t, u32);
+ int (*bind_memory)(agp_memory *, off_t);
+ int (*unbind_memory)(agp_memory *);
+ void (*enable)(u32);
+ int (*acquire)(void);
+ void (*release)(void);
+ void (*copy_info)(agp_kern_info *);
+} drm_agp_t;
+
+extern const drm_agp_t *drm_agp_p;
+
+/*
+ * Interface between drm and agp code. When agp initializes, it makes
+ * the above structure available via inter_module_register(), drm might
+ * use it. Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
+ */
+
#endif /* _AGP_BACKEND_H */
diff --git a/include/linux/blk.h b/include/linux/blk.h
index 66bbdcf60..eb4d603e7 100644
--- a/include/linux/blk.h
+++ b/include/linux/blk.h
@@ -115,7 +115,6 @@ void end_that_request_last(struct request *req);
/* ram disk */
#define DEVICE_NAME "ramdisk"
-#define DEVICE_REQUEST rd_request
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_NO_RANDOM
diff --git a/include/linux/byteorder/swabb.h b/include/linux/byteorder/swabb.h
index a10ef3086..3ce838219 100644
--- a/include/linux/byteorder/swabb.h
+++ b/include/linux/byteorder/swabb.h
@@ -37,7 +37,7 @@
__u32 __x = (x); \
((__u32)( \
(((__u32)(__x) & (__u32)0x00ff00ffUL) << 8) | \
- (((__u32)(__x) & (__u32)0xff00ff00UL) >> 8) )) \
+ (((__u32)(__x) & (__u32)0xff00ff00UL) >> 8) )); \
})
#define ___constant_swahw32(x) \
diff --git a/include/linux/divert.h b/include/linux/divert.h
index 624bc55ed..66e56ec15 100644
--- a/include/linux/divert.h
+++ b/include/linux/divert.h
@@ -112,6 +112,6 @@ void free_divert_blk(struct net_device *);
int divert_ioctl(unsigned int cmd, struct divert_cf *arg);
void divert_frame(struct sk_buff *skb);
-#endif __KERNEL__
+#endif
#endif /* _LINUX_DIVERT_H */
diff --git a/include/linux/dn.h b/include/linux/dn.h
index 266dc0f25..c7448158b 100644
--- a/include/linux/dn.h
+++ b/include/linux/dn.h
@@ -139,23 +139,4 @@ struct dn_addr {
#define OSIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, int)
#define OSIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, int)
-/*
- * An unofficial structure used to set/get routes.
- * Be warned, this will probably change as the routing
- * evolves. Also this is only for use with the ioctl()
- * and the routing will use rtnetlink eventually.
- */
-struct dn_fib_rtinfo {
- unsigned long flags; /* Flags */
-#define DN_FIB_RTINFO_F_REPLACE 0x0001 /* Replace any existing route */
-#define DN_FIB_RTINFO_F_DEVCOST 0x0002 /* Add cost of device */
- unsigned long timeout; /* Time in seconds route should last */
- unsigned short src; /* Source Address, 0 = any */
- unsigned short dst; /* Destination Address */
- unsigned short nhp; /* Next Hop Address */
- unsigned short hops; /* Hops on path */
- unsigned short cost; /* Cost of path */
- char device[16];
-};
-
#endif /* _LINUX_DN_H */
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
new file mode 100644
index 000000000..384171b3f
--- /dev/null
+++ b/include/linux/ethtool.h
@@ -0,0 +1,97 @@
+/* $Id: ethtool.h,v 1.2 2000/11/12 10:05:57 davem Exp $
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+ u32 cmd;
+ u32 supported; /* Features this interface supports */
+ u32 advertising; /* Features this interface advertises */
+ u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
+ u8 duplex; /* Duplex, half or full */
+ u8 port; /* Which connector port */
+ u8 phy_address;
+ u8 transceiver; /* Which tranceiver to use */
+ u8 autoneg; /* Enable or disable autonegotiation */
+ u32 maxtxpkt; /* Tx pkts before generating tx int */
+ u32 maxrxpkt; /* Rx pkts before generating rx int */
+ u32 reserved[4];
+};
+
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET 0x00000001 /* Get settings, non-privileged. */
+#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET ETHTOOL_GSET
+#define SPARC_ETH_SSET ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half (1 << 0)
+#define SUPPORTED_10baseT_Full (1 << 1)
+#define SUPPORTED_100baseT_Half (1 << 2)
+#define SUPPORTED_100baseT_Full (1 << 3)
+#define SUPPORTED_1000baseT_Half (1 << 4)
+#define SUPPORTED_1000baseT_Full (1 << 5)
+#define SUPPORTED_Autoneg (1 << 6)
+#define SUPPORTED_TP (1 << 7)
+#define SUPPORTED_AUI (1 << 8)
+#define SUPPORTED_MII (1 << 9)
+#define SUPPORTED_FIBRE (1 << 10)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half (1 << 0)
+#define ADVERTISED_10baseT_Full (1 << 1)
+#define ADVERTISED_100baseT_Half (1 << 2)
+#define ADVERTISED_100baseT_Full (1 << 3)
+#define ADVERTISED_1000baseT_Half (1 << 4)
+#define ADVERTISED_1000baseT_Full (1 << 5)
+#define ADVERTISED_Autoneg (1 << 6)
+#define ADVERTISED_TP (1 << 7)
+#define ADVERTISED_AUI (1 << 8)
+#define ADVERTISED_MII (1 << 9)
+#define ADVERTISED_FIBRE (1 << 10)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things. When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Which connector port. */
+#define PORT_TP 0x00
+#define PORT_AUI 0x01
+#define PORT_MII 0x02
+#define PORT_FIBRE 0x03
+#define PORT_BNC 0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL 0x00
+#define XCVR_EXTERNAL 0x01
+#define XCVR_DUMMY1 0x02
+#define XCVR_DUMMY2 0x03
+#define XCVR_DUMMY3 0x04
+
+/* Enable or disable autonegotiation. If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index fa8f9cded..357878b65 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -29,6 +29,9 @@
#define FBIO_FREE 0x4614
#define FBIOGET_GLYPH 0x4615
#define FBIOGET_HWCINFO 0x4616
+#define FBIOPUT_MODEINFO 0x4617
+#define FBIOGET_DISPINFO 0x4618
+
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 72effef4a..470186804 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -546,7 +546,6 @@ struct file_lock {
#endif
extern struct list_head file_lock_list;
-extern struct semaphore file_lock_sem;
#include <linux/fcntl.h>
@@ -1150,6 +1149,15 @@ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
extern void clear_inode(struct inode *);
extern struct inode * get_empty_inode(void);
+static inline struct inode * new_inode(struct super_block *sb)
+{
+ struct inode *inode = get_empty_inode();
+ if (inode) {
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ }
+ return inode;
+}
extern void insert_inode_hash(struct inode *);
extern void remove_inode_hash(struct inode *);
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 184407e40..9cac7759a 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -17,50 +17,56 @@ extern struct page * prepare_highmem_swapout(struct page *);
extern struct page * replace_with_highmem(struct page *);
extern struct buffer_head * create_bounce(int rw, struct buffer_head * bh_orig);
+
+static inline char *bh_kmap(struct buffer_head *bh)
+{
+ return kmap(bh->b_page) + bh_offset(bh);
+}
+
+static inline void bh_kunmap(struct buffer_head *bh)
+{
+ kunmap(bh->b_page);
+}
+
#else /* CONFIG_HIGHMEM */
static inline unsigned int nr_free_highpages(void) { return 0; }
#define prepare_highmem_swapout(page) page
#define replace_with_highmem(page) page
-static __inline__ unsigned long kmap(struct page * page) {
- return (unsigned long) page_address(page);
-}
+static inline void *kmap(struct page *page) { return page_address(page); }
#define kunmap(page) do { } while (0)
#define kmap_atomic(page,idx) kmap(page)
#define kunmap_atomic(page,idx) kunmap(page)
+#define bh_kmap(bh) ((bh)->b_data)
+#define bh_kunmap(bh) do { } while (0);
+
#endif /* CONFIG_HIGHMEM */
/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
{
- unsigned long kaddr;
-
- kaddr = kmap(page);
- clear_user_page((void *)kaddr, vaddr);
+ clear_user_page(kmap(page), vaddr);
kunmap(page);
}
static inline void clear_highpage(struct page *page)
{
- unsigned long kaddr;
-
- kaddr = kmap(page);
- clear_page((void *)kaddr);
+ clear_page(kmap(page));
kunmap(page);
}
static inline void memclear_highpage(struct page *page, unsigned int offset, unsigned int size)
{
- unsigned long kaddr;
+ char *kaddr;
if (offset + size > PAGE_SIZE)
BUG();
kaddr = kmap(page);
- memset((void *)(kaddr + offset), 0, size);
+ memset(kaddr + offset, 0, size);
kunmap(page);
}
@@ -69,34 +75,34 @@ static inline void memclear_highpage(struct page *page, unsigned int offset, uns
*/
static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
{
- unsigned long kaddr;
+ char *kaddr;
if (offset + size > PAGE_SIZE)
BUG();
kaddr = kmap(page);
- memset((void *)(kaddr + offset), 0, size);
+ memset(kaddr + offset, 0, size);
flush_page_to_ram(page);
kunmap(page);
}
static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr)
{
- unsigned long vfrom, vto;
+ char *vfrom, *vto;
vfrom = kmap(from);
vto = kmap(to);
- copy_user_page((void *)vto, (void *)vfrom, vaddr);
+ copy_user_page(vto, vfrom, vaddr);
kunmap(from);
kunmap(to);
}
static inline void copy_highpage(struct page *to, struct page *from)
{
- unsigned long vfrom, vto;
+ char *vfrom, *vto;
vfrom = kmap(from);
vto = kmap(to);
- copy_page((void *)vto, (void *)vfrom);
+ copy_page(vto, vfrom);
kunmap(from);
kunmap(to);
}
diff --git a/include/linux/irda.h b/include/linux/irda.h
index d8532c2fc..40aec1c8d 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -78,14 +78,17 @@ enum {
#define SOL_IRLMP 266 /* Same as SOL_IRDA for now */
#define SOL_IRTTP 266 /* Same as SOL_IRDA for now */
-#define IRLMP_ENUMDEVICES 1
-#define IRLMP_IAS_SET 2
-#define IRLMP_IAS_QUERY 3
-#define IRLMP_HINTS_SET 4
+#define IRLMP_ENUMDEVICES 1 /* Return discovery log */
+#define IRLMP_IAS_SET 2 /* Set an attribute in local IAS */
+#define IRLMP_IAS_QUERY 3 /* Query remote IAS for attribute */
+#define IRLMP_HINTS_SET 4 /* Set hint bits advertised */
#define IRLMP_QOS_SET 5
#define IRLMP_QOS_GET 6
#define IRLMP_MAX_SDU_SIZE 7
-#define IRLMP_IAS_GET 8
+#define IRLMP_IAS_GET 8 /* Get an attribute from local IAS */
+#define IRLMP_IAS_DEL 9 /* Remove attribute from local IAS */
+#define IRLMP_HINT_MASK_SET 10 /* Set discovery filter */
+#define IRLMP_WAITDEVICE 11 /* Wait for a new discovery */
#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
@@ -94,6 +97,12 @@ enum {
#define IAS_MAX_CLASSNAME 64
#define IAS_MAX_ATTRIBNAME 256
+/* Attribute type needed for struct irda_ias_set */
+#define IAS_MISSING 0
+#define IAS_INTEGER 1
+#define IAS_OCT_SEQ 2
+#define IAS_STRING 3
+
#define LSAP_ANY 0xff
struct sockaddr_irda {
@@ -132,6 +141,7 @@ struct irda_ias_set {
__u8 string[IAS_MAX_STRING];
} irda_attrib_string;
} attribute;
+ __u32 daddr; /* Address of device (for some queries only) */
};
/* Some private IOCTL's (max 16) */
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 7cdd4ff43..51c06aec7 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.106 2000/08/10 22:52:46 kai Exp $
+/* $Id: isdn.h,v 1.110 2000/11/01 17:54:01 detabc Exp $
* Main header for the Linux ISDN subsystem (linklevel).
*
@@ -66,8 +66,7 @@
#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
-#undef CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR
-#undef CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR
+#undef CONFIG_ISDN_WITH_ABC_IPTABLES_NETFILTER
/* New ioctl-codes */
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index 63543da77..471c9af2c 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -177,16 +177,17 @@ extern int iso_date(char *, int);
extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
-int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
extern struct dentry *isofs_lookup(struct inode *, struct dentry *);
extern int isofs_get_block(struct inode *, long, struct buffer_head *, int);
extern int isofs_bmap(struct inode *, int);
-extern int isofs_lookup_grandparent(struct inode *, int);
+extern struct buffer_head *isofs_bread(struct inode *, unsigned int, unsigned int);
extern struct inode_operations isofs_dir_inode_operations;
extern struct file_operations isofs_dir_operations;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index aa337fe6c..beb41bfa3 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -45,11 +45,15 @@
#define FASTCALL(x) x
#endif
+struct semaphore;
+
extern struct notifier_block *panic_notifier_list;
NORET_TYPE void panic(const char * fmt, ...)
__attribute__ ((NORET_AND format (printf, 1, 2)));
NORET_TYPE void do_exit(long error_code)
ATTRIB_NORET;
+NORET_TYPE void up_and_exit(struct semaphore *, long)
+ ATTRIB_NORET;
extern unsigned long simple_strtoul(const char *,char **,unsigned int);
extern long simple_strtol(const char *,char **,unsigned int);
extern int sprintf(char * buf, const char * fmt, ...);
diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
index 40530168e..acbdea338 100644
--- a/include/linux/kernelcapi.h
+++ b/include/linux/kernelcapi.h
@@ -1,5 +1,5 @@
/*
- * $Id: kernelcapi.h,v 1.7 2000/06/12 09:20:20 kai Exp $
+ * $Id: kernelcapi.h,v 1.8 2000/08/22 10:11:00 calle Exp $
*
* Kernel CAPI 2.0 Interface for Linux
*
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index bab128898..44e1ea652 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -1,22 +1,38 @@
+#ifndef __LINUX_KMOD_H__
+#define __LINUX_KMOD_H__
+
/*
- kmod header
-*/
+ * include/linux/kmod.h
+ *
+ * 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/errno.h>
#ifdef CONFIG_KMOD
extern int request_module(const char * name);
+#else
+static inline int request_module(const char * name) { return -ENOSYS; }
+#endif
+
extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
+extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
+
#ifdef CONFIG_HOTPLUG
extern char hotplug_path [];
-extern int call_usermodehelper(char *path, char *argv[], char *envp[]);
-#endif
-#else
-static inline int request_module(const char * name) { return -ENOSYS; }
-static inline int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
-{
- return -EACCES;
-}
#endif
+#endif /* __LINUX_KMOD_H__ */
diff --git a/include/linux/lapb.h b/include/linux/lapb.h
index bf1825a6b..2eeb76f2c 100644
--- a/include/linux/lapb.h
+++ b/include/linux/lapb.h
@@ -28,7 +28,7 @@ struct lapb_register_struct {
void (*connect_indication)(void *token, int reason);
void (*disconnect_confirmation)(void *token, int reason);
void (*disconnect_indication)(void *token, int reason);
- void (*data_indication)(void *token, struct sk_buff *skb);
+ int (*data_indication)(void *token, struct sk_buff *skb);
void (*data_transmit)(void *token, struct sk_buff *skb);
};
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 59355eb8a..70ffe28e4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -181,7 +181,8 @@ typedef struct page {
#define PG_skip 10
#define PG_inactive_clean 11
#define PG_highmem 12
- /* bits 21-30 unused */
+ /* bits 21-29 unused */
+#define PG_arch_1 30
#define PG_reserved 31
@@ -328,6 +329,10 @@ typedef struct page {
* parts of the address space.
*
* PG_error is set to indicate that an I/O error occurred on this page.
+ *
+ * PG_arch_1 is an architecture specific page state bit. The generic
+ * code guarentees that this bit is cleared for a page when it first
+ * is entered into the page cache.
*/
extern mem_map_t * mem_map;
@@ -412,8 +417,11 @@ extern void si_meminfo(struct sysinfo * val);
extern void swapin_readahead(swp_entry_t);
/* mmap.c */
+extern void lock_vma_mappings(struct vm_area_struct *);
+extern void unlock_vma_mappings(struct vm_area_struct *);
extern void merge_segments(struct mm_struct *, unsigned long, unsigned long);
extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
+extern void __insert_vm_struct(struct mm_struct *, struct vm_area_struct *);
extern void build_mmap_avl(struct mm_struct *);
extern void exit_mmap(struct mm_struct *);
extern unsigned long get_unmapped_area(unsigned long, unsigned long);
@@ -447,8 +455,6 @@ extern void truncate_inode_pages(struct address_space *, loff_t);
/* generic vm_area_ops exported for stackable file systems */
extern int filemap_swapout(struct page * page, struct file *file);
-extern pte_t filemap_swapin(struct vm_area_struct * vma,
- unsigned long offset, unsigned long entry);
extern int filemap_sync(struct vm_area_struct * vma, unsigned long address,
size_t size, unsigned int flags);
extern struct page *filemap_nopage(struct vm_area_struct * area,
diff --git a/include/linux/module.h b/include/linux/module.h
index 26f383a63..249cb0163 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -9,6 +9,7 @@
#include <linux/config.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
#ifdef __GENKSYMS__
# define _set_ver(sym) sym
@@ -78,11 +79,17 @@ struct module
unsigned long gp;
#endif
/* Members past this point are extensions to the basic
- module support and are optional. Use mod_opt_member()
+ module support and are optional. Use mod_member_present()
to examine them. */
const struct module_persist *persist_start;
const struct module_persist *persist_end;
int (*can_unload)(void);
+ int runsize; /* In modutils, not currently used */
+ const char *kallsyms_start; /* All symbols for kernel debugging */
+ const char *kallsyms_end;
+ const char *archdata_start; /* arch specific data for module */
+ const char *archdata_end;
+ const char *kernel_data; /* Reserved for kernel internal use */
};
struct module_info
@@ -123,6 +130,10 @@ struct module_info
((unsigned long)(&((struct module *)0L)->member + 1) \
<= (mod)->size_of_struct)
+/* Check if an address p with number of entries n is within the body of module m */
+#define mod_bound(p, n, m) ((unsigned long)(p) >= ((unsigned long)(m) + ((m)->size_of_struct)) && \
+ (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)
+
/* Backwards compatibility definition. */
#define GET_USE_COUNT(module) (atomic_read(&(module)->uc.usecount))
@@ -142,14 +153,34 @@ struct module_info
#define __MODULE_STRING_1(x) #x
#define __MODULE_STRING(x) __MODULE_STRING_1(x)
-/* Find a symbol exported by the kernel or another module */
-#ifdef CONFIG_MODULES
-extern unsigned long get_module_symbol(char *, char *);
-extern void put_module_symbol(unsigned long);
-#else
-static inline unsigned long get_module_symbol(char *unused1, char *unused2) { return 0; };
-static inline void put_module_symbol(unsigned long unused) { };
-#endif
+/* Generic inter module communication.
+ *
+ * NOTE: This interface is intended for small amounts of data that are
+ * passed between two objects and either or both of the objects
+ * might be compiled as modules. Do not over use this interface.
+ *
+ * If more than two objects need to communicate then you probably
+ * need a specific interface instead of abusing this generic
+ * interface. If both objects are *always* built into the kernel
+ * then a global extern variable is good enough, you do not need
+ * this interface.
+ *
+ * Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
+ */
+
+#define HAVE_INTER_MODULE
+extern void inter_module_register(const char *, struct module *, const void *);
+extern void inter_module_unregister(const char *);
+extern const void *inter_module_get(const char *);
+extern const void *inter_module_get_request(const char *, const char *);
+extern void inter_module_put(const char *);
+
+struct inter_module_entry {
+ struct list_head list;
+ const char *im_name;
+ struct module *owner;
+ const void *userdata;
+};
extern int try_inc_mod_count(struct module *mod);
@@ -313,4 +344,10 @@ __attribute__((section("__ksymtab"))) = \
#define EXPORT_NO_SYMBOLS
#endif /* MODULE */
+#ifdef CONFIG_MODULES
+#define SET_MODULE_OWNER(some_struct) do { some_struct->owner = THIS_MODULE; } while (0)
+#else
+#define SET_MODULE_OWNER(some_struct) do { } while (0)
+#endif
+
#endif /* _LINUX_MODULE_H */
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 46cb1d94b..c8bdd1cd7 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -92,6 +92,7 @@ struct cfi_private {
int numchips;
unsigned long chipshift; /* Because they're of the same type */
struct flchip chips[0]; /* per-chip data structure for each chip */
+ const char *im_name; /* inter_module name for cmdset_setup */
};
#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index 4ca86bc4e..ebb41c973 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -7,7 +7,6 @@
#include <linux/types.h>
#include <linux/mtd/mtd.h>
-#include <linux/kmod.h>
#include <linux/malloc.h>
/* The map stuff is very simple. You fill in your struct map_info with
@@ -52,6 +51,7 @@ struct map_info {
unsigned long map_priv_2;
void *fldrv_priv;
void (*fldrv_destroy)(struct mtd_info *);
+ const char *im_name;
};
/*
@@ -59,20 +59,13 @@ struct map_info {
* if anything is recognised. Doesn't register it because the calling
* map driver needs to set the 'module' field first.
*/
-static inline struct mtd_info *do_map_probe(struct map_info *map, char *funcname, char *modname)
+static inline struct mtd_info *do_map_probe(struct map_info *map, const char *funcname, const char *modname)
{
struct mtd_info *(*probe_p)(struct map_info *);
struct mtd_info *mtd = NULL;
- probe_p = (void *)get_module_symbol(NULL, funcname);
- if (!probe_p) {
- request_module(modname);
- probe_p = (void *)get_module_symbol(NULL, funcname);
- }
- if (probe_p) {
- mtd = (*probe_p)(map);
- put_module_symbol((unsigned long)probe_p);
- }
+ if ((probe_p = inter_module_get_request(modname, funcname)))
+ mtd = (*probe_p)(map); /* map->im_name is set by probe */
return mtd;
}
@@ -95,7 +88,7 @@ static inline void map_destroy(struct mtd_info *mtd)
struct map_info *map = mtd->priv;
map->fldrv_destroy(mtd);
- put_module_symbol((unsigned long)map->fldrv_destroy);
+ inter_module_put(map->im_name);
kfree(mtd);
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 32677edae..2c2bfd4d5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -383,6 +383,9 @@ struct net_device
int (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
int (*accept_fastpath)(struct net_device *, struct dst_entry*);
+ /* open/release and usage marking */
+ struct module *owner;
+
/* bridge stuff */
struct net_bridge_port *br_port;
diff --git a/include/linux/netfilter_decnet.h b/include/linux/netfilter_decnet.h
index 2f8704f02..3064eec9c 100644
--- a/include/linux/netfilter_decnet.h
+++ b/include/linux/netfilter_decnet.h
@@ -36,4 +36,24 @@
#define NF_DN_ROUTE 6
#define NF_DN_NUMHOOKS 7
+enum nf_dn_hook_priorities {
+ NF_DN_PRI_FIRST = INT_MIN,
+ NF_DN_PRI_CONNTRACK = -200,
+ NF_DN_PRI_MANGLE = -150,
+ NF_DN_PRI_NAT_DST = -100,
+ NF_DN_PRI_FILTER = 0,
+ NF_DN_PRI_NAT_SRC = 100,
+ NF_DN_PRI_DNRTMSG = 200,
+ NF_DN_PRI_LAST = INT_MAX,
+};
+
+struct nf_dn_rtmsg {
+ int nfdn_ifindex;
+};
+
+#define NFDN_RTMSG(r) ((unsigned char *)(r) + NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)))
+
+#define DNRMG_L1_GROUP 0x01
+#define DNRMG_L2_GROUP 0x02
+
#endif /*__LINUX_DECNET_NETFILTER_H*/
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 41e7d92cc..2afb52e98 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -8,6 +8,7 @@
#define NETLINK_ARPD 8
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
#define MAX_LINKS 32
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 5f6572b22..f6c35dc01 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -19,7 +19,7 @@
/*
* Valid flags for a dirty buffer
*/
-#define PG_BUSY 0x0001
+#define PG_BUSY 0
struct nfs_page {
struct list_head wb_hash, /* Inode */
@@ -38,7 +38,7 @@ struct nfs_page {
struct nfs_writeverf wb_verf; /* Commit cookie */
};
-#define NFS_WBACK_BUSY(req) ((req)->wb_flags & PG_BUSY)
+#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
extern struct nfs_page *nfs_create_request(struct file *file,
struct page *page,
@@ -68,10 +68,9 @@ extern spinlock_t nfs_wreq_lock;
static __inline__ int
nfs_lock_request(struct nfs_page *req)
{
- if (NFS_WBACK_BUSY(req))
+ if (test_and_set_bit(PG_BUSY, &req->wb_flags))
return 0;
req->wb_count++;
- req->wb_flags |= PG_BUSY;
return 1;
}
@@ -80,10 +79,13 @@ nfs_unlock_request(struct nfs_page *req)
{
if (!NFS_WBACK_BUSY(req)) {
printk(KERN_ERR "NFS: Invalid unlock attempted\n");
- return;
+ BUG();
}
- req->wb_flags &= ~PG_BUSY;
- wake_up(&req->wb_wait);
+ smp_mb__before_clear_bit();
+ clear_bit(PG_BUSY, &req->wb_flags);
+ smp_mb__after_clear_bit();
+ if (waitqueue_active(&req->wb_wait))
+ wake_up(&req->wb_wait);
nfs_release_request(req);
}
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 994e0889f..7a89c6525 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -340,6 +340,7 @@
#define PCI_DEVICE_ID_SI_620 0x0620
#define PCI_DEVICE_ID_SI_630 0x0630
#define PCI_DEVICE_ID_SI_630_VGA 0x6300
+#define PCI_DEVICE_ID_SI_730_VGA 0x7300
#define PCI_DEVICE_ID_SI_5107 0x5107
#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
@@ -1334,3 +1335,8 @@
#define PCI_DEVICE_ID_ARK_STING 0xa091
#define PCI_DEVICE_ID_ARK_STINGARK 0xa099
#define PCI_DEVICE_ID_ARK_2000MT 0xa0a1
+
+#define PCI_VENDOR_ID_MICROGATE 0x13c0
+#define PCI_DEVICE_ID_MICROGATE_USC 0x0010
+#define PCI_DEVICE_ID_MICROGATE_SCC 0x0020
+#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 28bf3daa0..da8f6b3dc 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -67,7 +67,7 @@ struct proc_dir_entry {
void *data;
read_proc_t *read_proc;
write_proc_t *write_proc;
- unsigned int count; /* use count */
+ atomic_t count; /* use count */
int deleted; /* delete flag */
kdev_t rdev;
};
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index ec87c2ddd..7b184ce94 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -28,7 +28,6 @@
#include <asm/bitops.h>
#include <linux/module.h>
#include <linux/hdreg.h>
-#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
@@ -88,5 +87,5 @@ extern void md_print_devices (void);
#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
-#endif _MD_H
+#endif
diff --git a/include/linux/raid/md_compatible.h b/include/linux/raid/md_compatible.h
index 1dd422185..35e60bd1a 100644
--- a/include/linux/raid/md_compatible.h
+++ b/include/linux/raid/md_compatible.h
@@ -31,7 +31,7 @@
/* 001 */
extern __inline__ int md_cpu_has_mmx(void)
{
- return boot_cpu_data.x86_capability & X86_FEATURE_MMX;
+ return test_bit(X86_FEATURE_MMX, &boot_cpu_data.x86_capability);
}
#endif
@@ -152,5 +152,5 @@ typedef wait_queue_head_t md_wait_queue_head_t;
/* END */
-#endif _MD_COMPATIBLE_H
+#endif
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index ce998195c..41d729e16 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -365,5 +365,5 @@ do { \
__wait_event_lock_irq(wq, condition, lock); \
} while (0)
-#endif _MD_K_H
+#endif
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index 0c6e1a368..d6bb37a81 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -168,5 +168,5 @@ static inline __u64 md_event(mdp_super_t *sb) {
return (ev<<32)| sb->events_lo;
}
-#endif _MD_P_H
+#endif
diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h
index 9478513f9..c96b0e404 100644
--- a/include/linux/raid/md_u.h
+++ b/include/linux/raid/md_u.h
@@ -111,5 +111,5 @@ typedef struct mdu_param_s
int max_fault; /* unused for now */
} mdu_param_t;
-#endif _MD_U_H
+#endif
diff --git a/include/linux/raid/xor.h b/include/linux/raid/xor.h
index c8034b759..0e6950a7b 100644
--- a/include/linux/raid/xor.h
+++ b/include/linux/raid/xor.h
@@ -3,10 +3,21 @@
#include <linux/raid/md.h>
-#define MAX_XOR_BLOCKS 4
+#define MAX_XOR_BLOCKS 5
-extern void calibrate_xor_block(void);
-extern void (*xor_block)(unsigned int count,
- struct buffer_head **bh_ptr);
+extern void xor_block(unsigned int count, struct buffer_head **bh_ptr);
+
+struct xor_block_template {
+ struct xor_block_template *next;
+ const char *name;
+ int speed;
+ void (*do_2)(unsigned long, unsigned long *, unsigned long *);
+ void (*do_3)(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *);
+ void (*do_4)(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *);
+ void (*do_5)(unsigned long, unsigned long *, unsigned long *,
+ unsigned long *, unsigned long *, unsigned long *);
+};
#endif
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 40738af95..0c7cab0de 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -139,6 +139,7 @@ enum
#define RTPROT_MRT 10 /* Merit MRT */
#define RTPROT_ZEBRA 11 /* Zebra */
#define RTPROT_BIRD 12 /* BIRD */
+#define RTPROT_DNROUTED 13 /* DECnet routing daemon */
/* rtm_scope
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9385c9ea8..a58b23c86 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -85,7 +85,6 @@ extern int last_pid;
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE 4
#define TASK_STOPPED 8
-#define TASK_EXCLUSIVE 32
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
@@ -150,6 +149,8 @@ extern void update_one_process(struct task_struct *p, unsigned long user,
extern signed long FASTCALL(schedule_timeout(signed long timeout));
asmlinkage void schedule(void);
+extern void schedule_task(struct tq_struct *task);
+
/*
* The default fd array needs to be at least BITS_PER_LONG,
* as this is the granularity returned by copy_fdset().
@@ -533,8 +534,8 @@ extern unsigned long prof_shift;
#define CURRENT_TIME (xtime.tv_sec)
-extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode));
-extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode));
+extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode));
+extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode));
extern void FASTCALL(sleep_on(wait_queue_head_t *q));
extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q,
signed long timeout));
@@ -543,12 +544,12 @@ extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q,
signed long timeout));
extern void FASTCALL(wake_up_process(struct task_struct * tsk));
-#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
-#define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
-#define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
-#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
-#define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE)
-#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
+#define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)
+#define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,0)
+#define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)
+#define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)
+#define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE,0)
+#define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE,WQ_FLAG_EXCLUSIVE)
extern int in_group_p(gid_t);
extern int in_egroup_p(gid_t);
diff --git a/include/linux/sisfb.h b/include/linux/sisfb.h
index cfc8ce704..2f5be6474 100644
--- a/include/linux/sisfb.h
+++ b/include/linux/sisfb.h
@@ -1,17 +1,91 @@
#ifndef _LINUX_SISFB
#define _LINUX_SISFB
+/* CRT2 connection */
+#define MASK_DISPTYPE_CRT2 0x04 /* Connect CRT2 */
+#define MASK_DISPTYPE_LCD 0x02 /* Connect LCD */
+#define MASK_DISPTYPE_TV 0x01 /* Connect TV */
+#define MASK_DISPTYPE_DISP2 (MASK_DISPTYPE_LCD | MASK_DISPTYPE_TV | MASK_DISPTYPE_CRT2)
+
+#define DISPTYPE_CRT1 0x00000008L
+#define DISPTYPE_CRT2 0x00000004L
+#define DISPTYPE_LCD 0x00000002L
+#define DISPTYPE_TV 0x00000001L
+#define DISPTYPE_DISP1 DISPTYPE_CRT1
+#define DISPTYPE_DISP2 (DISPTYPE_CRT2 | DISPTYPE_LCD | DISPTYPE_TV)
+#define DISPMODE_SINGLE 0x00000020L
+#define DISPMODE_MIRROR 0x00000010L
+#define DISPMODE_DUALVIEW 0x00000040L
+
+#define HASVB_NONE 0
+#define HASVB_301 1
+#define HASVB_LVDS 2
+#define HASVB_TRUMPION 3
+#define HASVB_LVDS_CHRONTEL 4
+#define HASVB_LVDS_ALL (HASVB_LVDS | HASVB_TRUMPION | HASVB_LVDS_CHRONTEL)
+
+enum _TVMODE
+{
+ TVMODE_NTSC = 0,
+ TVMODE_PAL,
+ TVMODE_HIVISION,
+ TVMODE_TOTAL
+};
+
+enum _TVPLUGTYPE
+{
+ TVPLUG_UNKNOWN = 0,
+ TVPLUG_COMPOSITE,
+ TVPLUG_SVIDEO,
+ TVPLUG_SCART,
+ TVPLUG_TOTAL
+};
+
+enum CHIPTYPE
+{
+ SiS_UNKNOWN = 0,
+ SiS_300,
+ SiS_540,
+ SiS_630,
+ SiS_630S,
+ SiS_730
+};
+
struct sis_memreq
{
unsigned long offset;
unsigned long size;
};
+/* Data for AP */
+struct mode_info
+{
+ int bpp;
+ int xres;
+ int yres;
+ int v_xres;
+ int v_yres;
+ int org_x;
+ int org_y;
+ unsigned int vrate;
+};
+
+struct ap_data
+{
+ struct mode_info minfo;
+ unsigned long iobase;
+ unsigned int mem_size;
+ unsigned long disp_state;
+ enum CHIPTYPE chip;
+};
+
+
+/* Data for kernel */
struct video_info
{
/* card parameters */
int chip_id;
- int video_size;
+ unsigned int video_size;
unsigned long video_base;
char *video_vbase;
unsigned long mmio_base;
@@ -22,8 +96,17 @@ struct video_info
int video_bpp;
int video_width;
int video_height;
- unsigned int refresh_rate;
- u8 status;
+ int video_vwidth;
+ int video_vheight;
+ int org_x;
+ int org_y;
+ unsigned int refresh_rate;
+
+ /* VB functions */
+ unsigned long disp_state;
+ unsigned char hasVB;
+ unsigned char TV_type;
+ unsigned char TV_plug;
};
#ifdef __KERNEL__
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index e9fd9e275..33ffddc50 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -75,6 +75,7 @@
#define SIOCGIFDIVERT 0x8944 /* Frame diversion support */
#define SIOCSIFDIVERT 0x8945 /* Set frame diversion options */
+#define SIOCETHTOOL 0x8946 /* Ethtool interface */
/* ARP cache control calls. */
/* 0x8950 - 0x8952 * obsolete calls, don't re-use */
diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h
index ca8ad780d..c7be4cc54 100644
--- a/include/linux/soundcard.h
+++ b/include/linux/soundcard.h
@@ -76,8 +76,8 @@
*/
#ifndef _SIOWR
-#if defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__INCioctlh) && !defined(__Lynx__)))
-/* Use already defined ioctl defines if they exist (except with Sun) */
+#if defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__sparc__) && !defined(__INCioctlh) && !defined(__Lynx__)))
+/* Use already defined ioctl defines if they exist (except with Sun or Sparc) */
#define SIOCPARM_MASK IOCPARM_MASK
#define SIOC_VOID IOC_VOID
#define SIOC_OUT IOC_OUT
@@ -179,7 +179,7 @@ typedef struct seq_event_rec {
* Some big endian/little endian handling macros
*/
-#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(HPPA) || defined(PPC)
+#if defined(_AIX) || defined(AIX) || defined(sparc) || defined(__sparc__) || defined(HPPA) || defined(PPC)
/* Big endian machines */
# define _PATCHKEY(id) (0xfd00|id)
# define AFMT_S16_NE AFMT_S16_BE
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index eb55e776c..5d1f842c8 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -54,7 +54,7 @@ extern unsigned int nlm_debug;
#undef ifdebug
#ifdef RPC_DEBUG
# define ifdebug(fac) if (rpc_debug & RPCDBG_##fac)
-# define dfprintk(fac, args...) do { ifdebug(fac) printk(## args); } while(0)
+# define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0)
# define RPC_IFDEBUG(x) x
#else
# define dfprintk(fac, args...) do ; while (0)
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 8b559703a..f3e9ad2be 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -80,8 +80,7 @@ struct rpc_task {
unsigned short tk_lock; /* Task lock counter */
unsigned char tk_active : 1,/* Task has been activated */
tk_wakeup : 1;/* Task waiting to wake up */
- volatile unsigned char tk_running : 1,/* Task is running */
- tk_sleeping : 1;/* Task is truly asleep */
+ unsigned int tk_runstate; /* Task run status */
#ifdef RPC_DEBUG
unsigned short tk_pid; /* debugging aid */
#endif
@@ -110,11 +109,26 @@ typedef void (*rpc_action)(struct rpc_task *);
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
-#define RPC_IS_RUNNING(t) ((t)->tk_running)
-#define RPC_IS_SLEEPING(t) ((t)->tk_sleeping)
#define RPC_IS_ACTIVATED(t) ((t)->tk_active)
#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL)
+#define RPC_TASK_SLEEPING 0
+#define RPC_TASK_RUNNING 1
+#define RPC_IS_SLEEPING(t) (test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+#define rpc_clear_running(t) (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_sleeping(t) (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+
+#define rpc_clear_sleeping(t) \
+ do { \
+ smp_mb__before_clear_bit(); \
+ clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate); \
+ smp_mb__after_clear_bit(); \
+ } while(0)
+
/*
* RPC synchronization objects
*/
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 450341b74..a733c79f4 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -1,9 +1,9 @@
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
- * ==FILEDATE 19990810==
+ * $Id: synclink.h,v 3.2 2000/11/06 22:34:38 paul Exp $
*
- * Copyright (C) 1998 by Microgate Corporation
+ * Copyright (C) 1998-2000 by Microgate Corporation
*
* Redistribution of this file is permitted under
* the terms of the GNU Public License (GPL)
@@ -11,6 +11,7 @@
#ifndef _SYNCLINK_H_
#define _SYNCLINK_H_
+#define SYNCLINK_H_VERSION 3.2
#define BOOLEAN int
#define TRUE 1
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index b5155a2b6..07f2c83e9 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -24,8 +24,12 @@
#ifndef _LINUX_SYSCTL_H
#define _LINUX_SYSCTL_H
+#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/list.h>
+struct file;
+
#define CTL_MAXNAME 10
struct __sysctl_args {
diff --git a/include/linux/time.h b/include/linux/time.h
index 87f334547..8d641efd8 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -12,6 +12,8 @@ struct timespec {
};
#endif /* _STRUCT_TIMESPEC */
+#ifdef __KERNEL__
+
/*
* Change timeval to jiffies, trying to avoid the
* most obvious overflows..
@@ -80,6 +82,8 @@ mktime (unsigned int year, unsigned int mon,
)*60 + sec; /* finally seconds */
}
+#endif /* __KERNEL__ */
+
struct timeval {
time_t tv_sec; /* seconds */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 428866672..2828238ac 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -350,7 +350,11 @@ struct usb_device_id {
struct usb_driver {
const char *name;
- void * (*probe)(struct usb_device *, unsigned int);
+ void *(*probe)(
+ struct usb_device *dev, /* the device */
+ unsigned intf, /* what interface */
+ const struct usb_device_id *id /* from id_table */
+ );
void (*disconnect)(struct usb_device *, void *);
struct list_head driver_list;
@@ -367,11 +371,6 @@ struct usb_driver {
* binding policy can be driven from user mode too
*/
const struct usb_device_id *id_table;
- void *(*bind)(
- struct usb_device *dev, /* the device */
- unsigned intf, /* what interface */
- const struct usb_device_id *id /* from id_table */
- );
/* suspend before the bus suspends;
* disconnect or resume when the bus resumes */
@@ -601,6 +600,9 @@ extern void usb_scan_devices(void);
extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv);
extern int usb_interface_claimed(struct usb_interface *iface);
extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
+const struct usb_device_id *usb_match_id(struct usb_device *dev,
+ struct usb_interface *interface,
+ const struct usb_device_id *id);
extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
extern void usb_free_bus(struct usb_bus *);
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 8629f3241..6b281ccad 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -44,7 +44,8 @@ extern int printk(const char *fmt, ...);
#endif
struct __wait_queue {
- unsigned int compiler_warning;
+ unsigned int flags;
+#define WQ_FLAG_EXCLUSIVE 0x01
struct task_struct * task;
struct list_head task_list;
#if WAITQUEUE_DEBUG
@@ -109,7 +110,7 @@ typedef struct __wait_queue_head wait_queue_head_t;
#endif
#define __WAITQUEUE_INITIALIZER(name,task) \
- { 0x1234567, task, { NULL, NULL } __WAITQUEUE_DEBUG_INIT(name)}
+ { 0x0, task, { NULL, NULL } __WAITQUEUE_DEBUG_INIT(name)}
#define DECLARE_WAITQUEUE(name,task) \
wait_queue_t name = __WAITQUEUE_INITIALIZER(name,task)
@@ -141,6 +142,7 @@ static inline void init_waitqueue_entry(wait_queue_t *q,
if (!q || !p)
WQ_BUG();
#endif
+ q->flags = 0;
q->task = p;
#if WAITQUEUE_DEBUG
q->__magic = (long)&q->__magic;
diff --git a/include/linux/wrapper.h b/include/linux/wrapper.h
index 36dd17fe4..3c62fdbc8 100644
--- a/include/linux/wrapper.h
+++ b/include/linux/wrapper.h
@@ -1,13 +1,6 @@
#ifndef _WRAPPER_H_
#define _WRAPPER_H_
-#define vma_set_inode(v,i) ((v)->vm_inode = (i))
-#define vma_get_flags(v) ((v)->vm_flags)
-#define vma_get_pgoff(v) ((v)->vm_pgoff)
-#define vma_get_start(v) ((v)->vm_start)
-#define vma_get_end(v) ((v)->vm_end)
-#define vma_get_page_prot(v) ((v)->vm_page_prot)
-
#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags))
#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags))
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 50d4aa889..525786901 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -159,15 +159,13 @@ typedef struct {
unsigned short slave_timeout; /* when? */
} ax25_dama_info;
-#ifndef _LINUX_SYSCTL_H
-#include <linux/sysctl.h>
-#endif
+struct ctl_table;
typedef struct ax25_dev {
struct ax25_dev *next;
- struct net_device *dev;
- struct net_device *forward;
- struct ctl_table systable[AX25_MAX_VALUES+1];
+ struct net_device *dev;
+ struct net_device *forward;
+ struct ctl_table *systable;
int values[AX25_MAX_VALUES];
#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
ax25_dama_info dama;
diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h
index 498ea16fd..8b628d2e5 100644
--- a/include/net/dn_nsp.h
+++ b/include/net/dn_nsp.h
@@ -39,9 +39,27 @@ extern int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
extern struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri);
extern struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *err);
-#define NSP_REASON_NR 1
-#define NSP_REASON_DC 42
-#define NSP_REASON_NL 41
+#define NSP_REASON_OK 0 /* No error */
+#define NSP_REASON_NR 1 /* No resources */
+#define NSP_REASON_UN 2 /* Unrecognised node name */
+#define NSP_REASON_SD 3 /* Node shutting down */
+#define NSP_REASON_ID 4 /* Invalid destination end user */
+#define NSP_REASON_ER 5 /* End user lacks resources */
+#define NSP_REASON_OB 6 /* Object too busy */
+#define NSP_REASON_US 7 /* Unspecified error */
+#define NSP_REASON_TP 8 /* Third-Party abort */
+#define NSP_REASON_EA 9 /* End user has aborted the link */
+#define NSP_REASON_IF 10 /* Invalid node name format */
+#define NSP_REASON_LS 11 /* Local node shutdown */
+#define NSP_REASON_LL 32 /* Node lacks logical-link resources */
+#define NSP_REASON_LE 33 /* End user lacks logical-link resources */
+#define NSP_REASON_UR 34 /* Unacceptable RQSTRID or PASSWORD field */
+#define NSP_REASON_UA 36 /* Unacceptable ACCOUNT field */
+#define NSP_REASON_TM 38 /* End user timed out logical link */
+#define NSP_REASON_NU 39 /* Node unreachable */
+#define NSP_REASON_NL 41 /* No-link message */
+#define NSP_REASON_DC 42 /* Disconnect confirm */
+#define NSP_REASON_IO 43 /* Image data field overflow */
#define NSP_DISCINIT 0x38
#define NSP_DISCCONF 0x48
diff --git a/include/net/irda/discovery.h b/include/net/irda/discovery.h
index 90b8abd41..dccf1246c 100644
--- a/include/net/irda/discovery.h
+++ b/include/net/irda/discovery.h
@@ -44,8 +44,8 @@
/*
* The DISCOVERY structure is used for both discovery requests and responses
*/
-typedef struct {
- queue_t q; /* Must be first! */
+typedef struct discovery_t {
+ irda_queue_t q; /* Must be first! */
__u32 saddr; /* Which link the device was discovered */
__u32 daddr; /* Remote device address */
@@ -59,10 +59,12 @@ typedef struct {
int gen_addr_bit; /* Need to generate a new device address? */
int nslots; /* Number of slots to use when discovering */
unsigned long timestamp; /* Time discovered */
+ unsigned long first_timestamp; /* First time discovered */
} discovery_t;
void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery);
void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log);
void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force);
+struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask);
#endif
diff --git a/include/net/irda/ircomm_core.h b/include/net/irda/ircomm_core.h
index b555b37e2..3e891c201 100644
--- a/include/net/irda/ircomm_core.h
+++ b/include/net/irda/ircomm_core.h
@@ -53,7 +53,7 @@ typedef struct {
} call_t;
struct ircomm_cb {
- queue_t queue;
+ irda_queue_t queue;
magic_t magic;
notify_t notify;
diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
index 3946ebb98..d66686510 100644
--- a/include/net/irda/ircomm_tty.h
+++ b/include/net/irda/ircomm_tty.h
@@ -48,7 +48,7 @@
* IrCOMM TTY driver state
*/
struct ircomm_tty_cb {
- queue_t queue; /* Must be first */
+ irda_queue_t queue; /* Must be first */
magic_t magic;
int state; /* Connect state */
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 3bb5e4e77..8bdfee75a 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -110,8 +110,14 @@ if(!(expr)) { \
typedef enum { FLOW_STOP, FLOW_START } LOCAL_FLOW;
+/* A few forward declarations (to make compiler happy) */
+struct tsap_cb; /* in <net/irda/irttp.h> */
+struct lsap_cb; /* in <net/irda/irlmp.h> */
+struct iriap_cb; /* in <net/irda/iriap.h> */
+struct ias_value; /* in <net/irda/irias_object.h> */
+struct discovery_t; /* in <net/irda/discovery.h> */
+
/* IrDA Socket */
-struct tsap_cb;
struct irda_sock {
__u32 saddr; /* my local address */
__u32 daddr; /* peer address */
@@ -137,14 +143,18 @@ struct irda_sock {
struct ias_object *ias_obj; /* Our service name + lsap in IAS */
struct iriap_cb *iriap; /* Used to query remote IAS */
- struct ias_value *ias_result; /* Used by getsockopt(IRLMP_IAS_QUERY) */
+ struct ias_value *ias_result; /* Result of remote IAS query */
+
+ hashbin_t *cachelog; /* Result of discovery query */
+ struct discovery_t *cachediscovery; /* Result of selective discovery query */
int nslots; /* Number of slots to use for discovery */
int errno; /* status of the IAS query */
struct sock *sk;
- wait_queue_head_t ias_wait; /* Wait for LM-IAS answer */
+ wait_queue_head_t query_wait; /* Wait for the answer to a query */
+ struct timer_list watchdog; /* Timeout for discovery */
LOCAL_FLOW tx_flow;
LOCAL_FLOW rx_flow;
@@ -166,12 +176,14 @@ typedef union {
* (must not exceed 48 bytes, check with struct sk_buff)
*/
struct irda_skb_cb {
- magic_t magic; /* Be sure that we can trust the information */
- __u32 speed; /* The Speed this frame should be sent with */
- __u16 mtt; /* Minimum turn around time */
- int xbofs; /* Number of xbofs required, used by SIR mode */
- __u8 line; /* Used by IrCOMM in IrLPT mode */
- void (*destructor)(struct sk_buff *skb); /* Used for flow control */
+ magic_t magic; /* Be sure that we can trust the information */
+ __u32 speed; /* The Speed this frame should be sent with */
+ __u16 mtt; /* Minimum turn around time */
+ __u16 xbofs; /* Number of xbofs required, used by SIR mode */
+ void *context; /* May be used by drivers */
+ void (*destructor)(struct sk_buff *skb); /* Used for flow control */
+ __u16 xbofs_delay; /* Number of xbofs used for generating the mtt */
+ __u8 line; /* Used by IrCOMM in IrLPT mode */
};
/* Misc status information */
@@ -232,6 +244,8 @@ typedef struct {
void (*disconnect_indication)(void *instance, void *sap,
LM_REASON reason, struct sk_buff *);
void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow);
+ void (*status_indication)(void *instance,
+ LINK_STATUS link, LOCK_STATUS lock);
void *instance; /* Layer instance pointer */
char name[16]; /* Name of layer */
} notify_t;
diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h
index d6733d60b..ac66f61bd 100644
--- a/include/net/irda/irda_device.h
+++ b/include/net/irda/irda_device.h
@@ -79,7 +79,7 @@ struct irda_task;
typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task);
struct irda_task {
- queue_t q;
+ irda_queue_t q;
magic_t magic;
IRDA_TASK_STATE state;
@@ -111,7 +111,7 @@ typedef struct {
/* Dongle registration info */
struct dongle_reg {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
IRDA_DONGLE type;
void (*open)(dongle_t *dongle, struct qos_info *qos);
diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h
index cd0dff5a9..8aed55b1c 100644
--- a/include/net/irda/iriap.h
+++ b/include/net/irda/iriap.h
@@ -58,7 +58,7 @@ typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id,
struct ias_value *value, void *priv);
struct iriap_cb {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
magic_t magic; /* Magic cookie */
int mode; /* Client or server */
diff --git a/include/net/irda/irias_object.h b/include/net/irda/irias_object.h
index cfa8e28ed..ff6b0b7b9 100644
--- a/include/net/irda/irias_object.h
+++ b/include/net/irda/irias_object.h
@@ -34,11 +34,15 @@
#define IAS_OCT_SEQ 2
#define IAS_STRING 3
+/* Object ownership of attributes (user or kernel) */
+#define IAS_KERNEL_ATTR 0
+#define IAS_USER_ATTR 1
+
/*
* LM-IAS Object
*/
struct ias_object {
- queue_t q; /* Must be first! */
+ irda_queue_t q; /* Must be first! */
magic_t magic;
char *name;
@@ -51,6 +55,7 @@ struct ias_object {
*/
struct ias_value {
__u8 type; /* Value description */
+ __u8 owner; /* Managed from user/kernel space */
int charset; /* Only used by string type */
int len;
@@ -66,7 +71,7 @@ struct ias_value {
* Attributes used by LM-IAS objects
*/
struct ias_attrib {
- queue_t q; /* Must be first! */
+ irda_queue_t q; /* Must be first! */
int magic;
char *name; /* Attribute name */
@@ -78,12 +83,15 @@ char *strdup(char *str);
struct ias_object *irias_new_object(char *name, int id);
void irias_insert_object(struct ias_object *obj);
int irias_delete_object(struct ias_object *obj);
+int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib);
void __irias_delete_object(struct ias_object *obj);
-void irias_add_integer_attrib(struct ias_object *obj, char *name, int value);
-void irias_add_string_attrib(struct ias_object *obj, char *name, char *value);
+void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
+ int user);
+void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
+ int user);
void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
- int len);
+ int len, int user);
int irias_object_change_attribute(char *obj_name, char *attrib_name,
struct ias_value *new_value);
struct ias_object *irias_find_object(char *name);
diff --git a/include/net/irda/irlan_client.h b/include/net/irda/irlan_client.h
index 62ea6157a..2aab19e90 100644
--- a/include/net/irda/irlan_client.h
+++ b/include/net/irda/irlan_client.h
@@ -34,7 +34,7 @@
#include <net/irda/irlan_event.h>
void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
-void irlan_client_discovery_indication(discovery_t *);
+void irlan_client_discovery_indication(discovery_t *, void *);
void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 9ed6a9c36..02ecaf8e3 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -161,28 +161,26 @@ struct irlan_provider_cb {
* IrLAN control block
*/
struct irlan_cb {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
int magic;
struct net_device dev; /* Ethernet device structure*/
struct net_device_stats stats;
- __u32 saddr; /* Source device address */
- __u32 daddr; /* Destination device address */
- int netdev_registered;
- int notify_irmanager;
+ __u32 saddr; /* Source device address */
+ __u32 daddr; /* Destination device address */
+ int disconnect_reason; /* Why we got disconnected */
- int media; /* Media type */
- __u8 version[2]; /* IrLAN version */
+ int media; /* Media type */
+ __u8 version[2]; /* IrLAN version */
- struct tsap_cb *tsap_data;
+ struct tsap_cb *tsap_data; /* Data TSAP */
- int master; /* Master instance? */
- int use_udata; /* Use Unit Data transfers */
+ int use_udata; /* Use Unit Data transfers */
- __u8 stsap_sel_data; /* Source data TSAP selector */
- __u8 dtsap_sel_data; /* Destination data TSAP selector */
- __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */
+ __u8 stsap_sel_data; /* Source data TSAP selector */
+ __u8 dtsap_sel_data; /* Destination data TSAP selector */
+ __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */
struct irlan_client_cb client; /* Client specific fields */
struct irlan_provider_cb provider; /* Provider specific fields */
@@ -190,10 +188,11 @@ struct irlan_cb {
__u32 max_sdu_size;
__u8 max_header_size;
+ wait_queue_head_t open_wait;
struct timer_list watchdog_timer;
};
-struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev);
+struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr);
void irlan_close(struct irlan_cb *self);
void irlan_close_tsaps(struct irlan_cb *self);
void irlan_mod_inc_use_count(void);
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index 36c1c03fd..3c1b95f50 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -81,7 +81,7 @@
#define irda_incomp (*self->decompressor.cp->incomp)
struct irda_compressor {
- queue_t q;
+ irda_queue_t q;
struct compressor *cp;
void *state; /* Not used by IrDA */
@@ -90,7 +90,7 @@ struct irda_compressor {
/* Main structure of IrLAP */
struct irlap_cb {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
magic_t magic;
struct net_device *netdev;
@@ -214,7 +214,7 @@ void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *);
void irlap_disconnect_request(struct irlap_cb *);
void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason);
-void irlap_status_indication(int quality_of_link);
+void irlap_status_indication(struct irlap_cb *, int quality_of_link);
void irlap_test_request(__u8 *info, int len);
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index 9c9fab54d..0fe946693 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -71,22 +71,23 @@ typedef enum {
S_END,
} SERVICE;
-typedef void (*DISCOVERY_CALLBACK1) (discovery_t *);
-typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *);
+typedef void (*DISCOVERY_CALLBACK1) (discovery_t *, void *);
+typedef void (*DISCOVERY_CALLBACK2) (hashbin_t *, void *);
typedef struct {
- queue_t queue; /* Must be first */
+ irda_queue_t queue; /* Must be first */
__u16 hints; /* Hint bits */
} irlmp_service_t;
typedef struct {
- queue_t queue; /* Must be first */
+ irda_queue_t queue; /* Must be first */
__u16 hint_mask;
- DISCOVERY_CALLBACK1 callback1;
- DISCOVERY_CALLBACK2 callback2;
+ DISCOVERY_CALLBACK1 disco_callback; /* Selective discovery */
+ DISCOVERY_CALLBACK1 expir_callback; /* Selective expiration */
+ void *priv; /* Used to identify client */
} irlmp_client_t;
struct lap_cb; /* Forward decl. */
@@ -95,7 +96,7 @@ struct lap_cb; /* Forward decl. */
* Information about each logical LSAP connection
*/
struct lsap_cb {
- queue_t queue; /* Must be first */
+ irda_queue_t queue; /* Must be first */
magic_t magic;
int connected;
@@ -121,7 +122,7 @@ struct lsap_cb {
* Information about each registred IrLAP layer
*/
struct lap_cb {
- queue_t queue; /* Must be first */
+ irda_queue_t queue; /* Must be first */
magic_t magic;
int reason; /* LAP disconnect reason */
@@ -174,10 +175,10 @@ struct irlmp_cb {
hashbin_t *clients;
hashbin_t *services;
- hashbin_t *cachelog;
- int running;
+ hashbin_t *cachelog; /* Current discovery log */
+ spinlock_t log_lock; /* discovery log spinlock */
- spinlock_t lock;
+ int running;
__u16_host_order hints; /* Hint bits */
};
@@ -191,11 +192,12 @@ void irlmp_close_lsap( struct lsap_cb *self);
__u16 irlmp_service_to_hint(int service);
__u32 irlmp_register_service(__u16 hints);
int irlmp_unregister_service(__u32 handle);
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
- DISCOVERY_CALLBACK2 callback2);
+__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+ DISCOVERY_CALLBACK1 expir_clb, void *priv);
int irlmp_unregister_client(__u32 handle);
int irlmp_update_client(__u32 handle, __u16 hint_mask,
- DISCOVERY_CALLBACK1, DISCOVERY_CALLBACK2);
+ DISCOVERY_CALLBACK1 disco_clb,
+ DISCOVERY_CALLBACK1 expir_clb, void *priv);
void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *);
void irlmp_unregister_link(__u32 saddr);
@@ -214,8 +216,10 @@ int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
void irlmp_discovery_confirm(hashbin_t *discovery_log);
void irlmp_discovery_request(int nslots);
+struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask);
void irlmp_do_discovery(int nslots);
discovery_t *irlmp_get_discovery_response(void);
+void irlmp_discovery_expiry(discovery_t *expiry);
int irlmp_data_request(struct lsap_cb *, struct sk_buff *);
void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
@@ -229,7 +233,7 @@ void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *);
#endif /* CONFIG_IRDA_ULTRA */
void irlmp_status_request(void);
-void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock);
+void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock);
int irlmp_slsap_inuse(__u8 slsap);
__u8 irlmp_find_free_slsap(void);
@@ -248,9 +252,12 @@ static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
static inline int irlmp_get_lap_tx_queue_len(struct lsap_cb *self)
{
- ASSERT(self != NULL, return 0;);
- ASSERT(self->lap != NULL, return 0;);
- ASSERT(self->lap->irlap != NULL, return 0;);
+ if (self == NULL)
+ return 0;
+ if (self->lap == NULL)
+ return 0;
+ if (self->lap->irlap == NULL)
+ return 0;
return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
}
diff --git a/include/net/irda/irmod.h b/include/net/irda/irmod.h
index ae61c8682..f2ccb854c 100644
--- a/include/net/irda/irmod.h
+++ b/include/net/irda/irmod.h
@@ -69,7 +69,7 @@ typedef void (*TODO_CALLBACK)( void *self, __u32 param);
* addtional information
*/
struct irda_event {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
struct irmanager_event event;
};
@@ -78,7 +78,7 @@ struct irda_event {
* Funtions with needs to be called with a process context
*/
struct irda_todo {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
void *self;
TODO_CALLBACK callback;
@@ -94,8 +94,8 @@ struct irda_cb {
int in_use;
- queue_t *event_queue; /* Events queued for the irmanager */
- queue_t *todo_queue; /* Todo list */
+ irda_queue_t *event_queue; /* Events queued for the irmanager */
+ irda_queue_t *todo_queue; /* Todo list */
};
int irmod_init_module(void);
diff --git a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h
index 3b5bfd492..f7c1ba659 100644
--- a/include/net/irda/irqueue.h
+++ b/include/net/irda/irqueue.h
@@ -30,8 +30,8 @@
#include <linux/types.h>
#include <linux/spinlock.h>
-#ifndef QUEUE_H
-#define QUEUE_H
+#ifndef IRDA_QUEUE_H
+#define IRDA_QUEUE_H
#define NAME_SIZE 32
@@ -62,39 +62,40 @@ typedef void (*FREE_FUNC)(void *arg);
*/
#define GET_HASHBIN(x) ( x & HASHBIN_MASK )
-struct irqueue {
- struct irqueue *q_next;
- struct irqueue *q_prev;
+struct irda_queue {
+ struct irda_queue *q_next;
+ struct irda_queue *q_prev;
char q_name[NAME_SIZE];
__u32 q_hash;
};
-typedef struct irqueue queue_t;
+typedef struct irda_queue irda_queue_t;
typedef struct hashbin_t {
__u32 magic;
int hb_type;
int hb_size;
spinlock_t hb_mutex[HASHBIN_SIZE] ALIGN;
- queue_t *hb_queue[HASHBIN_SIZE] ALIGN;
+ irda_queue_t *hb_queue[HASHBIN_SIZE] ALIGN;
- queue_t* hb_current;
+ irda_queue_t* hb_current;
} hashbin_t;
hashbin_t *hashbin_new(int type);
int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func);
int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func);
-void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv,
+void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv,
char* name);
void* hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name);
void* hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name);
void* hashbin_remove_first(hashbin_t *hashbin);
-queue_t *hashbin_get_first(hashbin_t *hashbin);
-queue_t *hashbin_get_next(hashbin_t *hashbin);
+void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry);
+irda_queue_t *hashbin_get_first(hashbin_t *hashbin);
+irda_queue_t *hashbin_get_next(hashbin_t *hashbin);
-void enqueue_last(queue_t **queue, queue_t* element);
-void enqueue_first(queue_t **queue, queue_t* element);
-queue_t *dequeue_first(queue_t **queue);
+void enqueue_last(irda_queue_t **queue, irda_queue_t* element);
+void enqueue_first(irda_queue_t **queue, irda_queue_t* element);
+irda_queue_t *dequeue_first(irda_queue_t **queue);
#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size
diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h
index 2b2547fa2..a3193d758 100644
--- a/include/net/irda/irttp.h
+++ b/include/net/irda/irttp.h
@@ -63,7 +63,7 @@
* connection.
*/
struct tsap_cb {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
magic_t magic; /* Just in case */
__u8 stsap_sel; /* Source TSAP */
@@ -129,6 +129,8 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb,
int priority);
void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
+void irttp_status_indication(void *instance,
+ LINK_STATUS link, LOCK_STATUS lock);
struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
diff --git a/include/net/irda/irtty.h b/include/net/irda/irtty.h
index f96976bc3..c6c54e1ad 100644
--- a/include/net/irda/irtty.h
+++ b/include/net/irda/irtty.h
@@ -45,7 +45,7 @@ struct irtty_info {
#define IRTTY_IOC_MAXNR 2
struct irtty_cb {
- queue_t q; /* Must be first */
+ irda_queue_t q; /* Must be first */
magic_t magic;
struct net_device *netdev; /* Yes! we are some kind of netdevice */
diff --git a/include/net/irda/qos.h b/include/net/irda/qos.h
index e88f0a3bd..d95f7ead9 100644
--- a/include/net/irda/qos.h
+++ b/include/net/irda/qos.h
@@ -86,6 +86,9 @@ struct qos_info {
#endif
};
+extern int sysctl_max_baud_rate;
+extern int sysctl_max_inactive_time;
+
extern __u32 baud_rates[];
extern __u32 data_sizes[];
extern __u32 min_turn_times[];
@@ -100,15 +103,7 @@ __u32 irlap_requested_line_capacity(struct qos_info *qos);
__u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time);
int msb_index(__u16 byte);
-int value_index(__u32 value, __u32 *array);
-__u32 byte_value(__u8 byte, __u32 *array);
-__u32 index_value(int index, __u32 *array);
-
void irda_qos_bits_to_value(struct qos_info *qos);
#endif
-
-
-
-
diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h
index af843bee3..f2cc642ec 100644
--- a/include/net/irda/timer.h
+++ b/include/net/irda/timer.h
@@ -76,12 +76,14 @@ inline void irlap_start_wd_timer(struct irlap_cb *self, int timeout);
inline void irlap_start_backoff_timer(struct irlap_cb *self, int timeout);
void irlap_start_mbusy_timer(struct irlap_cb *);
+void irlap_stop_mbusy_timer(struct irlap_cb *);
struct lsap_cb;
struct lap_cb;
inline void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout);
inline void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout);
inline void irlmp_start_idle_timer(struct lap_cb *, int timeout);
+inline void irlmp_stop_idle_timer(struct lap_cb *self);
#endif
diff --git a/include/net/x25.h b/include/net/x25.h
index fc3d83ee4..257618d44 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -169,6 +169,7 @@ extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *);
/* x25_in.c */
extern int x25_process_rx_frame(struct sock *, struct sk_buff *);
+extern int x25_backlog_rcv(struct sock *, struct sk_buff *);
/* x25_link.c */
extern void x25_link_control(struct sk_buff *, struct x25_neigh *, unsigned short);
@@ -220,5 +221,8 @@ extern unsigned long x25_display_timer(struct sock *);
/* sysctl_net_x25.c */
extern void x25_register_sysctl(void);
extern void x25_unregister_sysctl(void);
-
+struct x25_skb_cb {
+ unsigned flags;
+};
+#define X25_SKB_CB(s) ((struct x25_skb_cb *) ((s)->cb))
#endif
diff --git a/init/main.c b/init/main.c
index 1505510e7..6d8d413f4 100644
--- a/init/main.c
+++ b/init/main.c
@@ -96,6 +96,7 @@ extern void sysctl_init(void);
extern void signals_init(void);
extern void bdev_init(void);
extern int init_pcmcia_ds(void);
+extern void net_notifier_init(void);
extern void free_initmem(void);
extern void filesystem_setup(void);
@@ -714,6 +715,15 @@ static void __init do_basic_setup(void)
#ifdef CONFIG_PCMCIA
init_pcmcia_ds(); /* Do this last */
#endif
+
+#ifdef CONFIG_HOTPLUG
+ /* do this after other 'do this last' stuff, because we want
+ * to minimize spurious executions of /sbin/hotplug
+ * during boot-up
+ */
+ net_notifier_init();
+#endif
+
/* Mount the root filesystem.. */
mount_root();
diff --git a/ipc/shm.c b/ipc/shm.c
index 6205bc2d1..c4607fd5e 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -376,13 +376,14 @@ static void shm_read_inode(struct inode * inode)
struct shmid_kernel *shp;
id = inode->i_ino;
- inode->i_op = NULL;
inode->i_mode = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
if (id < SEQ_MULTIPLIER) {
- if (!(shp = shm_lock (id)))
+ if (!(shp = shm_lock (id))) {
+ make_bad_inode(inode);
return;
+ }
inode->i_mode = (shp->shm_flags & S_IALLUGO) | S_IFREG;
inode->i_uid = shp->shm_perm.uid;
inode->i_gid = shp->shm_perm.gid;
@@ -572,13 +573,13 @@ static pte_t **shm_alloc(unsigned long pages, int doacc)
if (pages == 0)
return NULL;
- ret = kmalloc ((dir+1) * sizeof(pte_t *), GFP_KERNEL);
+ ret = kmalloc ((dir+1) * sizeof(pte_t *), GFP_USER);
if (!ret)
goto nomem;
for (ptr = ret; ptr < ret+dir ; ptr++)
{
- *ptr = (pte_t *)__get_free_page (GFP_KERNEL);
+ *ptr = (pte_t *)__get_free_page (GFP_USER);
if (!*ptr)
goto free;
init_ptes (*ptr, PTES_PER_PAGE);
@@ -586,7 +587,7 @@ static pte_t **shm_alloc(unsigned long pages, int doacc)
/* The last one is probably not of PAGE_SIZE: we use kmalloc */
if (last) {
- *ptr = kmalloc (last*sizeof(pte_t), GFP_KERNEL);
+ *ptr = kmalloc (last*sizeof(pte_t), GFP_USER);
if (!*ptr)
goto free;
init_ptes (*ptr, last);
@@ -724,7 +725,7 @@ static struct shmid_kernel *seg_alloc(int numpages, size_t namelen)
struct shmid_kernel *shp;
pte_t **dir;
- shp = (struct shmid_kernel *) kmalloc (sizeof (*shp) + namelen, GFP_KERNEL);
+ shp = (struct shmid_kernel *) kmalloc (sizeof (*shp) + namelen, GFP_USER);
if (!shp)
return ERR_PTR(-ENOMEM);
@@ -1202,7 +1203,7 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
char name[SHM_FMT_LEN+1];
void *user_addr;
- if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
+ if (!shm_sb || shmid < 0 || (shmid % SEQ_MULTIPLIER) == zero_id)
return -EINVAL;
if ((addr = (ulong)shmaddr)) {
diff --git a/kernel/Makefile b/kernel/Makefile
index a13812119..8f4c218f3 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -12,16 +12,12 @@ O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
sysctl.o acct.o capability.o ptrace.o timer.o user.o
-OX_OBJS += signal.o sys.o
+OX_OBJS += signal.o sys.o kmod.o context.o
ifeq ($(CONFIG_UID16),y)
O_OBJS += uid16.o
endif
-ifeq ($(CONFIG_KMOD),y)
-O_OBJS += kmod.o
-endif
-
ifeq ($(CONFIG_MODULES),y)
OX_OBJS += ksyms.o
endif
diff --git a/kernel/context.c b/kernel/context.c
new file mode 100644
index 000000000..b5219786a
--- /dev/null
+++ b/kernel/context.c
@@ -0,0 +1,60 @@
+/*
+ * linux/kernel/context.c
+ *
+ * Mechanism for running arbitrary tasks in process context
+ *
+ * dwmw2@redhat.com
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+static DECLARE_TASK_QUEUE(tq_context);
+static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
+
+void schedule_task(struct tq_struct *task)
+{
+ queue_task(task, &tq_context);
+ wake_up(&context_task_wq);
+}
+
+EXPORT_SYMBOL(schedule_task);
+
+static int context_thread(void *dummy)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ daemonize();
+ strcpy(current->comm, "eventd");
+
+ spin_lock_irq(&current->sigmask_lock);
+ sigfillset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&context_task_wq, &wait);
+
+ /*
+ * Careful: we depend on the wait-queue modifications
+ * to also act as memory barriers.
+ */
+ if (!tq_context)
+ schedule();
+
+ remove_wait_queue(&context_task_wq, &wait);
+ current->state = TASK_RUNNING;
+ run_task_queue(&tq_context);
+ }
+}
+
+static int __init start_context_thread(void)
+{
+ kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ return 0;
+}
+
+module_init(start_context_thread);
diff --git a/kernel/exit.c b/kernel/exit.c
index 3f60ec29d..33b68980b 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -467,6 +467,14 @@ fake_volatile:
goto fake_volatile;
}
+NORET_TYPE void up_and_exit(struct semaphore *sem, long code)
+{
+ if (sem)
+ up(sem);
+
+ do_exit(code);
+}
+
asmlinkage long sys_exit(int error_code)
{
do_exit((error_code&0xff)<<8);
diff --git a/kernel/fork.c b/kernel/fork.c
index b93b0b0e4..d85c3494a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -39,6 +39,7 @@ void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
unsigned long flags;
wq_write_lock_irqsave(&q->lock, flags);
+ wait->flags = 0;
__add_wait_queue(q, wait);
wq_write_unlock_irqrestore(&q->lock, flags);
}
@@ -48,6 +49,7 @@ void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
unsigned long flags;
wq_write_lock_irqsave(&q->lock, flags);
+ wait->flags = WQ_FLAG_EXCLUSIVE;
__add_wait_queue_tail(q, wait);
wq_write_unlock_irqrestore(&q->lock, flags);
}
@@ -572,9 +574,9 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
*/
if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;
+
+ get_exec_domain(p->exec_domain);
- if (p->exec_domain && p->exec_domain->module)
- __MOD_INC_USE_COUNT(p->exec_domain->module);
if (p->binfmt && p->binfmt->module)
__MOD_INC_USE_COUNT(p->binfmt->module);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 3fff3ed3d..a21507eec 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -16,17 +16,13 @@
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-/*
- modprobe_path is set via /proc/sys.
-*/
-char modprobe_path[256] = "/sbin/modprobe";
-
extern int max_threads;
static inline void
@@ -118,7 +114,8 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
}
/* Give kmod all effective privileges.. */
- current->uid = current->euid = current->fsuid = 0;
+ current->euid = current->fsuid = 0;
+ current->egid = current->fsgid = 0;
cap_set_full(current->cap_effective);
/* Allow execve args to be in kernel space. */
@@ -130,10 +127,17 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
return 0;
}
+#ifdef CONFIG_KMOD
+
+/*
+ modprobe_path is set via /proc/sys.
+*/
+char modprobe_path[256] = "/sbin/modprobe";
+
static int exec_modprobe(void * module_name)
{
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { modprobe_path, "-s", "-k", (char*)module_name, NULL };
+ char *argv[] = { modprobe_path, "-s", "-k", "--", (char*)module_name, NULL };
int ret;
ret = exec_usermodehelper(modprobe_path, argv, envp);
@@ -226,6 +230,7 @@ int request_module(const char * module_name)
}
return 0;
}
+#endif /* CONFIG_KMOD */
#ifdef CONFIG_HOTPLUG
@@ -247,6 +252,10 @@ int request_module(const char * module_name)
*/
char hotplug_path[256] = "/sbin/hotplug";
+EXPORT_SYMBOL(hotplug_path);
+
+#endif /* CONFIG_HOTPLUG */
+
static int exec_helper (void *arg)
{
@@ -286,5 +295,10 @@ int call_usermodehelper (char *path, char **argv, char **envp)
return retval;
}
+EXPORT_SYMBOL(exec_usermodehelper);
+EXPORT_SYMBOL(call_usermodehelper);
+
+#ifdef CONFIG_KMOD
+EXPORT_SYMBOL(request_module);
#endif
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index b8eb6b4f0..100adaeb3 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -71,20 +71,12 @@ __attribute__((section("__ksymtab"))) = {
#endif
-#ifdef CONFIG_KMOD
-EXPORT_SYMBOL(request_module);
-EXPORT_SYMBOL(exec_usermodehelper);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(hotplug_path);
-EXPORT_SYMBOL(call_usermodehelper);
-#endif
-#endif
-
-#ifdef CONFIG_MODULES
-EXPORT_SYMBOL(get_module_symbol);
-EXPORT_SYMBOL(put_module_symbol);
+EXPORT_SYMBOL(inter_module_register);
+EXPORT_SYMBOL(inter_module_unregister);
+EXPORT_SYMBOL(inter_module_get);
+EXPORT_SYMBOL(inter_module_get_request);
+EXPORT_SYMBOL(inter_module_put);
EXPORT_SYMBOL(try_inc_mod_count);
-#endif
/* process memory management */
EXPORT_SYMBOL(do_mmap_pgoff);
@@ -124,6 +116,7 @@ EXPORT_SYMBOL(vmtruncate);
EXPORT_SYMBOL(find_vma);
EXPORT_SYMBOL(get_unmapped_area);
EXPORT_SYMBOL(init_mm);
+EXPORT_SYMBOL(deactivate_page);
#ifdef CONFIG_HIGHMEM
EXPORT_SYMBOL(kmap_high);
EXPORT_SYMBOL(kunmap_high);
@@ -215,7 +208,6 @@ EXPORT_SYMBOL(generic_buffer_fdatasync);
EXPORT_SYMBOL(page_hash_bits);
EXPORT_SYMBOL(page_hash_table);
EXPORT_SYMBOL(file_lock_list);
-EXPORT_SYMBOL(file_lock_sem);
EXPORT_SYMBOL(locks_init_lock);
EXPORT_SYMBOL(locks_copy_lock);
EXPORT_SYMBOL(posix_lock_file);
@@ -342,6 +334,7 @@ EXPORT_SYMBOL(register_sysctl_table);
EXPORT_SYMBOL(unregister_sysctl_table);
EXPORT_SYMBOL(sysctl_string);
EXPORT_SYMBOL(sysctl_intvec);
+EXPORT_SYMBOL(sysctl_jiffies);
EXPORT_SYMBOL(proc_dostring);
EXPORT_SYMBOL(proc_dointvec);
EXPORT_SYMBOL(proc_dointvec_jiffies);
@@ -425,6 +418,7 @@ EXPORT_SYMBOL(ioport_resource);
EXPORT_SYMBOL(iomem_resource);
/* process management */
+EXPORT_SYMBOL(up_and_exit);
EXPORT_SYMBOL(__wake_up);
EXPORT_SYMBOL(wake_up_process);
EXPORT_SYMBOL(sleep_on);
@@ -494,10 +488,6 @@ EXPORT_SYMBOL(remove_inode_hash);
EXPORT_SYMBOL(make_bad_inode);
EXPORT_SYMBOL(is_bad_inode);
EXPORT_SYMBOL(event);
-EXPORT_SYMBOL(__down);
-EXPORT_SYMBOL(__down_interruptible);
-EXPORT_SYMBOL(__down_trylock);
-EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(brw_page);
#ifdef CONFIG_UID16
diff --git a/kernel/module.c b/kernel/module.c
index 15efa305c..e89149de9 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1,11 +1,14 @@
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <asm/module.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
#include <asm/pgalloc.h>
#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
/*
* Originally by Anonymous (as far as I know...)
@@ -14,11 +17,17 @@
* Heavily modified by Bjorn Ekwall <bj0rn@blox.se> May 1994 (C)
* Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
* Add MOD_INITIALIZING Keith Owens <kaos@ocs.com.au> Nov 1999
+ * Add kallsyms support, Keith Owens <kaos@ocs.com.au> Apr 2000
+ * Add asm/module support, IA64 has special requirements. Keith Owens <kaos@ocs.com.au> Sep 2000
+ * Fix assorted bugs in module verification. Keith Owens <kaos@ocs.com.au> Sep 2000
+ * Fix sys_init_module race, Andrew Morton <andrewm@uow.edu.au> Oct 2000
+ * http://www.uwsg.iu.edu/hypermail/linux/kernel/0008.3/0379.html
+ * Replace xxx_module_symbol with inter_module_xxx. Keith Owens <kaos@ocs.com.au> Oct 2000
*
* This source is covered by the GNU GPL, the same as all kernel sources.
*/
-#ifdef CONFIG_MODULES /* a *big* #ifdef block... */
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
extern struct module_symbol __start___ksymtab[];
extern struct module_symbol __stop___ksymtab[];
@@ -26,6 +35,9 @@ extern struct module_symbol __stop___ksymtab[];
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
+extern const char __start___kallsyms[] __attribute__ ((weak));
+extern const char __stop___kallsyms[] __attribute__ ((weak));
+
static struct module kernel_module =
{
size_of_struct: sizeof(struct module),
@@ -33,16 +45,182 @@ static struct module kernel_module =
uc: {ATOMIC_INIT(1)},
flags: MOD_RUNNING,
syms: __start___ksymtab,
- ex_table_start: __start___ex_table,
- ex_table_end: __stop___ex_table
+ ex_table_start: __start___ex_table,
+ ex_table_end: __stop___ex_table,
+ kallsyms_start: __start___kallsyms,
+ kallsyms_end: __stop___kallsyms,
};
struct module *module_list = &kernel_module;
+#endif /* defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) */
+
+/* inter_module functions are always available, even when the kernel is
+ * compiled without modules. Consumers of inter_module_xxx routines
+ * will always work, even when both are built into the kernel, this
+ * approach removes lots of #ifdefs in mainline code.
+ */
+
+static struct list_head ime_list = LIST_HEAD_INIT(ime_list);
+static spinlock_t ime_lock = SPIN_LOCK_UNLOCKED;
+static int kmalloc_failed;
+
+/**
+ * inter_module_register - register a new set of inter module data.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ * @owner: module that is registering the data, always use THIS_MODULE
+ * @userdata: pointer to arbitrary userdata to be registered
+ *
+ * Description: Check that the im_name has not already been registered,
+ * complain if it has. For new data, add it to the inter_module_entry
+ * list.
+ */
+void inter_module_register(const char *im_name, struct module *owner, const void *userdata)
+{
+ struct list_head *tmp;
+ struct inter_module_entry *ime, *ime_new;
+
+ if (!(ime_new = kmalloc(sizeof(*ime), GFP_KERNEL))) {
+ /* Overloaded kernel, not fatal */
+ printk(KERN_ERR
+ "Aiee, inter_module_register: cannot kmalloc entry for '%s'\n",
+ im_name);
+ kmalloc_failed = 1;
+ return;
+ }
+ memset(ime_new, 0, sizeof(*ime_new));
+ ime_new->im_name = im_name;
+ ime_new->owner = owner;
+ ime_new->userdata = userdata;
+
+ spin_lock(&ime_lock);
+ list_for_each(tmp, &ime_list) {
+ ime = list_entry(tmp, struct inter_module_entry, list);
+ if (strcmp(ime->im_name, im_name) == 0) {
+ spin_unlock(&ime_lock);
+ kfree(ime_new);
+ /* Program logic error, fatal */
+ panic("inter_module_register: duplicate im_name '%s'", im_name);
+ }
+ }
+ list_add(&(ime_new->list), &ime_list);
+ spin_unlock(&ime_lock);
+}
+
+/**
+ * inter_module_unregister - unregister a set of inter module data.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: Check that the im_name has been registered, complain if
+ * it has not. For existing data, remove it from the
+ * inter_module_entry list.
+ */
+void inter_module_unregister(const char *im_name)
+{
+ struct list_head *tmp;
+ struct inter_module_entry *ime;
+
+ spin_lock(&ime_lock);
+ list_for_each(tmp, &ime_list) {
+ ime = list_entry(tmp, struct inter_module_entry, list);
+ if (strcmp(ime->im_name, im_name) == 0) {
+ list_del(&(ime->list));
+ spin_unlock(&ime_lock);
+ kfree(ime);
+ return;
+ }
+ }
+ spin_unlock(&ime_lock);
+ if (kmalloc_failed) {
+ printk(KERN_ERR
+ "inter_module_unregister: no entry for '%s', "
+ "probably caused by previous kmalloc failure\n",
+ im_name);
+ return;
+ }
+ else {
+ /* Program logic error, fatal */
+ panic("inter_module_unregister: no entry for '%s'", im_name);
+ }
+}
+
+/**
+ * inter_module_get - return arbitrary userdata from another module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: If the im_name has not been registered, return NULL.
+ * Try to increment the use count on the owning module, if that fails
+ * then return NULL. Otherwise return the userdata.
+ */
+const void *inter_module_get(const char *im_name)
+{
+ struct list_head *tmp;
+ struct inter_module_entry *ime;
+ const void *result = NULL;
+
+ spin_lock(&ime_lock);
+ list_for_each(tmp, &ime_list) {
+ ime = list_entry(tmp, struct inter_module_entry, list);
+ if (strcmp(ime->im_name, im_name) == 0) {
+ if (try_inc_mod_count(ime->owner))
+ result = ime->userdata;
+ break;
+ }
+ }
+ spin_unlock(&ime_lock);
+ return(result);
+}
+
+/**
+ * inter_module_get_request - im get with automatic request_module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ * @modname: module that is expected to register im_name
+ *
+ * Description: If inter_module_get fails, do request_module then retry.
+ */
+const void *inter_module_get_request(const char *im_name, const char *modname)
+{
+ const void *result = inter_module_get(im_name);
+ if (!result) {
+ request_module(modname);
+ result = inter_module_get(im_name);
+ }
+ return(result);
+}
+
+/**
+ * inter_module_put - release use of data from another module.
+ * @im_name: an arbitrary string to identify the data, must be unique
+ *
+ * Description: If the im_name has not been registered, complain,
+ * otherwise decrement the use count on the owning module.
+ */
+void inter_module_put(const char *im_name)
+{
+ struct list_head *tmp;
+ struct inter_module_entry *ime;
+
+ spin_lock(&ime_lock);
+ list_for_each(tmp, &ime_list) {
+ ime = list_entry(tmp, struct inter_module_entry, list);
+ if (strcmp(ime->im_name, im_name) == 0) {
+ if (ime->owner)
+ __MOD_DEC_USE_COUNT(ime->owner);
+ spin_unlock(&ime_lock);
+ return;
+ }
+ }
+ spin_unlock(&ime_lock);
+ panic("inter_module_put: no entry for '%s'", im_name);
+}
+
+
+#if defined(CONFIG_MODULES) /* The rest of the source */
+
static long get_mod_name(const char *user_name, char **buf);
static void put_mod_name(char *buf);
-static struct module *find_module(const char *name);
-static void free_module(struct module *, int tag_freed);
+struct module *find_module(const char *name);
+void free_module(struct module *, int tag_freed);
/*
@@ -151,7 +329,7 @@ asmlinkage long
sys_init_module(const char *name_user, struct module *mod_user)
{
struct module mod_tmp, *mod;
- char *name, *n_name;
+ char *name, *n_name, *name_tmp = NULL;
long namelen, n_namelen, i, error;
unsigned long mod_user_size;
struct module_ref *dep;
@@ -168,7 +346,7 @@ sys_init_module(const char *name_user, struct module *mod_user)
goto err1;
}
- /* Check module header size. We allow a bit of slop over the
+ /* Check module header size. We allow a bit of slop over the
size we are familiar with to cope with a version of insmod
for a newer kernel. But don't over do it. */
if ((error = get_user(mod_user_size, &mod_user->size_of_struct)) != 0)
@@ -185,8 +363,14 @@ sys_init_module(const char *name_user, struct module *mod_user)
/* Hold the current contents while we play with the user's idea
of righteousness. */
mod_tmp = *mod;
+ name_tmp = kmalloc(strlen(mod->name) + 1, GFP_KERNEL); /* Where's kstrdup()? */
+ if (name_tmp == NULL) {
+ error = -ENOMEM;
+ goto err1;
+ }
+ strcpy(name_tmp, mod->name);
- error = copy_from_user(mod, mod_user, sizeof(struct module));
+ error = copy_from_user(mod, mod_user, mod_user_size);
if (error) {
error = -EFAULT;
goto err2;
@@ -203,32 +387,29 @@ sys_init_module(const char *name_user, struct module *mod_user)
/* Make sure all interesting pointers are sane. */
-#define bound(p, n, m) ((unsigned long)(p) >= (unsigned long)(m+1) && \
- (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)
-
- if (!bound(mod->name, namelen, mod)) {
+ if (!mod_bound(mod->name, namelen, mod)) {
printk(KERN_ERR "init_module: mod->name out of bounds.\n");
goto err2;
}
- if (mod->nsyms && !bound(mod->syms, mod->nsyms, mod)) {
+ if (mod->nsyms && !mod_bound(mod->syms, mod->nsyms, mod)) {
printk(KERN_ERR "init_module: mod->syms out of bounds.\n");
goto err2;
}
- if (mod->ndeps && !bound(mod->deps, mod->ndeps, mod)) {
+ if (mod->ndeps && !mod_bound(mod->deps, mod->ndeps, mod)) {
printk(KERN_ERR "init_module: mod->deps out of bounds.\n");
goto err2;
}
- if (mod->init && !bound(mod->init, 0, mod)) {
+ if (mod->init && !mod_bound(mod->init, 0, mod)) {
printk(KERN_ERR "init_module: mod->init out of bounds.\n");
goto err2;
}
- if (mod->cleanup && !bound(mod->cleanup, 0, mod)) {
+ if (mod->cleanup && !mod_bound(mod->cleanup, 0, mod)) {
printk(KERN_ERR "init_module: mod->cleanup out of bounds.\n");
goto err2;
}
if (mod->ex_table_start > mod->ex_table_end
|| (mod->ex_table_start &&
- !((unsigned long)mod->ex_table_start >= (unsigned long)(mod+1)
+ !((unsigned long)mod->ex_table_start >= ((unsigned long)mod + mod->size_of_struct)
&& ((unsigned long)mod->ex_table_end
< (unsigned long)mod + mod->size)))
|| (((unsigned long)mod->ex_table_start
@@ -242,24 +423,51 @@ sys_init_module(const char *name_user, struct module *mod_user)
goto err2;
}
#ifdef __alpha__
- if (!bound(mod->gp - 0x8000, 0, mod)) {
+ if (!mod_bound(mod->gp - 0x8000, 0, mod)) {
printk(KERN_ERR "init_module: mod->gp out of bounds.\n");
goto err2;
}
#endif
if (mod_member_present(mod, can_unload)
- && mod->can_unload && !bound(mod->can_unload, 0, mod)) {
+ && mod->can_unload && !mod_bound(mod->can_unload, 0, mod)) {
printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n");
goto err2;
}
-
-#undef bound
+ if (mod_member_present(mod, kallsyms_end)) {
+ if (mod->kallsyms_end &&
+ (!mod_bound(mod->kallsyms_start, 0, mod) ||
+ !mod_bound(mod->kallsyms_end, 0, mod))) {
+ printk(KERN_ERR "init_module: mod->kallsyms out of bounds.\n");
+ goto err2;
+ }
+ if (mod->kallsyms_start > mod->kallsyms_end) {
+ printk(KERN_ERR "init_module: mod->kallsyms invalid.\n");
+ goto err2;
+ }
+ }
+ if (mod_member_present(mod, archdata_end)) {
+ if (mod->archdata_end &&
+ (!mod_bound(mod->archdata_start, 0, mod) ||
+ !mod_bound(mod->archdata_end, 0, mod))) {
+ printk(KERN_ERR "init_module: mod->archdata out of bounds.\n");
+ goto err2;
+ }
+ if (mod->archdata_start > mod->archdata_end) {
+ printk(KERN_ERR "init_module: mod->archdata invalid.\n");
+ goto err2;
+ }
+ }
+ if (mod_member_present(mod, kernel_data) && mod->kernel_data) {
+ printk(KERN_ERR "init_module: mod->kernel_data must be zero.\n");
+ goto err2;
+ }
/* Check that the user isn't doing something silly with the name. */
if ((n_namelen = get_mod_name(mod->name - (unsigned long)mod
+ (unsigned long)mod_user,
&n_name)) < 0) {
+ printk(KERN_ERR "init_module: get_mod_name failure.\n");
error = n_namelen;
goto err2;
}
@@ -277,13 +485,17 @@ sys_init_module(const char *name_user, struct module *mod_user)
goto err3;
}
+ if (module_arch_init(mod))
+ goto err3;
+
/* On some machines it is necessary to do something here
to make the I and D caches consistent. */
flush_icache_range((unsigned long)mod, (unsigned long)mod + mod->size);
- /* Update module references. */
mod->next = mod_tmp.next;
mod->refs = NULL;
+
+ /* Sanity check the module's dependents */
for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
struct module *o, *d = dep->dep;
@@ -294,18 +506,25 @@ sys_init_module(const char *name_user, struct module *mod_user)
goto err3;
}
- for (o = module_list; o != &kernel_module; o = o->next)
- if (o == d) goto found_dep;
+ /* Scan the current modules for this dependency */
+ for (o = module_list; o != &kernel_module && o != d; o = o->next)
+ ;
- printk(KERN_ERR "init_module: found dependency that is "
+ if (o != d) {
+ printk(KERN_ERR "init_module: found dependency that is "
"(no longer?) a module.\n");
- goto err3;
-
- found_dep:
+ goto err3;
+ }
+ }
+
+ /* Update module references. */
+ for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) {
+ struct module *d = dep->dep;
+
dep->ref = mod;
dep->next_ref = d->refs;
d->refs = dep;
- /* Being referenced by a dependent module counts as a
+ /* Being referenced by a dependent module counts as a
use as far as kmod is concerned. */
d->flags |= MOD_USED_ONCE;
}
@@ -335,10 +554,12 @@ err3:
put_mod_name(n_name);
err2:
*mod = mod_tmp;
+ strcpy((char *)mod->name, name_tmp); /* We know there is room for this */
err1:
put_mod_name(name);
err0:
unlock_kernel();
+ kfree(name_tmp);
return error;
}
@@ -384,11 +605,11 @@ sys_delete_module(const char *name_user)
}
put_mod_name(name);
error = -EBUSY;
- if (mod->refs != NULL)
+ if (mod->refs != NULL)
goto out;
spin_lock(&unload_lock);
- if (!__MOD_IN_USE(mod)) {
+ if (!__MOD_IN_USE(mod)) {
mod->flags |= MOD_DELETED;
spin_unlock(&unload_lock);
free_module(mod, 0);
@@ -768,7 +989,7 @@ out:
* Look for a module by name, ignoring modules marked for deletion.
*/
-static struct module *
+struct module *
find_module(const char *name)
{
struct module *mod;
@@ -787,7 +1008,7 @@ find_module(const char *name)
* Free the given module.
*/
-static void
+void
free_module(struct module *mod, int tag_freed)
{
struct module_ref *dep;
@@ -795,7 +1016,7 @@ free_module(struct module *mod, int tag_freed)
/* Let the module clean up. */
- if (mod->flags & MOD_RUNNING)
+ if (mod->flags & MOD_RUNNING)
{
if(mod->cleanup)
mod->cleanup();
@@ -852,7 +1073,7 @@ int get_module_list(char *p)
} while (0)
#define safe_copy_cstr(str) safe_copy_str(str, sizeof(str)-1)
- len = strlen(mod->name);
+ len = strlen(mod->name);
safe_copy_str(mod->name, len);
if ((len = 20 - len) > 0) {
@@ -961,58 +1182,6 @@ leave_the_loop:
return len;
}
-/*
- * Gets the address for a symbol in the given module. If modname is
- * NULL, it looks for the name in any registered symbol table. If the
- * modname is an empty string, it looks for the symbol in kernel exported
- * symbol tables. Increase the usage count of the module in which the
- * symbol was found - it's the only way we can guarantee that it's still
- * there by the time our caller actually uses it.
- */
-unsigned long
-get_module_symbol(char *modname, char *symname)
-{
- struct module *mp;
- struct module_symbol *sym;
- int i;
-
- spin_lock(&unload_lock);
- for (mp = module_list; mp; mp = mp->next) {
- if (((modname == NULL) || (strcmp(mp->name, modname) == 0)) &&
- MOD_CAN_QUERY(mp) &&
- (mp->nsyms > 0)) {
- for (i = mp->nsyms, sym = mp->syms;
- i > 0; --i, ++sym) {
-
- if (strcmp(sym->name, symname) == 0) {
- __MOD_INC_USE_COUNT(mp);
- spin_unlock(&unload_lock);
- return sym->value;
- }
- }
- }
- }
- spin_unlock(&unload_lock);
- return 0;
-}
-
-/* Decrease the use count of the module containing a symbol with the
- * address passed.
- */
-void put_module_symbol(unsigned long addr)
-{
- struct module *mp;
-
- for (mp = module_list; mp; mp = mp->next) {
- if (MOD_CAN_QUERY(mp) &&
- addr >= (unsigned long)mp &&
- addr < (unsigned long)mp + mp->size) {
- __MOD_DEC_USE_COUNT(mp);
- return;
- }
- }
-}
-
#else /* CONFIG_MODULES */
/* Dummy syscalls for people who don't want modules */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 87dea8254..957355ef4 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -24,7 +24,7 @@ static int access_one_page(struct mm_struct * mm, struct vm_area_struct * vma, u
pgd_t * pgdir;
pmd_t * pgmiddle;
pte_t * pgtable;
- unsigned long maddr;
+ char *maddr;
struct page *page;
repeat:
@@ -54,13 +54,13 @@ repeat:
if (write) {
maddr = kmap(page);
- memcpy((char *)maddr + (addr & ~PAGE_MASK), buf, len);
+ memcpy(maddr + (addr & ~PAGE_MASK), buf, len);
flush_page_to_ram(page);
flush_icache_page(vma, page, addr);
kunmap(page);
} else {
maddr = kmap(page);
- memcpy(buf, (char *)maddr + (addr & ~PAGE_MASK), len);
+ memcpy(buf, maddr + (addr & ~PAGE_MASK), len);
flush_page_to_ram(page);
kunmap(page);
}
diff --git a/kernel/resource.c b/kernel/resource.c
index 3d7aa17d0..b553eb0ff 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -288,7 +288,7 @@ void __release_region(struct resource *parent, unsigned long start, unsigned lon
}
p = &res->sibling;
}
- printk("Trying to free nonexistent resource <%04lx-%04lx>\n", start, end);
+ printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
}
/*
diff --git a/kernel/sched.c b/kernel/sched.c
index 927bf47e7..119edeb81 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -77,16 +77,14 @@ struct task_struct * init_tasks[NR_CPUS] = {&init_task, };
/*
* The tasklist_lock protects the linked list of processes.
*
- * The scheduler lock is protecting against multiple entry
- * into the scheduling code, and doesn't need to worry
- * about interrupts (because interrupts cannot call the
- * scheduler).
- *
- * The run-queue lock locks the parts that actually access
+ * The runqueue_lock locks the parts that actually access
* and change the run-queues, and have to be interrupt-safe.
+ *
+ * If both locks are to be concurrently held, the runqueue_lock
+ * nests inside the tasklist_lock.
*/
-spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* second */
-rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* third */
+spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* inner */
+rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */
static LIST_HEAD(runqueue_head);
@@ -199,12 +197,8 @@ static inline int preemption_goodness(struct task_struct * prev, struct task_str
/*
* This is ugly, but reschedule_idle() is very timing-critical.
- * We enter with the runqueue spinlock held, but we might end
- * up unlocking it early, so the caller must not unlock the
- * runqueue, it's always done by reschedule_idle().
- *
- * This function must be inline as anything that saves and restores
- * flags has to do so within the same register window on sparc (Anton)
+ * We `are called with the runqueue spinlock held and we must
+ * not claim the tasklist_lock.
*/
static FASTCALL(void reschedule_idle(struct task_struct * p));
@@ -433,15 +427,27 @@ static inline void __schedule_tail(struct task_struct *prev)
int policy;
/*
+ * prev->policy can be written from here only before `prev'
+ * can be scheduled (before setting prev->has_cpu to zero).
+ * Of course it must also be read before allowing prev
+ * to be rescheduled, but since the write depends on the read
+ * to complete, wmb() is enough. (the spin_lock() acquired
+ * before setting has_cpu is not enough because the spin_lock()
+ * common code semantics allows code outside the critical section
+ * to enter inside the critical section)
+ */
+ policy = prev->policy;
+ prev->policy = policy & ~SCHED_YIELD;
+ wmb();
+
+ /*
* fast path falls through. We have to clear has_cpu before
* checking prev->state to avoid a wakeup race - thus we
* also have to protect against the task exiting early.
*/
task_lock(prev);
- policy = prev->policy;
- prev->policy = policy & ~SCHED_YIELD;
prev->has_cpu = 0;
- wmb();
+ mb();
if (prev->state == TASK_RUNNING)
goto needs_resched;
@@ -535,7 +541,7 @@ handle_softirq_back:
goto move_rr_last;
move_rr_back:
- switch (prev->state & ~TASK_EXCLUSIVE) {
+ switch (prev->state) {
case TASK_INTERRUPTIBLE:
if (signal_pending(prev)) {
prev->state = TASK_RUNNING;
@@ -694,14 +700,14 @@ scheduling_in_interrupt:
}
static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
- const int sync)
+ unsigned int wq_mode, const int sync)
{
struct list_head *tmp, *head;
struct task_struct *p, *best_exclusive;
unsigned long flags;
int best_cpu, irq;
- if (!q || !waitqueue_active(q))
+ if (!q)
goto out;
best_cpu = smp_processor_id();
@@ -730,7 +736,7 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
#endif
p = curr->task;
state = p->state;
- if (state & (mode & ~TASK_EXCLUSIVE)) {
+ if (state & mode) {
#if WAITQUEUE_DEBUG
curr->__waker = (long)__builtin_return_address(0);
#endif
@@ -739,18 +745,19 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
* prefer processes which are affine to this
* CPU.
*/
- if (irq && (state & mode & TASK_EXCLUSIVE)) {
+ if (irq && (curr->flags & wq_mode & WQ_FLAG_EXCLUSIVE)) {
if (!best_exclusive)
best_exclusive = p;
- else if ((p->processor == best_cpu) &&
- (best_exclusive->processor != best_cpu))
- best_exclusive = p;
+ if (p->processor == best_cpu) {
+ best_exclusive = p;
+ break;
+ }
} else {
if (sync)
wake_up_process_synchronous(p);
else
wake_up_process(p);
- if (state & mode & TASK_EXCLUSIVE)
+ if (curr->flags & wq_mode & WQ_FLAG_EXCLUSIVE)
break;
}
}
@@ -766,14 +773,14 @@ out:
return;
}
-void __wake_up(wait_queue_head_t *q, unsigned int mode)
+void __wake_up(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
{
- __wake_up_common(q, mode, 0);
+ __wake_up_common(q, mode, wq_mode, 0);
}
-void __wake_up_sync(wait_queue_head_t *q, unsigned int mode)
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, unsigned int wq_mode)
{
- __wake_up_common(q, mode, 1);
+ __wake_up_common(q, mode, wq_mode, 1);
}
#define SLEEP_ON_VAR \
@@ -905,8 +912,8 @@ static int setscheduler(pid_t pid, int policy,
/*
* We play safe to avoid deadlocks.
*/
- spin_lock_irq(&runqueue_lock);
- read_lock(&tasklist_lock);
+ read_lock_irq(&tasklist_lock);
+ spin_lock(&runqueue_lock);
p = find_process_by_pid(pid);
@@ -950,8 +957,8 @@ static int setscheduler(pid_t pid, int policy,
current->need_resched = 1;
out_unlock:
- read_unlock(&tasklist_lock);
- spin_unlock_irq(&runqueue_lock);
+ spin_unlock(&runqueue_lock);
+ read_unlock_irq(&tasklist_lock);
out_nounlock:
return retval;
@@ -1227,7 +1234,9 @@ void daemonize(void)
fs = init_task.fs;
current->fs = fs;
atomic_inc(&fs->count);
-
+ exit_files(current);
+ current->files = init_task.files;
+ atomic_inc(&current->files->count);
}
void __init init_idle(void)
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 70da2a029..5591ee2bc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -54,10 +54,10 @@ static int minolduid;
#ifdef CONFIG_KMOD
extern char modprobe_path[];
+#endif
#ifdef CONFIG_HOTPLUG
extern char hotplug_path[];
#endif
-#endif
#ifdef CONFIG_CHR_DEV_SG
extern int sg_big_buff;
#endif
@@ -188,11 +188,11 @@ static ctl_table kern_table[] = {
#ifdef CONFIG_KMOD
{KERN_MODPROBE, "modprobe", &modprobe_path, 256,
0644, NULL, &proc_dostring, &sysctl_string },
+#endif
#ifdef CONFIG_HOTPLUG
{KERN_HOTPLUG, "hotplug", &hotplug_path, 256,
0644, NULL, &proc_dostring, &sysctl_string },
#endif
-#endif
#ifdef CONFIG_CHR_DEV_SG
{KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
0444, NULL, &proc_dointvec},
@@ -571,7 +571,7 @@ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root
}
/* Don't unregister proc entries that are still being used.. */
- if (de->count)
+ if (atomic_read(&de->count))
continue;
table->de = NULL;
@@ -1240,6 +1240,13 @@ int sysctl_intvec(ctl_table *table, int *name, int nlen,
return -ENOSYS;
}
+int sysctl_jiffies(ctl_table *table, int *name, int nlen,
+ void *oldval, size_t *oldlenp,
+ void *newval, size_t newlen, void **context)
+{
+ return -ENOSYS;
+}
+
int proc_dostring(ctl_table *table, int write, struct file *filp,
void *buffer, size_t *lenp)
{
diff --git a/mm/filemap.c b/mm/filemap.c
index b19f4c5b3..a191cc2f4 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -387,7 +387,7 @@ static inline void __add_to_page_cache(struct page * page,
if (PageLocked(page))
BUG();
- flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1));
page->flags = flags | (1 << PG_locked);
page_cache_get(page);
page->index = offset;
@@ -1095,14 +1095,14 @@ no_cached_page:
static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
- unsigned long kaddr;
+ char *kaddr;
unsigned long left, count = desc->count;
if (size > count)
size = count;
kaddr = kmap(page);
- left = __copy_to_user(desc->buf, (void *)(kaddr + offset), size);
+ left = __copy_to_user(desc->buf, kaddr + offset, size);
kunmap(page);
if (left) {
@@ -1146,7 +1146,7 @@ ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *
static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset , unsigned long size)
{
- unsigned long kaddr;
+ char *kaddr;
ssize_t written;
unsigned long count = desc->count;
struct file *file = (struct file *) desc->buf;
@@ -1158,8 +1158,7 @@ static int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned
set_fs(KERNEL_DS);
kaddr = kmap(page);
- written = file->f_op->write(file, (char *)kaddr + offset,
- size, &file->f_pos);
+ written = file->f_op->write(file, kaddr + offset, size, &file->f_pos);
kunmap(page);
set_fs(old_fs);
if (written < 0) {
@@ -1209,8 +1208,6 @@ asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t cou
if (!out_file->f_op || !out_file->f_op->write)
goto fput_out;
out_inode = out_file->f_dentry->d_inode;
- if (!out_inode)
- goto fput_out;
retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
if (retval)
goto fput_out;
@@ -1814,11 +1811,13 @@ static long madvise_fixup_start(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = end;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -1838,10 +1837,12 @@ static long madvise_fixup_end(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_end = start;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -1871,15 +1872,17 @@ static long madvise_fixup_middle(struct vm_area_struct * vma,
vma->vm_ops->open(left);
vma->vm_ops->open(right);
}
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = start;
vma->vm_end = end;
setup_read_behavior(vma, behavior);
vma->vm_raend = 0;
- insert_vm_struct(current->mm, left);
- insert_vm_struct(current->mm, right);
+ __insert_vm_struct(current->mm, left);
+ __insert_vm_struct(current->mm, right);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
diff --git a/mm/highmem.c b/mm/highmem.c
index d83d9bb87..5e8ebde4b 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -29,7 +29,7 @@ struct page * prepare_highmem_swapout(struct page * page)
{
struct page *new_page;
unsigned long regular_page;
- unsigned long vaddr;
+
/*
* If this is a highmem page so it can't be swapped out directly
* otherwise the b_data buffer addresses will break
@@ -50,8 +50,7 @@ struct page * prepare_highmem_swapout(struct page * page)
if (!regular_page)
return NULL;
- vaddr = kmap(page);
- copy_page((void *)regular_page, (void *)vaddr);
+ copy_page((void *)regular_page, kmap(page));
kunmap(page);
/*
@@ -67,7 +66,6 @@ struct page * prepare_highmem_swapout(struct page * page)
struct page * replace_with_highmem(struct page * page)
{
struct page *highpage;
- unsigned long vaddr;
if (PageHighMem(page) || !nr_free_highpages())
return page;
@@ -80,8 +78,7 @@ struct page * replace_with_highmem(struct page * page)
return page;
}
- vaddr = kmap(highpage);
- copy_page((void *)vaddr, page_address(page));
+ copy_page(kmap(highpage), page_address(page));
kunmap(highpage);
if (page->mapping)
@@ -188,7 +185,7 @@ start:
return vaddr;
}
-unsigned long kmap_high(struct page *page)
+void *kmap_high(struct page *page)
{
unsigned long vaddr;
@@ -206,7 +203,7 @@ unsigned long kmap_high(struct page *page)
if (pkmap_count[PKMAP_NR(vaddr)] < 2)
BUG();
spin_unlock(&kmap_lock);
- return vaddr;
+ return (void*) vaddr;
}
void kunmap_high(struct page *page)
@@ -242,7 +239,7 @@ static inline void copy_from_high_bh (struct buffer_head *to,
struct buffer_head *from)
{
struct page *p_from;
- unsigned long vfrom;
+ char *vfrom;
unsigned long flags;
p_from = from->b_page;
@@ -254,7 +251,7 @@ static inline void copy_from_high_bh (struct buffer_head *to,
__save_flags(flags);
__cli();
vfrom = kmap_atomic(p_from, KM_BOUNCE_WRITE);
- memcpy(to->b_data, (char *)vfrom + bh_offset(from), to->b_size);
+ memcpy(to->b_data, vfrom + bh_offset(from), to->b_size);
kunmap_atomic(vfrom, KM_BOUNCE_WRITE);
__restore_flags(flags);
}
@@ -263,14 +260,14 @@ static inline void copy_to_high_bh_irq (struct buffer_head *to,
struct buffer_head *from)
{
struct page *p_to;
- unsigned long vto;
+ char *vto;
unsigned long flags;
p_to = to->b_page;
__save_flags(flags);
__cli();
vto = kmap_atomic(p_to, KM_BOUNCE_READ);
- memcpy((char *)vto + bh_offset(to), from->b_data, to->b_size);
+ memcpy(vto + bh_offset(to), from->b_data, to->b_size);
kunmap_atomic(vto, KM_BOUNCE_READ);
__restore_flags(flags);
}
@@ -310,8 +307,6 @@ repeat_bh:
bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER);
if (!bh) {
wakeup_bdflush(1); /* Sets task->state to TASK_RUNNING */
- current->policy |= SCHED_YIELD;
- schedule();
goto repeat_bh;
}
/*
@@ -324,8 +319,6 @@ repeat_page:
page = alloc_page(GFP_BUFFER);
if (!page) {
wakeup_bdflush(1); /* Sets task->state to TASK_RUNNING */
- current->policy |= SCHED_YIELD;
- schedule();
goto repeat_page;
}
set_bh_page(bh, page, 0);
diff --git a/mm/memory.c b/mm/memory.c
index 11048ddce..f4bd5163e 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1201,29 +1201,32 @@ static inline int handle_pte_fault(struct mm_struct *mm,
{
pte_t entry;
+ /*
+ * We need the page table lock to synchronize with kswapd
+ * and the SMP-safe atomic PTE updates.
+ */
+ spin_lock(&mm->page_table_lock);
entry = *pte;
if (!pte_present(entry)) {
+ /*
+ * If it truly wasn't present, we know that kswapd
+ * and the PTE updates will not touch it later. So
+ * drop the lock.
+ */
+ spin_unlock(&mm->page_table_lock);
if (pte_none(entry))
return do_no_page(mm, vma, address, write_access, pte);
return do_swap_page(mm, vma, address, pte, pte_to_swp_entry(entry), write_access);
}
- /*
- * Ok, the entry was present, we need to get the page table
- * lock to synchronize with kswapd, and verify that the entry
- * didn't change from under us..
- */
- spin_lock(&mm->page_table_lock);
- if (pte_same(entry, *pte)) {
- if (write_access) {
- if (!pte_write(entry))
- return do_wp_page(mm, vma, address, pte, entry);
+ if (write_access) {
+ if (!pte_write(entry))
+ return do_wp_page(mm, vma, address, pte, entry);
- entry = pte_mkdirty(entry);
- }
- entry = pte_mkyoung(entry);
- establish_pte(vma, address, pte, entry);
+ entry = pte_mkdirty(entry);
}
+ entry = pte_mkyoung(entry);
+ establish_pte(vma, address, pte, entry);
spin_unlock(&mm->page_table_lock);
return 1;
}
diff --git a/mm/mlock.c b/mm/mlock.c
index f684a3c60..551d61d39 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -36,11 +36,13 @@ static inline int mlock_fixup_start(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = end;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -61,10 +63,12 @@ static inline int mlock_fixup_end(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_end = start;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -96,15 +100,17 @@ static inline int mlock_fixup_middle(struct vm_area_struct * vma,
vma->vm_ops->open(left);
vma->vm_ops->open(right);
}
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = start;
vma->vm_end = end;
vma->vm_flags = newflags;
vma->vm_raend = 0;
- insert_vm_struct(current->mm, left);
- insert_vm_struct(current->mm, right);
+ __insert_vm_struct(current->mm, left);
+ __insert_vm_struct(current->mm, right);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index c50de6ed8..da649f2a2 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -67,7 +67,7 @@ int vm_enough_memory(long pages)
}
/* Remove one vm structure from the inode's i_mapping address space. */
-static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
+static inline void __remove_shared_vm_struct(struct vm_area_struct *vma)
{
struct file * file = vma->vm_file;
@@ -75,14 +75,41 @@ static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
struct inode *inode = file->f_dentry->d_inode;
if (vma->vm_flags & VM_DENYWRITE)
atomic_inc(&inode->i_writecount);
- spin_lock(&inode->i_mapping->i_shared_lock);
if(vma->vm_next_share)
vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
*vma->vm_pprev_share = vma->vm_next_share;
- spin_unlock(&inode->i_mapping->i_shared_lock);
}
}
+static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
+{
+ lock_vma_mappings(vma);
+ __remove_shared_vm_struct(vma);
+ unlock_vma_mappings(vma);
+}
+
+void lock_vma_mappings(struct vm_area_struct *vma)
+{
+ struct address_space *mapping;
+
+ mapping = NULL;
+ if (vma->vm_file)
+ mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
+ if (mapping)
+ spin_lock(&mapping->i_shared_lock);
+}
+
+void unlock_vma_mappings(struct vm_area_struct *vma)
+{
+ struct address_space *mapping;
+
+ mapping = NULL;
+ if (vma->vm_file)
+ mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
+ if (mapping)
+ spin_unlock(&mapping->i_shared_lock);
+}
+
/*
* sys_brk() for the most part doesn't need the global kernel
* lock, except when an application is doing something nasty
@@ -316,13 +343,22 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
* after the call. Save the values we need now ...
*/
flags = vma->vm_flags;
- addr = vma->vm_start; /* can addr have changed?? */
+
+ /* Can addr have changed??
+ *
+ * Answer: Yes, several device drivers can do it in their
+ * f_op->mmap method. -DaveM
+ */
+ addr = vma->vm_start;
+
+ lock_vma_mappings(vma);
spin_lock(&mm->page_table_lock);
- insert_vm_struct(mm, vma);
+ __insert_vm_struct(mm, vma);
if (correct_wcount)
atomic_inc(&file->f_dentry->d_inode->i_writecount);
merge_segments(mm, vma->vm_start, vma->vm_end);
spin_unlock(&mm->page_table_lock);
+ unlock_vma_mappings(vma);
mm->total_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED) {
@@ -534,10 +570,12 @@ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm,
/* Work out to one of the ends. */
if (end == area->vm_end) {
area->vm_end = addr;
+ lock_vma_mappings(area);
spin_lock(&mm->page_table_lock);
} else if (addr == area->vm_start) {
area->vm_pgoff += (end - area->vm_start) >> PAGE_SHIFT;
area->vm_start = end;
+ lock_vma_mappings(area);
spin_lock(&mm->page_table_lock);
} else {
/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
@@ -560,12 +598,18 @@ static struct vm_area_struct * unmap_fixup(struct mm_struct *mm,
if (mpnt->vm_ops && mpnt->vm_ops->open)
mpnt->vm_ops->open(mpnt);
area->vm_end = addr; /* Truncate area */
+
+ /* Because mpnt->vm_file == area->vm_file this locks
+ * things correctly.
+ */
+ lock_vma_mappings(area);
spin_lock(&mm->page_table_lock);
- insert_vm_struct(mm, mpnt);
+ __insert_vm_struct(mm, mpnt);
}
- insert_vm_struct(mm, area);
+ __insert_vm_struct(mm, area);
spin_unlock(&mm->page_table_lock);
+ unlock_vma_mappings(area);
return extra;
}
@@ -811,10 +855,12 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
flags = vma->vm_flags;
addr = vma->vm_start;
+ lock_vma_mappings(vma);
spin_lock(&mm->page_table_lock);
- insert_vm_struct(mm, vma);
+ __insert_vm_struct(mm, vma);
merge_segments(mm, vma->vm_start, vma->vm_end);
spin_unlock(&mm->page_table_lock);
+ unlock_vma_mappings(vma);
mm->total_vm += len >> PAGE_SHIFT;
if (flags & VM_LOCKED) {
@@ -877,9 +923,10 @@ void exit_mmap(struct mm_struct * mm)
}
/* Insert vm structure into process list sorted by address
- * and into the inode's i_mmap ring.
+ * and into the inode's i_mmap ring. If vm_file is non-NULL
+ * then the i_shared_lock must be held here.
*/
-void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
+void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
{
struct vm_area_struct **pprev;
struct file * file;
@@ -916,15 +963,20 @@ void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
head = &mapping->i_mmap_shared;
/* insert vmp into inode's share list */
- spin_lock(&mapping->i_shared_lock);
if((vmp->vm_next_share = *head) != NULL)
(*head)->vm_pprev_share = &vmp->vm_next_share;
*head = vmp;
vmp->vm_pprev_share = head;
- spin_unlock(&mapping->i_shared_lock);
}
}
+void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
+{
+ lock_vma_mappings(vmp);
+ __insert_vm_struct(mm, vmp);
+ unlock_vma_mappings(vmp);
+}
+
/* Merge the list of memory segments if possible.
* Redundant vm_area_structs are freed.
* This assumes that the list is ordered by address.
@@ -986,11 +1038,13 @@ void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned l
mpnt->vm_pgoff += (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
mpnt->vm_start = mpnt->vm_end;
spin_unlock(&mm->page_table_lock);
+ unlock_vma_mappings(mpnt);
mpnt->vm_ops->close(mpnt);
+ lock_vma_mappings(mpnt);
spin_lock(&mm->page_table_lock);
}
mm->map_count--;
- remove_shared_vm_struct(mpnt);
+ __remove_shared_vm_struct(mpnt);
if (mpnt->vm_file)
fput(mpnt->vm_file);
kmem_cache_free(vm_area_cachep, mpnt);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 7b61abb3e..64c178b31 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -118,11 +118,13 @@ static inline int mprotect_fixup_start(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = end;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -145,10 +147,12 @@ static inline int mprotect_fixup_end(struct vm_area_struct * vma,
get_file(n->vm_file);
if (n->vm_ops && n->vm_ops->open)
n->vm_ops->open(n);
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_end = start;
- insert_vm_struct(current->mm, n);
+ __insert_vm_struct(current->mm, n);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
@@ -179,6 +183,7 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
vma->vm_ops->open(left);
vma->vm_ops->open(right);
}
+ lock_vma_mappings(vma);
spin_lock(&vma->vm_mm->page_table_lock);
vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
vma->vm_start = start;
@@ -186,9 +191,10 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
vma->vm_flags = newflags;
vma->vm_raend = 0;
vma->vm_page_prot = prot;
- insert_vm_struct(current->mm, left);
- insert_vm_struct(current->mm, right);
+ __insert_vm_struct(current->mm, left);
+ __insert_vm_struct(current->mm, right);
spin_unlock(&vma->vm_mm->page_table_lock);
+ unlock_vma_mappings(vma);
return 0;
}
diff --git a/mm/mremap.c b/mm/mremap.c
index 719ca1ec1..764cfabb8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -141,10 +141,12 @@ static inline unsigned long move_vma(struct vm_area_struct * vma,
get_file(new_vma->vm_file);
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
+ lock_vma_mappings(vma);
spin_lock(&current->mm->page_table_lock);
- insert_vm_struct(current->mm, new_vma);
+ __insert_vm_struct(current->mm, new_vma);
merge_segments(current->mm, new_vma->vm_start, new_vma->vm_end);
spin_unlock(&current->mm->page_table_lock);
+ unlock_vma_mappings(vma);
do_munmap(current->mm, addr, old_len);
current->mm->total_vm += new_len >> PAGE_SHIFT;
if (new_vma->vm_flags & VM_LOCKED) {
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 9882fe7cd..45e865d25 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -117,18 +117,18 @@ static int badness(struct task_struct *p)
*/
static struct task_struct * select_bad_process(void)
{
- int points = 0, maxpoints = 0;
+ int maxpoints = 0;
struct task_struct *p = NULL;
struct task_struct *chosen = NULL;
read_lock(&tasklist_lock);
- for_each_task(p)
- {
- if (p->pid)
- points = badness(p);
- if (points > maxpoints) {
- chosen = p;
- maxpoints = points;
+ for_each_task(p) {
+ if (p->pid) {
+ int points = badness(p);
+ if (points > maxpoints) {
+ chosen = p;
+ maxpoints = points;
+ }
}
}
read_unlock(&tasklist_lock);
@@ -156,7 +156,7 @@ void oom_kill(void)
if (p == NULL)
panic("Out of memory and no killable processes...\n");
- printk(KERN_ERR "Out of Memory: Killed process %d (%s).", p->pid, p->comm);
+ printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", p->pid, p->comm);
/*
* We give our sacrificial lamb high priority and access to
diff --git a/mm/swap_state.c b/mm/swap_state.c
index d26c66f54..3a91d955e 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -58,7 +58,7 @@ void add_to_swap_cache(struct page *page, swp_entry_t entry)
BUG();
if (page->mapping)
BUG();
- flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced) | (1 << PG_arch_1));
page->flags = flags | (1 << PG_uptodate);
add_to_page_cache_locked(page, &swapper_space, entry.val);
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 15261612e..339cffb5b 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -9,6 +9,7 @@
#include <linux/malloc.h>
#include <linux/vmalloc.h>
#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
@@ -137,24 +138,31 @@ inline int vmalloc_area_pages (unsigned long address, unsigned long size,
{
pgd_t * dir;
unsigned long end = address + size;
+ int ret;
dir = pgd_offset_k(address);
flush_cache_all();
+ lock_kernel();
do {
pmd_t *pmd;
pmd = pmd_alloc_kernel(dir, address);
+ ret = -ENOMEM;
if (!pmd)
- return -ENOMEM;
+ break;
+ ret = -ENOMEM;
if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot))
- return -ENOMEM;
+ break;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
+
+ ret = 0;
} while (address && (address < end));
+ unlock_kernel();
flush_tlb_all();
- return 0;
+ return ret;
}
struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
@@ -165,9 +173,15 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
+ size += PAGE_SIZE;
addr = VMALLOC_START;
write_lock(&vmlist_lock);
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+ if ((size + addr) < addr) {
+ write_unlock(&vmlist_lock);
+ kfree(area);
+ return NULL;
+ }
if (size + addr < (unsigned long) tmp->addr)
break;
addr = tmp->size + (unsigned long) tmp->addr;
@@ -179,7 +193,7 @@ struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
}
area->flags = flags;
area->addr = (void *)addr;
- area->size = size + PAGE_SIZE;
+ area->size = size;
area->next = *p;
*p = area;
write_unlock(&vmlist_lock);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index d7fd0aca8..dd92afecc 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -185,6 +185,8 @@ drop_pte:
if (!entry.val)
goto out_unlock_restore; /* No swap space left */
+ /* Make sure to flush the TLB _before_ we start copying things.. */
+ flush_tlb_page(vma, address);
if (!(page = prepare_highmem_swapout(page)))
goto out_swap_free;
@@ -196,7 +198,6 @@ drop_pte:
/* Put the swap entry into the pte after the page is in swapcache */
mm->rss--;
set_pte(page_table, swp_entry_to_pte(entry));
- flush_tlb_page(vma, address);
spin_unlock(&mm->page_table_lock);
/* OK, do a physical asynchronous write to swap. */
diff --git a/net/Makefile b/net/Makefile
index ff79d8584..ddfdab2a5 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -7,7 +7,7 @@
O_TARGET := network.o
-mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink
+mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm netlink sched
export-objs := netsyms.o
subdir-y := core ethernet
diff --git a/net/README b/net/README
index 7490dff2b..cacc02146 100644
--- a/net/README
+++ b/net/README
@@ -7,7 +7,7 @@ Code Section Bug Report Contact
[token ring ] p.norton@computer.org
appletalk jschlst@turbolinux.com
ax25 g4klx@g4klx.demon.co.uk
-bridge buytenh@openrock.net
+bridge buytenh@gnu.org
core alan@lxorguk.ukuu.org.uk
decnet SteveW@ACM.org
ethernet alan@lxorguk.ukuu.org.uk
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index ff28ed551..c47d6ca5c 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -130,7 +130,7 @@ static int __init atmpvc_init(void)
error = sock_register(&pvc_family_ops);
if (error < 0) {
printk(KERN_ERR "ATMPVC: can't register (%d)",error);
- return;
+ return error;
}
#ifdef CONFIG_ATM_CLIP
atm_clip_init();
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index dc7998fd1..0b3d64941 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -50,6 +50,7 @@ static void sigd_put_skb(struct sk_buff *skb)
}
schedule();
}
+ current->state = TASK_RUNNING;
remove_wait_queue(&sigd_sleep,&wait);
#else
if (!sigd) {
diff --git a/net/atm/svc.c b/net/atm/svc.c
index 7984cb22a..e53826b98 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -205,7 +205,6 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
}
- remove_wait_queue(&vcc->sleep,&wait);
clear_bit(ATM_VF_REGIS,&vcc->flags);
clear_bit(ATM_VF_RELEASED,&vcc->flags);
clear_bit(ATM_VF_CLOSE,&vcc->flags);
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index 2a88a9716..c01ae329c 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -114,15 +114,18 @@ void ax25_register_sysctl(void)
memset(ax25_table, 0x00, ax25_table_size);
for (n = 0, ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) {
+ ctl_table *child = kmalloc(sizeof(ax25_param_table), GFP_ATOMIC);
+ if (!child) {
+ while (n--)
+ kfree(ax25_table[n].child);
+ kfree(ax25_table);
+ return;
+ }
+ memcpy(child, ax25_param_table, sizeof(ax25_param_table));
+ ax25_table[n].child = ax25_dev->systable = child;
ax25_table[n].ctl_name = n + 1;
ax25_table[n].procname = ax25_dev->dev->name;
- ax25_table[n].data = NULL;
- ax25_table[n].maxlen = 0;
ax25_table[n].mode = 0555;
- ax25_table[n].child = ax25_dev->systable;
- ax25_table[n].proc_handler = NULL;
-
- memcpy(ax25_dev->systable, ax25_param_table, sizeof(ax25_dev->systable));
#ifndef CONFIG_AX25_DAMA_SLAVE
/*
@@ -131,13 +134,13 @@ void ax25_register_sysctl(void)
* AX.25 DAMA slave code, do we?
*/
- ax25_dev->systable[AX25_VALUES_DS_TIMEOUT].procname = NULL;
+ child[AX25_VALUES_DS_TIMEOUT].procname = NULL;
#endif
- ax25_dev->systable[AX25_MAX_VALUES].ctl_name = 0; /* just in case... */
+ child[AX25_MAX_VALUES].ctl_name = 0; /* just in case... */
for (k = 0; k < AX25_MAX_VALUES; k++)
- ax25_dev->systable[k].data = &ax25_dev->values[k];
+ child[k].data = &ax25_dev->values[k];
n++;
}
@@ -149,9 +152,11 @@ void ax25_register_sysctl(void)
void ax25_unregister_sysctl(void)
{
+ ctl_table *p;
unregister_sysctl_table(ax25_table_header);
- kfree(ax25_table);
-
ax25_dir_table[0].child = NULL;
+ for (p = ax25_table; p->ctl_name; p++)
+ kfree(p->child);
+ kfree(ax25_table);
}
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index be9d1867a..f942bfd45 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.4 2000/02/24 06:16:45 davem Exp $
+ * $Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -43,6 +43,7 @@ static __inline__ int has_expired(struct net_bridge *br,
static __inline__ void copy_fdb(struct __fdb_entry *ent, struct net_bridge_fdb_entry *f)
{
+ memset(ent, 0, sizeof(struct __fdb_entry));
memcpy(ent->mac_addr, f->addr.addr, ETH_ALEN);
ent->port_no = f->dst?f->dst->port_no:0;
ent->is_local = f->is_local;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 295cfc973..08c58f19f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.4 2000/10/05 01:58:16 davem Exp $
+ * $Id: br_if.c,v 1.5 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -279,12 +279,8 @@ int br_get_bridge_ifindices(int *indices, int num)
/* called under ioctl_lock */
void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
{
- int i;
struct net_bridge_port *p;
- for (i=0;i<256;i++)
- ifindices[i] = 0;
-
p = br->port_list;
while (p != NULL) {
ifindices[p->port_no] = p->dev->ifindex;
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 4d04aec66..840b3641e 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_ioctl.c,v 1.3 2000/10/05 01:58:16 davem Exp $
+ * $Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -53,6 +53,7 @@ static int br_ioctl_device(struct net_bridge *br,
{
struct __bridge_info b;
+ memset(&b, 0, sizeof(struct __bridge_info));
memcpy(&b.designated_root, &br->designated_root, 8);
memcpy(&b.bridge_id, &br->bridge_id, 8);
b.root_path_cost = br->root_path_cost;
@@ -81,8 +82,12 @@ static int br_ioctl_device(struct net_bridge *br,
case BRCTL_GET_PORT_LIST:
{
+ int i;
int indices[256];
+ for (i=0;i<256;i++)
+ indices[i] = 0;
+
br_get_port_ifindices(br, indices);
if (copy_to_user((void *)arg0, indices, 256*sizeof(int)))
return -EFAULT;
@@ -124,6 +129,7 @@ static int br_ioctl_device(struct net_bridge *br,
if ((pt = br_get_port(br, arg1)) == NULL)
return -EINVAL;
+ memset(&p, 0, sizeof(struct __port_info));
memcpy(&p.designated_root, &pt->designated_root, 8);
memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
p.port_id = pt->port_id;
@@ -189,8 +195,12 @@ static int br_ioctl_deviceless(unsigned int cmd,
case BRCTL_GET_BRIDGES:
{
+ int i;
int indices[64];
+ for (i=0;i<64;i++)
+ indices[i] = 0;
+
if (arg1 > 64)
arg1 = 64;
arg1 = br_get_bridge_ifindices(indices, arg1);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 7f85645f0..0b865f6b9 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -66,7 +66,7 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
DECLARE_WAITQUEUE(wait, current);
- __set_current_state(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE);
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue_exclusive(sk->sleep, &wait);
/* Socket errors? */
diff --git a/net/core/dev.c b/net/core/dev.c
index 17fae7a1e..1e5b59c3d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -93,6 +93,7 @@
#include <net/profile.h>
#include <linux/init.h>
#include <linux/kmod.h>
+#include <linux/module.h>
#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
@@ -666,9 +667,15 @@ int dev_open(struct net_device *dev)
/*
* Call device private open method
*/
-
- if (dev->open)
- ret = dev->open(dev);
+ if (try_inc_mod_count(dev->owner)) {
+ if (dev->open) {
+ ret = dev->open(dev);
+ if (ret != 0 && dev->owner)
+ __MOD_DEC_USE_COUNT(dev->owner);
+ }
+ } else {
+ ret = -ENODEV;
+ }
/*
* If it went open OK then:
@@ -784,6 +791,12 @@ int dev_close(struct net_device *dev)
*/
notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+ /*
+ * Drop the module refcount
+ */
+ if (dev->owner)
+ __MOD_DEC_USE_COUNT(dev->owner);
+
return(0);
}
@@ -2056,8 +2069,9 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
*/
default:
- if (cmd >= SIOCDEVPRIVATE &&
- cmd <= SIOCDEVPRIVATE + 15) {
+ if ((cmd >= SIOCDEVPRIVATE &&
+ cmd <= SIOCDEVPRIVATE + 15) ||
+ cmd == SIOCETHTOOL) {
if (dev->do_ioctl) {
if (!netif_device_present(dev))
return -ENODEV;
@@ -2178,6 +2192,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
case SIOCSIFHWBROADCAST:
case SIOCSIFTXQLEN:
case SIOCSIFNAME:
+ case SIOCETHTOOL:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
@@ -2688,3 +2703,67 @@ int __init net_dev_init(void)
return 0;
}
+
+#ifdef CONFIG_HOTPLUG
+
+/* Notify userspace when a netdevice event occurs,
+ * by running '/sbin/hotplug net' with certain
+ * environment variables set.
+ *
+ * Currently reported events are listed in netdev_event_names[].
+ */
+
+/* /sbin/hotplug ONLY executes for events named here */
+static char *netdev_event_names[] = {
+ [NETDEV_REGISTER] = "register",
+ [NETDEV_UNREGISTER] = "unregister",
+};
+
+static int run_sbin_hotplug(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = (struct net_device *) ptr;
+ char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+ int i;
+
+ if ((event >= ARRAY_SIZE(netdev_event_names)) ||
+ !netdev_event_names[event])
+ return NOTIFY_DONE;
+
+ sprintf(ifname, "INTERFACE=%s", dev->name);
+ sprintf(action, "ACTION=%s", netdev_event_names[event]);
+
+ i = 0;
+ argv[i++] = hotplug_path;
+ argv[i++] = "net";
+ argv[i] = 0;
+
+ i = 0;
+ /* minimal command environment */
+ envp [i++] = "HOME=/";
+ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp [i++] = ifname;
+ envp [i++] = action;
+ envp [i] = 0;
+
+ call_usermodehelper (argv [0], argv, envp);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block sbin_hotplug = {
+ notifier_call: run_sbin_hotplug,
+};
+
+/*
+ * called from init/main.c, -after- all the initcalls are complete.
+ * Registers a hook that calls /sbin/hotplug on every netdev
+ * addition and removal.
+ */
+void __init net_notifier_init (void)
+{
+ if (register_netdevice_notifier(&sbin_hotplug))
+ printk (KERN_WARNING "unable to register netdev notifier\n"
+ KERN_WARNING "/sbin/hotplug will not be run.\n");
+}
+#endif
diff --git a/net/core/scm.c b/net/core/scm.c
index a29c21a8a..0bd1b4004 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -204,12 +204,16 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
{
struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
- int fdmax = (msg->msg_controllen - sizeof(struct cmsghdr))/sizeof(int);
+ int fdmax = 0;
int fdnum = scm->fp->count;
struct file **fp = scm->fp->fp;
int *cmfptr;
int err = 0, i;
+ if (msg->msg_controllen > sizeof(struct cmsghdr))
+ fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr))
+ / sizeof(int));
+
if (fdnum < fdmax)
fdmax = fdnum;
@@ -245,7 +249,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
msg->msg_controllen -= cmlen;
}
}
- if (i < fdnum)
+ if (i < fdnum || (fdnum && fdmax <= 0))
msg->msg_flags |= MSG_CTRUNC;
/*
diff --git a/net/core/sock.c b/net/core/sock.c
index 8503e364f..7b9484437 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.100 2000/09/18 05:59:48 davem Exp $
+ * Version: $Id: sock.c,v 1.101 2000/11/10 04:02:04 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -819,7 +819,7 @@ void __lock_sock(struct sock *sk)
add_wait_queue_exclusive(&sk->lock.wq, &wait);
for(;;) {
- current->state = TASK_EXCLUSIVE | TASK_UNINTERRUPTIBLE;
+ current->state = TASK_UNINTERRUPTIBLE;
spin_unlock_bh(&sk->lock.slock);
schedule();
spin_lock_bh(&sk->lock.slock);
diff --git a/net/decnet/Config.in b/net/decnet/Config.in
index c019d3f59..94422e124 100644
--- a/net/decnet/Config.in
+++ b/net/decnet/Config.in
@@ -5,6 +5,8 @@ bool ' DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER
if [ "$CONFIG_DECNET_ROUTER" = "y" ]; then
- bool ' DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
+ if [ "$CONFIG_NETFILTER" = "y" ]; then
+ bool ' DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
+ fi
fi
fi
diff --git a/net/decnet/TODO b/net/decnet/TODO
index 72ab936a2..1607d6d1b 100644
--- a/net/decnet/TODO
+++ b/net/decnet/TODO
@@ -21,19 +21,11 @@ Steve's quick list of things that need finishing off:
send/recvmsg() calls should simply be a vector of set/getsockopt()
calls]
- o check MSG_TRUNC, MSG_CTRUNC are set where they should be.
+ o check MSG_CTRUNC is set where it should be.
o Start to hack together user level software and add more DECnet support
in ifconfig for example.
- o Fix conninit_rx to check out each CI before queuing it. Support code is
- now in place, so this should be easy.
-
- o Work out which errors we can return from conninit_rx. Support code is
- now in place, so this should be easy.
-
- o Check out receiving of errors in the light of what conninit_rx can return
-
o Test adding/deleting of routes
o Test route lookup
@@ -55,7 +47,11 @@ Steve's quick list of things that need finishing off:
allow DECnet support in netstat.
o Make sure that returned connect messages are generated when they should
- be, and that the correct error messages are sent too. Ensure that the
- conninit receiving routine does not accept conninits with parameters
- that we cannot handle.
+ be, and that the correct error messages are sent too.
+
+ o Add the routing message grabbing netfilter module [written, tested,
+ awaiting merge]
+
+ o Add perfect socket hashing - an idea suggested by Paul Koning [part written,
+ awaiting debugging and merge]
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 8de443979..ca0850b4a 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -33,6 +33,8 @@
* David S. Miller: New socket locking
* Steve Whitehouse: Socket list hashing/locking
* Arnaldo C. Melo: use capable, not suser
+ * Steve Whitehouse: Removed unused code. Fix to use sk->allocation
+ * when required.
*/
@@ -538,7 +540,7 @@ static void dn_destroy_sock(struct sock *sk)
switch(scp->state) {
case DN_DN:
- dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_KERNEL);
+ dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, sk->allocation);
scp->persist_fxn = dn_destroy_timer;
scp->persist = dn_nsp_persist(sk);
break;
@@ -550,7 +552,7 @@ static void dn_destroy_sock(struct sock *sk)
case DN_DI:
case DN_DR:
disc_reject:
- dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_KERNEL);
+ dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->allocation);
case DN_NC:
case DN_NR:
case DN_RJ:
@@ -967,7 +969,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
cb = (struct dn_skb_cb *)skb->cb;
- if ((newsk = dn_alloc_sock(newsock, GFP_KERNEL)) == NULL) {
+ if ((newsk = dn_alloc_sock(newsock, sk->allocation)) == NULL) {
release_sock(sk);
kfree_skb(skb);
return -ENOBUFS;
@@ -1031,7 +1033,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
if (newsk->protinfo.dn.accept_mode == ACC_IMMED) {
newsk->protinfo.dn.state = DN_CC;
- dn_send_conn_conf(newsk, GFP_KERNEL);
+ dn_send_conn_conf(newsk, newsk->allocation);
err = dn_wait_accept(newsock, flags);
}
@@ -1388,7 +1390,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
return -EINVAL;
scp->state = DN_CC;
- dn_send_conn_conf(sk, GFP_KERNEL);
+ dn_send_conn_conf(sk, sk->allocation);
err = dn_wait_accept(sock, sock->file->f_flags);
return err;
@@ -1399,7 +1401,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
scp->state = DN_DR;
sk->shutdown = SHUTDOWN_MASK;
- dn_nsp_send_disc(sk, 0x38, 0, GFP_KERNEL);
+ dn_nsp_send_disc(sk, 0x38, 0, sk->allocation);
break;
default:
@@ -1527,7 +1529,7 @@ static int dn_wait_run(struct sock *sk, int flags)
case DN_CR:
scp->state = DN_CC;
- dn_send_conn_conf(sk, GFP_KERNEL);
+ dn_send_conn_conf(sk, sk->allocation);
return dn_wait_accept(sk->socket, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);
case DN_CI:
case DN_CC:
@@ -2083,7 +2085,7 @@ static int __init decnet_init(void)
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
#endif
- printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.49s (C) 1995-2000 Linux DECnet Project Team\n");
+ printk(KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test10s (C) 1995-2000 Linux DECnet Project Team\n");
sock_register(&dn_family_ops);
dev_add_pack(&dn_dix_packet_type);
@@ -2102,6 +2104,14 @@ static int __init decnet_init(void)
#ifdef CONFIG_SYSCTL
dn_register_sysctl();
#endif /* CONFIG_SYSCTL */
+
+ /*
+ * Prevent DECnet module unloading until its fixed properly.
+ * Requires an audit of the code to check for memory leaks and
+ * initialisation problems etc.
+ */
+ MOD_INC_USE_COUNT;
+
return 0;
}
@@ -2111,7 +2121,6 @@ static int __init decnet_setup(char *str)
{
unsigned short area = simple_strtoul(str, &str, 0);
unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
- /* unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); */
decnet_address = dn_htons(area << 10 | node);
dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index f05568ee5..d8f91ac38 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -19,6 +19,7 @@
* Steve Whitehouse : SIOCGIFCONF is now a compile time option
* Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
* Steve Whitehouse : Removed timer1 - its a user space issue now
+ * Patrick Caulfield : Fixed router hello message format
*/
#include <linux/config.h>
@@ -795,13 +796,14 @@ static void dn_send_router_hello(struct net_device *dev)
DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
*((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
ptr += 2;
- *ptr++ = 0; /* Priority */
+ *ptr++ = dn_db->parms.priority; /* Priority */
*ptr++ = 0; /* Area: Reserved */
*((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
ptr += 2;
*ptr++ = 0; /* MPD: Reserved */
i1 = ptr++;
memset(ptr, 0, 7); /* Name: Reserved */
+ ptr += 7;
i2 = ptr++;
n = dn_neigh_elist(dev, ptr, n);
@@ -809,7 +811,7 @@ static void dn_send_router_hello(struct net_device *dev)
*i2 = 7 * n;
*i1 = 8 + *i2;
- skb_trim(skb, (26 + *i2));
+ skb_trim(skb, (27 + *i2));
pktlen = (unsigned short *)skb_push(skb, 2);
*pktlen = dn_htons(skb->len - 2);
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 6155ebccf..4754cd850 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -1,4 +1,3 @@
-
/*
* DECnet An implementation of the DECnet protocol suite for the LINUX
* operating system. DECnet is implemented using the BSD Socket
@@ -23,6 +22,9 @@
* Steve Whitehouse: Fixed lockup when socket filtering was enabled.
* Paul Koning: Fix to push CC sockets into RUN when acks are
* received.
+ * Steve Whitehouse:
+ * Patrick Caulfield: Checking conninits for correctness & sending of error
+ * responses.
*/
/******************************************************************************
@@ -71,6 +73,16 @@
#include <net/dn_dev.h>
#include <net/dn_route.h>
+extern int decnet_log_martians;
+
+static void dn_log_martian(struct sk_buff *skb, const char *msg)
+{
+ if (decnet_log_martians && net_ratelimit()) {
+ char *devname = skb->rx_dev ? skb->rx_dev->name : "???";
+ struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+ printk(KERN_INFO "DECnet: Martian packet (%s) rx_dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port);
+ }
+}
/*
* For this function we've flipped the cross-subchannel bit
@@ -83,8 +95,6 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
unsigned short type = ((ack >> 12) & 0x0003);
int wakeup = 0;
- /* printk(KERN_DEBUG "dn_ack: %hd 0x%04hx\n", type, ack); */
-
switch(type) {
case 0: /* ACK - Data */
if (after(ack, scp->ackrcv_dat)) {
@@ -148,50 +158,172 @@ static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
}
+/**
+ * dn_check_idf - Check an image data field format is correct.
+ * @pptr: Pointer to pointer to image data
+ * @len: Pointer to length of image data
+ * @max: The maximum allowed length of the data in the image data field
+ * @follow_on: Check that this many bytes exist beyond the end of the image data
+ *
+ * Returns: 0 if ok, -1 on error
+ */
+static inline int dn_check_idf(unsigned char **pptr, int *len, unsigned char max, unsigned char follow_on)
+{
+ unsigned char *ptr = *pptr;
+ unsigned char flen = *ptr++;
+
+ (*len)--;
+ if (flen > max)
+ return -1;
+ if ((flen + follow_on) > *len)
+ return -1;
+
+ *len -= flen;
+ *pptr = ptr + flen;
+ return 0;
+}
+
+/*
+ * Table of reason codes to pass back to node which sent us a badly
+ * formed message, plus text messages for the log. A zero entry in
+ * the reason field means "don't reply" otherwise a disc init is sent with
+ * the specified reason code.
+ */
+static struct {
+ unsigned short reason;
+ const char *text;
+} ci_err_table[] = {
+ { 0, "CI: Truncated message" },
+ { NSP_REASON_ID, "CI: Destination username error" },
+ { NSP_REASON_ID, "CI: Destination username type" },
+ { NSP_REASON_US, "CI: Source username error" },
+ { 0, "CI: Truncated at menuver" },
+ { 0, "CI: Truncated before access or user data" },
+ { NSP_REASON_IO, "CI: Access data format error" },
+ { NSP_REASON_IO, "CI: User data format error" }
+};
+
/*
* This function uses a slightly different lookup method
* to find its sockets, since it searches on object name/number
- * rather than port numbers
+ * rather than port numbers. Various tests are done to ensure that
+ * the incoming data is in the correct format before it is queued to
+ * a socket.
*/
-static struct sock *dn_find_listener(struct sk_buff *skb)
+static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason)
{
struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data;
- struct sockaddr_dn addr;
+ struct sockaddr_dn dstaddr;
+ struct sockaddr_dn srcaddr;
unsigned char type = 0;
+ int dstlen;
+ int srclen;
+ unsigned char *ptr;
+ int len;
+ int err = 0;
+ unsigned char menuver;
- memset(&addr, 0, sizeof(struct sockaddr_dn));
+ memset(&dstaddr, 0, sizeof(struct sockaddr_dn));
+ memset(&srcaddr, 0, sizeof(struct sockaddr_dn));
+ /*
+ * 1. Decode & remove message header
+ */
cb->src_port = msg->srcaddr;
cb->dst_port = msg->dstaddr;
cb->services = msg->services;
cb->info = msg->info;
cb->segsize = dn_ntohs(msg->segsize);
+ if (skb->len < sizeof(*msg))
+ goto err_out;
+
skb_pull(skb, sizeof(*msg));
- /* printk(KERN_DEBUG "username2sockaddr 1\n"); */
- if (dn_username2sockaddr(skb->data, skb->len, &addr, &type) < 0)
+ len = skb->len;
+ ptr = skb->data;
+
+ /*
+ * 2. Check destination end username format
+ */
+ dstlen = dn_username2sockaddr(ptr, len, &dstaddr, &type);
+ err++;
+ if (dstlen < 0)
goto err_out;
+ err++;
if (type > 1)
goto err_out;
- /* printk(KERN_DEBUG "looking for listener...\n"); */
- return dn_sklist_find_listener(&addr);
+ len -= dstlen;
+ ptr += dstlen;
+
+ /*
+ * 3. Check source end username format
+ */
+ srclen = dn_username2sockaddr(ptr, len, &srcaddr, &type);
+ err++;
+ if (srclen < 0)
+ goto err_out;
+
+ len -= srclen;
+ ptr += srclen;
+ err++;
+ if (len < 1)
+ goto err_out;
+
+ menuver = *ptr;
+ ptr++;
+ len--;
+
+ /*
+ * 4. Check that optional data actually exists if menuver says it does
+ */
+ err++;
+ if ((menuver & (DN_MENUVER_ACC | DN_MENUVER_USR)) && (len < 1))
+ goto err_out;
+
+ /*
+ * 5. Check optional access data format
+ */
+ err++;
+ if (menuver & DN_MENUVER_ACC) {
+ if (dn_check_idf(&ptr, &len, 39, 1))
+ goto err_out;
+ if (dn_check_idf(&ptr, &len, 39, 1))
+ goto err_out;
+ if (dn_check_idf(&ptr, &len, 39, (menuver & DN_MENUVER_USR) ? 1 : 0))
+ goto err_out;
+ }
+
+ /*
+ * 6. Check optional user data format
+ */
+ err++;
+ if (menuver & DN_MENUVER_USR) {
+ if (dn_check_idf(&ptr, &len, 16, 0))
+ goto err_out;
+ }
+
+ /*
+ * 7. Look up socket based on destination end username
+ */
+ return dn_sklist_find_listener(&dstaddr);
err_out:
+ dn_log_martian(skb, ci_err_table[err].text);
+ *reason = ci_err_table[err].reason;
return NULL;
}
+
static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb)
{
- /* printk(KERN_DEBUG "checking backlog...\n"); */
if (sk->ack_backlog >= sk->max_ack_backlog) {
kfree_skb(skb);
return;
}
- /* printk(KERN_DEBUG "waking up socket...\n"); */
sk->ack_backlog++;
skb_queue_tail(&sk->receive_queue, skb);
sk->state_change(sk);
@@ -528,13 +660,20 @@ static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb);
}
-static void dn_nsp_no_socket(struct sk_buff *skb)
+static void dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
{
struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
- switch(cb->nsp_flags) {
- case 0x28: /* Connect Confirm */
- dn_nsp_return_disc(skb, NSP_DISCCONF, NSP_REASON_NL);
+ if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
+ switch(cb->nsp_flags & 0x70) {
+ case 0x10:
+ case 0x60: /* (Retransmitted) Connect Init */
+ dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
+ break;
+ case 0x20: /* Connect Confirm */
+ dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
+ break;
+ }
}
kfree_skb(skb);
@@ -545,6 +684,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
struct sock *sk = NULL;
unsigned char *ptr = (unsigned char *)skb->data;
+ unsigned short reason = NSP_REASON_NL;
skb->h.raw = skb->data;
cb->nsp_flags = *ptr++;
@@ -584,7 +724,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
goto free_out;
case 0x10:
case 0x60:
- sk = dn_find_listener(skb);
+ sk = dn_find_listener(skb, &reason);
goto got_it;
}
}
@@ -632,7 +772,7 @@ got_it:
return ret;
}
- dn_nsp_no_socket(skb);
+ dn_nsp_no_socket(skb, reason);
return 1;
free_out:
@@ -664,7 +804,6 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
* Control packet.
*/
if ((cb->nsp_flags & 0x0c) == 0x08) {
- /* printk(KERN_DEBUG "control type\n"); */
switch(cb->nsp_flags & 0x70) {
case 0x10:
case 0x60:
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 669aeccce..6965cbf42 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -149,7 +149,7 @@ struct sk_buff *dn_alloc_send_skb(struct sock *sk, int *size, int noblock, int *
continue;
}
- if ((skb = dn_alloc_skb(sk, len, GFP_KERNEL)) == NULL)
+ if ((skb = dn_alloc_skb(sk, len, sk->allocation)) == NULL)
continue;
*size = len - 11;
@@ -444,7 +444,7 @@ void dn_send_conn_ack (struct sock *sk)
struct sk_buff *skb = NULL;
struct nsp_conn_ack_msg *msg;
- if ((skb = dn_alloc_skb(sk, 3, GFP_KERNEL)) == NULL)
+ if ((skb = dn_alloc_skb(sk, 3, sk->allocation)) == NULL)
return;
msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3);
@@ -626,7 +626,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg)
struct dn_skb_cb *cb;
unsigned char type = 1;
- if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? GFP_KERNEL : GFP_ATOMIC)) == NULL)
+ if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? sk->allocation : GFP_ATOMIC)) == NULL)
return;
cb = (struct dn_skb_cb *)skb->cb;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index a2bc39398..20ec07acc 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -812,8 +812,8 @@ non_local_input:
key.oif = 0;
key.scope = RT_SCOPE_UNIVERSE;
-#ifdef CONFIG_DECNET_ROUTE_FWMASK
- key.fwmark = skb->fwmark;
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+ key.fwmark = skb->nfmark;
#else
key.fwmark = 0;
#endif
@@ -890,7 +890,7 @@ int dn_route_input(struct sk_buff *skb)
if ((rt->key.saddr == cb->src) &&
(rt->key.daddr == cb->dst) &&
(rt->key.oif == 0) &&
-#ifdef CONFIG_DECNET_ROUTE_FWMASK
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
(rt->key.fwmark == skb->nfmark) &&
#endif
(rt->key.iif == cb->iif)) {
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index c1931c867..0c9fb1f7f 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -32,6 +32,7 @@ int decnet_time_wait = 30;
int decnet_dn_count = 1;
int decnet_di_count = 3;
int decnet_dr_count = 3;
+int decnet_log_martians = 1;
#ifdef CONFIG_SYSCTL
extern int decnet_dst_gc_interval;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 584814ad8..3222d25d1 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.121 2000/10/24 21:26:18 davem Exp $
+ * Version: $Id: af_inet.c,v 1.123 2000/11/10 01:42:43 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0f97c2d27..6b254e2ad 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.176 2000/10/06 22:45:41 davem Exp $
+ * Version: $Id: tcp.c,v 1.179 2000/11/10 04:02:04 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2011,7 +2011,7 @@ static int wait_for_connect(struct sock * sk, long timeo)
*/
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
- current->state = TASK_EXCLUSIVE | TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
release_sock(sk);
if (sk->tp_pinfo.af_tcp.accept_queue == NULL)
timeo = schedule_timeout(timeo);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1a0f278b4..9f16a976c 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.218 2000/10/18 18:04:22 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.220 2000/11/14 07:26:02 davem Exp $
*
* IPv4 specific functions
*
@@ -301,7 +301,7 @@ void tcp_put_port(struct sock *sk)
local_bh_enable();
}
-/* This lock without TASK_EXCLUSIVE is good on UP and it can be very bad on SMP.
+/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP.
* Look, when several writers sleep and reader wakes them up, all but one
* immediately hit write lock and grab all the cpus. Exclusive sleep solves
* this, _but_ remember, it adds useless work on UP machines (wake up each
@@ -317,7 +317,7 @@ void tcp_listen_wlock(void)
add_wait_queue_exclusive(&tcp_lhash_wait, &wait);
for (;;) {
- set_current_state(TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (atomic_read(&tcp_lhash_users) == 0)
break;
write_unlock_bh(&tcp_lhash_lock);
@@ -1721,93 +1721,88 @@ static void __tcp_v4_rehash(struct sock *sk)
sk->prot->hash(sk);
}
-int tcp_v4_rebuild_header(struct sock *sk)
+static int tcp_v4_reselect_saddr(struct sock *sk)
{
- struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
+ int err;
+ struct rtable *rt;
+ __u32 old_saddr = sk->saddr;
__u32 new_saddr;
- int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT &&
- !(sk->userlocks & SOCK_BINDADDR_LOCK);
+ __u32 daddr = sk->daddr;
- if (rt == NULL) {
- int err;
+ if(sk->protinfo.af_inet.opt && sk->protinfo.af_inet.opt->srr)
+ daddr = sk->protinfo.af_inet.opt->faddr;
- u32 daddr = sk->daddr;
+ /* Query new route. */
+ err = ip_route_connect(&rt, daddr, 0,
+ RT_TOS(sk->protinfo.af_inet.tos)|sk->localroute,
+ sk->bound_dev_if);
+ if (err)
+ return err;
- if(sk->protinfo.af_inet.opt && sk->protinfo.af_inet.opt->srr)
- daddr = sk->protinfo.af_inet.opt->faddr;
+ __sk_dst_set(sk, &rt->u.dst);
+ /* sk->route_caps = rt->u.dst.dev->features; */
- err = ip_route_output(&rt, daddr, sk->saddr,
- RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
- sk->bound_dev_if);
- if (err) {
- sk->err_soft=-err;
- sk->error_report(sk);
- return -1;
- }
- __sk_dst_set(sk, &rt->u.dst);
- }
+ new_saddr = rt->rt_src;
- /* Force route checking if want_rewrite. */
- if (want_rewrite) {
- int tmp;
- struct rtable *new_rt;
- __u32 old_saddr = rt->rt_src;
-
- /* Query new route using another rt buffer */
- tmp = ip_route_connect(&new_rt, rt->rt_dst, 0,
- RT_TOS(sk->protinfo.af_inet.tos)|sk->localroute,
- sk->bound_dev_if);
-
- /* Only useful if different source addrs */
- if (tmp == 0) {
- /*
- * Only useful if different source addrs
- */
- if (new_rt->rt_src != old_saddr ) {
- __sk_dst_set(sk, &new_rt->u.dst);
- rt = new_rt;
- goto do_rewrite;
- }
- dst_release(&new_rt->u.dst);
- }
+ if (new_saddr == old_saddr)
+ return 0;
+
+ if (sysctl_ip_dynaddr > 1) {
+ printk(KERN_INFO "tcp_v4_rebuild_header(): shifting sk->saddr "
+ "from %d.%d.%d.%d to %d.%d.%d.%d\n",
+ NIPQUAD(old_saddr),
+ NIPQUAD(new_saddr));
}
+ sk->saddr = new_saddr;
+ sk->rcv_saddr = new_saddr;
+
+ /* XXX The only one ugly spot where we need to
+ * XXX really change the sockets identity after
+ * XXX it has entered the hashes. -DaveM
+ *
+ * Besides that, it does not check for connection
+ * uniqueness. Wait for troubles.
+ */
+ __tcp_v4_rehash(sk);
return 0;
+}
-do_rewrite:
- new_saddr = rt->rt_src;
-
- /* Ouch!, this should not happen. */
- if (!sk->saddr || !sk->rcv_saddr) {
- printk(KERN_WARNING "tcp_v4_rebuild_header(): not valid sock addrs: "
- "saddr=%08X rcv_saddr=%08X\n",
- ntohl(sk->saddr),
- ntohl(sk->rcv_saddr));
- return -1;
- }
+int tcp_v4_rebuild_header(struct sock *sk)
+{
+ struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
+ u32 daddr;
+ int err;
- if (new_saddr != sk->saddr) {
- if (sysctl_ip_dynaddr > 1) {
- printk(KERN_INFO "tcp_v4_rebuild_header(): shifting sk->saddr "
- "from %d.%d.%d.%d to %d.%d.%d.%d\n",
- NIPQUAD(sk->saddr),
- NIPQUAD(new_saddr));
- }
+ /* Route is OK, nothing to do. */
+ if (rt != NULL)
+ return 0;
- sk->saddr = new_saddr;
- sk->rcv_saddr = new_saddr;
+ /* Reroute. */
+ daddr = sk->daddr;
+ if(sk->protinfo.af_inet.opt && sk->protinfo.af_inet.opt->srr)
+ daddr = sk->protinfo.af_inet.opt->faddr;
- /* XXX The only one ugly spot where we need to
- * XXX really change the sockets identity after
- * XXX it has entered the hashes. -DaveM
- *
- * Besides that, it does not check for connection
- * uniqueness. Wait for troubles.
- */
- __tcp_v4_rehash(sk);
- }
-
- return 0;
+ err = ip_route_output(&rt, daddr, sk->saddr,
+ RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
+ sk->bound_dev_if);
+ if (!err) {
+ __sk_dst_set(sk, &rt->u.dst);
+ /* sk->route_caps = rt->u.dst.dev->features; */
+ return 0;
+ }
+
+ /* Routing failed... */
+ /* sk->route_caps = 0; */
+
+ if (!sysctl_ip_dynaddr ||
+ sk->state != TCP_SYN_SENT ||
+ (sk->userlocks & SOCK_BINDADDR_LOCK) ||
+ (err = tcp_v4_reselect_saddr(sk)) != 0) {
+ sk->err_soft=-err;
+ /* sk->error_report(sk); */
+ }
+ return err;
}
static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 4a9af93e1..520a3b6c1 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -660,7 +660,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
if (ra_msg->reachable_time) {
__u32 rtime = (ntohl(ra_msg->reachable_time)*HZ)/1000;
- if (rtime != in6_dev->nd_parms->base_reachable_time) {
+ if (rtime &&
+ rtime != in6_dev->nd_parms->base_reachable_time) {
in6_dev->nd_parms->base_reachable_time = rtime;
in6_dev->nd_parms->gc_staletime = 3 * rtime;
in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e1832fd8c..e643a39eb 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.48 2000/08/10 01:17:13 davem Exp $
+ * $Id: route.c,v 1.49 2000/11/03 01:11:58 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1902,22 +1902,22 @@ ctl_table ipv6_route_table[] = {
&proc_dointvec},
{NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval",
&ip6_rt_gc_min_interval, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout",
&ip6_rt_gc_timeout, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval",
&ip6_rt_gc_interval, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity",
&ip6_rt_gc_elasticity, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires",
&ip6_rt_mtu_expires, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss",
&ip6_rt_min_advmss, sizeof(int), 0644, NULL,
- &proc_dointvec_jiffies},
+ &proc_dointvec_jiffies, &sysctl_jiffies},
{0}
};
diff --git a/net/ipx/Config.in b/net/ipx/Config.in
index 0070c5813..0c798e495 100644
--- a/net/ipx/Config.in
+++ b/net/ipx/Config.in
@@ -3,6 +3,6 @@
#
bool ' IPX: Full internal IPX network' CONFIG_IPX_INTERN
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate ' IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
-fi
+#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# dep_tristate ' IPX: SPX networking (EXPERIMENTAL)' CONFIG_SPX $CONFIG_IPX
+#fi
diff --git a/net/irda/Config.in b/net/irda/Config.in
index 6f4f716f8..5ab40b985 100644
--- a/net/irda/Config.in
+++ b/net/irda/Config.in
@@ -11,6 +11,7 @@ if [ "$CONFIG_NET" != "n" ]; then
if [ "$CONFIG_IRDA" != "n" ]; then
comment 'IrDA protocols'
source net/irda/irlan/Config.in
+ source net/irda/irnet/Config.in
source net/irda/ircomm/Config.in
bool ' Ultra (connectionless) protocol' CONFIG_IRDA_ULTRA
bool ' IrDA protocol options' CONFIG_IRDA_OPTIONS
diff --git a/net/irda/Makefile b/net/irda/Makefile
index ac2bdc063..3ab07c88d 100644
--- a/net/irda/Makefile
+++ b/net/irda/Makefile
@@ -7,7 +7,7 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-ALL_SUB_DIRS := irlan ircomm compressors
+ALL_SUB_DIRS := irlan irnet ircomm compressors
SUB_DIRS :=
MOD_SUB_DIRS :=
OX_OBJS :=
@@ -17,7 +17,7 @@ O_OBJS := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \
irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \
irttp.o irda_device.o irias_object.o crc.o wrapper.o af_irda.o \
discovery.o parameters.o
-OX_OBJS := irmod.o
+OX_OBJS := irsyms.o
ifeq ($(CONFIG_IRDA),m)
M_OBJS := $(O_TARGET)
@@ -44,6 +44,15 @@ else
endif
endif
+ifeq ($(CONFIG_IRNET),y)
+SUB_DIRS += irnet
+O_OBJS += irnet/irnet.o
+else
+ ifeq ($(CONFIG_IRNET),m)
+ MOD_SUB_DIRS += irnet
+ endif
+endif
+
ifeq ($(CONFIG_IRDA_COMPRESSION),y)
SUB_DIRS += compressors
MOD_IN_SUB_DIRS += compressors
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 69db79a0e..e5504ee96 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -7,11 +7,11 @@
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun May 31 10:12:43 1998
* Modified at: Sat Dec 25 21:10:23 1999
- * Modified by: Dag Brattli <dagb@cs.uit.no>
+ * Modified by: Dag Brattli <dag@brattli.net>
* Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
*
* Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no>
- * Copyright (c) 1999 Jean Tourrilhes <jeant@rockfort.hpl.hp.com>
+ * Copyright (c) 1999 Jean Tourrilhes <jt@hpl.hp.com>
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -43,10 +43,11 @@
********************************************************************/
#include <linux/config.h>
-#include <linux/init.h>
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
+#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/net.h>
#include <linux/irda.h>
@@ -79,11 +80,12 @@ static struct proto_ops irda_ultra_ops;
#define ULTRA_MAX_DATA 382
#endif /* CONFIG_IRDA_ULTRA */
-static hashbin_t *cachelog = NULL;
-static DECLARE_WAIT_QUEUE_HEAD(discovery_wait); /* Wait for discovery */
-
#define IRDA_MAX_HEADER (TTP_MAX_HEADER)
+#ifdef CONFIG_IRDA_DEBUG
+__u32 irda_debug = IRDA_DEBUG_LEVEL;
+#endif
+
/*
* Function irda_data_indication (instance, sap, skb)
*
@@ -117,7 +119,7 @@ static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb)
/*
* Function irda_disconnect_indication (instance, sap, reason, skb)
*
- * Connection has been closed. Chech reason to find out why
+ * Connection has been closed. Check reason to find out why
*
*/
static void irda_disconnect_indication(void *instance, void *sap,
@@ -141,6 +143,27 @@ static void irda_disconnect_indication(void *instance, void *sap,
sk->state_change(sk);
sk->dead = 1;
}
+
+ /* Close our TSAP.
+ * If we leave it open, IrLMP put it back into the list of
+ * unconnected LSAPs. The problem is that any incomming request
+ * can then be matched to this socket (and it will be, because
+ * it is at the head of the list). This would prevent any
+ * listening socket waiting on the same TSAP to get those requests.
+ * Some apps forget to close sockets, or hang to it a bit too long,
+ * so we may stay in this dead state long enough to be noticed...
+ * Note : all socket function do check sk->state, so we are safe...
+ * Jean II
+ */
+ irttp_close_tsap(self->tsap);
+ self->tsap = NULL;
+
+ /* Note : once we are there, there is not much you want to do
+ * with the socket anymore, apart from closing it.
+ * For example, bind() and connect() won't reset sk->err,
+ * sk->shutdown and sk->dead to valid values...
+ * Jean II
+ */
}
/*
@@ -326,19 +349,19 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
/*
* Function irda_getvalue_confirm (obj_id, value, priv)
*
- * Got answer from remote LM-IAS
+ * Got answer from remote LM-IAS, just pass object to requester...
*
+ * Note : duplicate from above, but we need our own version that
+ * doesn't touch the dtsap_sel and save the full value structure...
*/
static void irda_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
+ struct ias_value *value, void *priv)
{
struct irda_sock *self;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- ASSERT(priv != NULL, return;);
self = (struct irda_sock *) priv;
-
if (!self) {
WARNING(__FUNCTION__ "(), lost myself!\n");
return;
@@ -348,51 +371,90 @@ static void irda_getvalue_confirm(int result, __u16 obj_id,
iriap_close(self->iriap);
self->iriap = NULL;
- self->errno = result;
-
/* Check if request succeeded */
if (result != IAS_SUCCESS) {
- IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
+ IRDA_DEBUG(1, __FUNCTION__ "(), IAS query failed! (%d)\n",
+ result);
+
+ self->errno = result; /* We really need it later */
/* Wake up any processes waiting for result */
- wake_up_interruptible(&self->ias_wait);
+ wake_up_interruptible(&self->query_wait);
return;
}
- switch (value->type) {
- case IAS_INTEGER:
- IRDA_DEBUG(4, __FUNCTION__ "() int=%d\n", value->t.integer);
-
- if (value->t.integer != -1) {
- self->dtsap_sel = value->t.integer;
- } else
- self->dtsap_sel = 0;
- break;
- default:
- IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n");
- break;
- }
- irias_delete_value(value);
+ /* Pass the object to the caller (so the caller must delete it) */
+ self->ias_result = value;
+ self->errno = 0;
/* Wake up any processes waiting for result */
- wake_up_interruptible(&self->ias_wait);
+ wake_up_interruptible(&self->query_wait);
}
/*
- * Function irda_discovery_indication (log)
+ * Function irda_selective_discovery_indication (discovery)
*
- * Got a discovery log from IrLMP, wake ut any process waiting for answer
+ * Got a selective discovery indication from IrLMP.
*
+ * IrLMP is telling us that this node is matching our hint bit
+ * filter. Check if it's a newly discovered node (or if node changed its
+ * hint bits), and then wake up any process waiting for answer...
*/
-static void irda_discovery_indication(hashbin_t *log)
+static void irda_selective_discovery_indication(discovery_t *discovery,
+ void *priv)
{
+ struct irda_sock *self;
+
IRDA_DEBUG(2, __FUNCTION__ "()\n");
- cachelog = log;
+ self = (struct irda_sock *) priv;
+ if (!self) {
+ WARNING(__FUNCTION__ "(), lost myself!\n");
+ return;
+ }
+
+ /* Check if node is discovered is a new one or an old one.
+ * We check when how long ago this node was discovered, with a
+ * coarse timeout (we may miss some discovery events or be delayed).
+ * Note : by doing this test here, we avoid waking up a process ;-)
+ */
+ if((jiffies - discovery->first_timestamp) >
+ (sysctl_discovery_timeout * HZ)) {
+ return; /* Too old, not interesting -> goodbye */
+ }
+
+ /* Pass parameter to the caller */
+ self->cachediscovery = discovery;
/* Wake up process if its waiting for device to be discovered */
- wake_up_interruptible(&discovery_wait);
+ wake_up_interruptible(&self->query_wait);
+}
+
+/*
+ * Function irda_discovery_timeout (priv)
+ *
+ * Timeout in the selective discovery process
+ *
+ * We were waiting for a node to be discovered, but nothing has come up
+ * so far. Wake up the user and tell him that we failed...
+ */
+static void irda_discovery_timeout(u_long priv)
+{
+ struct irda_sock *self;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ self = (struct irda_sock *) priv;
+ ASSERT(self != NULL, return;);
+
+ /* Nothing for the caller */
+ self->cachelog = NULL;
+ self->cachediscovery = NULL;
+ self->errno = -ETIME;
+
+ /* Wake up process if its still waiting... */
+ wake_up_interruptible(&self->query_wait);
}
/*
@@ -470,6 +532,11 @@ static int irda_open_lsap(struct irda_sock *self, int pid)
*
* Try to lookup LSAP selector in remote LM-IAS
*
+ * Basically, we start a IAP query, and then go to sleep. When the query
+ * return, irda_getvalue_confirm will wake us up, and we can examine the
+ * result of the query...
+ * Note that in some case, the query fail even before we go to sleep,
+ * creating some races...
*/
static int irda_find_lsap_sel(struct irda_sock *self, char *name)
{
@@ -485,19 +552,53 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
irda_getvalue_confirm);
+ /* Treat unexpected signals as disconnect */
+ self->errno = -EHOSTUNREACH;
+
/* Query remote LM-IAS */
iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
name, "IrDA:TinyTP:LsapSel");
- /* Wait for answer */
- interruptible_sleep_on(&self->ias_wait);
+ /* Wait for answer (if not already failed) */
+ if(self->iriap != NULL)
+ interruptible_sleep_on(&self->query_wait);
+
+ /* Check what happened */
+ if (self->errno)
+ {
+ /* Requested object/attribute doesn't exist */
+ if((self->errno == IAS_CLASS_UNKNOWN) ||
+ (self->errno == IAS_ATTRIB_UNKNOWN))
+ return (-EADDRNOTAVAIL);
+ else
+ return (-EHOSTUNREACH);
+ }
+
+ /* Get the remote TSAP selector */
+ switch (self->ias_result->type) {
+ case IAS_INTEGER:
+ IRDA_DEBUG(4, __FUNCTION__ "() int=%d\n",
+ self->ias_result->t.integer);
+
+ if (self->ias_result->t.integer != -1)
+ self->dtsap_sel = self->ias_result->t.integer;
+ else
+ self->dtsap_sel = 0;
+ break;
+ default:
+ self->dtsap_sel = 0;
+ IRDA_DEBUG(0, __FUNCTION__ "(), bad type!\n");
+ break;
+ }
+ if (self->ias_result)
+ irias_delete_value(self->ias_result);
if (self->dtsap_sel)
return 0;
- return -ENETUNREACH; /* May not be true */
+ return -EADDRNOTAVAIL;
}
- /*
+/*
* Function irda_discover_daddr_and_lsap_sel (self, name)
*
* This try to find a device with the requested service.
@@ -516,71 +617,78 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
*/
static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
{
- discovery_t *discovery;
- int err = -ENETUNREACH;
- __u32 daddr = 0x0; /* Address we found the service on */
+ struct irda_device_info *discoveries; /* Copy of the discovery log */
+ int number; /* Number of nodes in the log */
+ int i;
+ int err = -ENETUNREACH;
+ __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */
__u8 dtsap_sel = 0x0; /* TSAP associated with it */
IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
ASSERT(self != NULL, return -1;);
- /* Tell IrLMP we want to be notified */
- irlmp_update_client(self->ckey, self->mask, NULL,
- irda_discovery_indication);
-
- /* Do some discovery */
- irlmp_discovery_request(self->nslots);
-
+ /* Ask lmp for the current discovery log
+ * Note : we have to use irlmp_get_discoveries(), as opposed
+ * to play with the cachelog directly, because while we are
+ * making our ias query, le log might change... */
+ discoveries = irlmp_get_discoveries(&number, self->mask);
/* Check if the we got some results */
- if (!cachelog)
- /* Wait for answer */
- /*interruptible_sleep_on(&self->discovery_wait);*/
- return -EAGAIN;
+ if (discoveries == NULL)
+ return -ENETUNREACH; /* No nodes discovered */
/*
* Now, check all discovered devices (if any), and connect
* client only about the services that the client is
* interested in...
*/
- discovery = (discovery_t *) hashbin_get_first(cachelog);
- while (discovery != NULL) {
- /* Mask out the ones we don't want */
- if (discovery->hints.word & self->mask) {
- /* Try this address */
- self->daddr = discovery->daddr;
- self->saddr = 0x0;
- IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n",
- self->daddr);
-
- /* Query remote LM-IAS for this service */
- err = irda_find_lsap_sel(self, name);
- if (err == 0) {
- /* We found the requested service */
- if(daddr != 0x0) {
- IRDA_DEBUG(0, __FUNCTION__
- "(), discovered service ''%s'' in two different devices !!!\n",
- name);
- return(-ENOTUNIQ);
- }
- /* First time we foun that one, save it ! */
- daddr = self->daddr;
- dtsap_sel = self->dtsap_sel;
+ for(i = 0; i < number; i++) {
+ /* Try the address in the log */
+ self->daddr = discoveries[i].daddr;
+ self->saddr = 0x0;
+ IRDA_DEBUG(1, __FUNCTION__ "(), trying daddr = %08x\n",
+ self->daddr);
+
+ /* Query remote LM-IAS for this service */
+ err = irda_find_lsap_sel(self, name);
+ switch (err) {
+ case 0:
+ /* We found the requested service */
+ if(daddr != DEV_ADDR_ANY) {
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), discovered service ''%s'' in two different devices !!!\n",
+ name);
+ self->daddr = DEV_ADDR_ANY;
+ kfree(discoveries);
+ return(-ENOTUNIQ);
}
+ /* First time we found that one, save it ! */
+ daddr = self->daddr;
+ dtsap_sel = self->dtsap_sel;
+ break;
+ case -EADDRNOTAVAIL:
+ /* Requested service simply doesn't exist on this node */
+ break;
+ default:
+ /* Something bad did happen :-( */
+ IRDA_DEBUG(0, __FUNCTION__
+ "(), unexpected IAS query failure\n");
+ self->daddr = DEV_ADDR_ANY;
+ kfree(discoveries);
+ return(-EHOSTUNREACH);
+ break;
}
-
- /* Next node, maybe we will be more lucky... */
- discovery = (discovery_t *) hashbin_get_next(cachelog);
}
- cachelog = NULL;
+ /* Cleanup our copy of the discovery log */
+ kfree(discoveries);
/* Check out what we found */
- if(daddr == 0x0) {
- IRDA_DEBUG(0, __FUNCTION__
+ if(daddr == DEV_ADDR_ANY) {
+ IRDA_DEBUG(1, __FUNCTION__
"(), cannot discover service ''%s'' in any device !!!\n",
name);
- self->daddr = 0; /* Guessing */
- return(-ENETUNREACH);
+ self->daddr = DEV_ADDR_ANY;
+ return(-EADDRNOTAVAIL);
}
/* Revert back to discovered device & service */
@@ -588,7 +696,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
self->saddr = 0x0;
self->dtsap_sel = dtsap_sel;
- IRDA_DEBUG(0, __FUNCTION__
+ IRDA_DEBUG(1, __FUNCTION__
"(), discovered requested service ''%s'' at address %08x\n",
name, self->daddr);
@@ -606,25 +714,26 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
{
struct sockaddr_irda saddr;
struct sock *sk = sock->sk;
+ struct irda_sock *self = sk->protinfo.irda;
if (peer) {
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
saddr.sir_family = AF_IRDA;
- saddr.sir_lsap_sel = sk->protinfo.irda->dtsap_sel;
- saddr.sir_addr = sk->protinfo.irda->daddr;
+ saddr.sir_lsap_sel = self->dtsap_sel;
+ saddr.sir_addr = self->daddr;
} else {
saddr.sir_family = AF_IRDA;
- saddr.sir_lsap_sel = sk->protinfo.irda->stsap_sel;
- saddr.sir_addr = sk->protinfo.irda->saddr;
+ saddr.sir_lsap_sel = self->stsap_sel;
+ saddr.sir_addr = self->saddr;
}
IRDA_DEBUG(1, __FUNCTION__ "(), tsap_sel = %#x\n", saddr.sir_lsap_sel);
IRDA_DEBUG(1, __FUNCTION__ "(), addr = %08x\n", saddr.sir_addr);
- if (*uaddr_len > sizeof (struct sockaddr_irda))
- *uaddr_len = sizeof (struct sockaddr_irda);
+ /* uaddr_len come to us uninitialised */
+ *uaddr_len = sizeof (struct sockaddr_irda);
memcpy(uaddr, &saddr, *uaddr_len);
return 0;
@@ -709,7 +818,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* Register with LM-IAS */
self->ias_obj = irias_new_object(addr->sir_name, jiffies);
irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel",
- self->stsap_sel);
+ self->stsap_sel, IAS_KERNEL_ATTR);
irias_insert_object(self->ias_obj);
#if 1 /* Will be removed in near future */
@@ -821,6 +930,20 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
*
* Connect to a IrDA device
*
+ * The main difference with a "standard" connect is that with IrDA we need
+ * to resolve the service name into a TSAP selector (in TCP, port number
+ * doesn't have to be resolved).
+ * Because of this service name resoltion, we can offer "auto-connect",
+ * where we connect to a service without specifying a destination address.
+ *
+ * Note : by consulting "errno", the user space caller may learn the cause
+ * of the failure. Most of them are visible in the function, others may come
+ * from subroutines called and are listed here :
+ * o EBUSY : already processing a connect
+ * o EHOSTUNREACH : bad addr->sir_addr argument
+ * o EADDRNOTAVAIL : bad addr->sir_name argument
+ * o ENOTUNIQ : more than one node has addr->sir_name (auto-connect)
+ * o ENETUNREACH : no node found on the network (auto-connect)
*/
static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
@@ -858,13 +981,13 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
return -EINVAL;
/* Check if user supplied any destination device address */
- if (!addr->sir_addr) {
+ if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) {
/* Try to find one suitable */
err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
if (err) {
IRDA_DEBUG(0, __FUNCTION__
"(), auto-connect failed!\n");
- return -EINVAL;
+ return err;
}
} else {
/* Use the one provided by the user */
@@ -922,6 +1045,9 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
sti();
+ /* At this point, IrLMP has assigned our source address */
+ self->saddr = irttp_get_saddr(self->tsap);
+
return 0;
}
@@ -957,7 +1083,7 @@ static int irda_create(struct socket *sock, int protocol)
return -ENOMEM;
memset(self, 0, sizeof(struct irda_sock));
- init_waitqueue_head(&self->ias_wait);
+ init_waitqueue_head(&self->query_wait);
self->sk = sk;
sk->protinfo.irda = self;
@@ -996,14 +1122,14 @@ static int irda_create(struct socket *sock, int protocol)
sk->protocol = protocol;
/* Register as a client with IrLMP */
- self->ckey = irlmp_register_client(0, NULL, NULL);
+ self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
self->mask = 0xffff;
self->rx_flow = self->tx_flow = FLOW_START;
self->nslots = DISCOVERY_DEFAULT_SLOTS;
- self->daddr = DEV_ADDR_ANY;
+ self->daddr = DEV_ADDR_ANY; /* Until we get connected */
+ self->saddr = 0x0; /* so IrLMP assign us any link */
- /* Notify that we are using the irda module, so nobody removes it */
- irda_mod_inc_use_count();
+ MOD_INC_USE_COUNT;
return 0;
}
@@ -1025,11 +1151,15 @@ void irda_destroy_socket(struct irda_sock *self)
irlmp_unregister_service(self->skey);
/* Unregister with LM-IAS */
- if (self->ias_obj)
+ if (self->ias_obj) {
irias_delete_object(self->ias_obj);
+ self->ias_obj = NULL;
+ }
- if (self->iriap)
+ if (self->iriap) {
iriap_close(self->iriap);
+ self->iriap = NULL;
+ }
if (self->tsap) {
irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
@@ -1043,10 +1173,8 @@ void irda_destroy_socket(struct irda_sock *self)
}
#endif /* CONFIG_IRDA_ULTRA */
kfree(self);
-
- /* Notify that we are not using the irda module anymore */
- irda_mod_dec_use_count();
-
+ MOD_DEC_USE_COUNT;
+
return;
}
@@ -1096,7 +1224,8 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
IRDA_DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
- if (msg->msg_flags & ~MSG_DONTWAIT)
+ /* Note : socket.c set MSG_EOR on SEQPACKET sockets */
+ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR))
return -EINVAL;
if (sk->shutdown & SEND_SHUTDOWN) {
@@ -1474,15 +1603,22 @@ static int irda_shutdown(struct socket *sock, int how)
sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
- if (self->iriap)
+ if (self->iriap) {
iriap_close(self->iriap);
-
+ self->iriap = NULL;
+ }
+
if (self->tsap) {
irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
irttp_close_tsap(self->tsap);
self->tsap = NULL;
}
+ /* A few cleanup so the socket look as good as new... */
+ self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */
+ self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */
+ self->saddr = 0x0; /* so IrLMP assign us any link */
+
return 0;
}
@@ -1606,6 +1742,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
struct irda_sock *self;
struct irda_ias_set ias_opt;
struct ias_object *ias_obj;
+ struct ias_attrib * ias_attr; /* Attribute in IAS object */
int opt;
self = sk->protinfo.irda;
@@ -1616,6 +1753,13 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case IRLMP_IAS_SET:
+ /* The user want to add an attribute to an existing IAS object
+ * (in the IAS database) or to create a new object with this
+ * attribute.
+ * We first query IAS to know if the object exist, and then
+ * create the right attribute...
+ */
+
if (optlen != sizeof(struct irda_ias_set))
return -EINVAL;
@@ -1639,9 +1783,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
switch(ias_opt.irda_attrib_type) {
case IAS_INTEGER:
/* Add an integer attribute */
- irias_add_integer_attrib(ias_obj,
- ias_opt.irda_attrib_name,
- ias_opt.attribute.irda_attrib_int);
+ irias_add_integer_attrib(
+ ias_obj,
+ ias_opt.irda_attrib_name,
+ ias_opt.attribute.irda_attrib_int,
+ IAS_USER_ATTR);
break;
case IAS_OCT_SEQ:
/* Check length */
@@ -1653,7 +1799,8 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
ias_obj,
ias_opt.irda_attrib_name,
ias_opt.attribute.irda_attrib_octet_seq.octet_seq,
- ias_opt.attribute.irda_attrib_octet_seq.len);
+ ias_opt.attribute.irda_attrib_octet_seq.len,
+ IAS_USER_ATTR);
break;
case IAS_STRING:
/* Should check charset & co */
@@ -1667,16 +1814,49 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
irias_add_string_attrib(
ias_obj,
ias_opt.irda_attrib_name,
- ias_opt.attribute.irda_attrib_string.string);
+ ias_opt.attribute.irda_attrib_string.string,
+ IAS_USER_ATTR);
break;
default :
return -EINVAL;
}
irias_insert_object(ias_obj);
break;
+ case IRLMP_IAS_DEL:
+ /* The user want to delete an object from our local IAS
+ * database. We just need to query the IAS, check is the
+ * object is not owned by the kernel and delete it.
+ */
- IRDA_DEBUG(0, __FUNCTION__ "(), sorry not impl. yet!\n");
- return -ENOPROTOOPT;
+ if (optlen != sizeof(struct irda_ias_set))
+ return -EINVAL;
+
+ /* Copy query to the driver. */
+ if (copy_from_user(&ias_opt, (char *)optval, optlen))
+ return -EFAULT;
+
+ /* Find the object we target */
+ ias_obj = irias_find_object(ias_opt.irda_class_name);
+ if(ias_obj == (struct ias_object *) NULL)
+ return -EINVAL;
+
+ /* Find the attribute (in the object) we target */
+ ias_attr = irias_find_attrib(ias_obj,
+ ias_opt.irda_attrib_name);
+ if(ias_attr == (struct ias_attrib *) NULL)
+ return -EINVAL;
+
+ /* Check is the user space own the object */
+ if(ias_attr->value->owner != IAS_USER_ATTR) {
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), attempting to delete a kernel attribute\n");
+ return -EPERM;
+ }
+
+ /* Remove the attribute (and maybe the object) */
+ irias_delete_attrib(ias_obj, ias_attr);
+
+ break;
case IRLMP_MAX_SDU_SIZE:
if (optlen < sizeof(int))
return -EINVAL;
@@ -1709,60 +1889,31 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
self->skey = irlmp_register_service((__u16) opt);
break;
- default:
- return -ENOPROTOOPT;
- }
- return 0;
-}
-
- /*
- * Function irda_simple_getvalue_confirm (obj_id, value, priv)
- *
- * Got answer from remote LM-IAS, just copy object to requester...
- *
- * Note : duplicate from above, but we need our own version that
- * doesn't touch the dtsap_sel and save the full value structure...
- */
-static void irda_simple_getvalue_confirm(int result, __u16 obj_id,
- struct ias_value *value, void *priv)
-{
- struct irda_sock *self;
-
- IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
- ASSERT(priv != NULL, return;);
- self = (struct irda_sock *) priv;
+ case IRLMP_HINT_MASK_SET:
+ /* As opposed to the previous case which set the hint bits
+ * that we advertise, this one set the filter we use when
+ * making a discovery (nodes which don't match any hint
+ * bit in the mask are not reported).
+ */
+ if (optlen < sizeof(int))
+ return -EINVAL;
- if (!self) {
- WARNING(__FUNCTION__ "(), lost myself!\n");
- return;
- }
-
- /* We probably don't need to make any more queries */
- iriap_close(self->iriap);
- self->iriap = NULL;
-
- /* Check if request succeeded */
- if (result != IAS_SUCCESS) {
- IRDA_DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
-
- self->errno = -EHOSTUNREACH;
+ if (get_user(opt, (int *)optval))
+ return -EFAULT;
- /* Wake up any processes waiting for result */
- wake_up_interruptible(&self->ias_wait);
+ /* Set the new hint mask */
+ self->mask = (__u16) opt;
+ /* Mask out extension bits */
+ self->mask &= 0x7f7f;
+ /* Check if no bits */
+ if(!self->mask)
+ self->mask = 0xFFFF;
- return;
+ break;
+ default:
+ return -ENOPROTOOPT;
}
-
- /* Clone the object (so the requester can free it) */
- self->ias_result = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
- memcpy(self->ias_result, value, sizeof(struct ias_value));
- irias_delete_value(value);
-
- self->errno = 0;
-
- /* Wake up any processes waiting for result */
- wake_up_interruptible(&self->ias_wait);
+ return 0;
}
/*
@@ -1803,6 +1954,7 @@ static int irda_extract_ias_value(struct irda_ias_set *ias_opt,
/* NULL terminate the string (avoid troubles) */
ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0';
break;
+ case IAS_MISSING:
default :
return -EINVAL;
}
@@ -1825,11 +1977,11 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
struct sock *sk = sock->sk;
struct irda_sock *self;
struct irda_device_list list;
- struct irda_device_info *info;
- discovery_t *discovery;
+ struct irda_device_info *discoveries;
struct irda_ias_set ias_opt; /* IAS get/query params */
struct ias_object * ias_obj; /* Object in IAS */
struct ias_attrib * ias_attr; /* Attribute in IAS object */
+ int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */
int val = 0;
int len = 0;
int err;
@@ -1845,67 +1997,38 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case IRLMP_ENUMDEVICES:
- /* Tell IrLMP we want to be notified */
- irlmp_update_client(self->ckey, self->mask, NULL,
- irda_discovery_indication);
-
- /* Do some discovery */
- irlmp_discovery_request(self->nslots);
-
+ /* Ask lmp for the current discovery log */
+ discoveries = irlmp_get_discoveries(&list.len, self->mask);
/* Check if the we got some results */
- if (!cachelog)
- return -EAGAIN;
+ if (discoveries == NULL)
+ return -EAGAIN; /* Didn't find any devices */
+ err = 0;
- info = &list.dev[0];
+ /* Write total list length back to client */
+ if (copy_to_user(optval, &list,
+ sizeof(struct irda_device_list) -
+ sizeof(struct irda_device_info)))
+ err = -EFAULT;
/* Offset to first device entry */
offset = sizeof(struct irda_device_list) -
sizeof(struct irda_device_info);
- total = offset; /* Initialized to size of the device list */
- list.len = 0; /* Initialize lenght of list */
-
- /*
- * Now, check all discovered devices (if any), and notify
- * client only about the services that the client is
- * interested in
- */
- discovery = (discovery_t *) hashbin_get_first(cachelog);
- while (discovery != NULL) {
- /* Mask out the ones we don't want */
- if (discovery->hints.word & self->mask) {
- /* Check if room for this device entry */
- if (len-total<sizeof(struct irda_device_info))
- break;
-
- /* Copy discovery information */
- info->saddr = discovery->saddr;
- info->daddr = discovery->daddr;
- info->charset = discovery->charset;
- info->hints[0] = discovery->hints.byte[0];
- info->hints[1] = discovery->hints.byte[1];
- strncpy(info->info, discovery->nickname,
- NICKNAME_MAX_LEN);
-
- if (copy_to_user(optval+total, info,
- sizeof(struct irda_device_info)))
- return -EFAULT;
- list.len++;
- total += sizeof(struct irda_device_info);
- }
- discovery = (discovery_t *) hashbin_get_next(cachelog);
- }
- cachelog = NULL;
+ /* Copy the list itself */
+ total = offset + (list.len * sizeof(struct irda_device_info));
+ if (total > len)
+ total = len;
+ if (copy_to_user(optval+offset, discoveries, total - offset))
+ err = -EFAULT;
/* Write total number of bytes used back to client */
if (put_user(total, optlen))
- return -EFAULT;
+ err = -EFAULT;
- /* Write total list length back to client */
- if (copy_to_user(optval, &list,
- sizeof(struct irda_device_list) -
- sizeof(struct irda_device_info)))
- return -EFAULT;
+ /* Free up our buffer */
+ kfree(discoveries);
+ if (err)
+ return err;
break;
case IRLMP_MAX_SDU_SIZE:
val = self->max_data_size;
@@ -1964,6 +2087,26 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
if (copy_from_user((char *) &ias_opt, (char *)optval, len))
return -EFAULT;
+ /* At this point, there are two cases...
+ * 1) the socket is connected - that's the easy case, we
+ * just query the device we are connected to...
+ * 2) the socket is not connected - the user doesn't want
+ * to connect and/or may not have a valid service name
+ * (so can't create a fake connection). In this case,
+ * we assume that the user pass us a valid destination
+ * address in the requesting structure...
+ */
+ if(self->daddr != DEV_ADDR_ANY) {
+ /* We are connected - reuse known daddr */
+ daddr = self->daddr;
+ } else {
+ /* We are not connected, we must specify a valid
+ * destination address */
+ daddr = ias_opt.daddr;
+ if((!daddr) || (daddr == DEV_ADDR_ANY))
+ return -EINVAL;
+ }
+
/* Check that we can proceed with IAP */
if (self->iriap) {
WARNING(__FUNCTION__
@@ -1972,26 +2115,34 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
}
self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
- irda_simple_getvalue_confirm);
+ irda_getvalue_confirm);
/* Treat unexpected signals as disconnect */
self->errno = -EHOSTUNREACH;
/* Query remote LM-IAS */
- iriap_getvaluebyclass_request(self->iriap,
- self->saddr, self->daddr,
+ iriap_getvaluebyclass_request(self->iriap,
+ self->saddr, daddr,
ias_opt.irda_class_name,
ias_opt.irda_attrib_name);
- /* Wait for answer */
- interruptible_sleep_on(&self->ias_wait);
+ /* Wait for answer (if not already failed) */
+ if(self->iriap != NULL)
+ interruptible_sleep_on(&self->query_wait);
/* Check what happened */
if (self->errno)
- return (self->errno);
+ {
+ /* Requested object/attribute doesn't exist */
+ if((self->errno == IAS_CLASS_UNKNOWN) ||
+ (self->errno == IAS_ATTRIB_UNKNOWN))
+ return (-EADDRNOTAVAIL);
+ else
+ return (-EHOSTUNREACH);
+ }
/* Translate from internal to user structure */
err = irda_extract_ias_value(&ias_opt, self->ias_result);
if (self->ias_result)
- kfree(self->ias_result);
+ irias_delete_value(self->ias_result);
if (err)
return err;
@@ -2001,6 +2152,76 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
/* Note : don't need to put optlen, we checked it */
break;
+ case IRLMP_WAITDEVICE:
+ /* This function is just another way of seeing life ;-)
+ * IRLMP_ENUMDEVICES assumes that you have a static network,
+ * and that you just want to pick one of the devices present.
+ * On the other hand, in here we assume that no device is
+ * present and that at some point in the future a device will
+ * come into range. When this device arrive, we just wake
+ * up the caller, so that he has time to connect to it before
+ * the device goes away...
+ * Note : once the node has been discovered for more than a
+ * few second, it won't trigger this function, unless it
+ * goes away and come back changes its hint bits (so we
+ * might call it IRLMP_WAITNEWDEVICE).
+ */
+
+ /* Check that the user is passing us an int */
+ if (len != sizeof(int))
+ return -EINVAL;
+ /* Get timeout in ms (max time we block the caller) */
+ if (get_user(val, (int *)optval))
+ return -EFAULT;
+
+ /* Tell IrLMP we want to be notified */
+ irlmp_update_client(self->ckey, self->mask,
+ irda_selective_discovery_indication,
+ NULL, (void *) self);
+
+ /* Do some discovery (and also return cached results) */
+ irlmp_discovery_request(self->nslots);
+
+ /* Wait until a node is discovered */
+ if (!self->cachediscovery) {
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), nothing discovered yet, going to sleep...\n");
+
+ /* Set watchdog timer to expire in <val> ms. */
+ self->watchdog.function = irda_discovery_timeout;
+ self->watchdog.data = (unsigned long) self;
+ self->watchdog.expires = jiffies + (val * HZ/1000);
+ add_timer(&(self->watchdog));
+
+ /* Wait for IR-LMP to call us back */
+ interruptible_sleep_on(&self->query_wait);
+
+ /* If watchdog is still activated, kill it! */
+ if(timer_pending(&(self->watchdog)))
+ del_timer(&(self->watchdog));
+
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), ...waking up !\n");
+ }
+ else
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), found immediately !\n");
+
+ /* Tell IrLMP that we have been notified */
+ irlmp_update_client(self->ckey, self->mask, NULL, NULL, NULL);
+
+ /* Check if the we got some results */
+ if (!self->cachediscovery)
+ return -EAGAIN; /* Didn't find any devices */
+ /* Cleanup */
+ self->cachediscovery = NULL;
+
+ /* Note : We don't return anything to the user.
+ * We could return the device that triggered the wake up,
+ * but it's probably better to force the user to query
+ * the whole discovery log and let him pick one device...
+ */
+ break;
default:
return -ENOPROTOOPT;
}
@@ -2150,24 +2371,44 @@ static struct notifier_block irda_dev_notifier = {
};
/*
+ * Function irda_proc_modcount (inode, fill)
+ *
+ * Use by the proc file system functions to prevent the irda module
+ * being removed while the use is standing in the net/irda directory
+ */
+void irda_proc_modcount(struct inode *inode, int fill)
+{
+#ifdef MODULE
+#ifdef CONFIG_PROC_FS
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+#endif /* CONFIG_PROC_FS */
+#endif /* MODULE */
+}
+
+/*
* Function irda_proto_init (pro)
*
* Initialize IrDA protocol layer
*
*/
-static int __init irda_proto_init(void)
+int __init irda_proto_init(void)
{
- sock_register(&irda_family_ops);
-
- irda_packet_type.type = htons(ETH_P_IRDA);
+ sock_register(&irda_family_ops);
+
+ irda_packet_type.type = htons(ETH_P_IRDA);
dev_add_pack(&irda_packet_type);
-
- register_netdevice_notifier(&irda_dev_notifier);
-
- irda_init();
+
+ register_netdevice_notifier(&irda_dev_notifier);
+
+ irda_init();
+#ifdef MODULE
+ irda_device_init(); /* Called by init/main.c when non-modular */
+#endif
return 0;
}
-module_init(irda_proto_init);
/*
* Function irda_proto_cleanup (void)
@@ -2188,5 +2429,11 @@ void irda_proto_cleanup(void)
return;
}
+module_init(irda_proto_init);
module_exit(irda_proto_cleanup);
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem");
+MODULE_PARM(irda_debug, "1l");
#endif /* MODULE */
+
diff --git a/net/irda/compressors/irda_deflate.c b/net/irda/compressors/irda_deflate.c
index 245185500..f0d2cbb0d 100644
--- a/net/irda/compressors/irda_deflate.c
+++ b/net/irda/compressors/irda_deflate.c
@@ -561,37 +561,37 @@ extern void irda_unregister_compressor (struct compressor *cp);
* Procedures exported to if_ppp.c.
*/
static struct compressor irda_deflate = {
- CI_DEFLATE, /* compress_proto */
- z_comp_alloc, /* comp_alloc */
- z_comp_free, /* comp_free */
- z_comp_init, /* comp_init */
- z_comp_reset, /* comp_reset */
- z_compress, /* compress */
- z_comp_stats, /* comp_stat */
- z_decomp_alloc, /* decomp_alloc */
- z_decomp_free, /* decomp_free */
- z_decomp_init, /* decomp_init */
- z_decomp_reset, /* decomp_reset */
- z_decompress, /* decompress */
- z_incomp, /* incomp */
- z_comp_stats, /* decomp_stat */
+compress_proto: CI_DEFLATE,
+comp_alloc: z_comp_alloc,
+comp_free: z_comp_free,
+comp_init: z_comp_init,
+comp_reset: z_comp_reset,
+compress: z_compress,
+comp_stat: z_comp_stats,
+decomp_alloc: z_decomp_alloc,
+decomp_free: z_decomp_free,
+decomp_init: z_decomp_init,
+decomp_reset: z_decomp_reset,
+decompress: z_decompress,
+incomp: z_incomp,
+decomp_stat: z_comp_stats
};
static struct compressor irda_deflate_draft = {
- CI_DEFLATE_DRAFT, /* compress_proto */
- z_comp_alloc, /* comp_alloc */
- z_comp_free, /* comp_free */
- z_comp_init, /* comp_init */
- z_comp_reset, /* comp_reset */
- z_compress, /* compress */
- z_comp_stats, /* comp_stat */
- z_decomp_alloc, /* decomp_alloc */
- z_decomp_free, /* decomp_free */
- z_decomp_init, /* decomp_init */
- z_decomp_reset, /* decomp_reset */
- z_decompress, /* decompress */
- z_incomp, /* incomp */
- z_comp_stats, /* decomp_stat */
+compress_proto: CI_DEFLATE_DRAFT,
+comp_alloc: z_comp_alloc,
+comp_free: z_comp_free,
+comp_init: z_comp_init,
+comp_reset: z_comp_reset,
+compress: z_compress,
+comp_stat: z_comp_stats,
+decomp_alloc: z_decomp_alloc,
+decomp_free: z_decomp_free,
+decomp_init: z_decomp_init,
+decomp_reset: z_decomp_reset,
+decompress: z_decompress,
+incomp: z_incomp,
+decomp_stat: z_comp_stats
};
int __init irda_deflate_init(void)
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index 957426154..d2fe17ff8 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -43,13 +43,25 @@
*
* Add a new discovery to the cachelog, and remove any old discoveries
* from the same device
+ *
+ * Note : we try to preserve the time this device was *first* discovered
+ * (as opposed to the time of last discovery used for cleanup). This is
+ * used by clients waiting for discovery events to tell if the device
+ * discovered is "new" or just the same old one. They can't rely there
+ * on a binary flag (new/old), because not all discovery events are
+ * propagated to them, and they might not always listen, so they would
+ * miss some new devices popping up...
+ * Jean II
*/
void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
{
discovery_t *discovery, *node;
unsigned long flags;
- spin_lock_irqsave(&irlmp->lock, flags);
+ /* Set time of first discovery if node is new (see below) */
+ new->first_timestamp = new->timestamp;
+
+ spin_lock_irqsave(&irlmp->log_lock, flags);
/*
* Remove all discoveries of devices that has previously been
@@ -59,27 +71,31 @@ void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
*/
discovery = (discovery_t *) hashbin_get_first(cachelog);
while (discovery != NULL ) {
- node = discovery;
+ node = discovery;
- /* Be sure to stay one item ahead */
- discovery = (discovery_t *) hashbin_get_next(cachelog);
-
- if ((node->daddr == new->daddr) ||
- (strcmp(node->nickname, new->nickname) == 0))
- {
- /* This discovery is a previous discovery
- * from the same device, so just remove it
- */
- hashbin_remove(cachelog, node->daddr, NULL);
- kfree(node);
- }
- }
+ /* Be sure to stay one item ahead */
+ discovery = (discovery_t *) hashbin_get_next(cachelog);
+ if ((node->saddr == new->saddr) &&
+ ((node->daddr == new->daddr) ||
+ (strcmp(node->nickname, new->nickname) == 0)))
+ {
+ /* This discovery is a previous discovery
+ * from the same device, so just remove it
+ */
+ hashbin_remove_this(cachelog, (irda_queue_t *) node);
+ /* Check if hints bits have changed */
+ if(node->hints.word == new->hints.word)
+ /* Set time of first discovery for this node */
+ new->first_timestamp = node->first_timestamp;
+ kfree(node);
+ }
+ }
/* Insert the new and updated version */
- hashbin_insert(cachelog, (queue_t *) new, new->daddr, NULL);
+ hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL);
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
}
/*
@@ -120,13 +136,18 @@ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
*
* Go through all discoveries and expire all that has stayed to long
*
+ * Note : this assume that IrLAP won't change its saddr, which
+ * currently is a valid assumption...
*/
void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
{
discovery_t *discovery, *curr;
+ unsigned long flags;
IRDA_DEBUG(4, __FUNCTION__ "()\n");
+ spin_lock_irqsave(&irlmp->log_lock, flags);
+
discovery = (discovery_t *) hashbin_get_first(log);
while (discovery != NULL) {
curr = discovery;
@@ -135,14 +156,20 @@ void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
discovery = (discovery_t *) hashbin_get_next(log);
/* Test if it's time to expire this discovery */
- if ((curr->saddr == saddr) && (force ||
- ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
+ if ((curr->saddr == saddr) &&
+ (force ||
+ ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT)))
{
- curr = hashbin_remove(log, curr->daddr, NULL);
+ /* Tell IrLMP and registered clients about it */
+ irlmp_discovery_expiry(curr);
+ /* Remove it from the log */
+ curr = hashbin_remove_this(log, (irda_queue_t *) curr);
if (curr)
kfree(curr);
}
}
+
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
}
/*
@@ -169,6 +196,75 @@ void irlmp_dump_discoveries(hashbin_t *log)
}
/*
+ * Function irlmp_copy_discoveries (log, pn, mask)
+ *
+ * Copy all discoveries in a buffer
+ *
+ * This function implement a safe way for lmp clients to access the
+ * discovery log. The basic problem is that we don't want the log
+ * to change (add/remove) while the client is reading it. If the
+ * lmp client manipulate directly the hashbin, he is sure to get
+ * into troubles...
+ * The idea is that we copy all the current discovery log in a buffer
+ * which is specific to the client and pass this copy to him. As we
+ * do this operation with the spinlock grabbed, we are safe...
+ * Note : we don't want those clients to grab the spinlock, because
+ * we have no control on how long they will hold it...
+ * Note : we choose to copy the log in "struct irda_device_info" to
+ * save space...
+ * Note : the client must kfree himself() the log...
+ * Jean II
+ */
+struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, __u16 mask)
+{
+ discovery_t * discovery;
+ unsigned long flags;
+ struct irda_device_info * buffer;
+ int i = 0;
+ int n;
+
+ ASSERT(pn != NULL, return NULL;);
+
+ /* Check if log is empty */
+ if(log == NULL)
+ return NULL;
+
+ /* Save spin lock - spinlock should be discovery specific */
+ spin_lock_irqsave(&irlmp->log_lock, flags);
+
+ /* Create the client specific buffer */
+ n = HASHBIN_GET_SIZE(log);
+ buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
+ if (buffer == NULL) {
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
+ return NULL;
+ }
+
+ discovery = (discovery_t *) hashbin_get_first(log);
+ while ((discovery != NULL) && (i < n)) {
+ /* Mask out the ones we don't want */
+ if (discovery->hints.word & mask) {
+ /* Copy discovery information */
+ buffer[i].saddr = discovery->saddr;
+ buffer[i].daddr = discovery->daddr;
+ buffer[i].charset = discovery->charset;
+ buffer[i].hints[0] = discovery->hints.byte[0];
+ buffer[i].hints[1] = discovery->hints.byte[1];
+ strncpy(buffer[i].info, discovery->nickname,
+ NICKNAME_MAX_LEN);
+ i++;
+ }
+ discovery = (discovery_t *) hashbin_get_next(log);
+ }
+
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
+
+ /* Get the actual number of device in the buffer and return */
+ *pn = i;
+ return(buffer);
+}
+
+/*
* Function irlmp_find_device (name, saddr)
*
* Look through the discovery log at each of the links and try to find
@@ -180,7 +276,7 @@ __u32 irlmp_find_device(hashbin_t *cachelog, char *name, __u32 *saddr)
unsigned long flags;
discovery_t *d;
- spin_lock_irqsave(&irlmp->lock, flags);
+ spin_lock_irqsave(&irlmp->log_lock, flags);
/* Look at all discoveries for that link */
d = (discovery_t *) hashbin_get_first(cachelog);
@@ -192,13 +288,13 @@ __u32 irlmp_find_device(hashbin_t *cachelog, char *name, __u32 *saddr)
if (strcmp(name, d->nickname) == 0) {
*saddr = d->saddr;
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return d->daddr;
}
d = (discovery_t *) hashbin_get_next(cachelog);
}
- spin_unlock_irqrestore(&irlmp->lock, flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return 0;
}
@@ -209,23 +305,23 @@ __u32 irlmp_find_device(hashbin_t *cachelog, char *name, __u32 *saddr)
* Print discovery information in /proc file system
*
*/
-int discovery_proc_read(char *buf, char **start, off_t offset, int len,
+int discovery_proc_read(char *buf, char **start, off_t offset, int length,
int unused)
{
discovery_t *discovery;
unsigned long flags;
hashbin_t *cachelog = irlmp_get_cachelog();
+ int len = 0;
if (!irlmp)
return len;
len = sprintf(buf, "IrLMP: Discovery log:\n\n");
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&irlmp->log_lock, flags);
+
discovery = (discovery_t *) hashbin_get_first(cachelog);
- while ( discovery != NULL) {
+ while (( discovery != NULL) && (len < length)) {
len += sprintf(buf+len, "nickname: %s,", discovery->nickname);
len += sprintf(buf+len, " hint: 0x%02x%02x",
@@ -266,7 +362,7 @@ int discovery_proc_read(char *buf, char **start, off_t offset, int len,
discovery = (discovery_t *) hashbin_get_next(cachelog);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&irlmp->log_lock, flags);
return len;
}
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index 805186128..ae626e08b 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -127,7 +127,7 @@ struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
self->service_type = service_type;
self->line = line;
- hashbin_insert(ircomm, (queue_t *) self, line, NULL);
+ hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL);
ircomm_next_state(self, IRCOMM_IDLE);
@@ -512,6 +512,9 @@ int ircomm_proc_read(char *buf, char **start, off_t offset, int len)
#endif /* CONFIG_PROC_FS */
#ifdef MODULE
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("IrCOMM protocol");
+
int init_module(void)
{
return ircomm_init();
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index d785983da..67925c5b5 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -29,6 +29,7 @@
*
********************************************************************/
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
@@ -69,9 +70,10 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
struct sk_buff *skb);
static void ircomm_tty_flow_indication(void *instance, void *sap,
LOCAL_FLOW cmd);
+#ifdef CONFIG_PROC_FS
static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
int *eof, void *unused);
-
+#endif /* CONFIG_PROC_FS */
static struct tty_driver driver;
static int ircomm_tty_refcount; /* If we manage several devices */
@@ -126,8 +128,9 @@ int __init ircomm_tty_init(void)
driver.start = ircomm_tty_start;
driver.hangup = ircomm_tty_hangup;
driver.wait_until_sent = ircomm_tty_wait_until_sent;
+#ifdef CONFIG_PROC_FS
driver.read_proc = ircomm_tty_read_proc;
-
+#endif /* CONFIG_PROC_FS */
if (tty_register_driver(&driver)) {
ERROR(__FUNCTION__ "Couldn't register serial driver\n");
return -1;
@@ -429,7 +432,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
tty->termios->c_oflag = 0;
/* Insert into hash */
- hashbin_insert(ircomm_tty, (queue_t *) self, line, NULL);
+ hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
}
self->open_count++;
@@ -1319,6 +1322,7 @@ static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf)
*
*
*/
+#ifdef CONFIG_PROC_FS
static int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len,
int *eof, void *unused)
{
@@ -1349,9 +1353,12 @@ done:
*start = buf + (offset-begin);
return ((len < begin+count-offset) ? len : begin+count-offset);
}
-
+#endif /* CONFIG_PROC_FS */
#ifdef MODULE
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("IrCOMM serial TTY driver");
+
int init_module(void)
{
return ircomm_tty_init();
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index 94c9fee09..ad5ee4b0f 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -46,7 +46,8 @@
#include <net/irda/ircomm_tty_attach.h>
static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
-static void ircomm_tty_discovery_indication(discovery_t *discovery);
+static void ircomm_tty_discovery_indication(discovery_t *discovery,
+ void *priv);
static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
struct ias_value *value, void *priv);
void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
@@ -213,7 +214,7 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
/* Register IrLPT with LM-IAS */
self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel",
- self->slsap_sel);
+ self->slsap_sel, IAS_KERNEL_ATTR);
irias_insert_object(self->obj);
} else {
hints = irlmp_service_to_hint(S_COMM);
@@ -221,7 +222,7 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
/* Register IrCOMM with LM-IAS */
self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel",
- self->slsap_sel);
+ self->slsap_sel, IAS_KERNEL_ATTR);
/* Code the parameters into the buffer */
irda_param_pack(oct_seq, "bbbbbb",
@@ -229,12 +230,13 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL);
/* Register parameters with LM-IAS */
- irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6);
+ irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
+ IAS_KERNEL_ATTR);
irias_insert_object(self->obj);
}
self->skey = irlmp_register_service(hints);
self->ckey = irlmp_register_client(
- hints, ircomm_tty_discovery_indication, NULL);
+ hints, ircomm_tty_discovery_indication, NULL, (void *) self);
}
/*
@@ -302,7 +304,8 @@ int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
* device it is, and which services it has.
*
*/
-static void ircomm_tty_discovery_indication(discovery_t *discovery)
+static void ircomm_tty_discovery_indication(discovery_t *discovery,
+ void *priv)
{
struct ircomm_tty_cb *self;
struct ircomm_tty_info info;
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index ca2903316..c77ca6268 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -58,6 +58,8 @@
extern int irtty_init(void);
extern int nsc_ircc_init(void);
extern int ircc_init(void);
+extern int toshoboe_init(void);
+extern int litelink_init(void);
extern int w83977af_init(void);
extern int esi_init(void);
extern int tekram_init(void);
@@ -183,7 +185,7 @@ void irda_device_set_media_busy(struct net_device *dev, int status)
IRDA_DEBUG( 4, "Media busy!\n");
} else {
self->media_busy = FALSE;
- del_timer(&self->media_busy_timer);
+ irlap_stop_mbusy_timer(self);
}
}
@@ -379,7 +381,7 @@ struct irda_task *irda_task_execute(void *instance,
init_timer(&task->timer);
/* Register task */
- hashbin_insert(tasks, (queue_t *) task, (int) task, NULL);
+ hashbin_insert(tasks, (irda_queue_t *) task, (int) task, NULL);
/* No time to waste, so lets get going! */
ret = irda_task_kick(task);
@@ -518,7 +520,7 @@ int irda_device_register_dongle(struct dongle_reg *new)
}
/* Insert IrDA dongle into hashbin */
- hashbin_insert(dongles, (queue_t *) new, new->type, NULL);
+ hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
return 0;
}
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 5f1140525..03014ac0d 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -107,7 +107,7 @@ int __init iriap_init(void)
/* Register the Device object with LM-IAS */
obj = irias_new_object("Device", IAS_DEVICE_ID);
- irias_add_string_attrib(obj, "DeviceName", "Linux");
+ irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR);
oct_seq[0] = 0x01; /* Version 1 */
oct_seq[1] = 0x00; /* IAS support bits */
@@ -115,7 +115,8 @@ int __init iriap_init(void)
#ifdef CONFIG_IRDA_ULTRA
oct_seq[2] |= 0x04; /* Connectionless Data support */
#endif
- irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3);
+ irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3,
+ IAS_KERNEL_ATTR);
irias_insert_object(obj);
/*
@@ -179,7 +180,7 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
init_timer(&self->watchdog_timer);
- hashbin_insert(iriap, (queue_t *) self, (int) self, NULL);
+ hashbin_insert(iriap, (irda_queue_t *) self, (int) self, NULL);
/* Initialize state machines */
iriap_next_client_state(self, S_DISCONNECT);
@@ -866,7 +867,7 @@ static int iriap_data_indication(void *instance, void *sap,
iriap_getvaluebyclass_confirm(self, skb);
break;
case IAS_CLASS_UNKNOWN:
- WARNING(__FUNCTION__ "(), No such class!\n");
+ IRDA_DEBUG(1, __FUNCTION__ "(), No such class!\n");
/* Finished, close connection! */
iriap_disconnect_request(self);
@@ -880,7 +881,7 @@ static int iriap_data_indication(void *instance, void *sap,
dev_kfree_skb(skb);
break;
case IAS_ATTRIB_UNKNOWN:
- WARNING(__FUNCTION__ "(), No such attribute!\n");
+ IRDA_DEBUG(1, __FUNCTION__ "(), No such attribute!\n");
/* Finished, close connection! */
iriap_disconnect_request(self);
@@ -889,7 +890,7 @@ static int iriap_data_indication(void *instance, void *sap,
* no to use self anymore after calling confirm
*/
if (self->confirm)
- self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
+ self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL,
self->priv);
dev_kfree_skb(skb);
break;
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index 17ad3801d..4a8fbed4c 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -148,6 +148,37 @@ int irias_delete_object(struct ias_object *obj)
}
/*
+ * Function irias_delete_attrib (obj)
+ *
+ * Remove attribute from hashbin and, if it was the last attribute of
+ * the object, remove the object as well.
+ *
+ */
+int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib)
+{
+ struct ias_attrib *node;
+
+ ASSERT(obj != NULL, return -1;);
+ ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
+ ASSERT(attrib != NULL, return -1;);
+
+ /* Remove atribute from object */
+ node = hashbin_remove(obj->attribs, 0, attrib->name);
+ if (!node)
+ return 0; /* Already removed or non-existent */
+
+ /* Deallocate attribute */
+ __irias_delete_attrib(node);
+
+ /* Check if object has still some attributes */
+ node = (struct ias_attrib *) hashbin_get_first(obj->attribs);
+ if (!node)
+ irias_delete_object(obj);
+
+ return 0;
+}
+
+/*
* Function irias_insert_object (obj)
*
* Insert an object into the LM-IAS database
@@ -158,7 +189,7 @@ void irias_insert_object(struct ias_object *obj)
ASSERT(obj != NULL, return;);
ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
- hashbin_insert(objects, (queue_t *) obj, 0, obj->name);
+ hashbin_insert(objects, (irda_queue_t *) obj, 0, obj->name);
}
/*
@@ -201,7 +232,8 @@ struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name)
* Add attribute to object
*
*/
-void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib)
+void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib,
+ int owner)
{
ASSERT(obj != NULL, return;);
ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;);
@@ -209,7 +241,10 @@ void irias_add_attrib( struct ias_object *obj, struct ias_attrib *attrib)
ASSERT(attrib != NULL, return;);
ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;);
- hashbin_insert(obj->attribs, (queue_t *) attrib, 0, attrib->name);
+ /* Set if attrib is owned by kernel or user space */
+ attrib->value->owner = owner;
+
+ hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name);
}
/*
@@ -262,7 +297,8 @@ int irias_object_change_attribute(char *obj_name, char *attrib_name,
* Add an integer attribute to an LM-IAS object
*
*/
-void irias_add_integer_attrib(struct ias_object *obj, char *name, int value)
+void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
+ int owner)
{
struct ias_attrib *attrib;
@@ -284,7 +320,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value)
/* Insert value */
attrib->value = irias_new_integer_value(value);
- irias_add_attrib(obj, attrib);
+ irias_add_attrib(obj, attrib, owner);
}
/*
@@ -295,7 +331,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value)
*/
void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
- int len)
+ int len, int owner)
{
struct ias_attrib *attrib;
@@ -319,7 +355,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
attrib->value = irias_new_octseq_value( octets, len);
- irias_add_attrib(obj, attrib);
+ irias_add_attrib(obj, attrib, owner);
}
/*
@@ -328,7 +364,8 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
* Add a string attribute to an LM-IAS object
*
*/
-void irias_add_string_attrib(struct ias_object *obj, char *name, char *value)
+void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
+ int owner)
{
struct ias_attrib *attrib;
@@ -351,7 +388,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value)
attrib->value = irias_new_string_value(value);
- irias_add_attrib(obj, attrib);
+ irias_add_attrib(obj, attrib, owner);
}
/*
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index 7c2d5b94e..e3a3ada15 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -104,8 +104,6 @@ void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
*/
void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
{
- struct irmanager_event mgr_event;
-
IRDA_DEBUG(1, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
@@ -117,41 +115,24 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
*/
if ((self->client.state != IRLAN_IDLE) ||
(self->provider.access_type == ACCESS_DIRECT))
- return;
+ {
+ IRDA_DEBUG(0, __FUNCTION__ "(), already awake!\n");
+ return;
+ }
- /* saddr may have changed! */
+ /* Address may have changed! */
self->saddr = saddr;
-
- /* Before we try to connect, we check if network device is up. If it
- * is up, that means that the "user" really wants to connect. If not
- * we notify the user about the possibility of an IrLAN connection
- */
- if (netif_running(&self->dev)) {
- /* Open TSAPs */
- irlan_client_open_ctrl_tsap(self);
- irlan_open_data_tsap(self);
-
- irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
- } else if (self->notify_irmanager) {
- /*
- * Tell irmanager that the device can now be
- * configured but only if the device was not taken
- * down by the user
- */
- mgr_event.event = EVENT_IRLAN_START;
- strcpy(mgr_event.devname, self->dev.name);
- irmanager_notify(&mgr_event);
-
- /*
- * We set this so that we only notify once, since if
- * configuration of the network device fails, the user
- * will have to sort it out first anyway. No need to
- * try again.
- */
- self->notify_irmanager = FALSE;
+
+ if (self->disconnect_reason == LM_USER_REQUEST) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), still stopped by user\n");
+ return;
}
- /* Restart watchdog timer */
- irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
+
+ /* Open TSAPs */
+ irlan_client_open_ctrl_tsap(self);
+ irlan_open_data_tsap(self);
+
+ irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
/* Start kick timer */
irlan_client_start_kick_timer(self, 2*HZ);
@@ -163,7 +144,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
* Remote device with IrLAN server support discovered
*
*/
-void irlan_client_discovery_indication(discovery_t *discovery)
+void irlan_client_discovery_indication(discovery_t *discovery, void *priv)
{
struct irlan_cb *self;
__u32 saddr, daddr;
@@ -176,29 +157,16 @@ void irlan_client_discovery_indication(discovery_t *discovery)
saddr = discovery->saddr;
daddr = discovery->daddr;
- /*
- * Check if we already dealing with this provider.
- */
- self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
- if (self) {
+ /* Find instance */
+ self = (struct irlan_cb *) hashbin_get_first(irlan);
+ if (self) {
ASSERT(self->magic == IRLAN_MAGIC, return;);
IRDA_DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
daddr);
irlan_client_wakeup(self, saddr, daddr);
-
- return;
}
-
- /*
- * We have no instance for daddr, so start a new one
- */
- IRDA_DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
- self = irlan_open(saddr, daddr, TRUE);
-
- /* Restart watchdog timer */
- irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
}
/*
@@ -449,9 +417,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
- /*
- * Media type
- */
+ /* Media type */
if (strcmp(param, "MEDIA") == 0) {
if (strcmp(value, "802.3") == 0)
self->media = MEDIA_802_3;
@@ -487,9 +453,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
IRDA_DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
}
}
- /*
- * IRLAN version
- */
+ /* IRLAN version */
if (strcmp(param, "IRLAN_VER") == 0) {
IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
(__u8) value[1]);
@@ -498,9 +462,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
self->version[1] = value[1];
return;
}
- /*
- * Which remote TSAP to use for data channel
- */
+ /* Which remote TSAP to use for data channel */
if (strcmp(param, "DATA_CHAN") == 0) {
self->dtsap_sel_data = value[0];
IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
@@ -521,9 +483,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
self->client.max_frame);
}
- /*
- * RECONNECT_KEY, in case the link goes down!
- */
+ /* RECONNECT_KEY, in case the link goes down! */
if (strcmp(param, "RECONNECT_KEY") == 0) {
IRDA_DEBUG(4, "Got reconnect key: ");
/* for (i = 0; i < val_len; i++) */
@@ -532,9 +492,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
self->client.key_len = val_len;
IRDA_DEBUG(4, "\n");
}
- /*
- * FILTER_ENTRY, have we got an ethernet address?
- */
+ /* FILTER_ENTRY, have we got an ethernet address? */
if (strcmp(param, "FILTER_ENTRY") == 0) {
bytes = value;
IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 5975909fe..686c163dc 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -50,6 +50,14 @@
#include <net/irda/irlan_eth.h>
#include <net/irda/irlan_filter.h>
+
+/*
+ * Send gratuitous ARP when connected to a new AP or not. May be a clever
+ * thing to do, but for some reason the machine crashes if you use DHCP. So
+ * lets not use it by default.
+ */
+#undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
+
/* extern char sysctl_devname[]; */
/*
@@ -62,6 +70,7 @@ static __u32 ckey, skey;
static int eth = 0; /* Use "eth" or "irlan" name for devices */
static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
+#ifdef CONFIG_PROC_FS
static char *irlan_state[] = {
"IRLAN_IDLE",
"IRLAN_QUERY",
@@ -88,6 +97,7 @@ static char *irlan_media[] = {
"802.3",
"802.5"
};
+#endif /* CONFIG_PROC_FS */
static void __irlan_close(struct irlan_cb *self);
static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
@@ -102,59 +112,6 @@ extern struct proc_dir_entry *proc_irda;
#endif /* CONFIG_PROC_FS */
/*
- * Function irlan_watchdog_timer_expired (data)
- *
- * Something has gone wrong during the connection establishment
- *
- */
-void irlan_watchdog_timer_expired(void *data)
-{
- struct irmanager_event mgr_event;
- struct irlan_cb *self;
-
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
- self = (struct irlan_cb *) data;
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Check if device still configured */
- if (netif_running(&self->dev)) {
- IRDA_DEBUG(0, __FUNCTION__
- "(), notifying irmanager to stop irlan!\n");
- mgr_event.event = EVENT_IRLAN_STOP;
- sprintf(mgr_event.devname, "%s", self->dev.name);
- irmanager_notify(&mgr_event);
-
- /*
- * We set this to false, so that irlan_dev_close known that
- * notify_irmanager should actually be set to TRUE again
- * instead of FALSE, since this close has not been initiated
- * by the user.
- */
- self->notify_irmanager = FALSE;
- } else {
- IRDA_DEBUG(0, __FUNCTION__ "(), closing instance!\n");
- /*irlan_close(self);*/
- }
-}
-
-/*
- * Function irlan_start_watchdog_timer (self, timeout)
- *
- *
- *
- */
-void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
-{
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
- irlan_watchdog_timer_expired);
-}
-
-/*
* Function irlan_init (void)
*
* Initialize IrLAN layer
@@ -165,8 +122,7 @@ int __init irlan_init(void)
struct irlan_cb *new;
__u16 hints;
- IRDA_DEBUG(4, __FUNCTION__"()\n");
-
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
/* Allocate master structure */
irlan = hashbin_new(HB_LOCAL);
if (irlan == NULL) {
@@ -178,22 +134,20 @@ int __init irlan_init(void)
#endif /* CONFIG_PROC_FS */
IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
hints = irlmp_service_to_hint(S_LAN);
/* Register with IrLMP as a client */
- ckey = irlmp_register_client(hints, irlan_client_discovery_indication,
- NULL);
+ ckey = irlmp_register_client(hints, &irlan_client_discovery_indication,
+ NULL, NULL);
/* Register with IrLMP as a service */
skey = irlmp_register_service(hints);
- /* Start the master IrLAN instance */
- new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
+ /* Start the master IrLAN instance (the only one for now) */
+ new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
/* The master will only open its (listen) control TSAP */
irlan_provider_open_ctrl_tsap(new);
- new->master = TRUE;
/* Do some fast discovery! */
irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
@@ -206,7 +160,6 @@ void irlan_cleanup(void)
IRDA_DEBUG(4, __FUNCTION__ "()\n");
irlmp_unregister_client(ckey);
-
irlmp_unregister_service(skey);
#ifdef CONFIG_PROC_FS
@@ -242,8 +195,6 @@ int irlan_register_netdev(struct irlan_cb *self)
IRDA_DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n");
return -1;
}
- self->netdev_registered = TRUE;
-
return 0;
}
@@ -253,7 +204,7 @@ int irlan_register_netdev(struct irlan_cb *self)
* Open new instance of a client/provider, we should only register the
* network device if this instance is ment for a particular client/provider
*/
-struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
+struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
{
struct irlan_cb *self;
@@ -287,32 +238,28 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
/* Provider access can only be PEER, DIRECT, or HOSTED */
self->provider.access_type = access;
self->media = MEDIA_802_3;
-
- self->notify_irmanager = TRUE;
-
+ self->disconnect_reason = LM_USER_REQUEST;
init_timer(&self->watchdog_timer);
init_timer(&self->client.kick_timer);
+ init_waitqueue_head(&self->open_wait);
- hashbin_insert(irlan, (queue_t *) self, daddr, NULL);
+ hashbin_insert(irlan, (irda_queue_t *) self, daddr, NULL);
skb_queue_head_init(&self->client.txq);
irlan_next_client_state(self, IRLAN_IDLE);
irlan_next_provider_state(self, IRLAN_IDLE);
- /* Register network device now, or wait until some later time? */
- if (netdev)
- irlan_register_netdev(self);
+ irlan_register_netdev(self);
return self;
}
/*
- * Function irlan_close (self)
+ * Function __irlan_close (self)
*
* This function closes and deallocates the IrLAN client instances. Be
* aware that other functions which calles client_close() must call
* hashbin_remove() first!!!
- *
*/
static void __irlan_close(struct irlan_cb *self)
{
@@ -333,49 +280,13 @@ static void __irlan_close(struct irlan_cb *self)
iriap_close(self->client.iriap);
/* Remove frames queued on the control channel */
- while ((skb = skb_dequeue(&self->client.txq))) {
+ while ((skb = skb_dequeue(&self->client.txq)))
dev_kfree_skb(skb);
- }
- if (self->netdev_registered) {
- unregister_netdev(&self->dev);
- self->netdev_registered = FALSE;
- }
+ unregister_netdev(&self->dev);
self->magic = 0;
- kfree(self);
-}
-
-/*
- * Function irlan_close (self)
- *
- * Close instance
- *
- */
-void irlan_close(struct irlan_cb *self)
-{
- struct irlan_cb *entry;
-
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRLAN_MAGIC, return;);
-
- /* Check if device is still configured */
- if (netif_running(&self->dev)) {
- IRDA_DEBUG(0, __FUNCTION__
- "(), Device still configured, closing later!\n");
-
- /* Give it a chance to reconnect */
- irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
- return;
- }
- IRDA_DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
- entry = hashbin_remove(irlan, self->daddr, NULL);
-
- ASSERT(entry == self, return;);
-
- __irlan_close(self);
+ kfree(self);
}
/*
@@ -419,7 +330,7 @@ void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
irlan_open_unicast_addr(self);
}
/* Ready to transfer Ethernet frames (at last) */
- netif_start_queue(&self->dev);
+ netif_start_queue(&self->dev); /* Clear reason */
}
void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
@@ -454,7 +365,11 @@ void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
/* Ready to transfer Ethernet frames */
netif_start_queue(&self->dev);
+ self->disconnect_reason = 0; /* Clear reason */
+#ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
irlan_eth_send_gratuitous_arp(&self->dev);
+#endif
+ wake_up_interruptible(&self->open_wait);
}
/*
@@ -483,28 +398,34 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason,
IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
- switch(reason) {
+ /* Save reason so we know if we should try to reconnect or not */
+ self->disconnect_reason = reason;
+
+ switch (reason) {
case LM_USER_REQUEST: /* User request */
- irlan_close(self);
+ IRDA_DEBUG(2, __FUNCTION__ "(), User requested\n");
break;
case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
- irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unexpected IrLAP disconnect\n");
break;
case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
- IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP connect failed\n");
break;
case LM_LAP_RESET: /* IrLAP reset */
- IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP reset\n");
break;
case LM_INIT_DISCONNECT:
- IRDA_DEBUG(2, __FUNCTION__ "(), LM_CONNECT_FAILURE not impl\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), IrLMP connect failed\n");
break;
default:
+ ERROR(__FUNCTION__ "(), Unknown disconnect reason\n");
break;
}
irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
+
+ wake_up_interruptible(&self->open_wait);
}
void irlan_open_data_tsap(struct irlan_cb *self)
@@ -553,9 +474,7 @@ void irlan_close_tsaps(struct irlan_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
- /*
- * Disconnect and close all open TSAP connections
- */
+ /* Disconnect and close all open TSAP connections */
if (self->tsap_data) {
irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
irttp_close_tsap(self->tsap_data);
@@ -573,6 +492,7 @@ void irlan_close_tsaps(struct irlan_cb *self)
irttp_close_tsap(self->provider.tsap_ctrl);
self->provider.tsap_ctrl = NULL;
}
+ self->disconnect_reason = LM_USER_REQUEST;
}
/*
@@ -595,7 +515,8 @@ void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
*/
if (!irias_find_object("IrLAN")) {
obj = irias_new_object("IrLAN", IAS_IRLAN_ID);
- irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel);
+ irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel,
+ IAS_KERNEL_ATTR);
irias_insert_object(obj);
} else {
new_value = irias_new_integer_value(tsap_sel);
@@ -607,18 +528,23 @@ void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
if (!irias_find_object("PnP")) {
obj = irias_new_object("PnP", IAS_PNP_ID);
#if 0
- irias_add_string_attrib(obj, "Name", sysctl_devname);
+ irias_add_string_attrib(obj, "Name", sysctl_devname,
+ IAS_KERNEL_ATTR);
#else
- irias_add_string_attrib(obj, "Name", "Linux");
+ irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR);
#endif
- irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
- irias_add_integer_attrib(obj, "CompCnt", 1);
+ irias_add_string_attrib(obj, "DeviceID", "HWP19F0",
+ IAS_KERNEL_ATTR);
+ irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR);
if (self->provider.access_type == ACCESS_PEER)
- irias_add_string_attrib(obj, "Comp#01", "PNP8389");
+ irias_add_string_attrib(obj, "Comp#01", "PNP8389",
+ IAS_KERNEL_ATTR);
else
- irias_add_string_attrib(obj, "Comp#01", "PNP8294");
+ irias_add_string_attrib(obj, "Comp#01", "PNP8294",
+ IAS_KERNEL_ATTR);
- irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
+ irias_add_string_attrib(obj, "Manufacturer",
+ "Linux-IrDA Project", IAS_KERNEL_ATTR);
irias_insert_object(obj);
}
}
@@ -633,7 +559,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
{
struct sk_buff *skb;
- IRDA_DEBUG(3, __FUNCTION__ "()\n");
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
if (irda_lock(&self->client.tx_busy) == FALSE)
return -EBUSY;
@@ -652,7 +578,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
dev_kfree_skb(skb);
return -1;
}
- IRDA_DEBUG(3, __FUNCTION__ "(), sending ...\n");
+ IRDA_DEBUG(2, __FUNCTION__ "(), sending ...\n");
return irttp_data_request(self->client.tsap_ctrl, skb);
}
@@ -741,7 +667,6 @@ void irlan_open_data_channel(struct irlan_cb *self)
/* self->use_udata = TRUE; */
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -810,7 +735,6 @@ void irlan_open_unicast_addr(struct irlan_cb *self)
irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -852,7 +776,6 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
else
irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -892,7 +815,6 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status)
else
irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -930,7 +852,6 @@ void irlan_get_unicast_addr(struct irlan_cb *self)
irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC");
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -965,8 +886,6 @@ void irlan_get_media_char(struct irlan_cb *self)
frame[1] = 0x01; /* One parameter */
irlan_insert_string_param(skb, "MEDIA", "802.3");
-
- /* irttp_data_request(self->client.tsap_ctrl, skb); */
irlan_ctrl_data_request(self, skb);
}
@@ -1169,35 +1088,32 @@ static int irlan_proc_read(char *buf, char **start, off_t offset, int len)
while (self != NULL) {
ASSERT(self->magic == IRLAN_MAGIC, return len;);
- /* Don't display the master server */
- if (self->master == 0) {
- len += sprintf(buf+len, "ifname: %s,\n",
- self->dev.name);
- len += sprintf(buf+len, "client state: %s, ",
- irlan_state[ self->client.state]);
- len += sprintf(buf+len, "provider state: %s,\n",
- irlan_state[ self->provider.state]);
- len += sprintf(buf+len, "saddr: %#08x, ",
- self->saddr);
- len += sprintf(buf+len, "daddr: %#08x\n",
- self->daddr);
- len += sprintf(buf+len, "version: %d.%d,\n",
- self->version[1], self->version[0]);
- len += sprintf(buf+len, "access type: %s\n",
- irlan_access[self->client.access_type]);
- len += sprintf(buf+len, "media: %s\n",
- irlan_media[self->media]);
-
- len += sprintf(buf+len, "local filter:\n");
- len += sprintf(buf+len, "remote filter: ");
- len += irlan_print_filter(self->client.filter_type,
- buf+len);
+ len += sprintf(buf+len, "ifname: %s,\n",
+ self->dev.name);
+ len += sprintf(buf+len, "client state: %s, ",
+ irlan_state[ self->client.state]);
+ len += sprintf(buf+len, "provider state: %s,\n",
+ irlan_state[ self->provider.state]);
+ len += sprintf(buf+len, "saddr: %#08x, ",
+ self->saddr);
+ len += sprintf(buf+len, "daddr: %#08x\n",
+ self->daddr);
+ len += sprintf(buf+len, "version: %d.%d,\n",
+ self->version[1], self->version[0]);
+ len += sprintf(buf+len, "access type: %s\n",
+ irlan_access[self->client.access_type]);
+ len += sprintf(buf+len, "media: %s\n",
+ irlan_media[self->media]);
+
+ len += sprintf(buf+len, "local filter:\n");
+ len += sprintf(buf+len, "remote filter: ");
+ len += irlan_print_filter(self->client.filter_type,
+ buf+len);
- len += sprintf(buf+len, "tx busy: %s\n",
- netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE");
+ len += sprintf(buf+len, "tx busy: %s\n",
+ netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE");
- len += sprintf(buf+len, "\n");
- }
+ len += sprintf(buf+len, "\n");
self = (struct irlan_cb *) hashbin_get_next(irlan);
}
@@ -1272,8 +1188,9 @@ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
MODULE_PARM(eth, "i");
+MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)");
MODULE_PARM(access, "i");
-MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3");
/*
* Function init_module (void)
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 1b46ab5b8..007c4acfd 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -48,7 +48,6 @@
*/
int irlan_eth_init(struct net_device *dev)
{
- struct irmanager_event mgr_event;
struct irlan_cb *self;
IRDA_DEBUG(2, __FUNCTION__"()\n");
@@ -85,22 +84,6 @@ int irlan_eth_init(struct net_device *dev)
get_random_bytes(dev->dev_addr+5, 1);
}
- /*
- * Network device has now been registered, so tell irmanager about
- * it, so it can be configured with network parameters
- */
- mgr_event.event = EVENT_IRLAN_START;
- sprintf(mgr_event.devname, "%s", self->dev.name);
- irmanager_notify(&mgr_event);
-
- /*
- * We set this so that we only notify once, since if
- * configuration of the network device fails, the user
- * will have to sort it out first anyway. No need to
- * try again.
- */
- self->notify_irmanager = FALSE;
-
return 0;
}
@@ -123,14 +106,16 @@ int irlan_eth_open(struct net_device *dev)
ASSERT(self != NULL, return -1;);
/* Ready to play! */
-/* netif_start_queue(dev) */ /* Wait until data link is ready */
-
- self->notify_irmanager = TRUE;
+ netif_stop_queue(dev); /* Wait until data link is ready */
/* We are now open, so time to do some work */
+ self->disconnect_reason = 0;
irlan_client_wakeup(self, self->saddr, self->daddr);
irlan_mod_inc_use_count();
+
+ /* Make sure we have a hardware address before we return, so DHCP clients gets happy */
+ interruptible_sleep_on(&self->open_wait);
return 0;
}
@@ -146,7 +131,8 @@ int irlan_eth_open(struct net_device *dev)
int irlan_eth_close(struct net_device *dev)
{
struct irlan_cb *self = (struct irlan_cb *) dev->priv;
-
+ struct sk_buff *skb;
+
IRDA_DEBUG(2, __FUNCTION__ "()\n");
/* Stop device */
@@ -155,20 +141,17 @@ int irlan_eth_close(struct net_device *dev)
irlan_mod_dec_use_count();
irlan_close_data_channel(self);
-
irlan_close_tsaps(self);
irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
- irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
-
- /* Device closed by user! */
- if (self->notify_irmanager)
- self->notify_irmanager = FALSE;
- else
- self->notify_irmanager = TRUE;
+ /* Remove frames queued on the control channel */
+ while ((skb = skb_dequeue(&self->client.txq)))
+ dev_kfree_skb(skb);
+ self->client.tx_busy = 0;
+
return 0;
}
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
index aeac03f7b..e06807bd9 100644
--- a/net/irda/irlan/irlan_provider.c
+++ b/net/irda/irlan/irlan_provider.c
@@ -116,16 +116,16 @@ static int irlan_provider_data_indication(void *instance, void *sap,
/*
* Function irlan_provider_connect_indication (handle, skb, priv)
*
- * Got connection from peer IrLAN layer
+ * Got connection from peer IrLAN client
*
*/
static void irlan_provider_connect_indication(void *instance, void *sap,
struct qos_info *qos,
__u32 max_sdu_size,
__u8 max_header_size,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
- struct irlan_cb *self, *new;
+ struct irlan_cb *self;
struct tsap_cb *tsap;
__u32 saddr, daddr;
@@ -137,82 +137,24 @@ static void irlan_provider_connect_indication(void *instance, void *sap,
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
- self->provider.max_sdu_size = max_sdu_size;
- self->provider.max_header_size = max_header_size;
-
ASSERT(tsap == self->provider.tsap_ctrl,return;);
ASSERT(self->provider.state == IRLAN_IDLE, return;);
daddr = irttp_get_daddr(tsap);
saddr = irttp_get_saddr(tsap);
+ self->provider.max_sdu_size = max_sdu_size;
+ self->provider.max_header_size = max_header_size;
- /* Check if we already dealing with this client or peer */
- new = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
- if (new) {
- ASSERT(new->magic == IRLAN_MAGIC, return;);
- IRDA_DEBUG(0, __FUNCTION__ "(), found instance!\n");
-
- /* Update saddr, since client may have moved to a new link */
- new->saddr = saddr;
- IRDA_DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", new->saddr);
-
- /* Make sure that any old provider control TSAP is removed */
- if ((new != self) && new->provider.tsap_ctrl) {
- irttp_disconnect_request(new->provider.tsap_ctrl,
- NULL, P_NORMAL);
- irttp_close_tsap(new->provider.tsap_ctrl);
- new->provider.tsap_ctrl = NULL;
- }
- } else {
- /* This must be the master instance, so start a new instance */
- IRDA_DEBUG(0, __FUNCTION__ "(), starting new provider!\n");
-
- new = irlan_open(saddr, daddr, TRUE);
- }
-
- /*
- * Check if the connection came in on the master server, or the
- * slave server. If it came on the slave, then everything is
- * really, OK (reconnect), if not we need to dup the connection and
- * hand it over to the slave.
- */
- if (new != self) {
-
- /* Now attach up the new "socket" */
- new->provider.tsap_ctrl = irttp_dup(self->provider.tsap_ctrl,
- new);
- if (!new->provider.tsap_ctrl) {
- IRDA_DEBUG(0, __FUNCTION__ "(), dup failed!\n");
- return;
- }
-
- /* new->stsap_sel = new->tsap->stsap_sel; */
- new->dtsap_sel_ctrl = new->provider.tsap_ctrl->dtsap_sel;
-
- /* Clean up the original one to keep it in listen state */
- self->provider.tsap_ctrl->dtsap_sel = LSAP_ANY;
- self->provider.tsap_ctrl->lsap->dlsap_sel = LSAP_ANY;
- self->provider.tsap_ctrl->lsap->lsap_state = LSAP_DISCONNECTED;
-
- /*
- * Use the new instance from here instead of the master
- * struct!
- */
- self = new;
- }
- /* Check if network device has been registered */
- if (!self->netdev_registered)
- irlan_register_netdev(self);
-
irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL);
/*
* If we are in peer mode, the client may not have got the discovery
* indication it needs to make progress. If the client is still in
- * IDLE state, we must kick it to
+ * IDLE state, we must kick it.
*/
if ((self->provider.access_type == ACCESS_PEER) &&
- (self->client.state == IRLAN_IDLE)) {
+ (self->client.state == IRLAN_IDLE))
+ {
irlan_client_wakeup(self, self->saddr, self->daddr);
}
}
@@ -231,11 +173,6 @@ void irlan_provider_connect_response(struct irlan_cb *self,
/* Just accept */
irttp_connect_response(tsap, IRLAN_MTU, NULL);
-
- /* Check if network device has been registered */
- if (!self->netdev_registered)
- irlan_register_netdev(self);
-
}
void irlan_provider_disconnect_indication(void *instance, void *sap,
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 1c2958c4b..38d66d327 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -154,7 +154,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos)
irlap_next_state(self, LAP_NDM);
- hashbin_insert(irlap, (queue_t *) self, self->saddr, NULL);
+ hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL);
irlmp_register_link(self, self->saddr, &self->notify);
@@ -232,7 +232,8 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
ASSERT(self->magic == LAP_MAGIC, return;);
irlap_init_qos_capabilities(self, NULL); /* No user QoS! */
-
+
+ skb_get(skb); /*LEVEL4*/
irlmp_link_connect_indication(self->notify.instance, self->saddr,
self->daddr, &self->qos_tx, skb);
}
@@ -248,6 +249,7 @@ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb)
IRDA_DEBUG(4, __FUNCTION__ "()\n");
irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
+ kfree_skb(skb);
}
/*
@@ -292,6 +294,7 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
ASSERT(self != NULL, return;);
ASSERT(self->magic == LAP_MAGIC, return;);
+ skb_get(skb); /*LEVEL4*/
irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
}
@@ -310,6 +313,7 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
#ifdef CONFIG_IRDA_COMPRESSION
if (self->qos_tx.compression.value) {
+ skb_get(skb); /*LEVEL4*/
skb = irlap_decompress_frame(self, skb);
if (!skb) {
IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
@@ -317,6 +321,7 @@ void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb,
}
}
#endif
+ skb_get(skb); /*LEVEL4*/
irlmp_link_data_indication(self->notify.instance, skb, unreliable);
}
@@ -373,6 +378,7 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
ASSERT(skb != NULL, return;);
}
irlap_do_event(self, SEND_I_CMD, skb, NULL);
+ kfree_skb(skb);
} else
skb_queue_tail(&self->txq, skb);
}
@@ -422,6 +428,7 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
/* Hide LAP header from IrLMP layer */
skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+ skb_get(skb); /*LEVEL4*/
irlmp_link_unitdata_indication(self->notify.instance, skb);
}
#endif /* CONFIG_IRDA_ULTRA */
@@ -610,7 +617,7 @@ void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
*
*
*/
-void irlap_status_indication(int quality_of_link)
+void irlap_status_indication(struct irlap_cb *self, int quality_of_link)
{
switch (quality_of_link) {
case STATUS_NO_ACTIVITY:
@@ -622,7 +629,8 @@ void irlap_status_indication(int quality_of_link)
default:
break;
}
- irlmp_status_indication(quality_of_link, LOCK_NO_CHANGE);
+ irlmp_status_indication(self->notify.instance,
+ quality_of_link, LOCK_NO_CHANGE);
}
/*
@@ -664,11 +672,16 @@ void irlap_reset_confirm(void)
*/
int irlap_generate_rand_time_slot(int S, int s)
{
+ static int rand;
int slot;
ASSERT((S - s) > 0, return 0;);
- slot = s + jiffies % (S-s);
+ rand += jiffies;
+ rand ^= (rand << 12);
+ rand ^= (rand >> 20);
+
+ slot = s + rand % (S-s);
ASSERT((slot >= s) || (slot < S), return 0;);
@@ -863,6 +876,8 @@ void irlap_flush_all_queues(struct irlap_cb *self)
*/
void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now)
{
+ struct sk_buff *skb;
+
IRDA_DEBUG(0, __FUNCTION__ "(), setting speed to %d\n", speed);
ASSERT(self != NULL, return;);
@@ -871,8 +886,11 @@ void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now)
self->speed = speed;
/* Change speed now, or just piggyback speed on frames */
- if (now)
- irda_device_change_speed(self->netdev, speed);
+ if (now) {
+ /* Send down empty frame to trigger speed change */
+ skb = dev_alloc_skb(0);
+ irlap_queue_xmit(self, skb);
+ }
}
#ifdef CONFIG_IRDA_COMPRESSION
@@ -973,8 +991,8 @@ void irlap_init_qos_capabilities(struct irlap_cb *self,
/* Set data size */
/*self->qos_rx.data_size.bits &= 0x03;*/
- /* Set disconnect time */
- self->qos_rx.link_disc_time.bits &= 0x07;
+ /* Set disconnect time -> done properly in qos.c */
+ /*self->qos_rx.link_disc_time.bits &= 0x07;*/
irda_qos_bits_to_value(&self->qos_rx);
}
@@ -998,7 +1016,7 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self)
irda_device_set_media_busy(self->netdev, TRUE);
/* Default value in NDM */
- self->bofs_count = 11;
+ self->bofs_count = 12;
/*
* Generate random connection address for this session, which must
@@ -1026,8 +1044,8 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self)
self->qos_rx.data_size.value = 64;
self->qos_tx.window_size.value = 1;
self->qos_rx.window_size.value = 1;
- self->qos_tx.additional_bofs.value = 11;
- self->qos_rx.additional_bofs.value = 11;
+ self->qos_tx.additional_bofs.value = 12;
+ self->qos_rx.additional_bofs.value = 12;
self->qos_tx.link_disc_time.value = 0;
self->qos_rx.link_disc_time.value = 0;
@@ -1071,7 +1089,12 @@ void irlap_apply_connection_parameters(struct irlap_cb *self)
*/
ASSERT(self->qos_tx.max_turn_time.value != 0, return;);
if (self->qos_tx.link_disc_time.value == 3)
- self->N1 = 0;
+ /*
+ * If we set N1 to 0, it will trigger immediately, which is
+ * not what we want. What we really want is to disable it,
+ * Jean II
+ */
+ self->N1 = -1; /* Disable */
else
self->N1 = 3000 / self->qos_tx.max_turn_time.value;
diff --git a/net/irda/irlap_comp.c b/net/irda/irlap_comp.c
index 942949ac8..e81fc7e4a 100644
--- a/net/irda/irlap_comp.c
+++ b/net/irda/irlap_comp.c
@@ -63,7 +63,7 @@ int irda_register_compressor( struct compressor *cp)
new->cp = cp;
/* Insert IrDA compressor into hashbin */
- hashbin_insert( irlap_compressors, (queue_t *) new, cp->compress_proto,
+ hashbin_insert( irlap_compressors, (irda_queue_t *) new, cp->compress_proto,
NULL);
return 0;
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 08501162e..ec5f6611c 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -9,8 +9,8 @@
* Modified at: Sat Dec 25 21:07:57 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
- * Thomas Davis <ratbert@radiks.net>
+ * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>,
+ * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net>
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -230,7 +230,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
if (!self || self->magic != LAP_MAGIC)
return;
-
+
IRDA_DEBUG(3, __FUNCTION__ "(), event = %s, state = %s\n",
irlap_event[event], irlap_state[self->state]);
@@ -252,6 +252,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
while ((skb = skb_dequeue(&self->txq)) != NULL) {
ret = (*state[self->state])(self, SEND_I_CMD,
skb, NULL);
+ kfree_skb(skb);
if (ret == -EPROTO)
break; /* Try again later! */
}
@@ -304,6 +305,17 @@ void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state)
if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
self->bytes_left = self->line_capacity;
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
+#ifdef CONFIG_IRDA_ULTRA
+ /* Send any pending Ultra frames if any */
+ /* The higher layers may have sent a few Ultra frames while we
+ * were doing discovery (either query or reply). Those frames
+ * have been queued, but were never sent. It is now time to
+ * send them...
+ * Jean II */
+ if ((state == LAP_NDM) && (!skb_queue_empty(&self->txq_ultra)))
+ /* Force us to listen 500 ms before sending Ultra */
+ irda_device_set_media_busy(self->netdev, TRUE);
+#endif /* CONFIG_IRDA_ULTRA */
}
/*
@@ -351,12 +363,11 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
self->caddr = info->caddr;
irlap_next_state(self, LAP_CONN);
-
+
irlap_connect_indication(self, skb);
} else {
IRDA_DEBUG(0, __FUNCTION__ "(), SNRM frame does not "
"contain an I field!\n");
- dev_kfree_skb(skb);
}
break;
case DISCOVERY_REQUEST:
@@ -375,6 +386,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
self->s = info->s;
irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE,
info->discovery);
+ self->frame_sent = FALSE;
self->s++;
irlap_start_slot_timer(self, self->slot_timeout);
@@ -385,12 +397,8 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
/* Assert that this is not the final slot */
if (info->s <= info->S) {
- /* self->daddr = info->daddr; */
self->slot = irlap_generate_rand_time_slot(info->S,
info->s);
- IRDA_DEBUG(4, "XID_CMD: S=%d, s=%d, slot %d\n", info->S,
- info->s, self->slot);
-
if (self->slot == info->s) {
discovery_rsp = irlmp_get_discovery_response();
discovery_rsp->daddr = info->daddr;
@@ -410,14 +418,34 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_query_timer(self, QUERY_TIMEOUT*info->S);
irlap_next_state(self, LAP_REPLY);
}
- dev_kfree_skb(skb);
+ else {
+ /* This is the final slot. How is it possible ?
+ * This would happen is both discoveries are just slightly
+ * offset (if they are in sync, all packets are lost).
+ * Most often, all the discovery requests will be received
+ * in QUERY state (see my comment there), except for the
+ * last frame that will come here.
+ * The big trouble when it happen is that active discovery
+ * doesn't happen, because nobody answer the discoveries
+ * frame of the other guy, so the log shows up empty.
+ * What should we do ?
+ * Not much. It's too late to answer those discovery frames,
+ * so we just pass the info to IrLMP who will put it in the
+ * log (and post an event).
+ * Jean II
+ */
+ IRDA_DEBUG(1, __FUNCTION__ "(), Receiving final discovery request, missed the discovery slots :-(\n");
+
+ /* Last discovery request -> in the log */
+ irlap_discovery_indication(self, info->discovery);
+ }
break;
#ifdef CONFIG_IRDA_ULTRA
case SEND_UI_FRAME:
/* Only allowed to repeat an operation twice */
for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) {
skb = skb_dequeue(&self->txq_ultra);
- if (skb)
+ if (skb)
irlap_send_ui_frame(self, skb, CBROADCAST,
CMD_FRAME);
else
@@ -433,7 +461,6 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
if (info->caddr != CBROADCAST) {
IRDA_DEBUG(0, __FUNCTION__
"(), not a broadcast frame!\n");
- dev_kfree_skb(skb);
} else
irlap_unitdata_indication(self, skb);
break;
@@ -447,19 +474,14 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
* will only be used to send out the same info as the cmd
*/
irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
- dev_kfree_skb(skb);
break;
case RECV_TEST_RSP:
IRDA_DEBUG(0, __FUNCTION__ "() not implemented!\n");
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -1;
break;
}
@@ -492,19 +514,51 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
WARNING(__FUNCTION__ "(), discovery log is gone! "
"maybe the discovery timeout has been set to "
"short?\n");
- dev_kfree_skb(skb);
break;
}
hashbin_insert(self->discovery_log,
- (queue_t *) info->discovery,
+ (irda_queue_t *) info->discovery,
info->discovery->daddr, NULL);
/* Keep state */
/* irlap_next_state(self, LAP_QUERY); */
- dev_kfree_skb(skb);
+ break;
+ case RECV_DISCOVERY_XID_CMD:
+ /* Yes, it is possible to receive those frames in this mode.
+ * Note that most often the last discovery request won't
+ * occur here but in NDM state (see my comment there).
+ * What should we do ?
+ * Not much. We are currently performing our own discovery,
+ * therefore we can't answer those frames. We don't want
+ * to change state either. We just pass the info to
+ * IrLMP who will put it in the log (and post an event).
+ * Jean II
+ */
+
+ ASSERT(info != NULL, return -1;);
+
+ IRDA_DEBUG(1, __FUNCTION__ "(), Receiving discovery request (s = %d) while performing discovery :-(\n", info->s);
+
+ /* Last discovery request ? */
+ if (info->s == 0xff)
+ irlap_discovery_indication(self, info->discovery);
break;
case SLOT_TIMER_EXPIRED:
+ /*
+ * Wait a little longer if we detect an incomming frame. This
+ * is not mentioned in the spec, but is a good thing to do,
+ * since we want to work even with devices that violate the
+ * timing requirements.
+ */
+ if (irda_device_is_receiving(self->netdev)) {
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), device is slow to answer, "
+ "waiting some more!\n");
+ irlap_start_slot_timer(self, MSECS_TO_JIFFIES(10));
+ return ret;
+ }
+
if (self->s < self->S) {
irlap_send_discovery_xid_frame(self, self->S,
self->s, TRUE,
@@ -537,9 +591,6 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -1;
break;
}
@@ -572,9 +623,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
break;
case RECV_DISCOVERY_XID_CMD:
ASSERT(info != NULL, return -1;);
- /*
- * Last frame?
- */
+ /* Last frame? */
if (info->s == 0xff) {
del_timer(&self->query_timer);
@@ -595,15 +644,11 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
self->frame_sent = TRUE;
irlap_next_state(self, LAP_REPLY);
}
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -1;
break;
}
@@ -665,14 +710,12 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NRM_S);
- dev_kfree_skb(skb);
break;
case RECV_DISCOVERY_XID_CMD:
IRDA_DEBUG(3, __FUNCTION__
"(), event RECV_DISCOVER_XID_CMD!\n");
irlap_next_state(self, LAP_NDM);
- dev_kfree_skb(skb);
break;
case DISCONNECT_REQUEST:
irlap_send_dm_frame(self);
@@ -682,9 +725,6 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -1;
break;
}
@@ -766,7 +806,6 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
} else {
/* We just ignore the other device! */
- dev_kfree_skb(skb);
irlap_next_state(self, LAP_SETUP);
}
break;
@@ -803,14 +842,11 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, %s\n", event,
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
+
ret = -1;
break;
}
@@ -860,14 +896,13 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(4, __FUNCTION__
"(), Not allowed to transmit more "
"bytes!\n");
- skb_queue_head(&self->txq, skb);
-
+ skb_queue_head(&self->txq, skb_get(skb));
/*
* We should switch state to LAP_NRM_P, but
* that is not possible since we must be sure
* that we poll the other side. Since we have
* used up our time, the poll timer should
- * trigger anyway now,so we just wait for it
+ * trigger anyway now, so we just wait for it
* DB
*/
return -EPROTO;
@@ -900,7 +935,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
} else {
IRDA_DEBUG(4, __FUNCTION__
"(), Unable to send! remote busy?\n");
- skb_queue_head(&self->txq, skb);
+ skb_queue_head(&self->txq, skb_get(skb));
/*
* The next ret is important, because it tells
@@ -929,9 +964,6 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -EINVAL;
break;
}
@@ -964,7 +996,6 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state(self, LAP_NDM);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
if (self->retry_count < self->N3) {
@@ -985,9 +1016,6 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d\n", event);
- if (skb)
- dev_kfree_skb(skb);
-
ret = -1;
break;
}
@@ -1041,7 +1069,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_P);
-
+
irlap_data_indication(self, skb, FALSE);
} else {
del_timer(&self->final_timer);
@@ -1065,7 +1093,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
* upper layers
*/
irlap_next_state(self, LAP_XMIT_P);
-
+
irlap_data_indication(self, skb, FALSE);
/* This is the last frame */
@@ -1102,7 +1130,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_final_timer(self, self->final_timeout);
irlap_next_state(self, LAP_NRM_P);
}
- dev_kfree_skb(skb);
break;
}
/*
@@ -1124,7 +1151,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_P);
-
+
irlap_data_indication(self, skb, FALSE);
} else {
/*
@@ -1142,7 +1169,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line!*/
irlap_next_state(self, LAP_NRM_P);
-
+
irlap_data_indication(self, skb, FALSE);
}
break;
@@ -1171,7 +1198,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->ack_required = FALSE;
}
- dev_kfree_skb(skb);
break;
}
@@ -1193,7 +1219,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
self->xmitflag = FALSE;
}
- dev_kfree_skb(skb);
break;
}
IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
@@ -1209,6 +1234,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
} else {
del_timer(&self->final_timer);
irlap_data_indication(self, skb, TRUE);
+ printk(__FUNCTION__ "(): RECV_UI_FRAME: next state %s\n", irlap_state[self->state]);
irlap_start_poll_timer(self, self->poll_timeout);
}
break;
@@ -1270,7 +1296,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
irlap_disconnect_indication(self, LAP_RESET_INDICATION);
self->xmitflag = TRUE;
}
- dev_kfree_skb(skb);
break;
case RECV_RNR_RSP:
ASSERT(info != NULL, return -1;);
@@ -1285,14 +1310,12 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
/* Start poll timer */
irlap_start_poll_timer(self, self->poll_timeout);
- dev_kfree_skb(skb);
break;
case RECV_FRMR_RSP:
del_timer(&self->final_timer);
self->xmitflag = TRUE;
irlap_next_state(self, LAP_RESET_WAIT);
irlap_reset_indication(self);
- dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
/*
@@ -1331,7 +1354,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
" retry_count=%d\n", self->retry_count);
/* Keep state */
} else if (self->retry_count == self->N1) {
- irlap_status_indication(STATUS_NO_ACTIVITY);
+ irlap_status_indication(self, STATUS_NO_ACTIVITY);
irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_send_rr_frame(self, CMD_FRAME);
@@ -1357,7 +1380,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
} else
irlap_resend_rejected_frames(self, CMD_FRAME);
irlap_start_final_timer(self, self->final_timeout);
- dev_kfree_skb(skb);
break;
case RECV_SREJ_RSP:
irlap_update_nr_received(self, info->nr);
@@ -1367,7 +1389,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
} else
irlap_resend_rejected_frame(self, CMD_FRAME);
irlap_start_final_timer(self, self->final_timeout);
- dev_kfree_skb(skb);
break;
case RECV_RD_RSP:
IRDA_DEBUG(0, __FUNCTION__ "(), RECV_RD_RSP\n");
@@ -1381,8 +1402,6 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -1;
break;
@@ -1428,10 +1447,8 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
irlap_next_state( self, LAP_PCLOSE);
break;
default:
- IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
+ IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -1;
break;
@@ -1467,7 +1484,6 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
- dev_kfree_skb(skb);
break;
case RECV_UA_RSP:
del_timer(&self->final_timer);
@@ -1483,7 +1499,6 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_poll_timer(self, self->poll_timeout);
- dev_kfree_skb(skb);
break;
case FINAL_TIMER_EXPIRED:
if (self->retry_count < 3) {
@@ -1522,13 +1537,10 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(0, __FUNCTION__
"(), SNRM frame contained an I field!\n");
}
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -1;
break;
@@ -1566,7 +1578,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
* speed and turn-around-time.
*/
if (skb->len > self->bytes_left) {
- skb_queue_head(&self->txq, skb);
+ skb_queue_head(&self->txq, skb_get(skb));
/*
* Switch to NRM_S, this is only possible
* when we are in secondary mode, since we
@@ -1600,7 +1612,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
}
} else {
IRDA_DEBUG(2, __FUNCTION__ "(), Unable to send!\n");
- skb_queue_head(&self->txq, skb);
+ skb_queue_head(&self->txq, skb_get(skb));
ret = -EPROTO;
}
break;
@@ -1613,8 +1625,6 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
default:
IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %s\n",
irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
break;
@@ -1676,7 +1686,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
#endif
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
-
+
irlap_data_indication(self, skb, FALSE);
break;
} else {
@@ -1739,7 +1749,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
}
- dev_kfree_skb(skb);
break;
}
@@ -1778,7 +1787,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
/* Keep state, do not move this line */
irlap_next_state(self, LAP_NRM_S);
-
+
irlap_data_indication(self, skb, FALSE);
irlap_start_wd_timer(self, self->wd_timeout);
}
@@ -1787,11 +1796,9 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
if (ret == NR_INVALID) {
IRDA_DEBUG(0, "NRM_S, NR_INVALID not implemented!\n");
- dev_kfree_skb(skb);
}
if (ret == NS_INVALID) {
IRDA_DEBUG(0, "NRM_S, NS_INVALID not implemented!\n");
- dev_kfree_skb(skb);
}
break;
case RECV_UI_FRAME:
@@ -1870,7 +1877,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(1, __FUNCTION__
"(), invalid nr not implemented!\n");
}
- dev_kfree_skb(skb);
break;
case RECV_SNRM_CMD:
/* SNRM frame is not allowed to contain an I-field */
@@ -1885,7 +1891,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
"(), SNRM frame contained an I-field!\n");
}
- dev_kfree_skb(skb);
break;
case RECV_REJ_CMD:
irlap_update_nr_received(self, info->nr);
@@ -1895,7 +1900,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
} else
irlap_resend_rejected_frames(self, CMD_FRAME);
irlap_start_wd_timer(self, self->wd_timeout);
- dev_kfree_skb(skb);
break;
case RECV_SREJ_CMD:
irlap_update_nr_received(self, info->nr);
@@ -1905,31 +1909,34 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
} else
irlap_resend_rejected_frame(self, CMD_FRAME);
irlap_start_wd_timer(self, self->wd_timeout);
- dev_kfree_skb(skb);
break;
case WD_TIMER_EXPIRED:
/*
* Wait until retry_count * n matches negotiated threshold/
* disconnect time (note 2 in IrLAP p. 82)
+ *
+ * Note : self->wd_timeout = (self->poll_timeout * 2),
+ * and self->final_timeout == self->poll_timeout,
+ * which explain why we use (self->retry_count * 2) here !!!
+ * Jean II
*/
IRDA_DEBUG(1, __FUNCTION__ "(), retry_count = %d\n",
self->retry_count);
- if ((self->retry_count < (self->N2/2)) &&
- (self->retry_count != self->N1/2)) {
+ if (((self->retry_count * 2) < self->N2) &&
+ ((self->retry_count * 2) != self->N1)) {
irlap_start_wd_timer(self, self->wd_timeout);
- self->retry_count++;
- } else if (self->retry_count == (self->N1/2)) {
- irlap_status_indication(STATUS_NO_ACTIVITY);
+ self->retry_count++;
+ } else if ((self->retry_count * 2) == self->N1) {
+ irlap_status_indication(self, STATUS_NO_ACTIVITY);
irlap_start_wd_timer(self, self->wd_timeout);
self->retry_count++;
- } else if (self->retry_count >= self->N2/2) {
+ } else if ((self->retry_count * 2) >= self->N2) {
irlap_apply_default_connection_parameters(self);
/* Always switch state before calling upper layers */
irlap_next_state(self, LAP_NDM);
-
irlap_disconnect_indication(self, LAP_NO_RESPONSE);
}
break;
@@ -1944,7 +1951,6 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_apply_default_connection_parameters(self);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
break;
case RECV_DISCOVERY_XID_CMD:
irlap_wait_min_turn_around(self, &self->qos_tx);
@@ -1953,24 +1959,20 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_start_wd_timer(self, self->wd_timeout);
irlap_next_state(self, LAP_NRM_S);
- dev_kfree_skb(skb);
break;
case RECV_TEST_CMD:
- /* Remove test frame header */
- skb_pull(skb, sizeof(struct test_frame));
+ /* Remove test frame header (only LAP header in NRM) */
+ skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
irlap_wait_min_turn_around(self, &self->qos_tx);
irlap_start_wd_timer(self, self->wd_timeout);
/* Send response (info will be copied) */
irlap_send_test_frame(self, self->caddr, info->daddr, skb);
- dev_kfree_skb(skb);
break;
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
event, irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
break;
@@ -2005,7 +2007,6 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
irlap_apply_default_connection_parameters(self);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
break;
case RECV_DM_RSP:
/* Always switch state before calling upper layers */
@@ -2015,7 +2016,6 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
irlap_apply_default_connection_parameters(self);
irlap_disconnect_indication(self, LAP_DISC_INDICATION);
- dev_kfree_skb(skb);
break;
case WD_TIMER_EXPIRED:
irlap_apply_default_connection_parameters(self);
@@ -2025,9 +2025,7 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
event, irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
-
+
ret = -EINVAL;
break;
}
@@ -2064,8 +2062,6 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
default:
IRDA_DEBUG(1, __FUNCTION__ "(), Unknown event %d, (%s)\n",
event, irlap_event[event]);
- if (skb)
- dev_kfree_skb(skb);
ret = -EINVAL;
break;
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 830fe6ef7..fff5bef93 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -69,7 +69,8 @@ static inline void irlap_insert_info(struct irlap_cb *self,
* Delay equals negotiated BOFs count, plus the number of BOFs to
* force the negotiated minimum turnaround time
*/
- cb->xbofs = self->bofs_count+self->xbofs_delay;
+ cb->xbofs = self->bofs_count;
+ cb->xbofs_delay = self->xbofs_delay;
/* Reset XBOF's delay (used only for getting min turn time) */
self->xbofs_delay = 0;
@@ -164,7 +165,6 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
IRDA_DEBUG(3, __FUNCTION__
"(), invalid connection address!\n");
- dev_kfree_skb(skb);
return;
}
@@ -175,13 +175,13 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
/* Only accept if addressed directly to us */
if (info->saddr != self->saddr) {
IRDA_DEBUG(2, __FUNCTION__ "(), not addressed to us!\n");
- dev_kfree_skb(skb);
return;
}
irlap_do_event(self, RECV_SNRM_CMD, skb, info);
- } else
+ } else {
/* Signal that this SNRM frame does not contain and I-field */
irlap_do_event(self, RECV_SNRM_CMD, skb, NULL);
+ }
}
/*
@@ -408,13 +408,11 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
IRDA_DEBUG(0, __FUNCTION__
"(), frame is not addressed to us!\n");
- dev_kfree_skb(skb);
return;
}
if ((discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
WARNING(__FUNCTION__ "(), kmalloc failed!\n");
- dev_kfree_skb(skb);
return;
}
memset(discovery, 0, sizeof(discovery_t));
@@ -476,7 +474,6 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
IRDA_DEBUG(0, __FUNCTION__
"(), frame is not addressed to us!\n");
- dev_kfree_skb(skb);
return;
}
@@ -506,13 +503,18 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
* Check if last frame
*/
if (info->s == 0xff) {
+ /* Check if things are sane at this point... */
+ if((discovery_info == NULL) || (skb->len < 3)) {
+ ERROR(__FUNCTION__ "(), discovery frame to short!\n");
+ return;
+ }
+
/*
* We now have some discovery info to deliver!
*/
discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
if (!discovery) {
WARNING(__FUNCTION__ "(), unable to malloc!\n");
- dev_kfree_skb(skb);
return;
}
@@ -541,7 +543,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
info->discovery = discovery;
} else
info->discovery = NULL;
-
+
irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info);
}
@@ -734,7 +736,6 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
/* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
- dev_kfree_skb(skb);
return;
}
@@ -747,7 +748,7 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
/*
* Insert frame in store, in case of retransmissions
*/
- skb_queue_tail(&self->wx_list, skb);
+ skb_queue_tail(&self->wx_list, skb_get(skb));
self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE;
@@ -756,7 +757,7 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
irlap_send_i_frame( self, tx_skb, CMD_FRAME);
} else {
IRDA_DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
- irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
self->window -= 1;
}
}
@@ -781,7 +782,6 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
/* Copy buffer */
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
- dev_kfree_skb(skb);
return;
}
@@ -794,7 +794,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
/*
* Insert frame in store, in case of retransmissions
*/
- skb_queue_tail(&self->wx_list, skb);
+ skb_queue_tail(&self->wx_list, skb_get(skb));
/*
* Set poll bit if necessary. We do this to the copied
@@ -819,12 +819,12 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
del_timer(&self->poll_timer);
if (self->ack_required) {
- irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
irlap_send_rr_frame(self, CMD_FRAME);
self->ack_required = FALSE;
} else {
skb->data[1] |= PF_BIT;
- irlap_send_ui_frame(self, skb, self->caddr, CMD_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
}
self->window = self->window_size;
irlap_start_final_timer(self, self->final_timeout);
@@ -857,7 +857,6 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
- dev_kfree_skb(skb);
return;
}
@@ -865,7 +864,7 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
skb_set_owner_w(tx_skb, skb->sk);
/* Insert frame in store */
- skb_queue_tail(&self->wx_list, skb);
+ skb_queue_tail(&self->wx_list, skb_get(skb));
tx_skb->data[1] |= PF_BIT;
@@ -878,12 +877,12 @@ void irlap_send_data_secondary_final(struct irlap_cb *self,
irlap_send_i_frame(self, tx_skb, RSP_FRAME);
} else {
if (self->ack_required) {
- irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
irlap_send_rr_frame(self, RSP_FRAME);
self->ack_required = FALSE;
} else {
skb->data[1] |= PF_BIT;
- irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
}
self->window = self->window_size;
@@ -912,7 +911,6 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
tx_skb = skb_clone(skb, GFP_ATOMIC);
if (tx_skb == NULL) {
- dev_kfree_skb(skb);
return;
}
@@ -920,7 +918,7 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
skb_set_owner_w(tx_skb, skb->sk);
/* Insert frame in store */
- skb_queue_tail(&self->wx_list, skb);
+ skb_queue_tail(&self->wx_list, skb_get(skb));
self->vs = (self->vs + 1) % 8;
self->ack_required = FALSE;
@@ -928,7 +926,7 @@ void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
irlap_send_i_frame(self, tx_skb, RSP_FRAME);
} else {
- irlap_send_ui_frame(self, skb, self->caddr, RSP_FRAME);
+ irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
self->window -= 1;
}
}
@@ -1023,6 +1021,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
} else {
irlap_send_data_primary_poll(self, skb);
}
+ kfree_skb(skb);
}
}
#endif
@@ -1212,7 +1211,7 @@ void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
struct test_frame *frame;
__u8 *info;
- skb = dev_alloc_skb(32);
+ skb = dev_alloc_skb(cmd->len+sizeof(struct test_frame));
if (!skb)
return;
@@ -1225,10 +1224,10 @@ void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(daddr);
} else
- frame = (struct test_frame *) skb_put(skb, LAP_MAX_HEADER);
+ frame = (struct test_frame *) skb_put(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER);
frame->caddr = caddr;
- frame->control = TEST_RSP;
+ frame->control = TEST_RSP | PF_BIT;
/* Copy info */
info = skb_put(skb, cmd->len);
@@ -1259,7 +1258,6 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
if (skb->len < sizeof(struct test_frame)) {
IRDA_DEBUG(0, __FUNCTION__
"() test frame to short!\n");
- dev_kfree_skb(skb);
return;
}
@@ -1270,7 +1268,6 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
/* Make sure frame is addressed to us */
if ((info->saddr != self->saddr) &&
(info->saddr != BROADCAST)) {
- dev_kfree_skb(skb);
return;
}
}
@@ -1323,8 +1320,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
/* First we check if this frame has a valid connection address */
if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
IRDA_DEBUG(0, __FUNCTION__ "(), wrong connection address!\n");
- dev_kfree_skb(skb);
- return 0;
+ goto out;
}
/*
* Optimize for the common case and check if the frame is an
@@ -1332,7 +1328,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
*/
if (~control & 0x01) {
irlap_recv_i_frame(self, skb, &info, command);
- return 0;
+ goto out;
}
/*
* We now check is the frame is an S(upervisory) frame. Only
@@ -1360,10 +1356,9 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
WARNING(__FUNCTION__
"() Unknown S-frame %02x received!\n",
info.control);
- dev_kfree_skb(skb);
break;
}
- return 0;
+ goto out;
}
/*
* This must be a C(ontrol) frame
@@ -1399,8 +1394,9 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
default:
WARNING(__FUNCTION__ "(), Unknown frame %02x received!\n",
info.control);
- dev_kfree_skb(skb);
break;
}
+out:
+ dev_kfree_skb(skb);
return 0;
}
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 5be0298a9..8b4d47caa 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -74,6 +74,7 @@ int irlmp_proc_read(char *buf, char **start, off_t offst, int len);
*/
int __init irlmp_init(void)
{
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
/* Initialize the irlmp structure. */
irlmp = kmalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
if (irlmp == NULL)
@@ -81,7 +82,7 @@ int __init irlmp_init(void)
memset(irlmp, 0, sizeof(struct irlmp_cb));
irlmp->magic = LMP_MAGIC;
- spin_lock_init(&irlmp->lock);
+ spin_lock_init(&irlmp->log_lock);
irlmp->clients = hashbin_new(HB_GLOBAL);
irlmp->services = hashbin_new(HB_GLOBAL);
@@ -178,7 +179,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
/* Insert into queue of unconnected LSAPs */
- hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self,
+ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self,
NULL);
return self;
@@ -284,9 +285,9 @@ void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
init_timer(&lap->idle_timer);
/*
- * Insert into queue of unconnected LSAPs
+ * Insert into queue of LMP links
*/
- hashbin_insert(irlmp->links, (queue_t *) lap, lap->saddr, NULL);
+ hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL);
/*
* We set only this variable so IrLAP can tell us on which link the
@@ -395,9 +396,25 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
return -EHOSTUNREACH;
}
+ /* Check if LAP is disconnected or already connected */
if (lap->daddr == DEV_ADDR_ANY)
lap->daddr = daddr;
else if (lap->daddr != daddr) {
+ struct lsap_cb *any_lsap;
+
+ /* Check if some LSAPs are active on this LAP */
+ any_lsap = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
+ if (any_lsap == NULL) {
+ /* No active connection, but LAP hasn't been
+ * disconnected yet (waiting for timeout in LAP).
+ * Maybe we could give LAP a bit of help in this case.
+ */
+ IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but I'm waiting for LAP to timeout!\n");
+ return -EAGAIN;
+ }
+
+ /* LAP is already connected to a different node, and LAP
+ * can only talk to one node at a time */
IRDA_DEBUG(0, __FUNCTION__ "(), sorry, but link is busy!\n");
return -EBUSY;
}
@@ -415,7 +432,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
ASSERT(lsap->lap != NULL, return -1;);
ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
- hashbin_insert(self->lap->lsaps, (queue_t *) self, (int) self, NULL);
+ hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL);
self->connected = TRUE;
@@ -557,7 +574,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
init_timer(&new->watchdog_timer);
- hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) new, (int) new,
+ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new,
NULL);
/* Make sure that we invalidate the cache */
@@ -612,7 +629,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
ASSERT(lsap == self, return -1;);
- hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) self, (int) self,
+ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self,
NULL);
/* Reset some values */
@@ -658,7 +675,7 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
ASSERT(lsap != NULL, return;);
ASSERT(lsap == self, return;);
- hashbin_insert(irlmp->unconnected_lsaps, (queue_t *) lsap, (int) lsap,
+ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap,
NULL);
self->lap = NULL;
@@ -749,6 +766,18 @@ void irlmp_discovery_request(int nslots)
irlmp_do_discovery(nslots);
}
+/*
+ * Function irlmp_get_discoveries (pn, mask)
+ *
+ * Return the current discovery log
+ *
+ */
+struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask)
+{
+ /* Return current cached discovery log */
+ return(irlmp_copy_discoveries(irlmp->cachelog, pn, mask));
+}
+
#if 0
/*
* Function irlmp_check_services (discovery)
@@ -759,7 +788,6 @@ void irlmp_discovery_request(int nslots)
void irlmp_check_services(discovery_t *discovery)
{
struct irlmp_client *client;
- struct irmanager_event event;
__u8 *service_log;
__u8 service;
int i = 0;
@@ -787,14 +815,7 @@ void irlmp_check_services(discovery_t *discovery)
continue;
/*
* Found no clients for dealing with this service,
- * so ask the user space irmanager to try to load
- * the right module for us
*/
- event.event = EVENT_DEVICE_DISCOVERED;
- event.service = service;
- event.daddr = discovery->daddr;
- sprintf(event.info, "%s", discovery->info);
- irmanager_notify(&event);
}
}
kfree(service_log);
@@ -805,17 +826,24 @@ void irlmp_check_services(discovery_t *discovery)
*
* Notify all about discovered devices
*
+ * Clients registered with IrLMP are :
+ * o IrComm
+ * o IrLAN
+ * o Any socket (in any state - ouch, that may be a lot !)
+ * The client may have defined a callback to be notified in case of
+ * partial/selective discovery based on the hints that it passed to IrLMP.
*/
-void irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
+static inline void
+irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
{
discovery_t *discovery;
IRDA_DEBUG(3, __FUNCTION__ "()\n");
- /* Check if client wants the whole log */
- if (client->callback2)
- client->callback2(log);
-
+ /* Check if client wants or not partial/selective log (optimisation) */
+ if (!client->disco_callback)
+ return;
+
/*
* Now, check all discovered devices (if any), and notify client
* only about the services that the client is interested in
@@ -828,10 +856,9 @@ void irlmp_notify_client(irlmp_client_t *client, hashbin_t *log)
* Any common hint bits? Remember to mask away the extension
* bits ;-)
*/
- if (client->hint_mask & discovery->hints.word & 0x7f7f) {
- if (client->callback1)
- client->callback1(discovery);
- }
+ if (client->hint_mask & discovery->hints.word & 0x7f7f)
+ client->disco_callback(discovery, client->priv);
+
discovery = (discovery_t *) hashbin_get_next(log);
}
}
@@ -864,9 +891,40 @@ void irlmp_discovery_confirm(hashbin_t *log)
}
/*
+ * Function irlmp_discovery_expiry (expiry)
+ *
+ * This device is no longer been discovered, and therefore it is beeing
+ * purged from the discovery log. Inform all clients who have
+ * registered for this event...
+ *
+ * Note : called exclusively from discovery.c
+ * Note : as we are currently processing the log, the clients callback
+ * should *NOT* attempt to touch the log now.
+ */
+void irlmp_discovery_expiry(discovery_t *expiry)
+{
+ irlmp_client_t *client;
+
+ IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
+ ASSERT(expiry != NULL, return;);
+
+ client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
+ while (client != NULL) {
+ /* Check if we should notify client */
+ if ((client->expir_callback) &&
+ (client->hint_mask & expiry->hints.word & 0x7f7f))
+ client->expir_callback(expiry, client->priv);
+
+ /* Next client */
+ client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
+ }
+}
+
+/*
* Function irlmp_get_discovery_response ()
*
- * Used by IrLAP to get the disocvery info it needs when answering
+ * Used by IrLAP to get the discovery info it needs when answering
* discovery requests by other devices.
*/
discovery_t *irlmp_get_discovery_response()
@@ -1046,9 +1104,35 @@ void irlmp_status_request(void)
IRDA_DEBUG(0, __FUNCTION__ "(), Not implemented\n");
}
-void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock)
+/*
+ * Propagate status indication from LAP to LSAPs (via LMP)
+ * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb,
+ * and the event is stateless, therefore we can bypass both state machines
+ * and send the event direct to the LSAP user.
+ * Jean II
+ */
+void irlmp_status_indication(struct lap_cb *self,
+ LINK_STATUS link, LOCK_STATUS lock)
{
- IRDA_DEBUG(1, __FUNCTION__ "(), Not implemented\n");
+ struct lsap_cb *next;
+ struct lsap_cb *curr;
+
+ /* Send status_indication to all LSAPs using this link */
+ next = (struct lsap_cb *) hashbin_get_first( self->lsaps);
+ while (next != NULL ) {
+ curr = next;
+ next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+
+ ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
+ /*
+ * Inform service user if he has requested it
+ */
+ if (curr->notify.status_indication != NULL)
+ curr->notify.status_indication(curr->notify.instance,
+ link, lock);
+ else
+ IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
+ }
}
/*
@@ -1207,7 +1291,7 @@ __u32 irlmp_register_service(__u16 hints)
return 0;
}
service->hints = hints;
- hashbin_insert(irlmp->services, (queue_t *) service, handle, NULL);
+ hashbin_insert(irlmp->services, (irda_queue_t *) service, handle, NULL);
return handle;
}
@@ -1255,15 +1339,20 @@ int irlmp_unregister_service(__u32 handle)
* Function irlmp_register_client (hint_mask, callback1, callback2)
*
* Register a local client with IrLMP
+ * First callback is selective discovery (based on hints)
+ * Second callback is for selective discovery expiries
*
* Returns: handle > 0 on success, 0 on error
*/
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
- DISCOVERY_CALLBACK2 callback2)
+__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+ DISCOVERY_CALLBACK1 expir_clb, void *priv)
{
irlmp_client_t *client;
__u32 handle;
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+ ASSERT(irlmp != NULL, return 0;);
+
/* Get a unique handle for this client */
get_random_bytes(&handle, sizeof(handle));
while (hashbin_find(irlmp->clients, handle, NULL) || !handle)
@@ -1273,16 +1362,16 @@ __u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
if (!client) {
IRDA_DEBUG( 1, __FUNCTION__ "(), Unable to kmalloc!\n");
-
return 0;
}
/* Register the details */
client->hint_mask = hint_mask;
- client->callback1 = callback1;
- client->callback2 = callback2;
+ client->disco_callback = disco_clb;
+ client->expir_callback = expir_clb;
+ client->priv = priv;
- hashbin_insert(irlmp->clients, (queue_t *) client, handle, NULL);
+ hashbin_insert(irlmp->clients, (irda_queue_t *) client, handle, NULL);
return handle;
}
@@ -1296,8 +1385,8 @@ __u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 callback1,
* Returns: 0 on success, -1 on error
*/
int irlmp_update_client(__u32 handle, __u16 hint_mask,
- DISCOVERY_CALLBACK1 callback1,
- DISCOVERY_CALLBACK2 callback2)
+ DISCOVERY_CALLBACK1 disco_clb,
+ DISCOVERY_CALLBACK1 expir_clb, void *priv)
{
irlmp_client_t *client;
@@ -1311,8 +1400,9 @@ int irlmp_update_client(__u32 handle, __u16 hint_mask,
}
client->hint_mask = hint_mask;
- client->callback1 = callback1;
- client->callback2 = callback2;
+ client->disco_callback = disco_clb;
+ client->expir_callback = expir_clb;
+ client->priv = priv;
return 0;
}
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
index ace20d70e..a4646b274 100644
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -122,7 +122,7 @@ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
IRDA_DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
- irlmp_event[event], irlmp_state[ self->lsap_state]);
+ irlmp_event[event], irlsap_state[ self->lsap_state]);
return (*lsap_state[self->lsap_state]) (self, event, skb);
}
@@ -393,6 +393,14 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
irlmp_next_lap_state(self, LAP_STANDBY);
self->refcount = 0;
+ /* In some case, at this point our side has already closed
+ * all lsaps, and we are waiting for the idle_timer to
+ * expire. If another device reconnect immediately, the
+ * idle timer will expire in the midle of the connection
+ * initialisation, screwing up things a lot...
+ * Therefore, we must stop the timer... */
+ irlmp_stop_idle_timer(self);
+
/*
* Inform all connected LSAP's using this link
*/
@@ -410,7 +418,8 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
}
break;
default:
- IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %d\n", event);
+ IRDA_DEBUG(0, __FUNCTION__ "(), Unknown event %s\n",
+ irlmp_event[event]);
if (skb)
dev_kfree_skb(skb);
break;
@@ -514,7 +523,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
ASSERT(self->lap != NULL, return -1;);
ASSERT(self->lap->lsaps != NULL, return -1;);
- hashbin_insert(self->lap->lsaps, (queue_t *) self, (int) self,
+ hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self,
NULL);
irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
index c9bca1ea2..56287afbb 100644
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -34,6 +34,9 @@
#include <net/irda/irlmp_frame.h>
#include <net/irda/discovery.h>
+#define DISCO_SMALL_DELAY 250 /* Delay for some discoveries in ms */
+struct timer_list disco_delay; /* The timer associated */
+
static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap,
__u8 slsap, int status, hashbin_t *);
@@ -124,9 +127,11 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
irlmp->unconnected_lsaps);
/* Maybe LSAP was already connected, so try one more time */
- if (!lsap)
+ if (!lsap) {
+ IRDA_DEBUG(1, __FUNCTION__ "(), incoming connection for LSAP already connected\n");
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
self->lsaps);
+ }
} else
lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
self->lsaps);
@@ -338,10 +343,50 @@ void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
}
/*
+ * Function irlmp_discovery_timeout (priv)
+ *
+ * Create a discovery event to the state machine (called after a delay)
+ *
+ * Note : irlmp_do_lap_event will handle the very rare case where the LAP
+ * is destroyed while we were sleeping.
+ */
+static void irlmp_discovery_timeout(u_long priv)
+{
+ struct lap_cb *self;
+
+ IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+ self = (struct lap_cb *) priv;
+ ASSERT(self != NULL, return;);
+
+ /* Just handle it the same way as a discovery confirm */
+ irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+}
+
+/*
* Function irlmp_link_discovery_indication (self, log)
*
* Device is discovering us
*
+ * It's not an answer to our own discoveries, just another device trying
+ * to perform discovery, but we don't want to miss the opportunity
+ * to exploit this information, because :
+ * o We may not actively perform discovery (just passive discovery)
+ * o This type of discovery is much more reliable. In some cases, it
+ * seem that less than 50% of our discoveries get an answer, while
+ * we always get ~100% of these.
+ * o Make faster discovery, statistically divide time of discovery
+ * events by 2 (important for the latency aspect and user feel)
+ * However, when both devices discover each other, they might attempt to
+ * connect to each other, and it would create collisions on the medium.
+ * The trick here is to defer the event by a little delay to avoid both
+ * devices to jump in exactly at the same time...
+ *
+ * The delay is currently set to 0.25s, which leave enough time to perform
+ * a connection and don't interfer with next discovery (the lowest discovery
+ * period/timeout that may be set is 1s). The message triggering this
+ * event was the last of the discovery, so the medium is now free...
+ * Maybe more testing is needed to get the value right...
*/
void irlmp_link_discovery_indication(struct lap_cb *self,
discovery_t *discovery)
@@ -351,11 +396,14 @@ void irlmp_link_discovery_indication(struct lap_cb *self,
irlmp_add_discovery(irlmp->cachelog, discovery);
-#if 0 /* This will just cause a lot of connection collisions */
-
- /* Just handle it the same way as a discovery confirm */
- irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
-#endif
+ /* If delay was activated, kill it! */
+ if(timer_pending(&disco_delay))
+ del_timer(&disco_delay);
+ /* Set delay timer to expire in 0.25s. */
+ disco_delay.expires = jiffies + (DISCO_SMALL_DELAY * HZ/1000);
+ disco_delay.function = irlmp_discovery_timeout;
+ disco_delay.data = (unsigned long) self;
+ add_timer(&disco_delay);
}
/*
@@ -374,7 +422,12 @@ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
ASSERT(self->magic == LMP_LAP_MAGIC, return;);
irlmp_add_discovery_log(irlmp->cachelog, log);
-
+
+ /* If discovery delay was activated, kill it! */
+ if(timer_pending(&disco_delay))
+ del_timer(&disco_delay);
+
+ /* Propagate event to the state machine */
irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
}
diff --git a/net/irda/irnet/Config.in b/net/irda/irnet/Config.in
new file mode 100644
index 000000000..d578593f1
--- /dev/null
+++ b/net/irda/irnet/Config.in
@@ -0,0 +1 @@
+dep_tristate ' IrNET protocol' CONFIG_IRNET $CONFIG_IRDA
diff --git a/net/irda/irnet/Makefile b/net/irda/irnet/Makefile
new file mode 100644
index 000000000..50554ac72
--- /dev/null
+++ b/net/irda/irnet/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the Linux IrDA IrNET protocol layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+MOD_LIST_NAME := IRDA_MODULES
+O_TARGET := irnet.o
+#O_OBJS := irnet_ppp.o
+O_OBJS := irnet_ppp.o irnet_irda.o
+M_OBJS := $(O_TARGET)
+MI_OBJS :=
+
+OX_OBJS +=
+
+include $(TOPDIR)/Rules.make
+
+tar:
+ tar -cvf /dev/f1 .
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
new file mode 100644
index 000000000..6c9df66b3
--- /dev/null
+++ b/net/irda/irnet/irnet.h
@@ -0,0 +1,453 @@
+/*
+ * IrNET protocol module : Synchronous PPP over an IrDA socket.
+ *
+ * Jean II - HPL `00 - <jt@hpl.hp.com>
+ *
+ * This file contains definitions and declarations global to the IrNET module,
+ * all grouped in one place...
+ * This file is a private header, so other modules don't want to know
+ * what's in there...
+ *
+ * Note : as most part of the Linux kernel, this module is available
+ * under the GNU Public License (GPL).
+ */
+
+#ifndef IRNET_H
+#define IRNET_H
+
+/************************** DOCUMENTATION ***************************/
+/*
+ * What is IrNET
+ * -------------
+ * IrNET is a protocol allowing to carry TCP/IP traffic between two
+ * IrDA peers in an efficient fashion. It is a thin layer, passing PPP
+ * packets to IrTTP and vice versa. It uses PPP in synchronous mode,
+ * because IrTTP offer a reliable sequenced packet service (as opposed
+ * to a byte stream). In fact, you could see IrNET as carrying TCP/IP
+ * in a IrDA socket, using PPP to provide the glue.
+ *
+ * The main difference with traditional PPP over IrCOMM is that we
+ * avoid the framing and serial emulation which are a performance
+ * bottleneck. It also allows multipoint communications in a sensible
+ * fashion.
+ *
+ * The main difference with IrLAN is that we use PPP for the link
+ * management, which is more standard, interoperable and flexible than
+ * the IrLAN protocol. For example, PPP adds authentication,
+ * encryption, compression, header compression and automated routing
+ * setup. And, as IrNET let PPP do the hard work, the implementation
+ * is much simpler than IrLAN.
+ *
+ * The Linux implementation
+ * ------------------------
+ * IrNET is written on top of the Linux-IrDA stack, and interface with
+ * the generic Linux PPP driver. Because IrNET depend on recent
+ * changes of the PPP driver interface, IrNET will work only with very
+ * recent kernel (2.3.99-pre6 and up).
+ *
+ * The present implementation offer the following features :
+ * o simple user interface using pppd
+ * o efficient implementation (interface directly to PPP and IrTTP)
+ * o addressing (you can specify the name of the IrNET recipient)
+ * o multipoint operation (limited by IrLAP specification)
+ * o information in /proc/net/irda/irnet
+ * o IrNET events on /dev/irnet (for user space daemon)
+ * o IrNET deamon (irnetd) to automatically handle incomming requests
+ * o Windows 2000 compatibility (tested, but need more work)
+ * Currently missing :
+ * o Lot's of testing (that's your job)
+ * o Connection retries (may be too hard to do)
+ * o Check pppd persist mode
+ * o User space deamon (to automatically handle incomming requests)
+ * o A registered device number (comming, waiting from an answer)
+ * o Final integration in Linux-IrDA (up to Dag)
+ *
+ * The setup is not currently the most easy, but this should get much
+ * better when everything will get integrated...
+ *
+ * Acknowledgements
+ * ----------------
+ * This module is based on :
+ * o The PPP driver (ppp_synctty/ppp_generic) by Paul Mackerras
+ * o The IrLAN protocol (irlan_common/XXX) by Dag Brattli
+ * o The IrSock interface (af_irda) by Dag Brattli
+ * o Some other bits from the kernel and my drivers...
+ * Infinite thanks to those brave souls for providing the infrastructure
+ * upon which IrNET is built.
+ *
+ * Thanks to all my collegues in HP for helping me. In particular,
+ * thanks to Salil Pradhan and Bill Serra for W2k testing...
+ * Thanks to Luiz Magalhaes for irnetd and much testing...
+ *
+ * Thanks to Alan Cox for answering lot's of my stupid questions, and
+ * to Paul Mackerras answering my questions on how to best integrate
+ * IrNET and pppd.
+ *
+ * Jean II
+ *
+ * Note on some implementations choices...
+ * ------------------------------------
+ * 1) Direct interface vs tty/socket
+ * I could have used a tty interface to hook to ppp and use the full
+ * socket API to connect to IrDA. The code would have been easier to
+ * maintain, and maybe the code would have been smaller...
+ * Instead, we hook directly to ppp_generic and to IrTTP, which make
+ * things more complicated...
+ *
+ * The first reason is flexibility : this allow us to create IrNET
+ * instances on demand (no /dev/ircommX crap) and to allow linkname
+ * specification on pppd command line...
+ *
+ * Second reason is speed optimisation. If you look closely at the
+ * transmit and receive paths, you will notice that they are "super lean"
+ * (that's why they look ugly), with no function calls and as little data
+ * copy and modification as I could...
+ *
+ * 2) irnetd in user space
+ * irnetd is implemented in user space, which is necessary to call pppd.
+ * This also give maximum benefits in term of flexibility and customability,
+ * and allow to offer the event channel, useful for other stuff like debug.
+ *
+ * On the other hand, this require a loose coordination between the
+ * present module and irnetd. One critical area is how incomming request
+ * are handled.
+ * When irnet receive an incomming request, it send an event to irnetd and
+ * drop the incomming IrNET socket.
+ * irnetd start a pppd instance, which create a new IrNET socket. This new
+ * socket is then connected in the originating node to the pppd instance.
+ * At this point, in the originating node, the first socket is closed.
+ *
+ * I admit, this is a bit messy and waste some ressources. The alternative
+ * is caching incomming socket, and that's also quite messy and waste
+ * ressources.
+ * We also make connection time slower. For example, on a 115 kb/s link it
+ * adds 60ms to the connection time (770 ms). However, this is slower than
+ * the time it takes to fire up pppd on my P133...
+ *
+ *
+ * History :
+ * -------
+ *
+ * v1 - 15/5/00 - Jean II
+ * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint)
+ * o control channel on /dev/irnet (set name/address)
+ * o event channel on /dev/irnet (for user space daemon)
+ *
+ * v2 - 5/6/00 - Jean II
+ * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness...
+ * o Add DISCONNECT_TO event and rename DISCONNECT_FROM.
+ * o Set official device number alloaction on /dev/irnet
+ *
+ * v3 - 30/8/00 - Jean II
+ * o Update to latest Linux-IrDA changes :
+ * - queue_t => irda_queue_t
+ * o Update to ppp-2.4.0 :
+ * - move irda_irnet_connect from PPPIOCATTACH to TIOCSETD
+ * o Add EXPIRE event (depend on new IrDA-Linux patch)
+ * o Switch from `hashbin_remove' to `hashbin_remove_this' to fix
+ * a multilink bug... (depend on new IrDA-Linux patch)
+ * o fix a self->daddr to self->raddr in irda_irnet_connect to fix
+ * another multilink bug (darn !)
+ * o Remove LINKNAME_IOCTL cruft
+ *
+ * v3b - 31/8/00 - Jean II
+ * o Dump discovery log at event channel startup
+ *
+ * v4 - 28/9/00 - Jean II
+ * o Fix interaction between poll/select and dump discovery log
+ * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch)
+ * o Add IRNET_NOANSWER_FROM event (mostly to help support)
+ * o Release flow control in disconnect_indication
+ * o Block packets while connecting (speed up connections)
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/tty.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/ppp_channel.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/iriap.h>
+#include <net/irda/irias_object.h>
+#include <net/irda/irlmp.h>
+#include <net/irda/irttp.h>
+#include <net/irda/discovery.h>
+
+/***************************** OPTIONS *****************************/
+/*
+ * Define or undefine to compile or not some optional part of the
+ * IrNET driver...
+ * Note : the present defaults make sense, play with that at your
+ * own risk...
+ */
+/* IrDA side of the business... */
+#define DISCOVERY_NOMASK /* To enable W2k compatibility... */
+#define ADVERTISE_HINT /* Advertise IrLAN hint bit */
+#define ALLOW_SIMULT_CONNECT /* This seem to work, cross fingers... */
+#define DISCOVERY_EVENTS /* Query the discovery log to post events */
+#define INITIAL_DISCOVERY /* Dump current discovery log as events */
+#undef STREAM_COMPAT /* Not needed - potentially messy */
+#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */
+#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */
+#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */
+
+/* PPP side of the business */
+#define BLOCK_WHEN_CONNECT /* Block packets when connecting */
+#undef CONNECT_IN_SEND /* Will crash hard your box... */
+#undef FLUSH_TO_PPP /* Not sure about this one, let's play safe */
+#undef SECURE_DEVIRNET /* Bah... */
+
+/****************************** DEBUG ******************************/
+
+/*
+ * This set of flags enable and disable all the various warning,
+ * error and debug message of this driver.
+ * Each section can be enabled and disabled independantly
+ */
+/* In the PPP part */
+#define DEBUG_CTRL_TRACE 0 /* Control channel */
+#define DEBUG_CTRL_INFO 0 /* various info */
+#define DEBUG_CTRL_ERROR 1 /* problems */
+#define DEBUG_FS_TRACE 0 /* filesystem callbacks */
+#define DEBUG_FS_INFO 0 /* various info */
+#define DEBUG_FS_ERROR 1 /* problems */
+#define DEBUG_PPP_TRACE 0 /* PPP related functions */
+#define DEBUG_PPP_INFO 0 /* various info */
+#define DEBUG_PPP_ERROR 1 /* problems */
+#define DEBUG_MODULE_TRACE 0 /* module insertion/removal */
+#define DEBUG_MODULE_ERROR 1 /* problems */
+
+/* In the IrDA part */
+#define DEBUG_IRDA_SR_TRACE 0 /* IRDA subroutines */
+#define DEBUG_IRDA_SR_INFO 0 /* various info */
+#define DEBUG_IRDA_SR_ERROR 1 /* problems */
+#define DEBUG_IRDA_SOCK_TRACE 0 /* IRDA main socket functions */
+#define DEBUG_IRDA_SOCK_INFO 0 /* various info */
+#define DEBUG_IRDA_SOCK_ERROR 1 /* problems */
+#define DEBUG_IRDA_SERV_TRACE 0 /* The IrNET server */
+#define DEBUG_IRDA_SERV_INFO 0 /* various info */
+#define DEBUG_IRDA_SERV_ERROR 1 /* problems */
+#define DEBUG_IRDA_TCB_TRACE 0 /* IRDA IrTTP callbacks */
+#define DEBUG_IRDA_OCB_TRACE 0 /* IRDA other callbacks */
+#define DEBUG_IRDA_CB_INFO 0 /* various info */
+#define DEBUG_IRDA_CB_ERROR 1 /* problems */
+
+#define DEBUG_ASSERT 0 /* Verify all assertions */
+
+/*
+ * These are the macros we are using to actually print the debug
+ * statements. Don't look at it, it's ugly...
+ *
+ * One of the trick is that, as the DEBUG_XXX are constant, the
+ * compiler will optimise away the if() in all cases.
+ */
+/* All error messages (will show up in the normal logs) */
+#define DERROR(dbg, args...) \
+ {if(DEBUG_##dbg) \
+ printk(KERN_INFO "irnet: " __FUNCTION__ "(): " args);}
+
+/* Normal debug message (will show up in /var/log/debug) */
+#define DEBUG(dbg, args...) \
+ {if(DEBUG_##dbg) \
+ printk(KERN_DEBUG "irnet: " __FUNCTION__ "(): " args);}
+
+/* Entering a function (trace) */
+#define DENTER(dbg, args...) \
+ {if(DEBUG_##dbg) \
+ printk(KERN_DEBUG "irnet: ->" __FUNCTION__ args);}
+
+/* Entering and exiting a function in one go (trace) */
+#define DPASS(dbg, args...) \
+ {if(DEBUG_##dbg) \
+ printk(KERN_DEBUG "irnet: <>" __FUNCTION__ args);}
+
+/* Exiting a function (trace) */
+#define DEXIT(dbg, args...) \
+ {if(DEBUG_##dbg) \
+ printk(KERN_DEBUG "irnet: <-" __FUNCTION__ "()" args);}
+
+/* Exit a function with debug */
+#define DRETURN(ret, dbg, args...) \
+ {DEXIT(dbg, ": " args);\
+ return(ret); }
+
+/* Exit a function on failed condition */
+#define DABORT(cond, ret, dbg, args...) \
+ {if(cond) {\
+ DERROR(dbg, args);\
+ return(ret); }}
+
+/* Invalid assertion, print out an error and exit... */
+#define DASSERT(cond, ret, dbg, args...) \
+ {if((DEBUG_ASSERT) && !(cond)) {\
+ DERROR(dbg, "Invalid assertion: " args);\
+ return ret; }}
+
+/************************ CONSTANTS & MACROS ************************/
+
+/* Paranoia */
+#define IRNET_MAGIC 0xB00754
+
+/* Number of control events in the control channel buffer... */
+#define IRNET_MAX_EVENTS 8 /* Should be more than enough... */
+
+/****************************** TYPES ******************************/
+
+/*
+ * This is the main structure where we store all the data pertaining to
+ * one instance of irnet.
+ * Note : in irnet functions, a pointer this structure is usually called
+ * "ap" or "self". If the code is borrowed from the IrDA stack, it tend
+ * to be called "self", and if it is borrowed from the PPP driver it is
+ * "ap". Apart from that, it's exactly the same structure ;-)
+ */
+typedef struct irnet_socket
+{
+ /* ------------------- Instance management ------------------- */
+ /* We manage a linked list of IrNET socket instances */
+ irda_queue_t q; /* Must be first - for hasbin */
+ int magic; /* Paranoia */
+
+ /* --------------------- FileSystem part --------------------- */
+ /* "pppd" interact directly with us on a /dev/ file */
+ struct file * file; /* File descriptor of this instance */
+ /* TTY stuff - to keep "pppd" happy */
+ struct termios termios; /* Various tty flags */
+ /* Stuff for the control channel */
+ int event_index; /* Last read in the event log */
+
+ /* ------------------------- PPP part ------------------------- */
+ /* We interface directly to the ppp_generic driver in the kernel */
+ int ppp_open; /* registered with ppp_generic */
+ struct ppp_channel chan; /* Interface to generic ppp layer */
+
+ int mru; /* Max size of PPP payload */
+ u32 xaccm[8]; /* Asynchronous character map (just */
+ u32 raccm; /* to please pppd - dummy) */
+ unsigned int flags; /* PPP flags (compression, ...) */
+ unsigned int rbits; /* Unused receive flags ??? */
+
+ /* ------------------------ IrTTP part ------------------------ */
+ /* We create a pseudo "socket" over the IrDA tranport */
+ int ttp_open; /* Set when IrTTP is ready */
+ struct tsap_cb * tsap; /* IrTTP instance (the connection) */
+
+ char rname[NICKNAME_MAX_LEN + 1];
+ /* IrDA nickname of destination */
+ __u32 raddr; /* Requested peer IrDA address */
+ __u32 saddr; /* my local IrDA address */
+ __u32 daddr; /* actual peer IrDA address */
+ __u8 dtsap_sel; /* Remote TSAP selector */
+ __u8 stsap_sel; /* Local TSAP selector */
+
+ __u32 max_sdu_size_rx;/* Socket parameters used for IrTTP */
+ __u32 max_sdu_size_tx;
+ __u32 max_data_size;
+ __u8 max_header_size;
+ LOCAL_FLOW tx_flow; /* State of the Tx path in IrTTP */
+
+ /* ------------------- IrLMP and IrIAS part ------------------- */
+ /* Used for IrDA Discovery and socket name resolution */
+ __u32 ckey; /* IrLMP client handle */
+ __u16 mask; /* Hint bits mask (filter discov.)*/
+ int nslots; /* Number of slots for discovery */
+
+ struct iriap_cb * iriap; /* Used to query remote IAS */
+ wait_queue_head_t query_wait; /* Wait for the answer to a query */
+ struct ias_value * ias_result; /* Result of remote IAS query */
+ int errno; /* status of the IAS query */
+
+ /* ---------------------- Optional parts ---------------------- */
+#ifdef INITIAL_DISCOVERY
+ /* Stuff used to dump discovery log */
+ struct irda_device_info *discoveries; /* Copy of the discovery log */
+ int disco_index; /* Last read in the discovery log */
+ int disco_number; /* Size of the discovery log */
+#endif INITIAL_DISCOVERY
+
+} irnet_socket;
+
+/*
+ * This is the various event that we will generate on the control channel
+ */
+typedef enum irnet_event
+{
+ IRNET_DISCOVER, /* New IrNET node discovered */
+ IRNET_EXPIRE, /* IrNET node expired */
+ IRNET_CONNECT_TO, /* IrNET socket has connected to other node */
+ IRNET_CONNECT_FROM, /* Other node has connected to IrNET socket */
+ IRNET_REQUEST_FROM, /* Non satisfied connection request */
+ IRNET_NOANSWER_FROM, /* Failed connection request */
+ IRNET_BLOCKED_LINK, /* Link (IrLAP) is blocked for > 3s */
+ IRNET_DISCONNECT_FROM, /* IrNET socket has disconnected */
+ IRNET_DISCONNECT_TO /* Closing IrNET socket */
+} irnet_event;
+
+/*
+ * This is the storage for an event and its arguments
+ */
+typedef struct irnet_log
+{
+ irnet_event event;
+ int unit;
+ __u32 addr;
+ char name[NICKNAME_MAX_LEN + 1];
+} irnet_log;
+
+/*
+ * This is the storage for all events and related stuff...
+ */
+typedef struct irnet_ctrl_channel
+{
+ irnet_log log[IRNET_MAX_EVENTS]; /* Event log */
+ int index; /* Current index in log */
+ spinlock_t spinlock; /* Serialize access to the event log */
+ wait_queue_head_t rwait; /* processes blocked on read (or poll) */
+} irnet_ctrl_channel;
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * Global functions of the IrNET module
+ * Note : we list here also functions called from one file to the other.
+ */
+
+/* -------------------------- IRDA PART -------------------------- */
+extern int
+ irda_irnet_create(irnet_socket *); /* Initialise a IrNET socket */
+extern int
+ irda_irnet_connect(irnet_socket *); /* Try to connect over IrDA */
+extern void
+ irda_irnet_destroy(irnet_socket *); /* Teardown a IrNET socket */
+extern int
+ irda_irnet_init(void); /* Initialise IrDA part of IrNET */
+extern void
+ irda_irnet_cleanup(void); /* Teardown IrDA part of IrNET */
+/* --------------------------- PPP PART --------------------------- */
+extern int
+ ppp_irnet_init(void); /* Initialise PPP part of IrNET */
+extern void
+ ppp_irnet_cleanup(void); /* Teardown PPP part of IrNET */
+/* ---------------------------- MODULE ---------------------------- */
+extern int
+ init_module(void); /* Initialise IrNET module */
+extern void
+ cleanup_module(void); /* Teardown IrNET module */
+
+/**************************** VARIABLES ****************************/
+
+/* Control channel stuff - allocated in irnet_irda.h */
+extern struct irnet_ctrl_channel irnet_events;
+
+#endif IRNET_H
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
new file mode 100644
index 000000000..ead7ef678
--- /dev/null
+++ b/net/irda/irnet/irnet_irda.c
@@ -0,0 +1,1481 @@
+/*
+ * IrNET protocol module : Synchronous PPP over an IrDA socket.
+ *
+ * Jean II - HPL `00 - <jt@hpl.hp.com>
+ *
+ * This file implement the IRDA interface of IrNET.
+ * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly,
+ * and exchange frames with IrTTP.
+ */
+
+#include <linux/config.h>
+#include "irnet_irda.h" /* Private header */
+
+/************************* CONTROL CHANNEL *************************/
+/*
+ * When ppp is not active, /dev/irnet act as a control channel.
+ * Writting allow to set up the IrDA destination of the IrNET channel,
+ * and any application may be read events happening on IrNET...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Post an event to the control channel...
+ * Put the event in the log, and then wait all process blocked on read
+ * so they can read the log...
+ */
+static void
+irnet_post_event(irnet_socket * ap,
+ irnet_event event,
+ __u32 addr,
+ char * name)
+{
+ unsigned long flags; /* For spinlock */
+ int index; /* In the log */
+
+ DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, addr=%08x, name=``%s'')\n",
+ (unsigned int) ap, event, addr, name);
+
+ /* Protect this section via spinlock.
+ * Note : as we are the only event producer, we only need to exclude
+ * ourself when touching the log, which is nice and easy.
+ */
+ spin_lock_irqsave(&irnet_events.spinlock, flags);
+
+ /* Copy the event in the log */
+ index = irnet_events.index;
+ irnet_events.log[index].event = event;
+ irnet_events.log[index].addr = addr;
+ /* Try to copy IrDA nickname */
+ if(name)
+ strcpy(irnet_events.log[index].name, name);
+ else
+ irnet_events.log[index].name[0] = '\0';
+ /* Try to get ppp unit number */
+ if((ap != (irnet_socket *) NULL) && (ap->ppp_open))
+ irnet_events.log[index].unit = ppp_unit_number(&ap->chan);
+ else
+ irnet_events.log[index].unit = -1;
+
+ /* Increment the index
+ * Note that we increment the index only after the event is written,
+ * to make sure that the readers don't get garbage... */
+ irnet_events.index = (index + 1) % IRNET_MAX_EVENTS;
+
+ DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index);
+
+ /* Spin lock end */
+ spin_unlock_irqrestore(&irnet_events.spinlock, flags);
+
+ /* Now : wake up everybody waiting for events... */
+ wake_up_interruptible_all(&irnet_events.rwait);
+
+ DEXIT(CTRL_TRACE, "\n");
+}
+
+/************************* IRDA SUBROUTINES *************************/
+/*
+ * These are a bunch of subroutines called from other functions
+ * down there, mostly common code or to improve readability...
+ *
+ * Note : we duplicate quite heavily some routines of af_irda.c,
+ * because our input structure (self) is quite different
+ * (struct irnet instead of struct irda_sock), which make sharing
+ * the same code impossible (at least, without templates).
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_open_tsap (self)
+ *
+ * Open local Transport Service Access Point (TSAP)
+ *
+ * Create a IrTTP instance for us and set all the IrTTP callbacks.
+ */
+static inline int
+irnet_open_tsap(irnet_socket * self)
+{
+ notify_t notify; /* Callback structure */
+
+ DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n");
+
+ /* Initialize IrTTP callbacks to be used by the IrDA stack */
+ irda_notify_init(&notify);
+ notify.connect_confirm = irnet_connect_confirm;
+ notify.connect_indication = irnet_connect_indication;
+ notify.disconnect_indication = irnet_disconnect_indication;
+ notify.data_indication = irnet_data_indication;
+ /*notify.udata_indication = NULL;*/
+ notify.flow_indication = irnet_flow_indication;
+ notify.status_indication = irnet_status_indication;
+ notify.instance = self;
+ strncpy(notify.name, IRNET_NOTIFY_NAME, NOTIFY_MAX_NAME);
+
+ /* Open an IrTTP instance */
+ self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
+ &notify);
+ DABORT(self->tsap == NULL, -ENOMEM,
+ IRDA_SR_ERROR, "Unable to allocate TSAP !\n");
+
+ /* Remember which TSAP selector we actually got */
+ self->stsap_sel = self->tsap->stsap_sel;
+
+ DEXIT(IRDA_SR_TRACE, " - tsap=0x%X, sel=0x%X\n",
+ (unsigned int) self->tsap, self->stsap_sel);
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_find_lsap_sel (self)
+ *
+ * Try to lookup LSAP selector in remote LM-IAS
+ *
+ * Basically, we start a IAP query, and then go to sleep. When the query
+ * return, irnet_getvalue_confirm will wake us up, and we can examine the
+ * result of the query...
+ * Note that in some case, the query fail even before we go to sleep,
+ * creating some races...
+ */
+static int
+irnet_find_lsap_sel(irnet_socket * self)
+{
+ DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* This should not happen */
+ DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n");
+
+ /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */
+ self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
+ irnet_getvalue_confirm);
+
+ /* Treat unexpected signals as disconnect */
+ self->errno = -EHOSTUNREACH;
+
+ /* Query remote LM-IAS */
+ iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
+ IRNET_SERVICE_NAME, IRNET_IAS_VALUE);
+ /* Wait for answer (if not already failed) */
+ if(self->iriap != NULL)
+ interruptible_sleep_on(&self->query_wait);
+
+ /* Check what happened */
+ if(self->errno)
+ {
+ DEBUG(IRDA_SR_INFO, "IAS query failed! (%d)\n", self->errno);
+ /* Requested object/attribute doesn't exist */
+ if((self->errno == IAS_CLASS_UNKNOWN) ||
+ (self->errno == IAS_ATTRIB_UNKNOWN))
+ return (-EADDRNOTAVAIL);
+ else
+ return (-EHOSTUNREACH);
+ }
+
+ /* Get the remote TSAP selector */
+ switch(self->ias_result->type)
+ {
+ case IAS_INTEGER:
+ DEBUG(IRDA_SR_INFO, "result=%d\n", self->ias_result->t.integer);
+ if(self->ias_result->t.integer != -1)
+ self->dtsap_sel = self->ias_result->t.integer;
+ else
+ self->dtsap_sel = 0;
+ break;
+ default:
+ self->dtsap_sel = 0;
+ DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", self->ias_result->type);
+ break;
+ }
+ /* Cleanup */
+ if(self->ias_result)
+ irias_delete_value(self->ias_result);
+
+ DEXIT(IRDA_SR_TRACE, "\n");
+ if(self->dtsap_sel)
+ return 0;
+
+ return -EADDRNOTAVAIL;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_discover_daddr_and_lsap_sel (self)
+ *
+ * This try to find a device with the requested service.
+ *
+ * It basically look into the discovery log. For each address in the list,
+ * it queries the LM-IAS of the device to find if this device offer
+ * the requested service.
+ * If there is more than one node supporting the service, we complain
+ * to the user (it should move devices around).
+ * The, we set both the destination address and the lsap selector to point
+ * on the service on the unique device we have found.
+ *
+ * Note : this function fails if there is more than one device in range,
+ * because IrLMP doesn't disconnect the LAP when the last LSAP is closed.
+ * Moreover, we would need to wait the LAP disconnection...
+ */
+static inline int
+irnet_discover_daddr_and_lsap_sel(irnet_socket * self)
+{
+ struct irda_device_info *discoveries; /* Copy of the discovery log */
+ int number; /* Number of nodes in the log */
+ int i;
+ int err = -ENETUNREACH;
+ __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */
+ __u8 dtsap_sel = 0x0; /* TSAP associated with it */
+
+ DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Ask lmp for the current discovery log
+ * Note : we have to use irlmp_get_discoveries(), as opposed
+ * to play with the cachelog directly, because while we are
+ * making our ias query, le log might change... */
+ discoveries = irlmp_get_discoveries(&number, self->mask);
+ /* Check if the we got some results */
+ if (discoveries == NULL)
+ DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
+
+ /*
+ * Now, check all discovered devices (if any), and connect
+ * client only about the services that the client is
+ * interested in...
+ */
+ for(i = 0; i < number; i++)
+ {
+ /* Try the address in the log */
+ self->daddr = discoveries[i].daddr;
+ self->saddr = 0x0;
+ DEBUG(IRDA_SR_INFO, "trying daddr = %08x\n", self->daddr);
+
+ /* Query remote LM-IAS for this service */
+ err = irnet_find_lsap_sel(self);
+ switch(err)
+ {
+ case 0:
+ /* We found the requested service */
+ if(daddr != DEV_ADDR_ANY)
+ {
+ DEBUG(IRDA_SR_INFO, "More than one device in range supports IrNET...\n");
+ }
+ else
+ {
+ /* First time we found that one, save it ! */
+ daddr = self->daddr;
+ dtsap_sel = self->dtsap_sel;
+ }
+ break;
+ case -EADDRNOTAVAIL:
+ /* Requested service simply doesn't exist on this node */
+ break;
+ default:
+ /* Something bad did happen :-( */
+ DERROR(IRDA_SR_ERROR, "unexpected IAS query failure\n");
+ self->daddr = DEV_ADDR_ANY;
+ kfree(discoveries);
+ return(-EHOSTUNREACH);
+ break;
+ }
+ }
+ /* Cleanup our copy of the discovery log */
+ kfree(discoveries);
+
+ /* Check out what we found */
+ if(daddr == DEV_ADDR_ANY)
+ {
+ self->daddr = DEV_ADDR_ANY;
+ DEXIT(IRDA_SR_INFO, "cannot discover IrNET in any device !!!\n");
+ return(-EADDRNOTAVAIL);
+ }
+
+ /* Revert back to discovered device & service */
+ self->daddr = daddr;
+ self->saddr = 0x0;
+ self->dtsap_sel = dtsap_sel;
+
+ DEBUG(IRDA_SR_INFO, "discovered IrNET at address %08x\n", self->daddr);
+ DEXIT(IRDA_SR_TRACE, "\n");
+
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_dname_to_daddr (self)
+ *
+ * Convert an IrDA nickname to a valid IrDA address
+ *
+ * It basically look into the discovery log until there is a match.
+ */
+static inline int
+irnet_dname_to_daddr(irnet_socket * self)
+{
+ struct irda_device_info *discoveries; /* Copy of the discovery log */
+ int number; /* Number of nodes in the log */
+ int i;
+
+ DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Ask lmp for the current discovery log */
+ discoveries = irlmp_get_discoveries(&number, 0xffff);
+ /* Check if the we got some results */
+ if(discoveries == NULL)
+ DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n");
+
+ /*
+ * Now, check all discovered devices (if any), and connect
+ * client only about the services that the client is
+ * interested in...
+ */
+ for(i = 0; i < number; i++)
+ {
+ /* Does the name match ? */
+ if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN))
+ {
+ /* Yes !!! Get it.. */
+ self->daddr = discoveries[i].daddr;
+ DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n",
+ self->rname, self->daddr);
+ kfree(discoveries);
+ DEXIT(IRDA_SR_TRACE, "\n");
+ return 0;
+ }
+ }
+ /* No luck ! */
+ DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname);
+ kfree(discoveries);
+ return(-EADDRNOTAVAIL);
+}
+
+
+/************************* SOCKET ROUTINES *************************/
+/*
+ * This are the main operations on IrNET sockets, basically to create
+ * and destroy IrNET sockets. These are called from the PPP part...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Create a IrNET instance : just initialise some parameters...
+ */
+int
+irda_irnet_create(irnet_socket * self)
+{
+ DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ self->magic = IRNET_MAGIC; /* Paranoia */
+
+ init_waitqueue_head(&self->query_wait);
+
+ self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */
+ self->rname[0] = '\0'; /* May be set via control channel */
+ self->raddr = DEV_ADDR_ANY; /* May be set via control channel */
+ self->daddr = DEV_ADDR_ANY; /* Until we get connected */
+ self->saddr = 0x0; /* so IrLMP assign us any link */
+ self->max_sdu_size_rx = TTP_SAR_UNBOUND;
+
+ /* Register as a client with IrLMP */
+ self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
+#ifdef DISCOVERY_NOMASK
+ self->mask = 0xffff; /* For W2k compatibility */
+#else DISCOVERY_NOMASK
+ self->mask = irlmp_service_to_hint(S_LAN);
+#endif DISCOVERY_NOMASK
+ self->tx_flow = FLOW_START; /* Flow control from IrTTP */
+
+ DEXIT(IRDA_SOCK_TRACE, "\n");
+ return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Connect to the other side :
+ * o convert device name to an address
+ * o find the socket number (dlsap)
+ * o Establish the connection
+ */
+int
+irda_irnet_connect(irnet_socket * self)
+{
+ int err;
+
+ DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Check if we have opened a local TSAP :
+ * If we have already opened a TSAP, it means that either we are already
+ * connected or in the process of doing so... */
+ if(self->tsap != NULL)
+ DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n");
+
+ /* Insert ourselves in the hashbin so that the IrNET server can find us.
+ * Notes : 4th arg is string of 32 char max and must be null terminated
+ * When 4th arg is used (string), 3rd arg isn't (int)
+ * Can't re-insert (MUST remove first) so check for that... */
+ if((irnet_server.running) && (self->q.q_next == NULL))
+ {
+ unsigned long flags;
+ spin_lock_irqsave(&irnet_server.spinlock, flags);
+ hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname);
+ spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname);
+ }
+
+ /* If we don't have anything (no address, no name) */
+ if((self->raddr == DEV_ADDR_ANY) && (self->rname[0] == '\0'))
+ {
+ /* Try to find a suitable address */
+ if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0)
+ DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n");
+ }
+ else
+ {
+ /* If we have only the name (no address), try to get an address */
+ if(self->raddr == DEV_ADDR_ANY)
+ {
+ if((err = irnet_dname_to_daddr(self)) != 0)
+ DRETURN(err, IRDA_SOCK_INFO, "name-connect failed!\n");
+ }
+ else
+ /* Use the requested destination address */
+ self->daddr = self->raddr;
+
+ /* Query remote LM-IAS to find LSAP selector */
+ if((err = irnet_find_lsap_sel(self)) != 0)
+ DRETURN(err, IRDA_SOCK_INFO, "connect failed!\n");
+ }
+ DEBUG(IRDA_SOCK_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n",
+ self->daddr, self->dtsap_sel);
+
+ /* Open a local TSAP (an IrTTP instance) */
+ err = irnet_open_tsap(self);
+ DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");
+
+ /* Connect to remote device */
+ err = irttp_connect_request(self->tsap, self->dtsap_sel,
+ self->saddr, self->daddr, NULL,
+ self->max_sdu_size_rx, NULL);
+ DABORT(err != 0, err, IRDA_SOCK_ERROR, "connect aborted!\n");
+
+ DEXIT(IRDA_SOCK_TRACE, "\n");
+ return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_irnet_destroy(self)
+ *
+ * Destroy irnet instance
+ *
+ */
+void
+irda_irnet_destroy(irnet_socket * self)
+{
+ DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ if(self == NULL)
+ return;
+
+ /* Remove ourselves from hashbin (if we are queued in hashbin)
+ * Note : `irnet_server.running' protect us from calls in hashbin_delete() */
+ if((irnet_server.running) && (self->q.q_next != NULL))
+ {
+ struct irnet_socket * entry;
+ unsigned long flags;
+ DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n");
+ spin_lock_irqsave(&irnet_server.spinlock, flags);
+ entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self);
+ self->q.q_next = NULL;
+ spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+ DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n");
+ }
+
+ /* Unregister with IrLMP */
+ irlmp_unregister_client(self->ckey);
+
+ /* Unregister with LM-IAS */
+ if(self->iriap)
+ iriap_close(self->iriap);
+
+ /* Prevent higher layer from accessing IrTTP */
+ self->ttp_open = 0;
+
+ /* Close our IrTTP connection */
+ if(self->tsap)
+ {
+ DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n");
+ irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+ irttp_close_tsap(self->tsap);
+ self->tsap = NULL;
+ /* Note : as the disconnect comes from ppp_generic, the unit number
+ * doesn't exist anymore when we post the event, so we need to pass
+ * NULL as the first arg... */
+ irnet_post_event(NULL, IRNET_DISCONNECT_TO, self->daddr, self->rname);
+ }
+ self->stsap_sel = 0;
+
+ DEXIT(IRDA_SOCK_TRACE, "\n");
+ return;
+}
+
+
+/************************** SERVER SOCKET **************************/
+/*
+ * The IrNET service is composed of one server socket and a variable
+ * number of regular IrNET sockets. The server socket is supposed to
+ * handle incomming connections and redirect them to one IrNET sockets.
+ * It's a superset of the regular IrNET socket, but has a very distinct
+ * behaviour...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_daddr_to_dname (self)
+ *
+ * Convert an IrDA address to a IrDA nickname
+ *
+ * It basically look into the discovery log until there is a match.
+ */
+static inline int
+irnet_daddr_to_dname(irnet_socket * self)
+{
+ struct irda_device_info *discoveries; /* Copy of the discovery log */
+ int number; /* Number of nodes in the log */
+ int i;
+
+ DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Ask lmp for the current discovery log */
+ discoveries = irlmp_get_discoveries(&number, 0xffff);
+ /* Check if the we got some results */
+ if (discoveries == NULL)
+ DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n");
+
+ /* Now, check all discovered devices (if any) */
+ for(i = 0; i < number; i++)
+ {
+ /* Does the name match ? */
+ if(discoveries[i].daddr == self->daddr)
+ {
+ /* Yes !!! Get it.. */
+ strncpy(self->rname, discoveries[i].info, NICKNAME_MAX_LEN);
+ self->rname[NICKNAME_MAX_LEN + 1] = '\0';
+ DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n",
+ self->daddr, self->rname);
+ kfree(discoveries);
+ DEXIT(IRDA_SERV_TRACE, "\n");
+ return 0;
+ }
+ }
+ /* No luck ! */
+ DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr);
+ kfree(discoveries);
+ return(-EADDRNOTAVAIL);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_find_socket (self)
+ *
+ * Find the correct IrNET socket
+ *
+ * Look into the list of IrNET sockets and finds one with the right
+ * properties...
+ */
+static inline irnet_socket *
+irnet_find_socket(irnet_socket * self)
+{
+ irnet_socket * new = (irnet_socket *) NULL;
+ unsigned long flags;
+ int err;
+
+ DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Get the address of the requester */
+ self->daddr = irttp_get_daddr(self->tsap);
+
+ /* Try to get the IrDA nickname of the requester */
+ err = irnet_daddr_to_dname(self);
+
+ /* Protect access to the instance list */
+ spin_lock_irqsave(&irnet_server.spinlock, flags);
+
+ /* So now, try to get an socket having specifically
+ * requested that nickname */
+ if(err == 0)
+ {
+ new = (irnet_socket *) hashbin_find(irnet_server.list,
+ 0, self->rname);
+ if(new)
+ DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches rname ``%s''.\n",
+ (unsigned int) new, new->rname);
+ }
+
+ /* If no name matches, try to find an socket by the destination address */
+ /* It can be either the requested destination address (set via the
+ * control channel), or the current destination address if the
+ * socket is in the middle of a connection request */
+ if(new == (irnet_socket *) NULL)
+ {
+ new = (irnet_socket *) hashbin_get_first(irnet_server.list);
+ while(new !=(irnet_socket *) NULL)
+ {
+ /* Does it have the same address ? */
+ if((new->raddr == self->daddr) || (new->daddr == self->daddr))
+ {
+ /* Yes !!! Get it.. */
+ DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches daddr %#08x.\n",
+ (unsigned int) new, self->daddr);
+ break;
+ }
+ new = (irnet_socket *) hashbin_get_next(irnet_server.list);
+ }
+ }
+
+ /* If we don't have any socket, get the first unconnected socket */
+ if(new == (irnet_socket *) NULL)
+ {
+ new = (irnet_socket *) hashbin_get_first(irnet_server.list);
+ while(new !=(irnet_socket *) NULL)
+ {
+ /* Is it available ? */
+ if(!(new->ttp_open) && (new->raddr == DEV_ADDR_ANY) &&
+ (new->rname[0] == '\0') && (new->ppp_open))
+ {
+ /* Yes !!! Get it.. */
+ DEBUG(IRDA_SERV_INFO, "Socket 0x%X is free.\n",
+ (unsigned int) new);
+ break;
+ }
+ new = (irnet_socket *) hashbin_get_next(irnet_server.list);
+ }
+ }
+
+ /* Spin lock end */
+ spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+
+ DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new);
+ return new;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_connect_socket (self)
+ *
+ * Connect an incomming connection to the socket
+ *
+ */
+static inline int
+irnet_connect_socket(irnet_socket * self,
+ irnet_socket * new,
+ struct qos_info * qos,
+ __u32 max_sdu_size,
+ __u8 max_header_size)
+{
+ DENTER(IRDA_SERV_TRACE, "(self=0x%X, new=0x%X)\n",
+ (unsigned int) self, (unsigned int) new);
+
+ /* Now attach up the new socket */
+ new->tsap = irttp_dup(self->tsap, new);
+ DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n");
+
+ /* Set up all the relevant parameters on the new socket */
+ new->stsap_sel = new->tsap->stsap_sel;
+ new->dtsap_sel = new->tsap->dtsap_sel;
+ new->saddr = irttp_get_saddr(new->tsap);
+ new->daddr = irttp_get_daddr(new->tsap);
+
+ new->max_header_size = max_header_size;
+ new->max_sdu_size_tx = max_sdu_size;
+ new->max_data_size = max_sdu_size;
+#ifdef STREAM_COMPAT
+ /* If we want to receive "stream sockets" */
+ if(max_sdu_size == 0)
+ new->max_data_size = irttp_get_max_seg_size(new->tsap);
+#endif STREAM_COMPAT
+
+ /* Clean up the original one to keep it in listen state */
+ self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
+ self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+
+ /* Send a connection response on the new socket */
+ irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL);
+
+ /* Allow PPP to send its junk over the new socket... */
+ new->ttp_open = 1;
+#ifdef CONNECT_INDIC_KICK
+ /* As currently we don't packets in ppp_irnet_send(), this is not needed...
+ * Also, not doing it give IrDA a chance to finish the setup properly
+ * before beeing swamped with packets... */
+ ppp_output_wakeup(&new->chan);
+#endif CONNECT_INDIC_KICK
+
+ /* Notify the control channel */
+ irnet_post_event(new, IRNET_CONNECT_FROM, new->daddr, self->rname);
+
+ DEXIT(IRDA_SERV_TRACE, "\n");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_disconnect_server (self)
+ *
+ * Cleanup the server socket when the incomming connection abort
+ *
+ */
+static inline void
+irnet_disconnect_server(irnet_socket * self,
+ struct sk_buff *skb)
+{
+ DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* Put the received packet in the black hole */
+ kfree_skb(skb);
+
+#ifdef FAIL_SEND_DISCONNECT
+ /* Tell the other party we don't want to be connected */
+ /* Hum... Is it the right thing to do ? And do we need to send
+ * a connect response before ? It looks ok without this... */
+ irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+#endif FAIL_SEND_DISCONNECT
+
+ /* Clean up the server to keep it in listen state */
+ self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
+ self->tsap->lsap->lsap_state = LSAP_DISCONNECTED;
+
+ /* Notify the control channel */
+ irnet_post_event(NULL, IRNET_REQUEST_FROM, self->daddr, self->rname);
+
+ DEXIT(IRDA_SERV_TRACE, "\n");
+ return;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_setup_server (self)
+ *
+ * Create a IrTTP server and set it up...
+ *
+ * Register the IrLAN hint bit, create a IrTTP instance for us,
+ * set all the IrTTP callbacks and create an IrIAS entry...
+ */
+static inline int
+irnet_setup_server(void)
+{
+ __u16 hints;
+
+ DENTER(IRDA_SERV_TRACE, "()\n");
+
+ /* Initialise the regular socket part of the server */
+ irda_irnet_create(&irnet_server.s);
+
+ /* Open a local TSAP (an IrTTP instance) for the server */
+ irnet_open_tsap(&irnet_server.s);
+
+ /* PPP part setup */
+ irnet_server.s.ppp_open = 0;
+ irnet_server.s.chan.private = NULL;
+ irnet_server.s.file = NULL;
+
+ /* Get the hint bit corresponding to IrLAN */
+ /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as
+ * we provide roughly the same functionality as IrLAN, this is ok.
+ * In fact, the situation is similar as JetSend overloading the Obex hint
+ */
+ hints = irlmp_service_to_hint(S_LAN);
+
+#ifdef ADVERTISE_HINT
+ /* Register with IrLMP as a service (advertise our hint bit) */
+ irnet_server.skey = irlmp_register_service(hints);
+#endif ADVERTISE_HINT
+
+ /* Register with LM-IAS (so that people can connect to us) */
+ irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies);
+ irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE,
+ irnet_server.s.stsap_sel, IAS_KERNEL_ATTR);
+ irias_insert_object(irnet_server.ias_obj);
+
+#ifdef DISCOVERY_EVENTS
+ /* Tell IrLMP we want to be notified of newly discovered nodes */
+ irlmp_update_client(irnet_server.s.ckey, hints,
+ irnet_discovery_indication, irnet_expiry_indication,
+ (void *) &irnet_server.s);
+#endif
+
+ DEXIT(IRDA_SERV_TRACE, " - self=0x%X\n", (unsigned int) &irnet_server.s);
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_destroy_server (self)
+ *
+ * Destroy the IrTTP server...
+ *
+ * Reverse of the previous function...
+ */
+static inline void
+irnet_destroy_server(void)
+{
+ DENTER(IRDA_SERV_TRACE, "()\n");
+
+#ifdef ADVERTISE_HINT
+ /* Unregister with IrLMP */
+ irlmp_unregister_service(irnet_server.skey);
+#endif ADVERTISE_HINT
+
+ /* Unregister with LM-IAS */
+ if(irnet_server.ias_obj)
+ irias_delete_object(irnet_server.ias_obj);
+
+ /* Cleanup the socket part */
+ irda_irnet_destroy(&irnet_server.s);
+
+ DEXIT(IRDA_SERV_TRACE, "\n");
+ return;
+}
+
+
+/************************ IRDA-TTP CALLBACKS ************************/
+/*
+ * When we create a IrTTP instance, we pass to it a set of callbacks
+ * that IrTTP will call in case of various events.
+ * We take care of those events here.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_data_indication (instance, sap, skb)
+ *
+ * Received some data from TinyTP. Just queue it on the receive queue
+ *
+ */
+static int
+irnet_data_indication(void * instance,
+ void * sap,
+ struct sk_buff *skb)
+{
+ irnet_socket * ap = (irnet_socket *) instance;
+ unsigned char * p;
+ int code = 0;
+
+ DENTER(IRDA_TCB_TRACE, "(self/ap=0x%X, skb=0x%X)\n",
+ (unsigned int) ap,(unsigned int) skb);
+ DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n");
+
+ /* Check is ppp is ready to receive our packet */
+ if(!ap->ppp_open)
+ {
+ DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n");
+ /* When we return error, TTP will need to requeue the skb and
+ * will stop the sender. IrTTP will stall until we send it a
+ * flow control request... */
+ return -ENOMEM;
+ }
+
+ /* strip address/control field if present */
+ p = skb->data;
+ if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI))
+ {
+ /* chop off address/control */
+ if(skb->len < 3)
+ goto err_exit;
+ p = skb_pull(skb, 2);
+ }
+
+ /* decompress protocol field if compressed */
+ if(p[0] & 1)
+ {
+ /* protocol is compressed */
+ skb_push(skb, 1)[0] = 0;
+ }
+ else
+ if(skb->len < 2)
+ goto err_exit;
+
+ /* pass to generic ppp layer */
+ /* Note : how do I know if ppp can accept or not the packet ? This is
+ * essential if I want to manage flow control smoothly... */
+ ppp_input(&ap->chan, skb);
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+ return 0;
+
+ err_exit:
+ DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n");
+ kfree_skb(skb);
+ ppp_input_error(&ap->chan, code);
+ return 0; /* Don't return an error code, only for flow control... */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_disconnect_indication (instance, sap, reason, skb)
+ *
+ * Connection has been closed. Chech reason to find out why
+ *
+ * Note : there are many cases where we come here :
+ * o attempted to connect, timeout
+ * o connected, link is broken, LAP has timeout
+ * o connected, other side close the link
+ * o connection request on the server no handled
+ */
+static void
+irnet_disconnect_indication(void * instance,
+ void * sap,
+ LM_REASON reason,
+ struct sk_buff *skb)
+{
+ irnet_socket * self = (irnet_socket *) instance;
+
+ DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
+
+ /* If we were active, notify the control channel */
+ if(self->ttp_open)
+ irnet_post_event(self, IRNET_DISCONNECT_FROM, self->daddr, self->rname);
+ else
+ /* If we were trying to connect, notify the control channel */
+ if((self->tsap) && (self != &irnet_server.s))
+ irnet_post_event(self, IRNET_NOANSWER_FROM, self->daddr, self->rname);
+
+ /* Prevent higher layer from accessing IrTTP */
+ self->ttp_open = 0;
+
+ /* Close our IrTTP connection */
+ if((self->tsap) && (self != &irnet_server.s))
+ {
+ DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n");
+ irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+ irttp_close_tsap(self->tsap);
+ self->tsap = NULL;
+
+ /* Flush (drain) ppp_generic Tx queue (most often we have blocked it) */
+ if(self->ppp_open)
+ ppp_output_wakeup(&self->chan);
+ }
+ /* Cleanup the socket in case we want to reconnect */
+ self->stsap_sel = 0;
+ self->daddr = DEV_ADDR_ANY;
+ self->tx_flow = FLOW_START;
+
+ /* Note : what should we say to ppp ?
+ * It seem the ppp_generic and pppd are happy that way and will eventually
+ * timeout gracefully, so don't bother them... */
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb)
+ *
+ * Connections has been confirmed by the remote device
+ *
+ */
+static void
+irnet_connect_confirm(void * instance,
+ void * sap,
+ struct qos_info *qos,
+ __u32 max_sdu_size,
+ __u8 max_header_size,
+ struct sk_buff *skb)
+{
+ irnet_socket * self = (irnet_socket *) instance;
+
+ DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+
+ /* How much header space do we need to reserve */
+ self->max_header_size = max_header_size;
+
+ /* IrTTP max SDU size in transmit direction */
+ self->max_sdu_size_tx = max_sdu_size;
+ self->max_data_size = max_sdu_size;
+#ifdef STREAM_COMPAT
+ if(max_sdu_size == 0)
+ self->max_data_size = irttp_get_max_seg_size(self->tsap);
+#endif STREAM_COMPAT
+
+ /* At this point, IrLMP has assigned our source address */
+ self->saddr = irttp_get_saddr(self->tsap);
+
+ /* Allow higher layer to access IrTTP */
+ self->ttp_open = 1;
+ /* Give a kick in the ass of ppp_generic so that he sends us some data */
+ ppp_output_wakeup(&self->chan);
+
+ /* Check size of received packet */
+ if(skb->len > 0)
+ {
+#ifdef PASS_CONNECT_PACKETS
+ DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
+ /* Try to pass it to PPP */
+ irnet_data_indication(instance, sap, skb);
+#else PASS_CONNECT_PACKETS
+ DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
+ kfree_skb(skb); /* Note : will be optimised with other kfree... */
+#endif PASS_CONNECT_PACKETS
+ }
+ else
+ kfree_skb(skb);
+
+ /* Notify the control channel */
+ irnet_post_event(self, IRNET_CONNECT_TO, self->daddr, self->rname);
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_flow_indication (instance, sap, flow)
+ *
+ * Used by TinyTP to tell us if it can accept more data or not
+ *
+ */
+static void
+irnet_flow_indication(void * instance,
+ void * sap,
+ LOCAL_FLOW flow)
+{
+ irnet_socket * self = (irnet_socket *) instance;
+
+ DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow);
+
+ /* Update our state */
+ self->tx_flow = flow;
+
+ /* Check what IrTTP want us to do... */
+ switch(flow)
+ {
+ case FLOW_START:
+ DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n");
+ ppp_output_wakeup(&self->chan);
+ break;
+ case FLOW_STOP:
+ DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n");
+ break;
+ default:
+ DEBUG(IRDA_CB_INFO, "Unknown flow command!\n");
+ break;
+ }
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_status_indication (instance, sap, reason, skb)
+ *
+ * Link (IrLAP) status report.
+ *
+ */
+static void
+irnet_status_indication(void * instance,
+ LINK_STATUS link,
+ LOCK_STATUS lock)
+{
+ irnet_socket * self = (irnet_socket *) instance;
+
+ DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
+
+ /* We can only get this event if we are connected */
+ switch(link)
+ {
+ case STATUS_NO_ACTIVITY:
+ irnet_post_event(self, IRNET_BLOCKED_LINK, self->daddr, self->rname);
+ break;
+ default:
+ DEBUG(IRDA_CB_INFO, "Unknown status...\n");
+ }
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata)
+ *
+ * Incomming connection
+ *
+ * In theory, this function is called only on the server socket.
+ * Some other node is attempting to connect to the IrNET service, and has
+ * sent a connection request on our server socket.
+ * We just redirect the connection to the relevant IrNET socket.
+ *
+ * Note : we also make sure that between 2 irnet nodes, there can
+ * exist only one irnet connection.
+ */
+static void
+irnet_connect_indication(void * instance,
+ void * sap,
+ struct qos_info *qos,
+ __u32 max_sdu_size,
+ __u8 max_header_size,
+ struct sk_buff *skb)
+{
+ irnet_socket * self = &irnet_server.s;
+ irnet_socket * new = (irnet_socket *) NULL;
+
+ DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(instance == &irnet_server, , IRDA_CB_ERROR,
+ "Invalid instance (0x%X) !!!\n", (unsigned int) instance);
+ DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n");
+
+ /* Try to find the most appropriate IrNET socket */
+ new = irnet_find_socket(self);
+
+ /* After all this hard work, do we have an socket ? */
+ if(new == (irnet_socket *) NULL)
+ {
+ DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n");
+ irnet_disconnect_server(self, skb);
+ return;
+ }
+
+ /* Is the socket already busy ? */
+ if(new->ttp_open)
+ {
+ DEXIT(IRDA_CB_INFO, ": Socket already connected.\n");
+ irnet_disconnect_server(self, skb);
+ return;
+ }
+
+ /* Socket connecting */
+ if(new->tsap != NULL)
+ {
+ /* The socket has sent a IrTTP connection request and is waiting for
+ * a connection response (that may never come).
+ * Now, the pain is that the socket has open a tsap and is waiting on it,
+ * while the other end is trying to connect to it on another tsap.
+ * Argh ! We will deal with that later...
+ */
+ DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
+#ifdef ALLOW_SIMULT_CONNECT
+ /* Close the connection the new socket was attempting.
+ * WARNING : This need more testing ! */
+ irttp_close_tsap(new->tsap);
+ /* Note : no return, fall through... */
+#else ALLOW_SIMULT_CONNECT
+ irnet_disconnect_server(self, skb);
+ return;
+#endif ALLOW_SIMULT_CONNECT
+ }
+
+ /* So : at this point, we have a socket, and it is idle. Good ! */
+ irnet_connect_socket(self, new, qos, max_sdu_size, max_header_size);
+
+ /* Check size of received packet */
+ if(skb->len > 0)
+ {
+#ifdef PASS_CONNECT_PACKETS
+ DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
+ /* Try to pass it to PPP */
+ irnet_data_indication(new, new->tsap, skb);
+#else PASS_CONNECT_PACKETS
+ DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
+ kfree_skb(skb); /* Note : will be optimised with other kfree... */
+#endif PASS_CONNECT_PACKETS
+ }
+ else
+ kfree_skb(skb);
+
+ DEXIT(IRDA_TCB_TRACE, "\n");
+}
+
+
+/********************** IRDA-IAS/LMP CALLBACKS **********************/
+/*
+ * These are the callbacks called by other layers of the IrDA stack,
+ * mainly LMP for discovery and IAS for name queries.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_getvalue_confirm (obj_id, value, priv)
+ *
+ * Got answer from remote LM-IAS, just pass object to requester...
+ *
+ */
+static void
+irnet_getvalue_confirm(int result,
+ __u16 obj_id,
+ struct ias_value *value,
+ void * priv)
+{
+ irnet_socket * self = (irnet_socket *) priv;
+
+ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n");
+
+ /* We probably don't need to make any more queries */
+ iriap_close(self->iriap);
+ self->iriap = NULL;
+
+ /* Check if request succeeded */
+ if(result != IAS_SUCCESS)
+ {
+ DEBUG(IRDA_CB_INFO, "IAS query failed! (%d)\n", result);
+ self->errno = result; /* We really need it later */
+ }
+ else
+ {
+ /* Pass the object to the caller (so the caller must delete it) */
+ self->ias_result = value;
+ self->errno = 0;
+ }
+
+ /* Wake up any processes waiting for result */
+ wake_up_interruptible(&self->query_wait);
+
+ DEXIT(IRDA_OCB_TRACE, "\n");
+}
+
+#ifdef DISCOVERY_EVENTS
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_discovery_indication (discovery)
+ *
+ * Got a discovery indication from IrLMP, post an event
+ *
+ * Note : IrLMP take care of matching the hint mask for us, we only
+ * check if it is a "new" node...
+ *
+ * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET
+ * nodes, so it's only at connection time that we will know if the
+ * node support IrNET, IrLAN or both. The other solution is to check
+ * in IAS the PNP ids and service name.
+ * Note : even if a node support IrNET (or IrLAN), it's no guarantee
+ * that we will be able to connect to it, the node might already be
+ * busy...
+ *
+ * One last thing : in some case, this function will trigger duplicate
+ * discovery events. On the other hand, we should catch all
+ * discoveries properly (i.e. not miss one). Filtering duplicate here
+ * is to messy, so we leave that to user space...
+ */
+static void
+irnet_discovery_indication(discovery_t *discovery,
+ void * priv)
+{
+ irnet_socket * self = &irnet_server.s;
+
+ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,
+ "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
+
+ /* Check if node is discovered is a new one or an old one.
+ * We check when how long ago this node was discovered, with a
+ * coarse timeout (we may miss some discovery events or be delayed).
+ */
+ if((jiffies - discovery->first_timestamp) >= (sysctl_discovery_timeout * HZ))
+ {
+ return; /* Too old, not interesting -> goodbye */
+ }
+
+ DEBUG(IRDA_CB_INFO, "Discovered new IrNET/IrLAN node %s...\n",
+ discovery->nickname);
+
+ /* Notify the control channel */
+ irnet_post_event(NULL, IRNET_DISCOVER, discovery->daddr,
+ discovery->nickname);
+
+ DEXIT(IRDA_OCB_TRACE, "\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_expiry_indication (expiry)
+ *
+ * Got a expiry indication from IrLMP, post an event
+ *
+ * Note : IrLMP take care of matching the hint mask for us, we only
+ * check if it is a "new" node...
+ */
+static void
+irnet_expiry_indication(discovery_t * expiry,
+ void * priv)
+{
+ irnet_socket * self = &irnet_server.s;
+
+ DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self);
+ DASSERT(priv == &irnet_server, , IRDA_CB_ERROR,
+ "Invalid instance (0x%X) !!!\n", (unsigned int) priv);
+
+ DEBUG(IRDA_CB_INFO, "IrNET/IrLAN node %s expired...\n",
+ expiry->nickname);
+
+ /* Notify the control channel */
+ irnet_post_event(NULL, IRNET_EXPIRE, expiry->daddr,
+ expiry->nickname);
+
+ DEXIT(IRDA_OCB_TRACE, "\n");
+}
+#endif DISCOVERY_EVENTS
+
+
+/*********************** PROC ENTRY CALLBACKS ***********************/
+/*
+ * We create a instance in the /proc filesystem, and here we take care
+ * of that...
+ */
+
+#ifdef CONFIG_PROC_FS
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_proc_read (buf, start, offset, len, unused)
+ *
+ * Give some info to the /proc file system
+ */
+static int
+irnet_proc_read(char * buf,
+ char ** start,
+ off_t offset,
+ int len)
+{
+ irnet_socket * self;
+ char * state;
+ unsigned long flags;
+ int i = 0;
+
+ len = 0;
+
+ /* Get the IrNET server information... */
+ len += sprintf(buf+len, "IrNET server - ");
+ len += sprintf(buf+len, "IrDA state: %s, ",
+ (irnet_server.running ? "running" : "dead"));
+ len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);
+ len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);
+
+ /* Do we need to continue ? */
+ if(!irnet_server.running)
+ return len;
+
+ /* Protect access to the instance list */
+ spin_lock_irqsave(&irnet_server.spinlock, flags);
+
+ /* Get the sockets one by one... */
+ self = (irnet_socket *) hashbin_get_first(irnet_server.list);
+ while(self != NULL)
+ {
+ /* Start printing info about the socket. */
+ len += sprintf(buf+len, "\nIrNET socket %d - ", i++);
+
+ /* First, get the requested configuration */
+ len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname);
+ len += sprintf(buf+len, "addr: %08x\n", self->raddr);
+
+ /* Second, get all the PPP info */
+ len += sprintf(buf+len, " PPP state: %s",
+ (self->ppp_open ? "registered" : "unregistered"));
+ if(self->ppp_open)
+ {
+ len += sprintf(buf+len, ", unit: ppp%d",
+ ppp_unit_number(&self->chan));
+ len += sprintf(buf+len, ", channel: %d",
+ ppp_channel_index(&self->chan));
+ len += sprintf(buf+len, ", mru: %d",
+ self->mru);
+ /* Maybe add self->flags ? Later... */
+ }
+
+ /* Then, get all the IrDA specific info... */
+ if(self->ttp_open)
+ state = "connected";
+ else
+ if(self->tsap != NULL)
+ state = "connecting";
+ else
+ state = "idle";
+ len += sprintf(buf+len, "\n IrDA state: %s, ", state);
+ len += sprintf(buf+len, "daddr: %08x, ", self->daddr);
+ len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel);
+ len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel);
+
+ /* Next socket, please... */
+ self = (irnet_socket *) hashbin_get_next(irnet_server.list);
+ }
+
+ /* Spin lock end */
+ spin_unlock_irqrestore(&irnet_server.spinlock, flags);
+
+ return len;
+}
+#endif /* PROC_FS */
+
+
+/********************** CONFIGURATION/CLEANUP **********************/
+/*
+ * Initialisation and teardown of the IrDA part, called at module
+ * insertion and removal...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare the IrNET layer for operation...
+ */
+int
+irda_irnet_init(void)
+{
+ int err = 0;
+
+ DENTER(MODULE_TRACE, "()\n");
+
+ /* Pure paranoia - should be redundant */
+ memset(&irnet_server, 0, sizeof(struct irnet_root));
+
+ /* Setup start of irnet instance list */
+ irnet_server.list = hashbin_new(HB_LOCAL);
+ DABORT(irnet_server.list == NULL, -ENOMEM,
+ MODULE_ERROR, "Can't allocate hashbin!\n");
+ /* Init spinlock for instance list */
+ spin_lock_init(&irnet_server.spinlock);
+
+ /* Initialise control channel */
+ init_waitqueue_head(&irnet_events.rwait);
+ irnet_events.index = 0;
+ /* Init spinlock for event logging */
+ spin_lock_init(&irnet_events.spinlock);
+
+#ifdef CONFIG_PROC_FS
+ /* Add a /proc file for irnet infos */
+ create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read);
+#endif /* CONFIG_PROC_FS */
+
+ /* Setup the IrNET server */
+ err = irnet_setup_server();
+
+ if(!err)
+ /* We are no longer functional... */
+ irnet_server.running = 1;
+
+ DEXIT(MODULE_TRACE, "\n");
+ return err;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Cleanup at exit...
+ */
+void
+irda_irnet_cleanup(void)
+{
+ DENTER(MODULE_TRACE, "()\n");
+
+ /* We are no longer there... */
+ irnet_server.running = 0;
+
+#ifdef CONFIG_PROC_FS
+ /* Remove our /proc file */
+ remove_proc_entry("irnet", proc_irda);
+#endif CONFIG_PROC_FS
+
+ /* Remove our IrNET server from existence */
+ irnet_destroy_server();
+
+ /* Remove all instances of IrNET socket still present */
+ hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy);
+
+ DEXIT(MODULE_TRACE, "\n");
+}
diff --git a/net/irda/irnet/irnet_irda.h b/net/irda/irnet/irnet_irda.h
new file mode 100644
index 000000000..0e5e9a36f
--- /dev/null
+++ b/net/irda/irnet/irnet_irda.h
@@ -0,0 +1,169 @@
+/*
+ * IrNET protocol module : Synchronous PPP over an IrDA socket.
+ *
+ * Jean II - HPL `00 - <jt@hpl.hp.com>
+ *
+ * This file contains all definitions and declarations necessary for the
+ * IRDA part of the IrNET module (dealing with IrTTP, IrIAS and co).
+ * This file is a private header, so other modules don't want to know
+ * what's in there...
+ */
+
+#ifndef IRNET_IRDA_H
+#define IRNET_IRDA_H
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/config.h>
+#include "irnet.h" /* Module global include */
+
+/************************ CONSTANTS & MACROS ************************/
+
+/*
+ * Name of the service (socket name) used by IrNET
+ */
+/* IAS object name (or part of it) */
+#define IRNET_SERVICE_NAME "IrNetv1"
+/* IAS attribute */
+#define IRNET_IAS_VALUE "IrDA:TinyTP:LsapSel"
+/* LMP notify name for client (only for /proc/net/irda/irlmp) */
+#define IRNET_NOTIFY_NAME "IrNET socket"
+/* LMP notify name for server (only for /proc/net/irda/irlmp) */
+#define IRNET_NOTIFY_NAME_SERV "IrNET server"
+
+/****************************** TYPES ******************************/
+
+/*
+ * This is the main structure where we store all the data pertaining to
+ * the IrNET server (listen for connection requests) and the root
+ * of the IrNET socket list
+ */
+typedef struct irnet_root
+{
+ irnet_socket s; /* To pretend we are a client... */
+
+ /* Generic stuff */
+ int magic; /* Paranoia */
+ int running; /* Are we operational ? */
+
+ /* Link list of all IrNET instances opened */
+ hashbin_t * list;
+ spinlock_t spinlock; /* Serialize access to the list */
+ /* Note : the way hashbin has been designed is absolutely not
+ * reentrant, beware... So, we blindly protect all with spinlock */
+
+ /* Handle for the hint bit advertised in IrLMP */
+ __u32 skey;
+
+ /* Server socket part */
+ struct ias_object * ias_obj; /* Our service name + lsap in IAS */
+
+} irnet_root;
+
+
+/**************************** PROTOTYPES ****************************/
+
+/* ----------------------- CONTROL CHANNEL ----------------------- */
+static void
+ irnet_post_event(irnet_socket *,
+ irnet_event,
+ __u32,
+ char *);
+/* ----------------------- IRDA SUBROUTINES ----------------------- */
+static inline int
+ irnet_open_tsap(irnet_socket *);
+static int
+ irnet_find_lsap_sel(irnet_socket *);
+static inline int
+ irnet_discover_daddr_and_lsap_sel(irnet_socket *);
+static inline int
+ irnet_dname_to_daddr(irnet_socket *);
+/* ------------------------ SERVER SOCKET ------------------------ */
+static inline int
+ irnet_daddr_to_dname(irnet_socket *);
+static inline irnet_socket *
+ irnet_find_socket(irnet_socket *);
+static inline int
+ irnet_connect_socket(irnet_socket *,
+ irnet_socket *,
+ struct qos_info *,
+ __u32,
+ __u8);
+static inline void
+ irnet_disconnect_server(irnet_socket *,
+ struct sk_buff *);
+static inline int
+ irnet_setup_server(void);
+static inline void
+ irnet_destroy_server(void);
+/* ---------------------- IRDA-TTP CALLBACKS ---------------------- */
+static int
+ irnet_data_indication(void *, /* instance */
+ void *, /* sap */
+ struct sk_buff *);
+static void
+ irnet_disconnect_indication(void *,
+ void *,
+ LM_REASON,
+ struct sk_buff *);
+static void
+ irnet_connect_confirm(void *,
+ void *,
+ struct qos_info *,
+ __u32,
+ __u8,
+ struct sk_buff *);
+static void
+ irnet_flow_indication(void *,
+ void *,
+ LOCAL_FLOW);
+static void
+ irnet_status_indication(void *,
+ LINK_STATUS,
+ LOCK_STATUS);
+static void
+ irnet_connect_indication(void *,
+ void *,
+ struct qos_info *,
+ __u32,
+ __u8,
+ struct sk_buff *);
+/* -------------------- IRDA-IAS/LMP CALLBACKS -------------------- */
+static void
+ irnet_getvalue_confirm(int,
+ __u16,
+ struct ias_value *,
+ void *);
+#ifdef DISCOVERY_EVENTS
+static void
+ irnet_discovery_indication(discovery_t *,
+ void *);
+static void
+ irnet_expiry_indication(discovery_t *,
+ void *);
+#endif
+/* -------------------------- PROC ENTRY -------------------------- */
+#ifdef CONFIG_PROC_FS
+static int
+ irnet_proc_read(char *,
+ char **,
+ off_t,
+ int);
+#endif CONFIG_PROC_FS
+
+/**************************** VARIABLES ****************************/
+
+/*
+ * The IrNET server. Listen to connection requests and co...
+ */
+static struct irnet_root irnet_server;
+
+/* Control channel stuff (note : extern) */
+struct irnet_ctrl_channel irnet_events;
+
+/* The /proc/net/irda directory, defined elsewhere... */
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_irda;
+#endif CONFIG_PROC_FS
+
+#endif IRNET_IRDA_H
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
new file mode 100644
index 000000000..96a5c4114
--- /dev/null
+++ b/net/irda/irnet/irnet_ppp.c
@@ -0,0 +1,1052 @@
+/*
+ * IrNET protocol module : Synchronous PPP over an IrDA socket.
+ *
+ * Jean II - HPL `00 - <jt@hpl.hp.com>
+ *
+ * This file implement the PPP interface and /dev/irnet character device.
+ * The PPP interface hook to the ppp_generic module, handle all our
+ * relationship to the PPP code in the kernel (and by extension to pppd),
+ * and exchange PPP frames with this module (send/receive).
+ * The /dev/irnet device is used primarily for 2 functions :
+ * 1) as a stub for pppd (the ppp daemon), so that we can appropriately
+ * generate PPP sessions (we pretend we are a tty).
+ * 2) as a control channel (write commands, read events)
+ */
+
+#include "irnet_ppp.h" /* Private header */
+
+/************************* CONTROL CHANNEL *************************/
+/*
+ * When a pppd instance is not active on /dev/irnet, it acts as a control
+ * channel.
+ * Writting allow to set up the IrDA destination of the IrNET channel,
+ * and any application may be read events happening in IrNET...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write is used to send a command to configure a IrNET channel
+ * before it is open by pppd. The syntax is : "command argument"
+ * Currently there is only two defined commands :
+ * o name : set the requested IrDA nickname of the IrNET peer.
+ * o addr : set the requested IrDA address of the IrNET peer.
+ * Note : the code is crude, but effective...
+ */
+static inline ssize_t
+irnet_ctrl_write(irnet_socket * ap,
+ const char * buf,
+ size_t count)
+{
+ char command[5 + NICKNAME_MAX_LEN + 2];
+ int length = count;
+
+ DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count);
+
+ /* Check for overflow... */
+ DABORT(count > (5 + NICKNAME_MAX_LEN + 1), -ENOMEM,
+ CTRL_ERROR, "Too much data !!!\n");
+
+ /* Get the data in the driver */
+ if(copy_from_user(command, buf, count))
+ {
+ DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
+ return -EFAULT;
+ }
+
+ /* Strip out '\n' if needed, and safe terminate the string */
+ if(command[length - 1] == '\0')
+ length--;
+ if(command[length - 1] == '\n')
+ length--;
+ command[length] = '\0';
+ DEBUG(CTRL_INFO, "Command received is ``%s'' (%d-%d).\n",
+ command, length, count);
+
+ /* Check if we recognised the command */
+ /* First command : name */
+ if(!strncmp(command, "name", 4))
+ {
+ /* Copy the name only if is included and not "any" */
+ if((length > 5) && (strcmp(command + 5, "any")))
+ {
+ /* Copy the name for later reuse (including the '/0') */
+ memcpy(ap->rname, command + 5, length - 5 + 1);
+ }
+ else
+ ap->rname[0] = '\0';
+ DEXIT(CTRL_TRACE, " - rname = ``%s''\n", ap->rname);
+ return(count);
+ }
+
+ /* Second command : addr */
+ if(!strncmp(command, "addr", 4))
+ {
+ /* Copy the address only if is included and not "any" */
+ if((length > 5) && (strcmp(command + 5, "any")))
+ {
+ char * endp;
+ __u32 daddr;
+
+ /* Convert argument to a number (last arg is the base) */
+ daddr = simple_strtoul(command + 5, &endp, 16);
+ /* Has it worked ? (endp should be command + count) */
+ DABORT(endp <= (command + 5), -EINVAL,
+ CTRL_ERROR, "Invalid address.\n");
+ /* Save it */
+ ap->raddr = daddr;
+ }
+ else
+ ap->raddr = DEV_ADDR_ANY;
+ DEXIT(CTRL_TRACE, " - raddr = %08x\n", ap->raddr);
+ return(count);
+ }
+
+ /* Other possible command : connect N (number of retries) */
+
+ /* Failed... */
+ DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n");
+}
+
+#ifdef INITIAL_DISCOVERY
+/*------------------------------------------------------------------*/
+/*
+ * Function irnet_read_discovery_log (self)
+ *
+ * Read the content on the discovery log
+ *
+ * This function dump the current content of the discovery log
+ * at the startup of the event channel.
+ * Return 1 if written on the control channel...
+ *
+ * State of the ap->disco_XXX variables :
+ * at socket creation : disco_index = 0 ; disco_number = 0
+ * while reading : disco_index = X ; disco_number = Y
+ * After reading : disco_index = Y ; disco_number = -1
+ */
+static inline int
+irnet_read_discovery_log(irnet_socket * ap,
+ char * event)
+{
+ int done_event = 0;
+
+ DENTER(CTRL_TRACE, "(ap=0x%X, event=0x%X)\n",
+ (unsigned int) ap, (unsigned int) event);
+
+ /* Test if we have some work to do or we have already finished */
+ if(ap->disco_number == -1)
+ {
+ DEBUG(CTRL_INFO, "Already done\n");
+ return 0;
+ }
+
+ /* Test if it's the first time and therefore we need to get the log */
+ if(ap->disco_index == 0)
+ {
+ __u16 mask = irlmp_service_to_hint(S_LAN);
+
+ /* Ask IrLMP for the current discovery log */
+ ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask);
+ /* Check if the we got some results */
+ if(ap->discoveries == NULL)
+ ap->disco_number = -1;
+ DEBUG(CTRL_INFO, "Got the log (0x%X), size is %d\n",
+ (unsigned int) ap->discoveries, ap->disco_number);
+ }
+
+ /* Check if we have more item to dump */
+ if(ap->disco_index < ap->disco_number)
+ {
+ /* Write an event */
+ sprintf(event, "Found %08x (%s)\n",
+ ap->discoveries[ap->disco_index].daddr,
+ ap->discoveries[ap->disco_index].info);
+ DEBUG(CTRL_INFO, "Writing discovery %d : %s\n",
+ ap->disco_index, ap->discoveries[ap->disco_index].info);
+
+ /* We have an event */
+ done_event = 1;
+ /* Next discovery */
+ ap->disco_index++;
+ }
+
+ /* Check if we have done the last item */
+ if(ap->disco_index >= ap->disco_number)
+ {
+ /* No more items : remove the log and signal termination */
+ DEBUG(CTRL_INFO, "Cleaning up log (0x%X)\n",
+ (unsigned int) ap->discoveries);
+ if(ap->discoveries != NULL)
+ {
+ /* Cleanup our copy of the discovery log */
+ kfree(ap->discoveries);
+ ap->discoveries = NULL;
+ }
+ ap->disco_number = -1;
+ }
+
+ return done_event;
+}
+#endif INITIAL_DISCOVERY
+
+/*------------------------------------------------------------------*/
+/*
+ * Read is used to get IrNET events
+ */
+static inline ssize_t
+irnet_ctrl_read(irnet_socket * ap,
+ struct file * file,
+ char * buf,
+ size_t count)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ char event[64]; /* Max event is 61 char */
+ ssize_t ret = 0;
+
+ DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count);
+
+ /* Check if we can write an event out in one go */
+ DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n");
+
+#ifdef INITIAL_DISCOVERY
+ /* Check if we have read the log */
+ if(irnet_read_discovery_log(ap, event))
+ {
+ /* We have an event !!! Copy it to the user */
+ if(copy_to_user(buf, event, strlen(event)))
+ {
+ DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
+ return -EFAULT;
+ }
+
+ DEXIT(CTRL_TRACE, "\n");
+ return(strlen(event));
+ }
+#endif INITIAL_DISCOVERY
+
+ /* Put ourselves on the wait queue to be woken up */
+ add_wait_queue(&irnet_events.rwait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+ for(;;)
+ {
+ /* If there is unread events */
+ ret = 0;
+ if(ap->event_index != irnet_events.index)
+ break;
+ ret = -EAGAIN;
+ if(file->f_flags & O_NONBLOCK)
+ break;
+ ret = -ERESTARTSYS;
+ if(signal_pending(current))
+ break;
+ /* Yield and wait to be woken up */
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&irnet_events.rwait, &wait);
+
+ /* Did we got it ? */
+ if(ret != 0)
+ {
+ /* No, return the error code */
+ DEXIT(CTRL_TRACE, " - ret %d\n", ret);
+ return ret;
+ }
+
+ /* Which event is it ? */
+ switch(irnet_events.log[ap->event_index].event)
+ {
+ case IRNET_DISCOVER:
+ sprintf(event, "Discovered %08x (%s)\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name);
+ break;
+ case IRNET_EXPIRE:
+ sprintf(event, "Expired %08x (%s)\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name);
+ break;
+ case IRNET_CONNECT_TO:
+ sprintf(event, "Connected to %08x (%s) on ppp%d\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name,
+ irnet_events.log[ap->event_index].unit);
+ break;
+ case IRNET_CONNECT_FROM:
+ sprintf(event, "Connection from %08x (%s) on ppp%d\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name,
+ irnet_events.log[ap->event_index].unit);
+ break;
+ case IRNET_REQUEST_FROM:
+ sprintf(event, "Request from %08x (%s)\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name);
+ break;
+ case IRNET_NOANSWER_FROM:
+ sprintf(event, "No-answer from %08x (%s) on ppp%d\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name,
+ irnet_events.log[ap->event_index].unit);
+ break;
+ case IRNET_BLOCKED_LINK:
+ sprintf(event, "Blocked link with %08x (%s) on ppp%d\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name,
+ irnet_events.log[ap->event_index].unit);
+ break;
+ case IRNET_DISCONNECT_FROM:
+ sprintf(event, "Disconnection from %08x (%s) on ppp%d\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name,
+ irnet_events.log[ap->event_index].unit);
+ break;
+ case IRNET_DISCONNECT_TO:
+ sprintf(event, "Disconnected to %08x (%s)\n",
+ irnet_events.log[ap->event_index].addr,
+ irnet_events.log[ap->event_index].name);
+ break;
+ default:
+ sprintf(event, "Bug\n");
+ }
+ /* Increment our event index */
+ ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS;
+
+ DEBUG(CTRL_INFO, "Event is :%s", event);
+
+ /* Copy it to the user */
+ if(copy_to_user(buf, event, strlen(event)))
+ {
+ DERROR(CTRL_ERROR, "Invalid user space pointer.\n");
+ return -EFAULT;
+ }
+
+ DEXIT(CTRL_TRACE, "\n");
+ return(strlen(event));
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Poll : called when someone do a select on /dev/irnet.
+ * Just check if there are new events...
+ */
+static inline unsigned int
+irnet_ctrl_poll(irnet_socket * ap,
+ struct file * file,
+ poll_table * wait)
+{
+ unsigned int mask;
+
+ DENTER(CTRL_TRACE, "(ap=0x%X)\n", (unsigned int) ap);
+
+ poll_wait(file, &irnet_events.rwait, wait);
+ mask = POLLOUT | POLLWRNORM;
+ /* If there is unread events */
+ if(ap->event_index != irnet_events.index)
+ mask |= POLLIN | POLLRDNORM;
+#ifdef INITIAL_DISCOVERY
+ if(ap->disco_number != -1)
+ mask |= POLLIN | POLLRDNORM;
+#endif INITIAL_DISCOVERY
+
+ DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask);
+ return mask;
+}
+
+
+/*********************** FILESYSTEM CALLBACKS ***********************/
+/*
+ * Implement the usual open, read, write functions that will be called
+ * by the file system when some action is performed on /dev/irnet.
+ * Most of those actions will in fact be performed by "pppd" or
+ * the control channel, we just act as a redirector...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Open : when somebody open /dev/irnet
+ * We basically create a new instance of irnet and initialise it.
+ */
+static int
+dev_irnet_open(struct inode * inode,
+ struct file * file)
+{
+ struct irnet_socket * ap;
+ int err;
+
+ DENTER(FS_TRACE, "(file=0x%X)\n", (unsigned int) file);
+
+#ifdef SECURE_DEVIRNET
+ /* This could (should?) be enforced by the permissions on /dev/irnet. */
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+#endif SECURE_DEVIRNET
+
+ /* Allocate a private structure for this IrNET instance */
+ ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
+
+ MOD_INC_USE_COUNT;
+
+ /* initialize the irnet structure */
+ memset(ap, 0, sizeof(*ap));
+ ap->file = file;
+
+ /* PPP channel setup */
+ ap->ppp_open = 0;
+ ap->chan.private = ap;
+ /* PPP parameters */
+ ap->mru = PPP_MRU;
+ ap->xaccm[0] = ~0U;
+ ap->xaccm[3] = 0x60000000U;
+ ap->raccm = ~0U;
+
+ /* Setup the IrDA part... */
+ err = irda_irnet_create(ap);
+ if(err)
+ {
+ DERROR(FS_ERROR, "Can't setup IrDA link...\n");
+ kfree(ap);
+ MOD_DEC_USE_COUNT;
+ return err;
+ }
+
+ /* For the control channel */
+ ap->event_index = irnet_events.index; /* Cancel all past events */
+
+ /* Put our stuff where we will be able to find it later */
+ file->private_data = ap;
+
+ DEXIT(FS_TRACE, " - ap=0x%X\n", (unsigned int) ap);
+ return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Close : when somebody close /dev/irnet
+ * Destroy the instance of /dev/irnet
+ */
+static int
+dev_irnet_close(struct inode * inode,
+ struct file * file)
+{
+ irnet_socket * ap = (struct irnet_socket *) file->private_data;
+
+ DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n",
+ (unsigned int) file, (unsigned int) ap);
+ DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n");
+
+ /* Detach ourselves */
+ file->private_data = NULL;
+
+ /* Close IrDA stuff */
+ irda_irnet_destroy(ap);
+
+ /* Disconnect from the generic PPP layer if not already done */
+ if(ap->ppp_open)
+ {
+ DERROR(FS_ERROR, "Channel still registered - deregistering !\n");
+ ppp_unregister_channel(&ap->chan);
+ ap->ppp_open = 0;
+ }
+
+ kfree(ap);
+ MOD_DEC_USE_COUNT;
+
+ DEXIT(FS_TRACE, "\n");
+ return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Write does nothing.
+ * (we receive packet from ppp_generic through ppp_irnet_send())
+ */
+static ssize_t
+dev_irnet_write(struct file * file,
+ const char * buf,
+ size_t count,
+ loff_t * ppos)
+{
+ irnet_socket * ap = (struct irnet_socket *) file->private_data;
+
+ DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n",
+ (unsigned int) file, (unsigned int) ap, count);
+ DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");
+
+ /* If we are connected to ppp_generic, let it handle the job */
+ if(ap->ppp_open)
+ return ppp_channel_write(&ap->chan, buf, count);
+ else
+ return irnet_ctrl_write(ap, buf, count);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read doesn't do much either.
+ * (pppd poll us, but ultimately reads through /dev/ppp)
+ */
+static ssize_t
+dev_irnet_read(struct file * file,
+ char * buf,
+ size_t count,
+ loff_t * ppos)
+{
+ irnet_socket * ap = (struct irnet_socket *) file->private_data;
+
+ DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n",
+ (unsigned int) file, (unsigned int) ap, count);
+ DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n");
+
+ /* If we are connected to ppp_generic, let it handle the job */
+ if(ap->ppp_open)
+ return ppp_channel_read(&ap->chan, file, buf, count);
+ else
+ return irnet_ctrl_read(ap, file, buf, count);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Poll : called when someone do a select on /dev/irnet
+ */
+static unsigned int
+dev_irnet_poll(struct file * file,
+ poll_table * wait)
+{
+ irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ unsigned int mask;
+
+ DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n",
+ (unsigned int) file, (unsigned int) ap);
+
+ mask = POLLOUT | POLLWRNORM;
+ DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n");
+
+ /* If we are connected to ppp_generic, let it handle the job */
+ if(ap->ppp_open)
+ mask |= ppp_channel_poll(&ap->chan, file, wait);
+ else
+ mask |= irnet_ctrl_poll(ap, file, wait);
+
+ DEXIT(FS_TRACE, " - mask=0x%X\n", mask);
+ return(mask);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * IOCtl : Called when someone does some ioctls on /dev/irnet
+ * This is the way pppd configure us and control us while the PPP
+ * instance is active.
+ */
+static int
+dev_irnet_ioctl(struct inode * inode,
+ struct file * file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ irnet_socket * ap = (struct irnet_socket *) file->private_data;
+ int err;
+ int val;
+
+ DENTER(FS_TRACE, "(file=0x%X, ap=0x%X, cmd=0x%X)\n",
+ (unsigned int) file, (unsigned int) ap, cmd);
+
+ /* Basic checks... */
+ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");
+#ifdef SECURE_DEVIRNET
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+#endif SECURE_DEVIRNET
+
+ err = -EFAULT;
+ switch(cmd)
+ {
+ /* Set discipline (should be N_SYNC_PPP or N_TTY) */
+ case TIOCSETD:
+ if(get_user(val, (int *) arg))
+ break;
+ if((val == N_SYNC_PPP) || (val == N_PPP))
+ {
+ DEBUG(FS_INFO, "Entering PPP discipline.\n");
+ /* PPP channel setup */
+ ap->chan.private = ap;
+ ap->chan.ops = &irnet_ppp_ops;
+ ap->chan.mtu = PPP_MRU;
+ err = ppp_register_channel(&ap->chan);
+ if(err == 0)
+ {
+ /* Our ppp side is active */
+ ap->ppp_open = 1;
+
+ DEBUG(FS_INFO, "Trying to establish a connection.\n");
+ /* Setup the IrDA link now - may fail... */
+ irda_irnet_connect(ap);
+ }
+ else
+ DERROR(FS_ERROR, "Can't setup PPP channel...\n");
+ }
+ else
+ {
+ /* In theory, should be N_TTY */
+ DEBUG(FS_INFO, "Exiting PPP discipline.\n");
+ /* Disconnect from the generic PPP layer */
+ if(ap->ppp_open)
+ ppp_unregister_channel(&ap->chan);
+ else
+ DERROR(FS_ERROR, "Channel not registered !\n");
+ ap->ppp_open = 0;
+ err = 0;
+ }
+ break;
+
+ /* Attach this PPP instance to the PPP driver (set it active) */
+ case PPPIOCATTACH:
+ case PPPIOCDETACH:
+ if(ap->ppp_open)
+ err = ppp_channel_ioctl(&ap->chan, cmd, arg);
+ else
+ DERROR(FS_ERROR, "Channel not registered !\n");
+ break;
+
+ /* Query PPP channel and unit number */
+ case PPPIOCGCHAN:
+ if(!ap->ppp_open)
+ break;
+ if(put_user(ppp_channel_index(&ap->chan), (int *) arg))
+ break;
+ DEBUG(FS_INFO, "Query channel.\n");
+ err = 0;
+ break;
+ case PPPIOCGUNIT:
+ if(!ap->ppp_open)
+ break;
+ if(put_user(ppp_unit_number(&ap->chan), (int *) arg))
+ break;
+ DEBUG(FS_INFO, "Query unit number.\n");
+ err = 0;
+ break;
+
+ /* All these ioctls can be passed both directly and from ppp_generic,
+ * so we just deal with them in one place...
+ */
+ case PPPIOCGFLAGS:
+ case PPPIOCSFLAGS:
+ case PPPIOCGASYNCMAP:
+ case PPPIOCSASYNCMAP:
+ case PPPIOCGRASYNCMAP:
+ case PPPIOCSRASYNCMAP:
+ case PPPIOCGXASYNCMAP:
+ case PPPIOCSXASYNCMAP:
+ case PPPIOCGMRU:
+ case PPPIOCSMRU:
+ DEBUG(FS_INFO, "Standard PPP ioctl.\n");
+ if(!capable(CAP_NET_ADMIN))
+ err = -EPERM;
+ else
+ err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
+ break;
+
+ /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */
+ /* Get termios */
+ case TCGETS:
+ DEBUG(FS_INFO, "Get termios.\n");
+ if(kernel_termios_to_user_termios((struct termios *)arg, &ap->termios))
+ break;
+ err = 0;
+ break;
+ /* Set termios */
+ case TCSETSF:
+ DEBUG(FS_INFO, "Set termios.\n");
+ if(user_termios_to_kernel_termios(&ap->termios, (struct termios *) arg))
+ break;
+ err = 0;
+ break;
+
+ /* Set DTR/RTS */
+ case TIOCMBIS:
+ case TIOCMBIC:
+ /* Set exclusive/non-exclusive mode */
+ case TIOCEXCL:
+ case TIOCNXCL:
+ DEBUG(FS_INFO, "TTY compatibility.\n");
+ err = 0;
+ break;
+
+ case TCGETA:
+ DEBUG(FS_INFO, "TCGETA\n");
+ break;
+
+ case TCFLSH:
+ DEBUG(FS_INFO, "TCFLSH\n");
+ /* Note : this will flush buffers in PPP, so it *must* be done
+ * We should also worry that we don't accept junk here and that
+ * we get rid of our own buffers */
+#ifdef FLUSH_TO_PPP
+ ppp_output_wakeup(&ap->chan);
+#endif FLUSH_TO_PPP
+ err = 0;
+ break;
+
+ case FIONREAD:
+ DEBUG(FS_INFO, "FIONREAD\n");
+ val = 0;
+ if(put_user(val, (int *) arg))
+ break;
+ err = 0;
+ break;
+
+ default:
+ DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);
+ err = -ENOIOCTLCMD;
+ }
+
+ DEXIT(FS_TRACE, " - err = 0x%X\n", err);
+ return err;
+}
+
+/************************** PPP CALLBACKS **************************/
+/*
+ * This are the functions that the generic PPP driver in the kernel
+ * will call to communicate to us.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare the ppp frame for transmission over the IrDA socket.
+ * We make sure that the header space is enough, and we change ppp header
+ * according to flags passed by pppd.
+ * This is not a callback, but just a helper function used in ppp_irnet_send()
+ */
+static inline struct sk_buff *
+irnet_prepare_skb(irnet_socket * ap,
+ struct sk_buff * skb)
+{
+ unsigned char * data;
+ int proto; /* PPP protocol */
+ int islcp; /* Protocol == LCP */
+ int needaddr; /* Need PPP address */
+
+ DENTER(PPP_TRACE, "(ap=0x%X, skb=0x%X)\n",
+ (unsigned int) ap, (unsigned int) skb);
+
+ /* Extract PPP protocol from the frame */
+ 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);
+
+ /* Check if we need address/control fields */
+ needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp);
+
+ /* Is the skb headroom large enough to contain all IrDA-headers? */
+ if((skb_headroom(skb) < (ap->max_header_size + needaddr)) ||
+ (skb_shared(skb)))
+ {
+ struct sk_buff * new_skb;
+
+ DEBUG(PPP_INFO, "Reallocating skb\n");
+
+ /* Create a new skb */
+ new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr);
+
+ /* We have to free the original skb anyway */
+ dev_kfree_skb(skb);
+
+ /* Did the realloc succeed ? */
+ DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n");
+
+ /* Use the new skb instead */
+ skb = new_skb;
+ }
+
+ /* prepend address/control fields if necessary */
+ if(needaddr)
+ {
+ skb_push(skb,2);
+ skb->data[0] = PPP_ALLSTATIONS;
+ skb->data[1] = PPP_UI;
+ }
+
+ DEXIT(PPP_TRACE, "\n");
+
+ return skb;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Send a packet to the peer over the IrTTP connection.
+ * Returns 1 iff the packet was accepted.
+ * Returns 0 iff packet was not consumed.
+ * If the packet was not accepted, we will call ppp_output_wakeup
+ * at some later time to reactivate flow control in ppp_generic.
+ */
+static int
+ppp_irnet_send(struct ppp_channel * chan,
+ struct sk_buff * skb)
+{
+ irnet_socket * self = (struct irnet_socket *) chan->private;
+ int ret;
+
+ DENTER(PPP_TRACE, "(channel=0x%X, ap/self=0x%X)\n",
+ (unsigned int) chan, (unsigned int) self);
+
+ /* Check if things are somewhat valid... */
+ DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n");
+
+ /* Check if we are connected */
+ if(self->ttp_open == 0)
+ {
+#ifdef CONNECT_IN_SEND
+ /* Let's try to connect one more time... */
+ /* Note : we won't connect fully yet, but we should be ready for
+ * next packet... */
+ /* Note : we can't do that, we need to have a process context to
+ * go through interruptible_sleep_on() in irnet_find_lsap_sel()
+ * We need to find another way... */
+ irda_irnet_connect(self);
+#endif CONNECT_IN_SEND
+
+ DEBUG(PPP_INFO, "IrTTP not ready ! (%d-0x%X)\n",
+ self->ttp_open, (unsigned int) self->tsap);
+
+ /* Note : we can either drop the packet or block the packet.
+ *
+ * Blocking the packet allow us a better connection time,
+ * because by calling ppp_output_wakeup() we can have
+ * ppp_generic resending the LCP request immediately to us,
+ * rather than waiting for one of pppd periodic transmission of
+ * LCP request.
+ *
+ * On the other hand, if we block all packet, all those periodic
+ * transmissions of pppd accumulate in ppp_generic, creating a
+ * backlog of LCP request. When we eventually connect later on,
+ * we have to transmit all this backlog before we can connect
+ * proper (if we don't timeout before).
+ *
+ * The current strategy is as follow :
+ * While we are attempting to connect, we block packets to get
+ * a better connection time.
+ * If we fail to connect, we drain the queue and start dropping packets
+ */
+#ifdef BLOCK_WHEN_CONNECT
+ /* If we are attempting to connect */
+ if(self->tsap)
+ {
+ /* Blocking packet, ppp_generic will retry later */
+ return 0;
+ }
+#endif BLOCK_WHEN_CONNECT
+
+ /* Dropping packet, pppd will retry later */
+ dev_kfree_skb(skb);
+ return 1;
+ }
+
+ /* Check if the queue can accept any packet, otherwise block */
+ if(self->tx_flow != FLOW_START)
+ DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n",
+ skb_queue_len(&self->tsap->tx_queue));
+
+ /* Prepare ppp frame for transmission */
+ skb = irnet_prepare_skb(self, skb);
+ DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n");
+
+ /* Send the packet to IrTTP */
+ ret = irttp_data_request(self->tsap, skb);
+ if(ret < 0)
+ {
+ /*
+ * > IrTTPs tx queue is full, so we just have to
+ * > drop the frame! You might think that we should
+ * > just return -1 and don't deallocate the frame,
+ * > but that is dangerous since it's possible that
+ * > we have replaced the original skb with a new
+ * > one with larger headroom, and that would really
+ * > confuse do_dev_queue_xmit() in dev.c! I have
+ * > tried :-) DB
+ * Correction : we verify the flow control above (self->tx_flow),
+ * so we come here only if IrTTP doesn't like the packet (empty,
+ * too large, IrTTP not connected). In those rare cases, it's ok
+ * to drop it, we don't want to see it here again...
+ * Jean II
+ */
+ DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret);
+ dev_kfree_skb(skb);
+ }
+
+ DEXIT(PPP_TRACE, "\n");
+ return 1; /* Packet has been consumed */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Take care of the ioctls that ppp_generic doesn't want to deal with...
+ * Note : we are also called from dev_irnet_ioctl().
+ */
+static int
+ppp_irnet_ioctl(struct ppp_channel * chan,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ irnet_socket * ap = (struct irnet_socket *) chan->private;
+ int err;
+ int val;
+ u32 accm[8];
+
+ DENTER(PPP_TRACE, "(channel=0x%X, ap=0x%X, cmd=0x%X)\n",
+ (unsigned int) chan, (unsigned int) ap, cmd);
+
+ /* Basic checks... */
+ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n");
+
+ err = -EFAULT;
+ switch(cmd)
+ {
+ /* PPP flags */
+ 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;
+
+ /* Async map stuff - all dummy to please pppd */
+ 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;
+
+ /* Max PPP frame size */
+ 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:
+ DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd);
+ err = -ENOIOCTLCMD;
+ }
+
+ DEXIT(PPP_TRACE, " - err = 0x%X\n", err);
+ return err;
+}
+
+/************************** INITIALISATION **************************/
+/*
+ * Module initialisation and all that jazz...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Hook our device callbacks in the filesystem, to connect our code
+ * to /dev/irnet
+ */
+int
+ppp_irnet_init(void)
+{
+ int err = 0;
+
+ DENTER(MODULE_TRACE, "()\n");
+
+ /* Allocate ourselves as a minor in the misc range */
+ err = misc_register(&irnet_misc_device);
+
+ DEXIT(MODULE_TRACE, "\n");
+ return err;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Cleanup at exit...
+ */
+void
+ppp_irnet_cleanup(void)
+{
+ DENTER(MODULE_TRACE, "()\n");
+
+ /* De-allocate /dev/irnet minor in misc range */
+ misc_deregister(&irnet_misc_device);
+
+ DEXIT(MODULE_TRACE, "\n");
+}
+
+#ifdef MODULE
+/*------------------------------------------------------------------*/
+/*
+ * Module main entry point
+ */
+int
+init_module(void)
+{
+ int err;
+
+ /* Initialise both parts... */
+ err = irda_irnet_init();
+ if(!err)
+ err = ppp_irnet_init();
+ return err;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Module exit
+ */
+void
+cleanup_module(void)
+{
+ irda_irnet_cleanup();
+ return ppp_irnet_cleanup();
+}
+#endif /* MODULE */
diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h
new file mode 100644
index 000000000..8e8365374
--- /dev/null
+++ b/net/irda/irnet/irnet_ppp.h
@@ -0,0 +1,130 @@
+/*
+ * IrNET protocol module : Synchronous PPP over an IrDA socket.
+ *
+ * Jean II - HPL `00 - <jt@hpl.hp.com>
+ *
+ * This file contains all definitions and declarations necessary for the
+ * PPP part of the IrNET module.
+ * This file is a private header, so other modules don't want to know
+ * what's in there...
+ */
+
+#ifndef IRNET_PPP_H
+#define IRNET_PPP_H
+
+/***************************** INCLUDES *****************************/
+
+#include "irnet.h" /* Module global include */
+
+/************************ CONSTANTS & MACROS ************************/
+
+/* /dev/irnet file constants */
+#define IRNET_MAJOR 10 /* Misc range */
+#define IRNET_MINOR 187 /* Official allocation */
+
+#ifdef LINKNAME_IOCTL
+/* Compatibility with old ppp drivers
+ * Should be defined in <linux/if_ppp.h> */
+#ifndef PPPIOCSLINKNAME
+#define PPPIOCSLINKNAME _IOW('t', 74, struct ppp_option_data)
+#endif PPPIOCSLINKNAME
+#endif LINKNAME_IOCTL
+
+/* PPP hardcore stuff */
+
+/* Bits in rbits (PPP flags in irnet struct) */
+#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+/* Bit numbers in busy */
+#define XMIT_BUSY 0
+#define RECV_BUSY 1
+#define XMIT_WAKEUP 2
+#define XMIT_FULL 3
+
+/* Queue management */
+#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */
+
+/****************************** TYPES ******************************/
+
+
+/**************************** PROTOTYPES ****************************/
+
+/* ----------------------- CONTROL CHANNEL ----------------------- */
+static inline ssize_t
+ irnet_ctrl_write(irnet_socket *,
+ const char *,
+ size_t);
+static inline ssize_t
+ irnet_ctrl_read(irnet_socket *,
+ struct file *,
+ char *,
+ size_t);
+static inline unsigned int
+ irnet_ctrl_poll(irnet_socket *,
+ struct file *,
+ poll_table *);
+/* ----------------------- CHARACTER DEVICE ----------------------- */
+static int
+ dev_irnet_open(struct inode *, /* fs callback : open */
+ struct file *),
+ dev_irnet_close(struct inode *,
+ struct file *);
+static ssize_t
+ dev_irnet_write(struct file *,
+ const char *,
+ size_t,
+ loff_t *),
+ dev_irnet_read(struct file *,
+ char *,
+ size_t,
+ loff_t *);
+static unsigned int
+ dev_irnet_poll(struct file *,
+ poll_table *);
+static int
+ dev_irnet_ioctl(struct inode *,
+ struct file *,
+ unsigned int,
+ unsigned long);
+/* ------------------------ PPP INTERFACE ------------------------ */
+static inline struct sk_buff *
+ irnet_prepare_skb(irnet_socket *,
+ struct sk_buff *);
+static int
+ ppp_irnet_send(struct ppp_channel *,
+ struct sk_buff *);
+static int
+ ppp_irnet_ioctl(struct ppp_channel *,
+ unsigned int,
+ unsigned long);
+
+/**************************** VARIABLES ****************************/
+
+/* Filesystem callbacks (to call us) */
+static struct file_operations irnet_device_fops =
+{
+ read: dev_irnet_read,
+ write: dev_irnet_write,
+ poll: dev_irnet_poll,
+ ioctl: dev_irnet_ioctl,
+ open: dev_irnet_open,
+ release: dev_irnet_close
+ /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
+};
+
+/* Structure so that the misc major (drivers/char/misc.c) take care of us... */
+static struct miscdevice irnet_misc_device =
+{
+ IRNET_MINOR,
+ "irnet",
+ &irnet_device_fops
+};
+
+/* Generic PPP callbacks (to call us) */
+struct ppp_channel_ops irnet_ppp_ops =
+{
+ ppp_irnet_send,
+ ppp_irnet_ioctl
+};
+
+#endif IRNET_PPP_H
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index 1d26d8f19..d2e4da720 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -36,7 +36,7 @@
#include <net/irda/irqueue.h>
#include <net/irda/irmod.h>
-static queue_t *dequeue_general( queue_t **queue, queue_t* element);
+static irda_queue_t *dequeue_general( irda_queue_t **queue, irda_queue_t* element);
static __u32 hash( char* name);
/*
@@ -79,7 +79,7 @@ hashbin_t *hashbin_new(int type)
*/
int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
{
- queue_t* queue;
+ irda_queue_t* queue;
int i;
ASSERT(hashbin != NULL, return -1;);
@@ -89,12 +89,12 @@ int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
* Free the entries in the hashbin
*/
for (i = 0; i < HASHBIN_SIZE; i ++ ) {
- queue = dequeue_first( (queue_t**) &hashbin->hb_queue[i]);
+ queue = dequeue_first( (irda_queue_t**) &hashbin->hb_queue[i]);
while (queue) {
if (free_func)
(*free_func)(queue);
queue = dequeue_first(
- (queue_t**) &hashbin->hb_queue[i]);
+ (irda_queue_t**) &hashbin->hb_queue[i]);
}
}
hashbin->hb_size = 0;
@@ -112,7 +112,7 @@ int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
*/
int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
{
- queue_t* queue;
+ irda_queue_t* queue;
int i;
ASSERT(hashbin != NULL, return -1;);
@@ -123,12 +123,12 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
* it has been shown to work
*/
for (i = 0; i < HASHBIN_SIZE; i ++ ) {
- queue = dequeue_first((queue_t**) &hashbin->hb_queue[i]);
+ queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]);
while (queue ) {
if (free_func)
(*free_func)(queue);
queue = dequeue_first(
- (queue_t**) &hashbin->hb_queue[i]);
+ (irda_queue_t**) &hashbin->hb_queue[i]);
}
}
@@ -210,7 +210,7 @@ void hashbin_unlock(hashbin_t* hashbin, __u32 hashv, char* name,
* Insert an entry into the hashbin
*
*/
-void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
+void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, char* name)
{
unsigned long flags = 0;
int bin;
@@ -250,7 +250,7 @@ void hashbin_insert(hashbin_t* hashbin, queue_t* entry, __u32 hashv, char* name)
*/
if ( hashbin->hb_type & HB_SORTED) {
} else {
- enqueue_first( (queue_t**) &hashbin->hb_queue[ bin ],
+ enqueue_first( (irda_queue_t**) &hashbin->hb_queue[ bin ],
entry);
}
hashbin->hb_size++;
@@ -275,7 +275,7 @@ void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name )
{
int bin, found = FALSE;
unsigned long flags = 0;
- queue_t* entry;
+ irda_queue_t* entry;
IRDA_DEBUG( 4, "hashbin_find()\n");
@@ -342,7 +342,7 @@ void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name )
void *hashbin_remove_first( hashbin_t *hashbin)
{
unsigned long flags;
- queue_t *entry = NULL;
+ irda_queue_t *entry = NULL;
save_flags(flags);
cli();
@@ -367,7 +367,7 @@ void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
{
int bin, found = FALSE;
unsigned long flags = 0;
- queue_t* entry;
+ irda_queue_t* entry;
IRDA_DEBUG( 4, __FUNCTION__ "()\n");
@@ -381,6 +381,7 @@ void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
hashv = hash( name );
bin = GET_HASHBIN( hashv );
+ /* Synchronize */
if ( hashbin->hb_type & HB_GLOBAL ) {
spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
@@ -421,8 +422,8 @@ void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
* If entry was found, dequeue it
*/
if ( found ) {
- dequeue_general( (queue_t**) &hashbin->hb_queue[ bin ],
- (queue_t*) entry );
+ dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
+ (irda_queue_t*) entry );
hashbin->hb_size--;
/*
@@ -450,6 +451,75 @@ void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
}
+/*
+ * Function hashbin_remove (hashbin, hashv, name)
+ *
+ * Remove entry with the given name
+ *
+ * In some cases, the user of hashbin can't guarantee the unicity
+ * of either the hashv or name.
+ * In those cases, using the above function is guaranteed to cause troubles,
+ * so we use this one instead...
+ * And by the way, it's also faster, because we skip the search phase ;-)
+ */
+void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
+{
+ unsigned long flags = 0;
+ int bin;
+ __u32 hashv;
+
+ IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+
+ ASSERT( hashbin != NULL, return NULL;);
+ ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+ ASSERT( entry != NULL, return NULL;);
+
+ /* Check if valid and not already removed... */
+ if((entry->q_next == NULL) || (entry->q_prev == NULL))
+ return NULL;
+
+ /*
+ * Locate hashbin
+ */
+ hashv = entry->q_hash;
+ bin = GET_HASHBIN( hashv );
+
+ /* Synchronize */
+ if ( hashbin->hb_type & HB_GLOBAL ) {
+ spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
+
+ } else if ( hashbin->hb_type & HB_LOCAL ) {
+ save_flags(flags);
+ cli();
+ } /* Default is no-lock */
+
+ /*
+ * Dequeue the entry...
+ */
+ dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
+ (irda_queue_t*) entry );
+ hashbin->hb_size--;
+ entry->q_next = NULL;
+ entry->q_prev = NULL;
+
+ /*
+ * Check if this item is the currently selected item, and in
+ * that case we must reset hb_current
+ */
+ if ( entry == hashbin->hb_current)
+ hashbin->hb_current = NULL;
+
+ /* Release lock */
+ if ( hashbin->hb_type & HB_GLOBAL) {
+ spin_unlock_irq( &hashbin->hb_mutex[ bin]);
+
+ } else if ( hashbin->hb_type & HB_LOCAL) {
+ restore_flags( flags);
+ }
+
+ return entry;
+}
+
/*
* Function hashbin_get_first (hashbin)
*
@@ -457,9 +527,9 @@ void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
* called before any calls to hashbin_get_next()!
*
*/
-queue_t *hashbin_get_first( hashbin_t* hashbin)
+irda_queue_t *hashbin_get_first( hashbin_t* hashbin)
{
- queue_t *entry;
+ irda_queue_t *entry;
int i;
ASSERT( hashbin != NULL, return NULL;);
@@ -489,9 +559,9 @@ queue_t *hashbin_get_first( hashbin_t* hashbin)
* NULL when all items have been traversed
*
*/
-queue_t *hashbin_get_next( hashbin_t *hashbin)
+irda_queue_t *hashbin_get_next( hashbin_t *hashbin)
{
- queue_t* entry;
+ irda_queue_t* entry;
int bin;
int i;
@@ -542,7 +612,7 @@ queue_t *hashbin_get_next( hashbin_t *hashbin)
* Insert item into end of queue.
*
*/
-static void __enqueue_last( queue_t **queue, queue_t* element)
+static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element)
{
IRDA_DEBUG( 4, __FUNCTION__ "()\n");
@@ -566,7 +636,7 @@ static void __enqueue_last( queue_t **queue, queue_t* element)
}
}
-inline void enqueue_last( queue_t **queue, queue_t* element)
+inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element)
{
unsigned long flags;
@@ -584,7 +654,7 @@ inline void enqueue_last( queue_t **queue, queue_t* element)
* Insert item first in queue.
*
*/
-void enqueue_first(queue_t **queue, queue_t* element)
+void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
{
IRDA_DEBUG( 4, __FUNCTION__ "()\n");
@@ -616,9 +686,9 @@ void enqueue_first(queue_t **queue, queue_t* element)
* Insert a queue (list) into the start of the first queue
*
*/
-void enqueue_queue( queue_t** queue, queue_t** list )
+void enqueue_queue( irda_queue_t** queue, irda_queue_t** list )
{
- queue_t* tmp;
+ irda_queue_t* tmp;
/*
* Check if queue is empty
@@ -643,7 +713,7 @@ void enqueue_queue( queue_t** queue, queue_t** list )
*
*/
#if 0
-static void enqueue_second(queue_t **queue, queue_t* element)
+static void enqueue_second(irda_queue_t **queue, irda_queue_t* element)
{
IRDA_DEBUG( 0, "enqueue_second()\n");
@@ -674,9 +744,9 @@ static void enqueue_second(queue_t **queue, queue_t* element)
* Remove first entry in queue
*
*/
-queue_t *dequeue_first(queue_t **queue)
+irda_queue_t *dequeue_first(irda_queue_t **queue)
{
- queue_t *ret;
+ irda_queue_t *ret;
IRDA_DEBUG( 4, "dequeue_first()\n");
@@ -715,9 +785,9 @@ queue_t *dequeue_first(queue_t **queue)
*
*
*/
-static queue_t *dequeue_general(queue_t **queue, queue_t* element)
+static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element)
{
- queue_t *ret;
+ irda_queue_t *ret;
IRDA_DEBUG( 4, "dequeue_general()\n");
diff --git a/net/irda/irmod.c b/net/irda/irsyms.c
index 39257f87a..117f23ecc 100644
--- a/net/irda/irmod.c
+++ b/net/irda/irsyms.c
@@ -1,8 +1,8 @@
/*********************************************************************
*
- * Filename: irmod.c
- * Version: 0.8
- * Description: IrDA module code and some other stuff
+ * Filename: irsyms.c
+ * Version: 0.9
+ * Description: IrDA module symbols
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Dec 15 13:55:39 1997
@@ -23,7 +23,7 @@
********************************************************************/
#include <linux/config.h>
-#include <linux/module.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
@@ -49,18 +49,12 @@
extern struct proc_dir_entry *proc_irda;
-struct irda_cb irda; /* One global instance */
-
-#ifdef CONFIG_IRDA_DEBUG
-__u32 irda_debug = IRDA_DEBUG_LEVEL;
-#endif
-
extern void irda_proc_register(void);
extern void irda_proc_unregister(void);
extern int irda_sysctl_register(void);
extern void irda_sysctl_unregister(void);
-extern void irda_proto_init(struct net_proto *pro);
+extern int irda_proto_init(void);
extern void irda_proto_cleanup(void);
extern int irda_device_init(void);
@@ -78,26 +72,6 @@ extern irda_deflate_init();
#endif /* CONFIG_IRDA_DEFLATE */
#endif /* CONFIG_IRDA_COMPRESSION */
-static int irda_open(struct inode * inode, struct file *file);
-static int irda_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-static int irda_close(struct inode *inode, struct file *file);
-static ssize_t irda_read(struct file *file, char *buffer, size_t count,
- loff_t *noidea);
-static ssize_t irda_write(struct file *file, const char *buffer,
- size_t count, loff_t *noidea);
-static u_int irda_poll(struct file *file, poll_table *wait);
-
-static struct file_operations irda_fops = {
- owner: THIS_MODULE,
- read: irda_read,
- write: irda_write,
- poll: irda_poll,
- ioctl: irda_ioctl,
- open: irda_open,
- release: irda_close,
-};
-
/* IrTTP */
EXPORT_SYMBOL(irttp_open_tsap);
EXPORT_SYMBOL(irttp_close_tsap);
@@ -114,7 +88,6 @@ EXPORT_SYMBOL(irttp_dup);
EXPORT_SYMBOL(irda_debug);
#endif
EXPORT_SYMBOL(irda_notify_init);
-EXPORT_SYMBOL(irmanager_notify);
EXPORT_SYMBOL(irda_lock);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(proc_irda);
@@ -145,6 +118,8 @@ EXPORT_SYMBOL(irias_new_octseq_value);
/* IrLMP */
EXPORT_SYMBOL(irlmp_discovery_request);
+EXPORT_SYMBOL(irlmp_get_discoveries);
+EXPORT_SYMBOL(sysctl_discovery_timeout);
EXPORT_SYMBOL(irlmp_register_client);
EXPORT_SYMBOL(irlmp_unregister_client);
EXPORT_SYMBOL(irlmp_update_client);
@@ -168,6 +143,7 @@ EXPORT_SYMBOL(hashbin_new);
EXPORT_SYMBOL(hashbin_insert);
EXPORT_SYMBOL(hashbin_delete);
EXPORT_SYMBOL(hashbin_remove);
+EXPORT_SYMBOL(hashbin_remove_this);
EXPORT_SYMBOL(hashbin_get_next);
EXPORT_SYMBOL(hashbin_get_first);
@@ -208,14 +184,11 @@ EXPORT_SYMBOL(irtty_set_packet_mode);
int __init irda_init(void)
{
- MESSAGE("IrDA (tm) Protocols for Linux-2.3 (Dag Brattli)\n");
-
+ IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
irlmp_init();
irlap_init();
-#ifdef MODULE
- irda_device_init(); /* Called by init/main.c when non-modular */
-#endif
iriap_init();
irttp_init();
@@ -225,17 +198,6 @@ int __init irda_init(void)
#ifdef CONFIG_SYSCTL
irda_sysctl_register();
#endif
- init_waitqueue_head(&irda.wait_queue);
- irda.dev.minor = MISC_DYNAMIC_MINOR;
- irda.dev.name = "irda";
- irda.dev.fops = &irda_fops;
-
- misc_register(&irda.dev);
-
- irda.in_use = FALSE;
-
- init_waitqueue_head(&irda.wait_queue);
-
/*
* Initialize modules that got compiled into the kernel
*/
@@ -256,11 +218,8 @@ int __init irda_init(void)
return 0;
}
-#ifdef MODULE
-void irda_cleanup(void)
+static void __exit irda_cleanup(void)
{
- misc_deregister(&irda.dev);
-
#ifdef CONFIG_SYSCTL
irda_sysctl_unregister();
#endif
@@ -279,7 +238,6 @@ void irda_cleanup(void)
/* Remove middle layer */
irlmp_cleanup();
}
-#endif /* MODULE */
/*
* Function irda_unlock (lock)
@@ -310,241 +268,8 @@ void irda_notify_init(notify_t *notify)
notify->connect_indication = NULL;
notify->disconnect_indication = NULL;
notify->flow_indication = NULL;
+ notify->status_indication = NULL;
notify->instance = NULL;
strncpy(notify->name, "Unknown", NOTIFY_MAX_NAME);
}
-/*
- * Function irda_execute_as_process (self, callback, param)
- *
- * If a layer needs to have a function executed with a process context,
- * then it can register the function here, and the function will then
- * be executed as fast as possible.
- *
- */
-void irda_execute_as_process( void *self, TODO_CALLBACK callback, __u32 param)
-{
- struct irda_todo *new;
- struct irmanager_event event;
-
- /* Make sure irmanager is running */
- if (!irda.in_use) {
- return;
- }
-
- /* Make new todo event */
- new = (struct irda_todo *) kmalloc( sizeof(struct irda_todo),
- GFP_ATOMIC);
- if ( new == NULL) {
- return;
- }
- memset( new, 0, sizeof( struct irda_todo));
-
- new->self = self;
- new->callback = callback;
- new->param = param;
-
- /* Queue todo */
- enqueue_last(&irda.todo_queue, (queue_t *) new);
-
- event.event = EVENT_NEED_PROCESS_CONTEXT;
-
- /* Notify the user space manager */
- irmanager_notify(&event);
-}
-
-/*
- * Function irmanger_notify (event)
- *
- * Send an event to the user space manager
- *
- */
-void irmanager_notify( struct irmanager_event *event)
-{
- struct irda_event *new;
-
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- /* Make sure irmanager is running */
- if (!irda.in_use) {
- return;
- }
-
- /* Make new IrDA Event */
- new = (struct irda_event *) kmalloc( sizeof(struct irda_event),
- GFP_ATOMIC);
- if ( new == NULL) {
- return;
- }
- memset(new, 0, sizeof( struct irda_event));
- new->event = *event;
-
- /* Queue event */
- enqueue_last(&irda.event_queue, (queue_t *) new);
-
- /* Wake up irmanager sleeping on read */
- wake_up_interruptible(&irda.wait_queue);
-}
-
-static int irda_open( struct inode * inode, struct file *file)
-{
- IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
- lock_kernel();
- if (irda.in_use) {
- unlock_kernel();
- IRDA_DEBUG(0, __FUNCTION__
- "(), irmanager is already running!\n");
- return -1;
- }
- irda.in_use = TRUE;
- unlock_kernel();
-
- return 0;
-}
-
-/*
- * Function irda_ioctl (inode, filp, cmd, arg)
- *
- * Ioctl, used by irmanager to ...
- *
- */
-static int irda_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct irda_todo *todo;
- int err = 0;
- int size = _IOC_SIZE(cmd);
-
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- if (_IOC_DIR(cmd) & _IOC_READ)
- err = verify_area( VERIFY_WRITE, (void *) arg, size);
- else if (_IOC_DIR(cmd) & _IOC_WRITE)
- err = verify_area( VERIFY_READ, (void *) arg, size);
- if (err)
- return err;
-
- switch (cmd) {
- case IRMGR_IOCTNPC:
- /* Got process context! */
- IRDA_DEBUG(4, __FUNCTION__ "(), got process context!\n");
-
- while ((todo = (struct irda_todo *) dequeue_first(
- &irda.todo_queue)) != NULL)
- {
- todo->callback(todo->self, todo->param);
-
- kfree(todo);
- }
- break;
-
- default:
- return -ENOIOCTLCMD;
- }
-
- return 0;
-}
-
-static int irda_close(struct inode *inode, struct file *file)
-{
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- lock_kernel();
- irda.in_use = FALSE;
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t irda_read(struct file *file, char *buffer, size_t count,
- loff_t *noidea)
-{
- struct irda_event *event;
- unsigned long flags;
- int len;
-
- IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
- /* * Go to sleep and wait for event if there is no event to be read! */
- save_flags( flags);
- cli();
- if ( !irda.event_queue)
- interruptible_sleep_on( &irda.wait_queue);
- restore_flags(flags);
-
- /*
- * Ensure proper reaction to signals, and screen out
- * blocked signals (page 112. linux device drivers)
- */
- if (signal_pending( current))
- return -ERESTARTSYS;
-
- event = (struct irda_event *) dequeue_first( &irda.event_queue);
- if (!event)
- return 0;
-
- len = sizeof(struct irmanager_event);
- copy_to_user(buffer, &event->event, len);
-
- /* Finished with event */
- kfree(event);
-
- return len;
-}
-
-static ssize_t irda_write(struct file *file, const char *buffer,
- size_t count, loff_t *noidea)
-{
- IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
- return 0;
-}
-
-static u_int irda_poll(struct file *file, poll_table *wait)
-{
- IRDA_DEBUG(0, __FUNCTION__ "(), Sorry not implemented yet!\n");
-
- return 0;
-}
-
-void irda_mod_inc_use_count(void)
-{
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
-}
-
-void irda_mod_dec_use_count(void)
-{
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-}
-
-/*
- * Function irda_proc_modcount (inode, fill)
- *
- * Use by the proc file system functions to prevent the irda module
- * being removed while the use is standing in the net/irda directory
- */
-void irda_proc_modcount(struct inode *inode, int fill)
-{
-#ifdef MODULE
-#ifdef CONFIG_PROC_FS
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-#endif /* CONFIG_PROC_FS */
-#endif /* MODULE */
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem");
-MODULE_PARM(irda_debug, "1l");
-module_exit(irda_proto_cleanup);
-#endif /* MODULE */
-
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 1efeedc69..4c6218527 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -29,10 +29,11 @@
#include <asm/segment.h>
#include <net/irda/irda.h>
+#include <net/irda/irias_object.h>
#define NET_IRDA 412 /* Random number */
enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, DISCOVERY_TIMEOUT,
- SLOT_TIMEOUT };
+ SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME };
extern int sysctl_discovery;
extern int sysctl_discovery_slots;
@@ -41,17 +42,35 @@ extern int sysctl_slot_timeout;
extern int sysctl_fast_poll_increase;
int sysctl_compression = 0;
extern char sysctl_devname[];
+extern int sysctl_max_baud_rate;
+extern int sysctl_max_inactive_time;
#ifdef CONFIG_IRDA_DEBUG
extern unsigned int irda_debug;
#endif
+static int do_devname(ctl_table *table, int write, struct file *filp,
+ void *buffer, size_t *lenp)
+{
+ int ret;
+
+ ret = proc_dostring(table, write, filp, buffer, lenp);
+ if (ret == 0 && write) {
+ struct ias_value *val;
+
+ val = irias_new_string_value(sysctl_devname);
+ if (val)
+ irias_object_change_attribute("Device", "DeviceName", val);
+ }
+ return ret;
+}
+
/* One file */
static ctl_table irda_table[] = {
{ DISCOVERY, "discovery", &sysctl_discovery,
sizeof(int), 0644, NULL, &proc_dointvec },
{ DEVNAME, "devname", sysctl_devname,
- 65, 0644, NULL, &proc_dostring, &sysctl_string},
+ 65, 0644, NULL, &do_devname, &sysctl_string},
{ COMPRESSION, "compression", &sysctl_compression,
sizeof(int), 0644, NULL, &proc_dointvec },
#ifdef CONFIG_IRDA_DEBUG
@@ -68,6 +87,10 @@ static ctl_table irda_table[] = {
sizeof(int), 0644, NULL, &proc_dointvec },
{ SLOT_TIMEOUT, "slot_timeout", &sysctl_slot_timeout,
sizeof(int), 0644, NULL, &proc_dointvec },
+ { MAX_BAUD_RATE, "max_baud_rate", &sysctl_max_baud_rate,
+ sizeof(int), 0644, NULL, &proc_dointvec },
+ { MAX_INACTIVE_TIME, "max_inactive_time", &sysctl_max_inactive_time,
+ sizeof(int), 0644, NULL, &proc_dointvec },
{ 0 }
};
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index e9d120efb..645815835 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -156,6 +156,8 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
ttp_notify.disconnect_indication = irttp_disconnect_indication;
ttp_notify.data_indication = irttp_data_indication;
ttp_notify.udata_indication = irttp_udata_indication;
+ if(notify->status_indication != NULL)
+ ttp_notify.status_indication = irttp_status_indication;
ttp_notify.instance = self;
strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME);
@@ -185,7 +187,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
self->notify = *notify;
self->lsap = lsap;
- hashbin_insert(irttp->tsaps, (queue_t *) self, (int) self, NULL);
+ hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
if (credit > TTP_MAX_QUEUE)
self->initial_credit = TTP_MAX_QUEUE;
@@ -608,6 +610,34 @@ static int irttp_data_indication(void *instance, void *sap,
}
/*
+ * Function irttp_status_indication (self, reason)
+ *
+ * Status_indication, just pass to the higher layer...
+ *
+ */
+void irttp_status_indication(void *instance,
+ LINK_STATUS link, LOCK_STATUS lock)
+{
+ struct tsap_cb *self;
+
+ IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+ self = (struct tsap_cb *) instance;
+
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+
+ /*
+ * Inform service user if he has requested it
+ */
+ if (self->notify.status_indication != NULL)
+ self->notify.status_indication(self->notify.instance,
+ link, lock);
+ else
+ IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
+}
+
+/*
* Function irttp_flow_request (self, command)
*
* This funtion could be used by the upper layers to tell IrTTP to stop
@@ -1002,7 +1032,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
skb_queue_head_init(&new->tx_queue);
skb_queue_head_init(&new->rx_fragments);
- hashbin_insert(irttp->tsaps, (queue_t *) new, (int) new, NULL);
+ hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (int) new, NULL);
return new;
}
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index b43bbd70e..2b013ff43 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -513,10 +513,7 @@ int irda_param_extract(void *self, __u8 *buf, int len, pi_param_info_t *info)
buf[0]);
/* Skip this parameter */
- n += (2 + buf[n+1]);
- len -= (2 + buf[n+1]);
-
- return 0; /* Continue */
+ return 2 + buf[n + 1]; /* Continue */
}
/* Lookup the info on how to parse this parameter */
@@ -532,10 +529,7 @@ int irda_param_extract(void *self, __u8 *buf, int len, pi_param_info_t *info)
if (!pi_minor_info->func) {
MESSAGE(__FUNCTION__"(), no handler for pi=%#x\n", buf[n]);
/* Skip this parameter */
- n += (2 + buf[n+1]);
- len -= (2 + buf[n+1]);
-
- return 0; /* Continue */
+ return 2 + buf[n + 1]; /* Continue */
}
/* Parse parameter value */
diff --git a/net/irda/qos.c b/net/irda/qos.c
index 10a7765cb..997b3e8ff 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -43,6 +43,21 @@
#define CI_BZIP2 27 /* Random pick */
#endif
+/*
+ * Maximum values of the baud rate we negociate with the other end.
+ * Most often, you don't have to change that, because Linux-IrDA will
+ * use the maximum offered by the link layer, which usually works fine.
+ * In some very rare cases, you may want to limit it to lower speeds...
+ */
+int sysctl_max_baud_rate = 16000000;
+/*
+ * Maximum value of the lap disconnect timer we negociate with the other end.
+ * Most often, the value below represent the best compromise, but some user
+ * may want to keep the LAP alive longuer or shorter in case of link failure.
+ * Remember that the threshold time (early warning) is fixed to 3s...
+ */
+int sysctl_max_inactive_time = 12;
+
static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
int get);
@@ -55,6 +70,10 @@ static int irlap_param_additional_bofs(void *instance, irda_param_t *parm,
int get);
static int irlap_param_min_turn_time(void *instance, irda_param_t *param,
int get);
+static int value_index(__u32 value, __u32 *array, int size);
+static __u32 byte_value(__u8 byte, __u32 *array);
+static __u32 index_value(int index, __u32 *array);
+static int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field);
__u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
__u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
@@ -147,19 +166,31 @@ void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
*/
void irda_init_max_qos_capabilies(struct qos_info *qos)
{
+ int i;
/*
* These are the maximum supported values as specified on pages
* 39-43 in IrLAP
*/
+ /* Use sysctl to set some configurable values... */
+ /* Set configured max speed */
+ i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10,
+ &qos->baud_rate.bits);
+ sysctl_max_baud_rate = index_value(i, baud_rates);
+
+ /* Set configured max disc time */
+ i = value_lower_bits(sysctl_max_inactive_time, link_disc_times, 8,
+ &qos->link_disc_time.bits);
+ sysctl_max_inactive_time = index_value(i, link_disc_times);
+
/* LSB is first byte, MSB is second byte */
- qos->baud_rate.bits = 0x01ff;
+ qos->baud_rate.bits &= 0x03ff;
qos->window_size.bits = 0x7f;
qos->min_turn_time.bits = 0xff;
qos->max_turn_time.bits = 0x0f;
qos->data_size.bits = 0x3f;
- qos->link_disc_time.bits = 0xff;
+ qos->link_disc_time.bits &= 0xff;
qos->additional_bofs.bits = 0xff;
#ifdef CONFIG_IRDA_COMPRESSION
@@ -197,7 +228,7 @@ void irlap_adjust_qos_settings(struct qos_info *qos)
* The data size must be adjusted according to the baud rate and max
* turn time
*/
- index = value_index(qos->data_size.value, data_sizes);
+ index = value_index(qos->data_size.value, data_sizes, 6);
line_capacity = irlap_max_line_capacity(qos->baud_rate.value,
qos->max_turn_time.value);
@@ -537,8 +568,8 @@ __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, max_turn_time=%d\n",
speed, max_turn_time);
- i = value_index(speed, baud_rates);
- j = value_index(max_turn_time, max_turn_times);
+ i = value_index(speed, baud_rates, 10);
+ j = value_index(max_turn_time, max_turn_times, 4);
ASSERT(((i >=0) && (i <=10)), return 0;);
ASSERT(((j >=0) && (j <=4)), return 0;);
@@ -574,7 +605,7 @@ __u32 irlap_min_turn_time_in_bytes(__u32 speed, __u32 min_turn_time)
return bytes;
}
-__u32 byte_value(__u8 byte, __u32 *array)
+static __u32 byte_value(__u8 byte, __u32 *array)
{
int index;
@@ -602,20 +633,19 @@ int msb_index (__u16 word)
msb >>=1;
index--;
}
-
return index;
}
/*
- * Function value_index (value, array)
+ * Function value_index (value, array, size)
*
* Returns the index to the value in the specified array
*/
-int value_index(__u32 value, __u32 *array)
+static int value_index(__u32 value, __u32 *array, int size)
{
int i;
- for (i=0;i<8;i++)
+ for (i=0; i < size; i++)
if (array[i] == value)
break;
return i;
@@ -627,11 +657,38 @@ int value_index(__u32 value, __u32 *array)
* Returns value to index in array, easy!
*
*/
-__u32 index_value(int index, __u32 *array)
+static __u32 index_value(int index, __u32 *array)
{
return array[index];
}
+/*
+ * Function value_lower_bits (value, array)
+ *
+ * Returns a bit field marking all possibility lower than value.
+ * We may need a "value_higher_bits" in the future...
+ */
+static int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field)
+{
+ int i;
+ __u16 mask = 0x1;
+ __u16 result = 0x0;
+
+ for (i=0; i < size; i++) {
+ /* Add the current value to the bit field, shift mask */
+ result |= mask;
+ mask <<= 1;
+ /* Finished ? */
+ if (array[i] >= value)
+ break;
+ }
+ /* Send back a valid index */
+ if(i >= size)
+ i = size - 1; /* Last item */
+ *field = result;
+ return i;
+}
+
void irda_qos_bits_to_value(struct qos_info *qos)
{
int index;
@@ -667,10 +724,3 @@ void irda_qos_bits_to_value(struct qos_info *qos)
qos->compression.value = 0;
#endif
}
-
-
-
-
-
-
-
diff --git a/net/irda/timer.c b/net/irda/timer.c
index 7625eecfc..ac80c1a23 100644
--- a/net/irda/timer.c
+++ b/net/irda/timer.c
@@ -24,6 +24,7 @@
********************************************************************/
#include <asm/system.h>
+#include <linux/config.h>
#include <linux/delay.h>
#include <net/irda/timer.h>
@@ -99,6 +100,25 @@ void irlap_start_mbusy_timer(struct irlap_cb *self)
(void *) self, irlap_media_busy_expired);
}
+void irlap_stop_mbusy_timer(struct irlap_cb *self)
+{
+ /* If timer is activated, kill it! */
+ if(timer_pending(&self->media_busy_timer))
+ del_timer(&self->media_busy_timer);
+
+#ifdef CONFIG_IRDA_ULTRA
+ /* Send any pending Ultra frames if any */
+ if (!skb_queue_empty(&self->txq_ultra))
+ /* Note : we don't send the frame, just post an event.
+ * Frames will be sent only if we are in NDM mode (see
+ * irlap_event.c).
+ * Also, moved this code from irlap_media_busy_expired()
+ * to here to catch properly all cases...
+ * Jean II */
+ irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
+#endif /* CONFIG_IRDA_ULTRA */
+}
+
void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout)
{
irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
@@ -117,6 +137,13 @@ void irlmp_start_idle_timer(struct lap_cb *self, int timeout)
irlmp_idle_timer_expired);
}
+void irlmp_stop_idle_timer(struct lap_cb *self)
+{
+ /* If timer is activated, kill it! */
+ if(timer_pending(&self->idle_timer))
+ del_timer(&self->idle_timer);
+}
+
/*
* Function irlap_slot_timer_expired (data)
*
@@ -210,8 +237,5 @@ void irlap_media_busy_expired(void* data)
ASSERT(self != NULL, return;);
irda_device_set_media_busy(self->netdev, FALSE);
-
- /* Send any pending Ultra frames if any */
- if (!skb_queue_empty(&self->txq_ultra))
- irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);
+ /* Note : will deal with Ultra frames */
}
diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c
index 623328af1..a9f6d7328 100644
--- a/net/irda/wrapper.c
+++ b/net/irda/wrapper.c
@@ -69,6 +69,7 @@ static void (*state[])(struct net_device *dev, struct net_device_stats *stats,
*/
int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
{
+ struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
int xbofs;
int i;
int n;
@@ -85,7 +86,8 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
* Send XBOF's for required min. turn time and for the negotiated
* additional XBOFS
*/
- if (((struct irda_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
+
+ if (cb->magic != LAP_MAGIC) {
/*
* This will happen for all frames sent from user-space.
* Nothing to worry about, but we set the default number of
@@ -94,7 +96,7 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
IRDA_DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
xbofs = 10;
} else
- xbofs = ((struct irda_skb_cb *)(skb->cb))->xbofs;
+ xbofs = cb->xbofs + cb->xbofs_delay;
IRDA_DEBUG(4, __FUNCTION__ "(), xbofs=%d\n", xbofs);
@@ -287,6 +289,8 @@ static void state_link_escape(struct net_device *dev,
{
switch (byte) {
case BOF: /* New frame? */
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), Discarding incomplete frame\n");
rx_buff->state = BEGIN_FRAME;
irda_device_set_media_busy(dev, TRUE);
break;
@@ -328,6 +332,8 @@ static void state_inside_frame(struct net_device *dev,
switch (byte) {
case BOF: /* New frame? */
+ IRDA_DEBUG(1, __FUNCTION__
+ "(), Discarding incomplete frame\n");
rx_buff->state = BEGIN_FRAME;
irda_device_set_media_busy(dev, TRUE);
break;
diff --git a/net/khttpd/README b/net/khttpd/README
index 57d974051..84ccd6575 100644
--- a/net/khttpd/README
+++ b/net/khttpd/README
@@ -117,17 +117,6 @@ echo 1 > /proc/sys/net/khttpd/start
Port 8080
- in /etc/apache/httpd.conf. For security-reasons, you can also change
-
- BindAddress *
-
- to
-
- BindAddress 127.0.0.1
-
- (in the same file) to prevent outside users from accessing Apache
- directly.
-
Stopping kHTTPd
diff --git a/net/khttpd/datasending.c b/net/khttpd/datasending.c
index a26afe191..5726dca32 100644
--- a/net/khttpd/datasending.c
+++ b/net/khttpd/datasending.c
@@ -58,7 +58,7 @@ It sends the data to the socket indicated by desc->buf.
static int sock_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
int written;
- unsigned long kaddr;
+ char *kaddr;
unsigned long count = desc->count;
struct socket *sock = (struct socket *) desc->buf;
mm_segment_t old_fs;
@@ -69,7 +69,7 @@ static int sock_send_actor(read_descriptor_t * desc, struct page *page, unsigned
set_fs(KERNEL_DS);
kaddr = kmap(page);
- written = SendBuffer_async(sock,(char *)kaddr + offset,size);
+ written = SendBuffer_async(sock, kaddr + offset, size);
kunmap(page);
set_fs(old_fs);
if (written < 0) {
@@ -114,7 +114,7 @@ int DataSending(const int CPUNR)
inode = CurrentRequest->filp->f_dentry->d_inode;
- if (inode && inode->i_mapping->a_ops->readpage) {
+ if (inode->i_mapping->a_ops->readpage) {
/* This does the actual transfer using sendfile */
read_descriptor_t desc;
loff_t *ppos;
diff --git a/net/khttpd/main.c b/net/khttpd/main.c
index 5c39c59b9..2ade82be2 100644
--- a/net/khttpd/main.c
+++ b/net/khttpd/main.c
@@ -101,15 +101,12 @@ static int MainDaemon(void *cpu_pointer)
MOD_INC_USE_COUNT;
- current->state |= TASK_EXCLUSIVE;
-
CPUNR=0;
if (cpu_pointer!=NULL)
CPUNR=(int)*(int*)cpu_pointer;
sprintf(current->comm,"khttpd - %i",CPUNR);
- lock_kernel(); /* This seems to be required for exit_mm */
- exit_mm(current);
+ daemonize();
init_waitqueue_head(&(DummyWQ[CPUNR]));
@@ -148,7 +145,6 @@ static int MainDaemon(void *cpu_pointer)
changes +=AcceptConnections(CPUNR,MainSocket);
}
- set_current_state(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE);
if (changes==0)
{
(void)interruptible_sleep_on_timeout(&(DummyWQ[CPUNR]),1);
@@ -200,8 +196,7 @@ static int ManagementDaemon(void *unused)
sprintf(current->comm,"khttpd manager");
- lock_kernel(); /* This seems to be required for exit_mm */
- exit_mm(current);
+ daemonize();
/* Block all signals except SIGKILL and SIGSTOP */
diff --git a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
index bdc84d72f..1723588da 100644
--- a/net/lapb/lapb_iface.c
+++ b/net/lapb/lapb_iface.c
@@ -12,6 +12,7 @@
* History
* LAPB 001 Jonathan Naylor Started Coding
* LAPB 002 Jonathan Naylor New timer architecture.
+ * 2000-10-29 Henner Eisen lapb_data_indication() return status.
*/
#include <linux/config.h>
@@ -370,14 +371,11 @@ void lapb_disconnect_indication(lapb_cb *lapb, int reason)
int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb)
{
- int used = 0;
-
if (lapb->callbacks.data_indication != NULL) {
- (lapb->callbacks.data_indication)(lapb->token, skb);
- used = 1;
+ return (lapb->callbacks.data_indication)(lapb->token, skb);
}
-
- return used;
+ kfree_skb(skb);
+ return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */
}
int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb)
diff --git a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
index 4e7a9ca4d..0b45f57f5 100644
--- a/net/lapb/lapb_in.c
+++ b/net/lapb/lapb_in.c
@@ -12,6 +12,7 @@
* History
* LAPB 001 Jonathan Naulor Started Coding
* LAPB 002 Jonathan Naylor New timer architecture.
+ * 2000-10-29 Henner Eisen lapb_data_indication() return status.
*/
#include <linux/config.h>
@@ -464,8 +465,21 @@ static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_
lapb_check_iframes_acked(lapb, frame->nr);
}
if (frame->ns == lapb->vr) {
+ int cn;
+ cn = lapb_data_indication(lapb, skb);
+ queued = 1;
+ /*
+ * If upper layer has dropped the frame, we
+ * basically ignore any further protocol
+ * processing. This will cause the peer
+ * to re-transmit the frame later like
+ * a frame lost on the wire.
+ */
+ if(cn == NET_RX_DROP){
+ printk(KERN_DEBUG "LAPB: rx congestion\n");
+ break;
+ }
lapb->vr = (lapb->vr + 1) % modulus;
- queued = lapb_data_indication(lapb, skb);
lapb->condition &= ~LAPB_REJECT_CONDITION;
if (frame->pf) {
lapb_enquiry_response(lapb);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3927d9c3a..a8218d679 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -96,7 +96,7 @@ static void netlink_sock_destruct(struct sock *sk)
#endif
}
-/* This lock without TASK_EXCLUSIVE is good on UP and it is _very_ bad on SMP.
+/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP.
* Look, when several writers sleep and reader wakes them up, all but one
* immediately hit write lock and grab all the cpus. Exclusive sleep solves
* this, _but_ remember, it adds useless work on UP machines.
@@ -111,7 +111,7 @@ static void netlink_table_grab(void)
add_wait_queue_exclusive(&nl_table_wait, &wait);
for(;;) {
- set_current_state(TASK_UNINTERRUPTIBLE|TASK_EXCLUSIVE);
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (atomic_read(&nl_table_users) == 0)
break;
write_unlock_bh(&nl_table_lock);
diff --git a/net/socket.c b/net/socket.c
index 58df6d92e..5c5c5a85b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -277,14 +277,12 @@ static struct super_operations sockfs_ops = {
static struct super_block * sockfs_read_super(struct super_block *sb, void *data, int silent)
{
- struct inode *root = get_empty_inode();
+ struct inode *root = new_inode(sb);
if (!root)
return NULL;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
- root->i_sb = sb;
- root->i_dev = sb->s_dev;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = SOCKFS_MAGIC;
@@ -407,7 +405,7 @@ struct socket *sockfd_lookup(int fd, int *err)
}
inode = file->f_dentry->d_inode;
- if (!inode || !inode->i_sock || !(sock = socki_lookup(inode)))
+ if (!inode->i_sock || !(sock = socki_lookup(inode)))
{
*err = -ENOTSOCK;
fput(file);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index de359d2f5..9eee6afe2 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -257,7 +257,7 @@ rpc_make_runnable(struct rpc_task *task)
printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
return;
}
- task->tk_running = 1;
+ rpc_set_running(task);
if (RPC_IS_ASYNC(task)) {
if (RPC_IS_SLEEPING(task)) {
int status;
@@ -265,13 +265,14 @@ rpc_make_runnable(struct rpc_task *task)
if (status < 0) {
printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
task->tk_status = status;
- } else
- task->tk_sleeping = 0;
+ return;
+ }
+ rpc_clear_sleeping(task);
+ if (waitqueue_active(&rpciod_idle))
+ wake_up(&rpciod_idle);
}
- if (waitqueue_active(&rpciod_idle))
- wake_up(&rpciod_idle);
} else {
- task->tk_sleeping = 0;
+ rpc_clear_sleeping(task);
if (waitqueue_active(&task->tk_wait))
wake_up(&task->tk_wait);
}
@@ -287,7 +288,7 @@ rpc_schedule_run(struct rpc_task *task)
if (RPC_IS_ACTIVATED(task))
return;
task->tk_active = 1;
- task->tk_sleeping = 1;
+ rpc_set_sleeping(task);
rpc_make_runnable(task);
}
@@ -326,7 +327,7 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
/* Mark the task as being activated if so needed */
if (!RPC_IS_ACTIVATED(task)) {
task->tk_active = 1;
- task->tk_sleeping = 1;
+ rpc_set_sleeping(task);
}
status = __rpc_add_wait_queue(q, task);
@@ -334,7 +335,7 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
task->tk_status = status;
} else {
- task->tk_running = 0;
+ rpc_clear_running(task);
if (task->tk_callback) {
dprintk(KERN_ERR "RPC: %4d overwrites an active callback\n", task->tk_pid);
BUG();
@@ -590,21 +591,15 @@ __rpc_execute(struct rpc_task *task)
/*
* Check whether task is sleeping.
- * Note that if the task goes to sleep in tk_action,
- * and the RPC reply arrives before we get here, it will
- * have state RUNNING, but will still be on schedq.
- * 27/9/99: The above has been attempted fixed by
- * introduction of task->tk_sleeping.
*/
spin_lock_bh(&rpc_queue_lock);
if (!RPC_IS_RUNNING(task)) {
- task->tk_sleeping = 1;
+ rpc_set_sleeping(task);
if (RPC_IS_ASYNC(task)) {
spin_unlock_bh(&rpc_queue_lock);
return 0;
}
- } else
- task->tk_sleeping = 0;
+ }
spin_unlock_bh(&rpc_queue_lock);
while (RPC_IS_SLEEPING(task)) {
@@ -684,7 +679,7 @@ rpc_execute(struct rpc_task *task)
}
task->tk_active = 1;
- task->tk_running = 1;
+ rpc_set_running(task);
return __rpc_execute(task);
out_release:
rpc_release_task(task);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7603a9221..e48b8549a 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.107 2000/10/19 01:05:36 davem Exp $
+ * Version: $Id: af_unix.c,v 1.108 2000/11/10 04:02:04 davem Exp $
*
* Fixes:
* Linus Torvalds : Assorted bug cures.
@@ -832,7 +832,7 @@ static long unix_wait_for_peer(unix_socket *other, long timeo)
int sched;
DECLARE_WAITQUEUE(wait, current);
- __set_current_state(TASK_INTERRUPTIBLE|TASK_EXCLUSIVE);
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue_exclusive(&other->protinfo.af_unix.peer_wait, &wait);
sched = (!other->dead &&
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 3fcf7464c..16d46de54 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -100,7 +100,7 @@ extern inline unix_socket *unix_get_socket(struct file *filp)
/*
* Socket ?
*/
- if (inode && inode->i_sock) {
+ if (inode->i_sock) {
struct socket * sock = &inode->u.socket_i;
struct sock * s = sock->sk;
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 320722c40..0242b12e5 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -16,13 +16,16 @@
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor Centralised disconnect handling.
* New timer architecture.
- * 2000-11-03 Henner Eisen MSG_EOR handling more POSIX compliant.
- * 2000-22-03 Daniela Squassoni Allowed disabling/enabling of
+ * 2000-03-11 Henner Eisen MSG_EOR handling more POSIX compliant.
+ * 2000-03-22 Daniela Squassoni Allowed disabling/enabling of
* facilities negotiation and increased
* the throughput upper limit.
- * 2000-27-08 Arnaldo C. Melo s/suser/capable/ + micro cleanups
- * 2000-04-09 Henner Eisen Set sock->state in x25_accept().
+ * 2000-08-27 Arnaldo C. Melo s/suser/capable/ + micro cleanups
+ * 2000-09-04 Henner Eisen Set sock->state in x25_accept().
* Fixed x25_output() related skb leakage.
+ * 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket.
+ * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation.
+ * 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN
*/
#include <linux/config.h>
@@ -191,6 +194,7 @@ static void x25_kill_by_device(struct net_device *dev)
static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
+ struct x25_neigh *neigh;
if (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
@@ -201,6 +205,10 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, vo
case NETDEV_UP:
x25_link_device_up(dev);
break;
+ case NETDEV_GOING_DOWN:
+ if ((neigh = x25_get_neigh(dev)))
+ x25_terminate_link(neigh);
+ break;
case NETDEV_DOWN:
x25_kill_by_device(dev);
x25_route_device_down(dev);
@@ -471,6 +479,7 @@ static int x25_create(struct socket *sock, int protocol)
sock->ops = &x25_proto_ops;
sk->protocol = protocol;
+ sk->backlog_rcv = x25_backlog_rcv;
x25->t21 = sysctl_x25_call_request_timeout;
x25->t22 = sysctl_x25_reset_request_timeout;
@@ -905,6 +914,7 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
return err;
+ X25_SKB_CB(skb)->flags = msg->msg_flags;
skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
@@ -974,14 +984,31 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
if (msg->msg_flags & MSG_OOB) {
skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb);
} else {
- err = x25_output(sk, skb);
- if(err){
- len = err;
+ len = x25_output(sk, skb);
+ if(len<0){
kfree_skb(skb);
+ } else {
+ if(sk->protinfo.x25->qbitincl) len++;
}
}
+ /*
+ * lock_sock() is currently only used to serialize this x25_kick()
+ * against input-driven x25_kick() calls. It currently only blocks
+ * incoming packets for this socket and does not protect against
+ * any other socket state changes and is not called from anywhere
+ * else. As x25_kick() cannot block and as long as all socket
+ * operations are BKL-wrapped, we don't need take to care about
+ * purging the backlog queue in x25_release().
+ *
+ * Using lock_sock() to protect all socket operations entirely
+ * (and making the whole x25 stack SMP aware) unfortunately would
+ * require major changes to {send,recv}msg and skb allocation methods.
+ * -> 2.5 ;)
+ */
+ lock_sock(sk);
x25_kick(sk);
+ release_sock(sk);
return len;
}
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index d986022fb..fbc781dce 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -68,8 +68,17 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
* Find an existing socket.
*/
if ((sk = x25_find_socket(lci, neigh)) != NULL) {
+ int queued = 1;
+
skb->h.raw = skb->data;
- return x25_process_rx_frame(sk, skb);
+ bh_lock_sock(sk);
+ if (!sk->lock.users) {
+ queued = x25_process_rx_frame(sk, skb);
+ } else {
+ sk_add_backlog(sk, skb);
+ }
+ bh_unlock_sock(sk);
+ return queued;
}
/*
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c
index 5110d327a..bcb5f1cf4 100644
--- a/net/x25/x25_in.c
+++ b/net/x25/x25_in.c
@@ -16,8 +16,10 @@
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor Centralised disconnection code.
* New timer architecture.
- * mar/20/00 Daniela Squassoni Disabling/enabling of facilities
+ * 2000-03-20 Daniela Squassoni Disabling/enabling of facilities
* negotiation.
+ * 2000-11-10 Henner Eisen Check and reset for out-of-sequence
+ * i-frames.
*/
#include <linux/config.h>
@@ -216,7 +218,8 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
case X25_DATA: /* XXX */
sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
- if (!x25_validate_nr(sk, nr)) {
+ if ((ns!=sk->protinfo.x25->vr) ||
+ !x25_validate_nr(sk, nr)) {
x25_clear_queues(sk);
x25_write_internal(sk, X25_RESET_REQUEST);
x25_start_t22timer(sk);
@@ -357,4 +360,14 @@ int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
return queued;
}
+int x25_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+{
+ int queued;
+
+ queued = x25_process_rx_frame(sk,skb);
+ if(!queued) kfree_skb(skb);
+
+ return 0;
+}
+
#endif
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c
index 077f2c0b4..b3ce30477 100644
--- a/net/x25/x25_out.c
+++ b/net/x25/x25_out.c
@@ -15,7 +15,10 @@
* History
* X.25 001 Jonathan Naylor Started coding.
* X.25 002 Jonathan Naylor New timer architecture.
- * 2000-09-04 Henner Eisen Prevented x25_output() skb leakage.
+ * 2000-09-04 Henner Eisen Prevented x25_output() skb leakage.
+ * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation.
+ * 2000-11-10 Henner Eisen x25_send_iframe(): re-queued frames
+ * needed cleaned seq-number fields.
*/
#include <linux/config.h>
@@ -55,13 +58,17 @@ static int x25_pacsize_to_bytes(unsigned int pacsize)
}
/*
- * This is where all X.25 information frames pass;
+ * This is where all X.25 information frames pass.
+ *
+ * Returns the amount of user data bytes sent on success
+ * or a negative error code on failure.
*/
int x25_output(struct sock *sk, struct sk_buff *skb)
{
struct sk_buff *skbn;
unsigned char header[X25_EXT_MIN_LEN];
int err, frontlen, len, header_len, max_len;
+ int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT;
header_len = (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
max_len = x25_pacsize_to_bytes(sk->protinfo.x25->facilities.pacsize_out);
@@ -74,11 +81,14 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
frontlen = skb_headroom(skb);
while (skb->len > 0) {
- if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL){
- int unsent = skb->len - header_len;
- SOCK_DEBUG(sk, "x25_output: framgent allocation failed, err=%d, %d bytes unsent\n", err, unsent);
- return err;
+ if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, noblock, &err)) == NULL){
+ if(err == -EWOULDBLOCK && noblock){
+ kfree_skb(skb);
+ return sent;
}
+ SOCK_DEBUG(sk, "x25_output: fragment allocation failed, err=%d, %d bytes sent\n", err, sent);
+ return err;
+ }
skb_reserve(skbn, frontlen);
@@ -100,13 +110,15 @@ int x25_output(struct sock *sk, struct sk_buff *skb)
}
skb_queue_tail(&sk->write_queue, skbn);
+ sent += len;
}
kfree_skb(skb);
} else {
skb_queue_tail(&sk->write_queue, skb);
+ sent = skb->len - header_len;
}
- return 0;
+ return sent;
}
/*
@@ -119,9 +131,11 @@ static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
return;
if (sk->protinfo.x25->neighbour->extended) {
- skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0xFE;
+ skb->data[2] = (sk->protinfo.x25->vs << 1) & 0xFE;
+ skb->data[3] &= X25_EXT_M_BIT;
skb->data[3] |= (sk->protinfo.x25->vr << 1) & 0xFE;
} else {
+ skb->data[2] &= X25_STD_M_BIT;
skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0x0E;
skb->data[2] |= (sk->protinfo.x25->vr << 5) & 0xE0;
}