summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-02 02:36:47 +0000
commit8624512aa908741ba2795200133eae0d7f4557ea (patch)
treed5d3036fccf2604f4c98dedc11e8adb929d6b52e
parent7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff)
Merge with 2.3.48.
-rw-r--r--CREDITS38
-rw-r--r--Documentation/Changes22
-rw-r--r--Documentation/Configure.help303
-rw-r--r--Documentation/IRQ-affinity.txt37
-rw-r--r--Documentation/fb/matroxfb.txt31
-rw-r--r--Documentation/floppy.txt (renamed from drivers/block/README.fd)2
-rw-r--r--Documentation/ide.txt2
-rw-r--r--Documentation/ioctl-number.txt3
-rw-r--r--Documentation/m68k/README.buddha (renamed from drivers/block/README.buddha)0
-rw-r--r--Documentation/networking/8139too.txt194
-rw-r--r--Documentation/networking/fore200e.txt55
-rw-r--r--Documentation/networking/tulip.txt244
-rw-r--r--Documentation/networking/wavelan.txt114
-rw-r--r--Documentation/parport-lowlevel.txt1490
-rw-r--r--Documentation/pci.txt2
-rw-r--r--Documentation/pm.txt151
-rw-r--r--Documentation/vm/balance14
-rw-r--r--MAINTAINERS17
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/config.in5
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c6
-rw-r--r--arch/alpha/kernel/core_tsunami.c35
-rw-r--r--arch/alpha/kernel/irq.c68
-rw-r--r--arch/alpha/kernel/pci_iommu.c53
-rw-r--r--arch/alpha/kernel/process.c109
-rw-r--r--arch/alpha/kernel/proto.h3
-rw-r--r--arch/alpha/kernel/semaphore.c4
-rw-r--r--arch/alpha/kernel/setup.c4
-rw-r--r--arch/alpha/kernel/smp.c41
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c26
-rw-r--r--arch/alpha/kernel/sys_dp264.c124
-rw-r--r--arch/alpha/kernel/sys_sio.c2
-rw-r--r--arch/alpha/kernel/time.c1
-rw-r--r--arch/alpha/kernel/traps.c4
-rw-r--r--arch/alpha/vmlinux.lds1
-rw-r--r--arch/arm/kernel/armksyms.c1
-rw-r--r--arch/arm/mm/consistent.c6
-rw-r--r--arch/i386/defconfig3
-rw-r--r--arch/i386/kernel/acpi.c37
-rw-r--r--arch/i386/kernel/apm.c14
-rw-r--r--arch/i386/kernel/entry.S2
-rw-r--r--arch/i386/kernel/i386_ksyms.c4
-rw-r--r--arch/i386/kernel/i8259.c36
-rw-r--r--arch/i386/kernel/io_apic.c102
-rw-r--r--arch/i386/kernel/irq.c419
-rw-r--r--arch/i386/kernel/microcode.c46
-rw-r--r--arch/i386/kernel/mpparse.c29
-rw-r--r--arch/i386/kernel/mtrr.c9
-rw-r--r--arch/i386/kernel/process.c9
-rw-r--r--arch/i386/kernel/semaphore.c5
-rw-r--r--arch/i386/kernel/setup.c17
-rw-r--r--arch/i386/kernel/traps.c5
-rw-r--r--arch/i386/mm/init.c4
-rw-r--r--arch/ia64/ia32/binfmt_elf32.c2
-rw-r--r--arch/ia64/ia32/ia32_entry.S2
-rw-r--r--arch/ia64/ia32/sys_ia32.c21
-rw-r--r--arch/ia64/kdb/kdbsupport.c27
-rw-r--r--arch/ia64/kernel/irq.c3
-rw-r--r--arch/ia64/kernel/irq_internal.c2
-rw-r--r--arch/ia64/kernel/ivt.S2
-rw-r--r--arch/ia64/kernel/process.c8
-rw-r--r--arch/ia64/kernel/time.c20
-rw-r--r--arch/ia64/kernel/traps.c116
-rw-r--r--arch/ia64/kernel/unaligned.c47
-rw-r--r--arch/ia64/lib/copy_user.S440
-rw-r--r--arch/mips/defconfig4
-rw-r--r--arch/mips/kernel/irixelf.c21
-rw-r--r--arch/mips/kernel/irq.c20
-rw-r--r--arch/mips/kernel/mips_ksyms.c4
-rw-r--r--arch/mips/kernel/proc.c5
-rw-r--r--arch/mips/kernel/setup.c4
-rw-r--r--arch/mips/sgi/kernel/indy_int.c20
-rw-r--r--arch/mips64/defconfig1
-rw-r--r--arch/mips64/defconfig-ip221
-rw-r--r--arch/mips64/defconfig-ip271
-rw-r--r--arch/mips64/kernel/proc.c7
-rw-r--r--arch/mips64/kernel/setup.c4
-rw-r--r--arch/mips64/sgi-ip22/ip22-int.c20
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c22
-rw-r--r--arch/ppc/chrpboot/main.c20
-rw-r--r--arch/ppc/chrpboot/piggyback.c3
-rw-r--r--arch/ppc/coffboot/piggyback.c3
-rw-r--r--arch/ppc/config.in7
-rw-r--r--arch/ppc/configs/common_defconfig26
-rw-r--r--arch/ppc/defconfig26
-rw-r--r--arch/ppc/kernel/Makefile20
-rw-r--r--arch/ppc/kernel/apus_setup.c159
-rw-r--r--arch/ppc/kernel/entry.S4
-rw-r--r--arch/ppc/kernel/hashtable.S80
-rw-r--r--arch/ppc/kernel/head.S7
-rw-r--r--arch/ppc/kernel/irq.c3
-rw-r--r--arch/ppc/kernel/misc.S11
-rw-r--r--arch/ppc/kernel/mk_defs.c1
-rw-r--r--arch/ppc/kernel/pmac_pic.c24
-rw-r--r--arch/ppc/kernel/ppc_htab.c9
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c17
-rw-r--r--arch/ppc/kernel/process.c2
-rw-r--r--arch/ppc/kernel/prom.c1
-rw-r--r--arch/ppc/kernel/setup.c60
-rw-r--r--arch/ppc/kernel/smp.c3
-rw-r--r--arch/ppc/mm/init.c86
-rw-r--r--arch/ppc/mm/mem_pieces.c2
-rw-r--r--arch/ppc/xmon/xmon.c46
-rw-r--r--arch/sparc/boot/Makefile14
-rw-r--r--arch/sparc/kernel/ioport.c40
-rw-r--r--arch/sparc/kernel/irq.c7
-rw-r--r--arch/sparc/kernel/setup.c6
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c4
-rw-r--r--arch/sparc/lib/locks.S21
-rw-r--r--arch/sparc/mm/init.c4
-rw-r--r--arch/sparc64/defconfig6
-rw-r--r--arch/sparc64/kernel/irq.c7
-rw-r--r--arch/sparc64/kernel/setup.c6
-rw-r--r--arch/sparc64/kernel/signal32.c4
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c3
-rw-r--r--arch/sparc64/lib/VIScsum.S693
-rw-r--r--arch/sparc64/lib/VIScsumcopy.S1176
-rw-r--r--arch/sparc64/lib/VIScsumcopyusr.S1162
-rw-r--r--drivers/Makefile5
-rw-r--r--drivers/atm/Config.in25
-rw-r--r--drivers/atm/Makefile52
-rw-r--r--drivers/atm/atmdev_init.c6
-rw-r--r--drivers/atm/eni.c125
-rw-r--r--drivers/atm/eni.h4
-rw-r--r--drivers/atm/fore200e.c2973
-rw-r--r--drivers/atm/fore200e.h952
-rw-r--r--drivers/atm/fore200e_firmware_copyright31
-rw-r--r--drivers/atm/fore200e_mkfirm.c155
-rw-r--r--drivers/atm/iphase.c6
-rw-r--r--drivers/atm/pca200e.data850
-rw-r--r--drivers/atm/pca200e_ecd.data906
-rw-r--r--drivers/atm/sba200e_ecd.data928
-rw-r--r--drivers/atm/zatm.c11
-rw-r--r--drivers/block/Config.in45
-rw-r--r--drivers/block/Makefile8
-rw-r--r--drivers/block/README.lvm8
-rw-r--r--drivers/block/README.md4
-rw-r--r--drivers/block/aec6210.c64
-rw-r--r--drivers/block/ali14xx.c12
-rw-r--r--drivers/block/alim15x3.c21
-rw-r--r--drivers/block/amd7409.c220
-rw-r--r--drivers/block/buddha.c10
-rw-r--r--drivers/block/cmd640.c20
-rw-r--r--drivers/block/cmd64x.c278
-rw-r--r--drivers/block/cs5530.c174
-rw-r--r--drivers/block/cy82c693.c5
-rw-r--r--drivers/block/dtc2278.c4
-rw-r--r--drivers/block/falconide.c4
-rw-r--r--drivers/block/gayle.c4
-rw-r--r--drivers/block/hpt34x.c87
-rw-r--r--drivers/block/hpt366.c84
-rw-r--r--drivers/block/ht6560b.c359
-rw-r--r--drivers/block/ide-cd.h8
-rw-r--r--drivers/block/ide-disk.c2
-rw-r--r--drivers/block/ide-dma.c21
-rw-r--r--drivers/block/ide-features.c199
-rw-r--r--drivers/block/ide-floppy.c9
-rw-r--r--drivers/block/ide-pci.c54
-rw-r--r--drivers/block/ide-probe.c108
-rw-r--r--drivers/block/ide-proc.c93
-rw-r--r--drivers/block/ide-tape.c191
-rw-r--r--drivers/block/ide.c171
-rw-r--r--drivers/block/ide_modes.h5
-rw-r--r--drivers/block/linear.c8
-rw-r--r--drivers/block/ll_rw_blk.c95
-rw-r--r--drivers/block/lvm.c13
-rw-r--r--drivers/block/macide.c6
-rw-r--r--drivers/block/md.c102
-rw-r--r--drivers/block/ns87415.c2
-rw-r--r--drivers/block/opti621.c2
-rw-r--r--drivers/block/pdc202xx.c76
-rw-r--r--drivers/block/pdc4030.c2
-rw-r--r--drivers/block/pdc4030.h2
-rw-r--r--drivers/block/piix.c169
-rw-r--r--drivers/block/qd6580.c4
-rw-r--r--drivers/block/raid0.c25
-rw-r--r--drivers/block/rapide.c6
-rw-r--r--drivers/block/rz1000.c2
-rw-r--r--drivers/block/sis5513.c11
-rw-r--r--drivers/block/sl82c105.c2
-rw-r--r--drivers/block/trm290.c2
-rw-r--r--drivers/block/umc8672.c6
-rw-r--r--drivers/block/via82cxxx.c23
-rw-r--r--drivers/char/Config.in3
-rw-r--r--drivers/char/Makefile15
-rw-r--r--drivers/char/agp/agpgart_be.c2
-rw-r--r--drivers/char/ds1620.c436
-rw-r--r--drivers/char/efirtc.c2
-rw-r--r--drivers/char/h8.c74
-rw-r--r--drivers/char/h8.h6
-rw-r--r--drivers/char/lp.c4
-rw-r--r--drivers/char/mem.c12
-rw-r--r--drivers/char/nwbutton.c276
-rw-r--r--drivers/char/nwbutton.h48
-rw-r--r--drivers/char/nwflash.c708
-rw-r--r--drivers/char/raw.c7
-rw-r--r--drivers/char/rtc.c8
-rw-r--r--drivers/char/wdt285.c204
-rw-r--r--drivers/char/wdt977.c204
-rw-r--r--drivers/i2c/i2c-core.c6
-rw-r--r--drivers/isdn/avmb1/b1dma.c7
-rw-r--r--drivers/isdn/avmb1/capi.c5
-rw-r--r--drivers/isdn/divert/divert_procfs.c6
-rw-r--r--drivers/isdn/eicon/eicon_idi.c57
-rw-r--r--drivers/isdn/eicon/eicon_isa.c11
-rw-r--r--drivers/isdn/eicon/eicon_mod.c14
-rw-r--r--drivers/isdn/hisax/avm_pci.c11
-rw-r--r--drivers/isdn/hisax/config.c9
-rw-r--r--drivers/isdn/hisax/diva.c9
-rw-r--r--drivers/isdn/hisax/elsa_ser.c8
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c21
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c13
-rw-r--r--drivers/isdn/hisax/hfc_pci.c17
-rw-r--r--drivers/isdn/hisax/hfc_sx.c20
-rw-r--r--drivers/isdn/hisax/hisax.h8
-rw-r--r--drivers/isdn/hisax/hscx.c7
-rw-r--r--drivers/isdn/hisax/hscx_irq.c7
-rw-r--r--drivers/isdn/hisax/isac.c11
-rw-r--r--drivers/isdn/hisax/isar.c9
-rw-r--r--drivers/isdn/hisax/jade.c7
-rw-r--r--drivers/isdn/hisax/jade_irq.c7
-rw-r--r--drivers/isdn/hisax/l3dss1.c12
-rw-r--r--drivers/isdn/hisax/md5sums.asc24
-rw-r--r--drivers/isdn/hisax/netjet.c11
-rw-r--r--drivers/isdn/hisax/w6692.c17
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c6
-rw-r--r--drivers/isdn/hysdn/hysdn_procfs.c23
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c6
-rw-r--r--drivers/isdn/isdn_common.c28
-rw-r--r--drivers/isdn/isdn_net.c28
-rw-r--r--drivers/isdn/isdn_tty.c164
-rw-r--r--drivers/isdn/isdn_tty.h36
-rw-r--r--drivers/isdn/sc/debug.h2
-rw-r--r--drivers/net/3c505.c3
-rw-r--r--drivers/net/8139too.c475
-rw-r--r--drivers/net/Config.in4
-rw-r--r--drivers/net/Makefile12
-rw-r--r--drivers/net/eepro100.c74
-rw-r--r--drivers/net/hamradio/6pack.c4
-rw-r--r--drivers/net/irda/nsc-ircc.c49
-rw-r--r--drivers/net/irda/smc-ircc.c15
-rw-r--r--drivers/net/pcmcia/3c589_cs.c3
-rw-r--r--drivers/net/sk_g16.c2
-rw-r--r--drivers/net/tokenring/olympic.c9
-rw-r--r--drivers/net/tulip.c3159
-rw-r--r--drivers/net/tulip/21142.c235
-rw-r--r--drivers/net/tulip/Makefile14
-rw-r--r--drivers/net/tulip/eeprom.c270
-rw-r--r--drivers/net/tulip/interrupt.c337
-rw-r--r--drivers/net/tulip/media.c403
-rw-r--r--drivers/net/tulip/pnic.c146
-rw-r--r--drivers/net/tulip/timer.c208
-rw-r--r--drivers/net/tulip/tulip.h342
-rw-r--r--drivers/net/tulip/tulip_core.c1391
-rw-r--r--drivers/net/wan/cosa.c70
-rw-r--r--drivers/net/wan/syncppp.c17
-rw-r--r--drivers/net/wavelan.c244
-rw-r--r--drivers/net/wavelan.p.h59
-rw-r--r--drivers/parport/daisy.c32
-rw-r--r--drivers/parport/parport_pc.c190
-rw-r--r--drivers/parport/probe.c11
-rw-r--r--drivers/parport/share.c14
-rw-r--r--drivers/pci/pci.ids2
-rw-r--r--drivers/pci/proc.c6
-rw-r--r--drivers/pcmcia/i82365.c35
-rw-r--r--drivers/pcmcia/yenta.c70
-rw-r--r--drivers/pnp/isapnp_proc.c14
-rw-r--r--drivers/scsi/3w-xxxx.c10
-rw-r--r--drivers/scsi/ChangeLog.sym53c8xx14
-rw-r--r--drivers/scsi/Config.in16
-rw-r--r--drivers/scsi/eata_dma_proc.c2
-rw-r--r--drivers/scsi/pci2000.c3
-rw-r--r--drivers/scsi/pci2000.h74
-rw-r--r--drivers/scsi/pci2220i.c3
-rw-r--r--drivers/scsi/pci2220i.h74
-rw-r--r--drivers/scsi/qla1280.c23
-rw-r--r--drivers/scsi/qlogicfc.c355
-rw-r--r--drivers/scsi/qlogicfc.h2
-rw-r--r--drivers/scsi/sr_ioctl.c4
-rw-r--r--drivers/scsi/sun3_scsi.c6
-rw-r--r--drivers/scsi/sym53c8xx.c794
-rw-r--r--drivers/sound/Makefile4
-rw-r--r--drivers/sound/README.CONFIG75
-rw-r--r--drivers/sound/ac97_codec.c3
-rw-r--r--drivers/sound/ad1816.c4
-rw-r--r--drivers/sound/ad1848.c26
-rw-r--r--drivers/sound/adlib_card.c2
-rw-r--r--drivers/sound/audio.c4
-rw-r--r--drivers/sound/cs4232.c8
-rw-r--r--drivers/sound/dev_table.c12
-rw-r--r--drivers/sound/dev_table.h32
-rw-r--r--drivers/sound/dmabuf.c4
-rw-r--r--drivers/sound/es1371.c38
-rw-r--r--drivers/sound/finetune.h32
-rw-r--r--drivers/sound/gus_card.c16
-rw-r--r--drivers/sound/gus_midi.c8
-rw-r--r--drivers/sound/gus_vol.c3
-rw-r--r--drivers/sound/gus_wave.c9
-rw-r--r--drivers/sound/ics2101.c3
-rw-r--r--drivers/sound/legacy.h50
-rw-r--r--drivers/sound/lowlevel/Config.in9
-rw-r--r--drivers/sound/mad16.c21
-rw-r--r--drivers/sound/maui.c14
-rw-r--r--drivers/sound/midi_synth.c9
-rw-r--r--drivers/sound/midibuf.c4
-rw-r--r--drivers/sound/mpu401.c16
-rw-r--r--drivers/sound/opl3.c4
-rw-r--r--drivers/sound/opl3sa.c16
-rw-r--r--drivers/sound/opl3sa2.c15
-rw-r--r--drivers/sound/pas2_card.c17
-rw-r--r--drivers/sound/pas2_midi.c7
-rw-r--r--drivers/sound/pas2_mixer.c4
-rw-r--r--drivers/sound/pas2_pcm.c6
-rw-r--r--drivers/sound/pss.c22
-rw-r--r--drivers/sound/sb.h3
-rw-r--r--drivers/sound/sb_audio.c4
-rw-r--r--drivers/sound/sb_card.c203
-rw-r--r--drivers/sound/sb_common.c40
-rw-r--r--drivers/sound/sb_midi.c6
-rw-r--r--drivers/sound/sb_mixer.c24
-rw-r--r--drivers/sound/sb_mixer.h6
-rw-r--r--drivers/sound/sequencer.c11
-rw-r--r--drivers/sound/sequencer_syms.c1
-rw-r--r--drivers/sound/sgalaxy.c5
-rw-r--r--drivers/sound/softoss.c5
-rw-r--r--drivers/sound/softoss_rs.c3
-rw-r--r--drivers/sound/sound_config.h1
-rw-r--r--drivers/sound/sound_timer.c4
-rw-r--r--drivers/sound/soundcard.c66
-rw-r--r--drivers/sound/sscape.c10
-rw-r--r--drivers/sound/sys_timer.c4
-rw-r--r--drivers/sound/trident.c4
-rw-r--r--drivers/sound/trix.c26
-rw-r--r--drivers/sound/uart401.c8
-rw-r--r--drivers/sound/uart6850.c7
-rw-r--r--drivers/sound/v_midi.c6
-rw-r--r--drivers/sound/vidc.c522
-rw-r--r--drivers/sound/vidc.h11
-rw-r--r--drivers/sound/vidc_audio.c314
-rw-r--r--drivers/sound/vidc_fill.S18
-rw-r--r--drivers/sound/vidc_mixer.c151
-rw-r--r--drivers/sound/vidc_synth.c91
-rw-r--r--drivers/sound/waveartist.c2
-rw-r--r--drivers/sound/wavfront.c4
-rw-r--r--drivers/usb/acm.c20
-rw-r--r--drivers/usb/devio.c6
-rw-r--r--drivers/usb/evdev.c14
-rw-r--r--drivers/usb/ftdi_sio.h380
-rw-r--r--drivers/usb/graphire.c18
-rw-r--r--drivers/usb/hid.c25
-rw-r--r--drivers/usb/inode.c40
-rw-r--r--drivers/usb/input.c33
-rw-r--r--drivers/usb/joydev.c38
-rw-r--r--drivers/usb/keybdev.c20
-rw-r--r--drivers/usb/mousedev.c15
-rw-r--r--drivers/usb/printer.c17
-rw-r--r--drivers/usb/scanner.c12
-rw-r--r--drivers/usb/usb-core.c16
-rw-r--r--drivers/usb/usb-ohci.c12
-rw-r--r--drivers/usb/usb-serial.c590
-rw-r--r--drivers/usb/usb-serial.h64
-rw-r--r--drivers/usb/usb-storage-debug.h1
-rw-r--r--drivers/usb/usbkbd.c18
-rw-r--r--drivers/usb/usbmouse.c17
-rw-r--r--drivers/usb/wmforce.c18
-rw-r--r--drivers/video/Config.in4
-rw-r--r--drivers/video/Makefile21
-rw-r--r--drivers/video/aty128fb.c134
-rw-r--r--drivers/video/atyfb.c63
-rw-r--r--drivers/video/matrox/Makefile60
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c348
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c924
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h147
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c862
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.h13
-rw-r--r--drivers/video/matrox/matroxfb_accel.c1212
-rw-r--r--drivers/video/matrox/matroxfb_accel.h12
-rw-r--r--drivers/video/matrox/matroxfb_base.c2544
-rw-r--r--drivers/video/matrox/matroxfb_base.h825
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c788
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.h44
-rw-r--r--drivers/video/matrox/matroxfb_maven.c1040
-rw-r--r--drivers/video/matrox/matroxfb_maven.h23
-rw-r--r--drivers/video/matrox/matroxfb_misc.c660
-rw-r--r--drivers/video/matrox/matroxfb_misc.h21
-rw-r--r--drivers/video/matroxfb.c6107
-rw-r--r--drivers/video/vgacon.c7
-rw-r--r--drivers/zorro/proc.c6
-rw-r--r--fs/Config.in2
-rw-r--r--fs/adfs/adfs.h2
-rw-r--r--fs/adfs/dir.c15
-rw-r--r--fs/adfs/file.c5
-rw-r--r--fs/adfs/inode.c17
-rw-r--r--fs/adfs/super.c15
-rw-r--r--fs/affs/dir.c30
-rw-r--r--fs/affs/file.c39
-rw-r--r--fs/affs/inode.c16
-rw-r--r--fs/affs/namei.c8
-rw-r--r--fs/affs/super.c17
-rw-r--r--fs/affs/symlink.c6
-rw-r--r--fs/attr.c4
-rw-r--r--fs/autofs/autofs_i.h2
-rw-r--r--fs/autofs/dir.c7
-rw-r--r--fs/autofs/inode.c18
-rw-r--r--fs/autofs/root.c16
-rw-r--r--fs/autofs4/autofs_i.h2
-rw-r--r--fs/autofs4/inode.c7
-rw-r--r--fs/autofs4/root.c38
-rw-r--r--fs/bad_inode.c30
-rw-r--r--fs/bfs/dir.c19
-rw-r--r--fs/bfs/file.c3
-rw-r--r--fs/bfs/inode.c11
-rw-r--r--fs/binfmt_elf.c10
-rw-r--r--fs/binfmt_em86.c5
-rw-r--r--fs/block_dev.c6
-rw-r--r--fs/buffer.c43
-rw-r--r--fs/coda/cnode.c17
-rw-r--r--fs/coda/dir.c28
-rw-r--r--fs/coda/file.c20
-rw-r--r--fs/coda/inode.c19
-rw-r--r--fs/coda/pioctl.c17
-rw-r--r--fs/cramfs/inode.c35
-rw-r--r--fs/devfs/base.c26
-rw-r--r--fs/devices.c11
-rw-r--r--fs/devpts/devpts_i.h2
-rw-r--r--fs/devpts/inode.c16
-rw-r--r--fs/devpts/root.c7
-rw-r--r--fs/efs/dir.c7
-rw-r--r--fs/efs/file.c9
-rw-r--r--fs/efs/inode.c14
-rw-r--r--fs/efs/super.c12
-rw-r--r--fs/exec.c8
-rw-r--r--fs/ext2/dir.c28
-rw-r--r--fs/ext2/file.c3
-rw-r--r--fs/ext2/ialloc.c1
-rw-r--r--fs/ext2/inode.c12
-rw-r--r--fs/ext2/namei.c35
-rw-r--r--fs/ext2/super.c17
-rw-r--r--fs/fat/dir.c8
-rw-r--r--fs/fat/fatfs_syms.c3
-rw-r--r--fs/fat/file.c17
-rw-r--r--fs/fat/inode.c18
-rw-r--r--fs/fcntl.c4
-rw-r--r--fs/fifo.c6
-rw-r--r--fs/file_table.c4
-rw-r--r--fs/hfs/dir.c13
-rw-r--r--fs/hfs/dir_cap.c32
-rw-r--r--fs/hfs/dir_dbl.c21
-rw-r--r--fs/hfs/dir_nat.c36
-rw-r--r--fs/hfs/file.c17
-rw-r--r--fs/hfs/file_cap.c32
-rw-r--r--fs/hfs/file_hdr.c22
-rw-r--r--fs/hfs/inode.c46
-rw-r--r--fs/hfs/super.c15
-rw-r--r--fs/hpfs/dir.c5
-rw-r--r--fs/hpfs/hpfs_fn.h1
-rw-r--r--fs/hpfs/inode.c57
-rw-r--r--fs/hpfs/super.c20
-rw-r--r--fs/inode.c5
-rw-r--r--fs/isofs/Makefile2
-rw-r--r--fs/isofs/dir.c7
-rw-r--r--fs/isofs/file.c31
-rw-r--r--fs/isofs/inode.c29
-rw-r--r--fs/minix/bitmap.c1
-rw-r--r--fs/minix/dir.c28
-rw-r--r--fs/minix/file.c15
-rw-r--r--fs/minix/inode.c30
-rw-r--r--fs/minix/namei.c35
-rw-r--r--fs/msdos/namei.c17
-rw-r--r--fs/ncpfs/dir.c36
-rw-r--r--fs/ncpfs/file.c18
-rw-r--r--fs/ncpfs/inode.c23
-rw-r--r--fs/nfs/dir.c37
-rw-r--r--fs/nfs/file.c19
-rw-r--r--fs/nfs/inode.c30
-rw-r--r--fs/nfs/symlink.c2
-rw-r--r--fs/nfs/write.c20
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/nfsd/vfs.c7
-rw-r--r--fs/ntfs/fs.c46
-rw-r--r--fs/open.c2
-rw-r--r--fs/openpromfs/inode.c54
-rw-r--r--fs/partitions/check.c6
-rw-r--r--fs/partitions/msdos.c4
-rw-r--r--fs/pipe.c7
-rw-r--r--fs/proc/base.c77
-rw-r--r--fs/proc/generic.c30
-rw-r--r--fs/proc/inode.c26
-rw-r--r--fs/proc/kcore.c8
-rw-r--r--fs/proc/kmsg.c6
-rw-r--r--fs/proc/proc_misc.c45
-rw-r--r--fs/proc/root.c15
-rw-r--r--fs/qnx4/dir.c18
-rw-r--r--fs/qnx4/file.c3
-rw-r--r--fs/qnx4/inode.c9
-rw-r--r--fs/read_write.c10
-rw-r--r--fs/romfs/inode.c77
-rw-r--r--fs/smbfs/dir.c34
-rw-r--r--fs/smbfs/file.c44
-rw-r--r--fs/smbfs/inode.c29
-rw-r--r--fs/smbfs/sock.c60
-rw-r--r--fs/sysv/dir.c28
-rw-r--r--fs/sysv/file.c11
-rw-r--r--fs/sysv/ialloc.c1
-rw-r--r--fs/sysv/inode.c33
-rw-r--r--fs/sysv/namei.c38
-rw-r--r--fs/udf/dir.c30
-rw-r--r--fs/udf/file.c3
-rw-r--r--fs/udf/ialloc.c1
-rw-r--r--fs/udf/inode.c2
-rw-r--r--fs/udf/namei.c36
-rw-r--r--fs/udf/super.c24
-rw-r--r--fs/udf/udfdecl.h11
-rw-r--r--fs/ufs/Makefile2
-rw-r--r--fs/ufs/acl.c68
-rw-r--r--fs/ufs/dir.c21
-rw-r--r--fs/ufs/file.c3
-rw-r--r--fs/ufs/ialloc.c1
-rw-r--r--fs/ufs/inode.c8
-rw-r--r--fs/ufs/namei.c32
-rw-r--r--fs/ufs/super.c19
-rw-r--r--fs/umsdos/check.c1
-rw-r--r--fs/umsdos/dir.c35
-rw-r--r--fs/umsdos/inode.c36
-rw-r--r--fs/umsdos/rdir.c21
-rw-r--r--fs/vfat/namei.c17
-rw-r--r--include/asm-alpha/atomic.h8
-rw-r--r--include/asm-alpha/bitops.h12
-rw-r--r--include/asm-alpha/parport.h2
-rw-r--r--include/asm-alpha/pci.h19
-rw-r--r--include/asm-alpha/semaphore-helper.h4
-rw-r--r--include/asm-alpha/semaphore.h16
-rw-r--r--include/asm-alpha/spinlock.h8
-rw-r--r--include/asm-alpha/system.h36
-rw-r--r--include/asm-arm/arch-arc/io.h2
-rw-r--r--include/asm-arm/arch-cl7500/io.h2
-rw-r--r--include/asm-arm/arch-ebsa110/io.h2
-rw-r--r--include/asm-arm/arch-ebsa285/io.h4
-rw-r--r--include/asm-arm/arch-nexuspci/io.h2
-rw-r--r--include/asm-arm/arch-rpc/io.h2
-rw-r--r--include/asm-arm/arch-sa1100/io.h4
-rw-r--r--include/asm-arm/parport.h2
-rw-r--r--include/asm-i386/atomic.h11
-rw-r--r--include/asm-i386/hardirq.h32
-rw-r--r--include/asm-i386/hw_irq.h10
-rw-r--r--include/asm-i386/mpspec.h3
-rw-r--r--include/asm-i386/parport.h22
-rw-r--r--include/asm-i386/pgtable.h1
-rw-r--r--include/asm-i386/smp.h2
-rw-r--r--include/asm-i386/softirq.h8
-rw-r--r--include/asm-ia64/offsets.h6
-rw-r--r--include/asm-ia64/page.h5
-rw-r--r--include/asm-ia64/pgalloc.h21
-rw-r--r--include/asm-ia64/pgtable.h14
-rw-r--r--include/asm-ia64/processor.h36
-rw-r--r--include/asm-ia64/siginfo.h21
-rw-r--r--include/asm-mips/hardirq.h19
-rw-r--r--include/asm-mips/hw_irq.h5
-rw-r--r--include/asm-mips/parport.h22
-rw-r--r--include/asm-mips/pgtable.h3
-rw-r--r--include/asm-mips/softirq.h10
-rw-r--r--include/asm-mips64/hardirq.h15
-rw-r--r--include/asm-mips64/hw_irq.h5
-rw-r--r--include/asm-mips64/parport.h22
-rw-r--r--include/asm-mips64/pgtable.h3
-rw-r--r--include/asm-mips64/softirq.h10
-rw-r--r--include/asm-ppc/hw_irq.h21
-rw-r--r--include/asm-ppc/io.h98
-rw-r--r--include/asm-ppc/irq.h56
-rw-r--r--include/asm-ppc/pci.h3
-rw-r--r--include/asm-ppc/processor.h11
-rw-r--r--include/asm-ppc/system.h1
-rw-r--r--include/asm-ppc/types.h9
-rw-r--r--include/asm-ppc/vga.h4
-rw-r--r--include/asm-sparc/termbits.h5
-rw-r--r--include/asm-sparc64/io.h24
-rw-r--r--include/asm-sparc64/siginfo.h2
-rw-r--r--include/asm-sparc64/termbits.h5
-rw-r--r--include/linux/ac97_codec.h (renamed from drivers/sound/ac97_codec.h)2
-rw-r--r--include/linux/affs_fs.h4
-rw-r--r--include/linux/bfs_fs.h2
-rw-r--r--include/linux/blkdev.h5
-rw-r--r--include/linux/coda_linux.h1
-rw-r--r--include/linux/dlists.h108
-rw-r--r--include/linux/efs_fs.h2
-rw-r--r--include/linux/ext2_fs.h15
-rw-r--r--include/linux/fb.h19
-rw-r--r--include/linux/fs.h15
-rw-r--r--include/linux/hdreg.h66
-rw-r--r--include/linux/hfs_fs.h16
-rw-r--r--include/linux/ide.h14
-rw-r--r--include/linux/irq.h34
-rw-r--r--include/linux/isdn.h27
-rw-r--r--include/linux/iso_fs.h2
-rw-r--r--include/linux/list.h3
-rw-r--r--include/linux/lists.h62
-rw-r--r--include/linux/matroxfb.h32
-rw-r--r--include/linux/minix_fs.h13
-rw-r--r--include/linux/mm.h3
-rw-r--r--include/linux/mmzone.h5
-rw-r--r--include/linux/msdos_fs.h1
-rw-r--r--include/linux/ncp_fs.h2
-rw-r--r--include/linux/netdevice.h49
-rw-r--r--include/linux/nfs_fs.h3
-rw-r--r--include/linux/pci.h1
-rw-r--r--include/linux/pci_ids.h8
-rw-r--r--include/linux/pm.h15
-rw-r--r--include/linux/prctl.h6
-rw-r--r--include/linux/proc_fs.h12
-rw-r--r--include/linux/qnx4_fs.h2
-rw-r--r--include/linux/raid/md_k.h4
-rw-r--r--include/linux/smb_fs.h2
-rw-r--r--include/linux/sysctl.h6
-rw-r--r--include/linux/sysv_fs.h14
-rw-r--r--include/linux/timer.h1
-rw-r--r--include/linux/ufs_fs.h15
-rw-r--r--include/linux/umsdos_fs.h3
-rw-r--r--include/linux/wait.h1
-rw-r--r--include/net/atmclip.h7
-rw-r--r--init/main.c1
-rw-r--r--ipc/shm.c409
-rw-r--r--ipc/util.c5
-rw-r--r--kernel/exit.c11
-rw-r--r--kernel/ksyms.c4
-rw-r--r--kernel/pm.c39
-rw-r--r--kernel/sched.c11
-rw-r--r--kernel/sys.c19
-rw-r--r--kernel/sysctl.c59
-rw-r--r--mm/bootmem.c2
-rw-r--r--mm/filemap.c34
-rw-r--r--mm/memory.c30
-rw-r--r--mm/page_alloc.c26
-rw-r--r--mm/vmscan.c21
-rw-r--r--net/atm/clip.c67
-rw-r--r--net/atm/lec.c255
-rw-r--r--net/atm/mpoa_proc.c9
-rw-r--r--net/atm/proc.c13
-rw-r--r--net/atm/raw.c4
-rw-r--r--net/bridge/br_device.c8
-rw-r--r--net/bridge/br_fdb.c9
-rw-r--r--net/bridge/br_forward.c2
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_input.c63
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_notify.c2
-rw-r--r--net/bridge/br_stp.c2
-rw-r--r--net/bridge/br_stp_bpdu.c2
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/bridge/br_stp_timer.c2
-rw-r--r--net/core/dev.c41
-rw-r--r--net/decnet/af_decnet.c3
-rw-r--r--net/ipv4/af_inet.c7
-rw-r--r--net/ipv4/igmp.c11
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/tcp_output.c2
-rw-r--r--net/irda/ircomm/ircomm_tty.c5
-rw-r--r--net/netsyms.c3
-rw-r--r--net/packet/af_packet.c4
-rw-r--r--net/sched/sch_atm.c67
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sched/sch_dsmark.c8
-rw-r--r--net/wanrouter/wanproc.c46
662 files changed, 36048 insertions, 18782 deletions
diff --git a/CREDITS b/CREDITS
index a816e6127..7192442b9 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1511,15 +1511,17 @@ S: Santa Clara, CA 95052
S: USA
N: Martin Mares
-E: mj@atrey.karlin.mff.cuni.cz
+E: mj@suse.cz
+E: mj@ucw.cz
W: http://atrey.karlin.mff.cuni.cz/~mj/
D: BIOS video mode handling code
D: MOXA C-218 serial board driver
D: Network autoconfiguration
+D: PCI subsystem
D: Random kernel hacking
S: Kankovskeho 1241
S: 182 00 Praha 8
-S: Czech Republic
+S: Czech Republic
N: John A. Martin
E: jam@acm.org
@@ -2023,6 +2025,14 @@ S: 301/222 City Walk
S: Canberra ACT 2601
S: Australia
+N: Sampo Saaristo
+E: sambo@cs.tut.fi
+D: Co-author of Multi-Protocol Over ATM (MPOA)
+S: Tampere University of Technology / Telecom lab
+S: Hermiankatu 12C
+S: FIN-33720 Tampere
+S: Finland
+
N: Thomas Sailer
E: sailer@ife.ee.ethz.ch
E: HB9JNX@HB9W.CHE.EU (packet radio)
@@ -2405,6 +2415,14 @@ S: 27 Spencer Drive
S: Nashua, New Hampshire 03062
S: USA
+N: Heikki Vatiainen
+E: hessu@cs.tut.fi
+D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks
+S: Tampere University of Technology / Telecom lab
+S: Hermiankatu 12C
+S: FIN-33720 Tampere
+S: Finland
+
N: Andrew Veliath
E: andrewtv@usa.net
D: Turtle Beach MultiSound sound driver
@@ -2431,6 +2449,14 @@ S: Kruislaan 419
S: 1098 VA Amsterdam
S: The Netherlands
+N: Peter Shaobo Wang
+E: pwang@mmdcorp.com
+W: http://www.mmdcorp.com/pw/linux
+D: Driver for Interphase ATM (i)Chip SAR adapter card family (x575, x525, x531).
+S: 1513 Brewster Dr.
+S: Carrollton, TX 75010
+S: USA
+
N: Tim Waugh
E: tim@cyberelk.demon.co.uk
D: Co-architect of the parallel-port sharing system
@@ -2471,6 +2497,14 @@ S: UC Berkeley
S: Berkeley, CA 94720-1776
S: USA
+N: Bill Wendling
+E: wendling@ganymede.isdn.uiuc.edu
+W: http://www.ncsa.uiuc.edu/~wendling/
+D: Various random hacks. Mostly on poll/select logic.
+S: 605 E. Springfield Ave.
+S: Champaign, IL 61820
+S: USA
+
N: Mike Westall
D: IBM Turboways 25 ATM Device Driver
E: westall@cs.clemson.edu
diff --git a/Documentation/Changes b/Documentation/Changes
index f07a1876f..ea01182b0 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -33,7 +33,7 @@ pour la traduction français.
Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
needs.
-Last updated: March 16, 1999
+Last updated: Feb 21, 2000
Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu).
Current Minimal Requirements
@@ -512,6 +512,12 @@ recomented.
Older isdn4k-utils versions don't support EXTRAVERSION into kernel version
string.
+Logical Volume Manager
+======================
+Since 2.3.47 the kernel contains the Logical Volume Manager aka LVM. To use it,
+you need to install the LVM tools. More information can be found at the home page
+of the LVM project at http://linux.msede.com/lvm/.
+
Where to get the files
**********************
@@ -751,9 +757,9 @@ http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.0-pre-19981104.tar.gz
PCI utils
=========
-The 2.0 release:
-ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz
-ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz
+The 2.1.5 release:
+ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.1.5.tar.gz
+ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.1.5.tar.gz
Powertweak
==========
@@ -795,9 +801,17 @@ ftp://ftp.gnu.org/gnu/patch/patch-2.5.tar.gz
ISDN4Linux
==========
+
The v3.1beta7 release:
ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz
+Logical Volume Manager
+======================
+
+The 0.7 release:
+ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz
+
+
Other Info
==========
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 82bbd2b50..878b5abe0 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -323,27 +323,31 @@ CONFIG_BLK_DEV_NBD
Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
CONFIG_BLK_DEV_IDE
If you say Y here, you will use the full-featured IDE driver to
- control up to eight IDE interfaces, each being able to serve a
- "master" and a "slave" device, for a total of up to sixteen IDE
+ control up to ten ATA/IDE interfaces, each being able to serve a
+ "master" and a "slave" device, for a total of up to twenty ATA/IDE
disk/cdrom/tape/floppy drives. People with SCSI-only systems
- can say N here.
+ can say N or M here.
Useful information about large (>540 MB) IDE disks, multiple
- interfaces, what to do if IDE devices are not automatically
- detected, sound card IDE ports, module support, and other topics, is
- contained in Documentation/ide.txt. For detailed information about
+ interfaces, what to do if ATA/IDE devices are not automatically
+ detected, sound card ATA/IDE ports, module support, and other topics, is
+ contained in Documentation/ata-ide.txt. For detailed information about
hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO,
available from http://www.linuxdoc.org/docs.html#howto .
- To fine-tune IDE drive/interface parameters for improved
+ To fine-tune ATA/IDE drive/interface parameters for improved
+ performance, look for the hdparm package at
+ ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ .
+
+ To fine-tune ATA/IDE drive/interface parameters for improved
performance, look for the hdparm package at
ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ .
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read Documentation/modules.txt and
- Documentation/ide.txt. The module will be called ide.o. Do not
- compile this driver as a module if your root file system (the one
+ Documentation/ide.txt. The module will be called ide-mod.o. Do not
+ compile this driver as a module if your root filesystem (the one
containing the directory /) is located on an IDE device.
If you have one or more IDE drives, say Y or M here. If your system
@@ -557,13 +561,6 @@ CONFIG_BLK_DEV_RZ1000
People with SCSI-only systems should say N here. If unsure, say Y.
-Cyrix CS5530 MediaGX chipset support
-CONFIG_BLK_DEV_CS5530
- Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
- will automatically be detected and configured if found.
-
- It is safe to say Y to this question.
-
Generic PCI IDE chipset support
CONFIG_BLK_DEV_IDEPCI
Say Y here for PCI systems which use IDE drive(s).
@@ -572,6 +569,15 @@ CONFIG_BLK_DEV_IDEPCI
People with SCSI-only systems should say N here; if unsure say Y.
+Support for sharing PCI IDE interrupts
+CONFIG_IDEPCI_SHARE_IRQ
+ Some ATA/IDE chipsets have hardware support which allows for
+ sharing a single IRQ with other cards. To enable support for
+ this in the ATA/IDE driver, say Y here.
+
+ It is safe to say Y to this question, in most cases.
+ If unsure, say N.
+
Generic PCI bus-master DMA support
CONFIG_BLK_DEV_IDEDMA_PCI
If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
@@ -584,7 +590,7 @@ CONFIG_BLK_DEV_IDEDMA_PCI
the latest version of the hdparm utility from
ftp://metalab.unc.edu/pub/Linux/system/hardware/ .
- Read the comments at the beginning of drivers/block/idedma.c and the
+ Read the comments at the beginning of drivers/block/ide-dma.c and the
file Documentation/ide.txt for more information.
It is safe to say Y to this question.
@@ -614,7 +620,7 @@ CONFIG_BLK_DEV_OFFBOARD
If you say Y here, and you actually want to reverse the device scan
order as explained above, you also need to issue the kernel command
- line option "pci=reverse". (Try "man bootparam" or see the
+ line option "ide=reverse". (Try "man bootparam" or see the
documentation of your boot loader (lilo or loadlin) about how to
pass options to the kernel at boot time. The lilo procedure is also
explained in the SCSI-HOWTO, available from
@@ -639,6 +645,23 @@ CONFIG_IDEDMA_PCI_AUTO
It is normally safe to answer Y to this question unless your
motherboard uses a VIA VP2 chipset, in which case you should say N.
+Various ATA, Work(s) In Progress (EXPERIMENTAL)
+CONFIG_IDEDMA_PCI_WIP
+ If you enable this you will be capable of using and testing
+ highly developmentail projects.
+
+ It is SAFEST to say N to this question.
+
+3ware Hardware ATA-RAID support (EXPERIMENTAL)
+CONFIG_BLK_DEV_3W_XXXX_RAID
+ 3ware is the only hardware ATA-Raid product in Linux to date.
+ This card is 2,4, or 8 channel master mode support only.
+ SCSI support required!!!
+
+ http://www.3ware.com/
+
+ Please read the comments at the top of drivers/scsi/3w-xxxx.c
+
AEC6210 chipset support
CONFIG_BLK_DEV_AEC6210
This driver adds up to 4 more EIDE devices sharing a single
@@ -648,6 +671,12 @@ CONFIG_BLK_DEV_AEC6210
available".
Please read the comments at the top of drivers/block/aec6210.c
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
+
+AEC6210 Tuning support (WIP)
+CONFIG_AEC6210_TUNING
+ Please read the comments at the top of drivers/block/aec6210.c
+ If unsure, say N.
ALI M15x3 chipset support
CONFIG_BLK_DEV_ALI15X3
@@ -655,9 +684,8 @@ CONFIG_BLK_DEV_ALI15X3
1535, 1535D onboard chipsets. It also tests for Simplex mode and
enables normal dual channel support.
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above.
Please read the comments at the top of drivers/block/alim15x3.c
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
@@ -665,10 +693,14 @@ AMD7409 chipset support (EXPERIMENTAL)
CONFIG_BLK_DEV_AMD7409
This driver ensures (U)DMA support for AMD756 Viper chipset.
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above.
Please read the comments at the top of drivers/block/amd7409.c
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
+ If unsure, say N.
+AMD Viper ATA-66 Override support (WIP)
+CONFIG_AMD7409_OVERRIDE
+ This option auto-forces the ata66 flag.
+ This effect can be also invoked by calling "idex=ata66"
If unsure, say N.
CMD64X chipset support
@@ -676,8 +708,8 @@ CONFIG_BLK_DEV_CMD64X
Say Y here if you have an IDE controller which uses any of these chipsets,
CMD643, CMD646, or CMD648.
-CMD64X chipset RAID support (EXPERIMENTAL) (WIP)
-CONFIG_BLK_DEV_CMD64X
+CMD64X chipset RAID support (WIP)
+CONFIG_CMD64X_RAID
Work in progress for hardware raid ata-33/66..........rev 7 minimum.
Say N for now.
@@ -686,8 +718,14 @@ CONFIG_BLK_DEV_CY82C693
This driver adds detection and support for the CY82C693 chipset
used on Digital's PC-Alpha 164SX boards.
- If you say Y here, you need to say Y to "Use DMA by default
- when available" as well.
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
+
+Cyrix CS5530 MediaGX chipset support
+CONFIG_BLK_DEV_CS5530
+ Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
+ will automatically be detected and configured if found.
+
+ It is safe to say Y to this question.
HPT34X chipset support
CONFIG_BLK_DEV_HPT34X
@@ -698,12 +736,13 @@ CONFIG_BLK_DEV_HPT34X
chipset during the ide-probe at boot time. It is reported to support
DVD II drives, by the manufacturer.
-HPT34X DMA support (EXPERIMENTAL)
-CONFIG_BLK_DEV_HPT34X_DMA
- you need to say Y to "Use DMA by default when available" if you say
- Y here.
-
+HPT34X AUTODMA support (WIP)
+CONFIG_HPT34X_AUTODMA
+ This is a dangerous thing to attempt currently!
Please read the comments at the top of drivers/block/hpt34x.c
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
+
+ If unsure, say N.
HPT366 chipset support
CONFIG_BLK_DEV_HPT366
@@ -716,13 +755,14 @@ CONFIG_BLK_DEV_HPT366
manufacturer.
Please read the comments at the top of drivers/block/hpt366.c
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
-HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)
-CONFIG_HPT366_FAST_IRQ_PREDICTION
+HPT366 Fast Interrupts (WIP)
+CONFIG_HPT366_FIP
If unsure, say N.
-HPT366 mode three unsupported (EXPERIMENTAL) (WIP)
+HPT366 mode three unsupported (WIP)
CONFIG_HPT366_MODE3
This is an undocumented mode that the HA366 can default to in many cases.
If unsure, say N.
@@ -748,11 +788,11 @@ CONFIG_BLK_DEV_PIIX
Please read the comments at the top of drivers/block/piix.c
- Should also include "PIIXn Tuning support" CONFIG_BLK_DEV_PIIX_TUNING
+ Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING
If unsure, say Y.
PIIXn Tuning support
-CONFIG_BLK_DEV_PIIX_TUNING
+CONFIG_PIIX_TUNING
This driver extension adds DMA mode setting and tuning for all PIIX
IDE controllers by Intel. Since the BIOS can sometimes improperly
set up the device/adapter combination and speed limits, it has
@@ -784,15 +824,13 @@ CONFIG_BLK_DEV_PDC202XX
boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS
1.11 or newer required.
- If you say Y here, you need to say Y to "Use DMA by default when
- available" as well.
-
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
Please read the comments at the top of drivers/block/pdc202xx.c
If unsure, say N.
Special UDMA Feature
-CONFIG_PDC202XX_FORCE_BURST_BIT
+CONFIG_PDC202XX_BURST
For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally
for PDC20246/Ultra33 that has BIOS setup failures when using 3 or
more cards.
@@ -801,8 +839,8 @@ CONFIG_PDC202XX_FORCE_BURST_BIT
If unsure, say N.
-Special Mode Feature (EXPERIMENTAL)
-CONFIG_PDC202XX_FORCE_MASTER_MODE
+Special Mode Feature (WIP)
+CONFIG_PDC202XX_MASTER
For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for
possible Hardware RAID 0,1 for the FastTrak Series.
@@ -832,8 +870,7 @@ CONFIG_BLK_DEV_VIA82CXXX
(while running a "cat") provided you enabled "proc" support.
Please read the comments at the top of drivers/block/via82cxxx.c
- If you say Y here, you also need to say Y to "Use DMA by default
- when available", above.
+ If you say Y here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
@@ -908,16 +945,6 @@ CONFIG_BLK_DEV_UMC8672
See the files Documentation/ide.txt and drivers/block/umc8672.c for
more info.
-PS/2 ESDI hard disk support
-CONFIG_BLK_DEV_PS2
- Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
- hard disk.
-
- If you want to compile the driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read Documentation/modules.txt. The module will be
- called ps2esdi.o.
-
Amiga builtin Gayle IDE interface support
CONFIG_BLK_DEV_GAYLE
This is the IDE driver for the builtin IDE interface on some Amiga
@@ -968,7 +995,14 @@ CONFIG_BLK_DEV_IDEDMA_PMAC
Use DMA by default
CONFIG_IDEDMA_PMAC_AUTO
- No help for CONFIG_IDEDMA_PMAC_AUTO
+ Prior to kernel version 2.1.112, Linux used to automatically use
+ DMA for IDE drives and chipsets which support it. Due to concerns
+ about a couple of cases where buggy hardware may have caused damage,
+ the default is now to NOT use DMA automatically. To revert to the
+ previous behaviour, say Y to this question.
+
+ If you suspect your hardware is at all flakey, say N here.
+ Do NOT email the IDE kernel people regarding this issue!
Macintosh Quadra/Powerbook IDE interface support
CONFIG_BLK_DEV_MAC_IDE
@@ -981,9 +1015,16 @@ CONFIG_BLK_DEV_MAC_IDE
devices (hard disks, CD-ROM drives, etc.) that are connected to the
builtin IDE interface.
+IDE card support
+CONFIG_BLK_DEV_IDE_CARDS
+ On Acorn systems, say Y here if you wish to use an IDE interface
+ expansion card. If you do not or are unsure, say N to this.
+
ICS IDE interface support
CONFIG_BLK_DEV_IDE_ICSIDE
- No help for CONFIG_BLK_DEV_IDE_ICSIDE
+ On Acorn systems, say Y here if you wish to use the ICS IDE
+ interface card. This is not required for ICS partition support.
+ If you are unsure, say N to this.
ICS DMA support
CONFIG_BLK_DEV_IDEDMA_ICS
@@ -991,7 +1032,14 @@ CONFIG_BLK_DEV_IDEDMA_ICS
Use ICS DMA by default
CONFIG_IDEDMA_ICS_AUTO
- No help for CONFIG_IDEDMA_ICS_AUTO
+ Prior to kernel version 2.1.112, Linux used to automatically use
+ DMA for IDE drives and chipsets which support it. Due to concerns
+ about a couple of cases where buggy hardware may have caused damage,
+ the default is now to NOT use DMA automatically. To revert to the
+ previous behaviour, say Y to this question.
+
+ If you suspect your hardware is at all flakey, say N here.
+ Do NOT email the IDE kernel people regarding this issue!
RapIDE interface support
CONFIG_BLK_DEV_IDE_RAPIDE
@@ -1009,6 +1057,16 @@ CONFIG_BLK_DEV_XD
It's pretty unlikely that you have one of these: say N.
+PS/2 ESDI hard disk support
+CONFIG_BLK_DEV_PS2
+ Say Y here if you have a PS/2 machine with a MCA bus and an ESDI
+ hard disk.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want),
+ say M here and read Documentation/modules.txt. The module will be
+ called ps2esdi.o.
+
Mylex DAC960/DAC1100 PCI RAID Controller support
CONFIG_BLK_DEV_DAC960
This driver adds support for the Mylex DAC960, AcceleRAID, and
@@ -1599,7 +1657,7 @@ CONFIG_NETFILTER
Chances are that you should say Y here if you compile a kernel which
will run as a router and N for regular hosts. If unsure, say N.
-SIN flood protection
+SYN flood protection
CONFIG_SYN_COOKIES
Normal TCP/IP networking is open to an attack known as "SYN
flooding". This denial-of-service attack prevents legitimate remote
@@ -1982,7 +2040,7 @@ CONFIG_PNP
Say Y here if you would like Linux to configure your Plug and Play
devices. You should then also say Y to "ISA Plug and Play support",
below. Alternatively, you can configure your PnP devices using the
- user space utilities contained in the ISAPNP tools package.
+ user space utilities contained in the isapnptools package.
This support is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
@@ -2540,6 +2598,52 @@ CONFIG_FB_MATROX_G100
you select "Advanced lowlevel driver options", you should check 8
bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32
bpp packed pixel. You can also use font widths different from 8.
+
+ If you need support for G400 secondary head, you must first enable
+ I2C support and I2C bit-banging support in character devices section,
+ and then Matrox I2C support and G400 secondary head support here
+ in framebuffer section.
+
+Matrox I2C support
+CONFIG_FB_MATROX_I2C
+ This drivers creates I2C buses which are needed for accessing
+ DDC (I2C) bus present on all Matroxes, I2C bus which interconnects
+ Matrox optional devices, like MGA-TVO on G200 and G400, and
+ secondary head DDC bus, present on G400 only.
+
+ You can say Y or M here if you want to experiment with monitor
+ detection code. You must say Y or M here if you want to use either
+ second head of G400 or MGA-TVO on G200 or G400.
+
+ If you compile it as module, it will create module named i2c-matroxfb.o.
+
+Matrox G400 second head support
+CONFIG_FB_MATROX_MAVEN
+ Say Y or M here if you want to use secondary head on G400 or MGA-TVO
+ add-on on G200. Secondary head is not compatible with accelerated
+ XFree 3.3.x SVGA servers - secondary head output is blanked while you
+ are in X. With XFree 3.9.17 preview you can use both heads if you use
+ SVGA over fbdev or fbdev driver on first head and fbdev driver on
+ second head.
+
+ If you compile it as module, two modules are created, matroxfb_crtc2.o
+ and matroxfb_maven.o. Matroxfb_maven is needed for both G200 and G400,
+ matroxfb_crtc2 is needed only by G400. You must also load i2c-matroxfb
+ to get it to run.
+
+ Driver starts in monitor mode and you must use matroxset tool (available
+ at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to switch it to PAL
+ or NTSC or to swap primary and secondary head outputs. Secondary head
+ driver also always start in 640x480 resolution, you must use fbset to
+ change it.
+
+ Also do not forget that second head supports only 16 and 32 bpp packed
+ pixels, so it is good idea to compile them into kernel too. You can
+ use only some font widths, as driver uses generic painting procedures
+ (secondary head does not use acceleration engine).
+
+ There is no need for enabling 'Matrox multihead support' if you have
+ only one Matrox card in the box.
Matrox unified driver multihead support
CONFIG_FB_MATROX_MULTIHEAD
@@ -4226,6 +4330,82 @@ CONFIG_ATM_IA_DEBUG
speed of the driver, and the size of your syslog files! When
inactive, they will have only a modest impact on performance.
+FORE Systems 200E-series
+CONFIG_ATM_FORE200E
+ This is a driver for the FORE Systems 200E-series ATM adapter
+ cards. It simultaneously supports PCA-200E and SBA-200E models
+ on PCI and SBUS hosts. Say Y (or M to compile as a module
+ named fore_200e.o) here if you have one of these ATM adapters.
+
+ See the file Documentation/networking/fore200e.txt for further
+ details.
+
+Enable PCA-200E card support on PCI-based hosts
+CONFIG_ATM_FORE200E_PCA
+ Enable this if you want your PCA-200E cards to be probed.
+
+Use default PCA-200E firmware
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
+ Use the default PCA-200E firmware data shipped with the driver.
+
+ Normal users do not have to deal with the firmware stuff, so
+ this feature is normally enabled.
+
+Pathname of user-supplied binary firmware
+CONFIG_ATM_FORE200E_PCA_FW
+ This defines the pathname of an alternative PCA-200E binary
+ firmware image supplied by the user. This pathname may be
+ absolute or relative to the drivers/atm directory.
+
+ The driver comes with an adequate firmware image, so normal users
+ do not have to supply an alternative one. They just enable the use
+ of the default firmware instead.
+
+Enable SBA-200E card support on SBUS-based hosts
+CONFIG_ATM_FORE200E_SBA
+ Enable this if you want your SBA-200E cards to be probed.
+
+Use default SBA-200E firmware
+CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
+ Use the default SBA-200E firmware data shipped with the driver.
+
+ Normal users do not have to deal with the firmware stuff, so
+ this feature is normally enabled.
+
+Pathname of user-supplied binary firmware
+CONFIG_ATM_FORE200E_SBA_FW
+ This defines the pathname of an alternative SBA-200E binary
+ firmware image supplied by the user. This pathname may be
+ absolute or relative to the drivers/atm directory.
+
+ The driver comes with an adequate firmware image, so normal users
+ do not have to supply an alternative one. They just enable the use
+ of the default firmware instead.
+
+Maximum number of tx retries
+CONFIG_ATM_FORE200E_TX_RETRY
+ Specifies the number of times the driver attempts to transmit
+ a message before giving up, if the transmit queue of the ATM card
+ is transiently saturated.
+
+ Saturation of the transmit queue may occur only under extreme
+ conditions, e.g. when a fast host continuously submits very small
+ frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter.
+
+ Note that under common conditions, it is unlikely that you encounter
+ a saturation of the transmit queue, so the retry mechanism never
+ comes into play.
+
+Debugging level (0-3)
+CONFIG_ATM_FORE200E_DEBUG
+ Specifies the level of debugging messages issued by the driver.
+ The verbosity of the driver increases with the value of this
+ parameter.
+
+ When active, these messages can have a significant impact on
+ the performances of the driver, and the size of your syslog files!
+ Keep the debugging level to 0 during normal operations.
+
SCSI support?
CONFIG_SCSI
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or
@@ -7558,6 +7738,11 @@ CONFIG_EEPRO100
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
+EtherExpress PRO/100 support
+CONFIG_EEPRO100_PM (EXPERIMENTAL)
+ If you want to play around with power management code
+ that has reported to lock up some machines, say Y here.
+
ICL EtherTeam 16i/32 support (EXPERIMENTAL)
CONFIG_ETH16I
If you have a network (Ethernet) card of this type, say Y and read
diff --git a/Documentation/IRQ-affinity.txt b/Documentation/IRQ-affinity.txt
new file mode 100644
index 000000000..7c582f494
--- /dev/null
+++ b/Documentation/IRQ-affinity.txt
@@ -0,0 +1,37 @@
+
+SMP IRQ affinity, started by Ingo Molnar <mingo@redhat.com>
+
+
+/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted
+for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed
+to turn off all CPUs, and if an IRQ controller does not support IRQ
+affinity then the value will not change from the default 0xffffffff.
+
+Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting
+the IRQ to CPU4-8 (this is an 8-CPU SMP box):
+
+[root@moon 44]# cat smp_affinity
+ffffffff
+[root@moon 44]# echo 0f > smp_affinity
+[root@moon 44]# cat smp_affinity
+0000000f
+[root@moon 44]# ping -f h
+PING hell (195.4.7.3): 56 data bytes
+...
+--- hell ping statistics ---
+6029 packets transmitted, 6027 packets received, 0% packet loss
+round-trip min/avg/max = 0.1/0.1/0.4 ms
+[root@moon 44]# cat /proc/interrupts | grep 44:
+ 44: 0 1785 1785 1783 1783 1
+1 0 IO-APIC-level eth1
+[root@moon 44]# echo f0 > smp_affinity
+[root@moon 44]# ping -f h
+PING hell (195.4.7.3): 56 data bytes
+..
+--- hell ping statistics ---
+2779 packets transmitted, 2777 packets received, 0% packet loss
+round-trip min/avg/max = 0.1/0.5/585.4 ms
+[root@moon 44]# cat /proc/interrupts | grep 44:
+ 44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1
+[root@moon 44]#
+
diff --git a/Documentation/fb/matroxfb.txt b/Documentation/fb/matroxfb.txt
index 6506273ea..d79f6694f 100644
--- a/Documentation/fb/matroxfb.txt
+++ b/Documentation/fb/matroxfb.txt
@@ -105,7 +105,7 @@ problem and not mine, but I'm not sure.
Configuration
=============
-You can pass kernel command line options to vesafb with
+You can pass kernel command line options to matroxfb with
`video=matrox:option1,option2:value2,option3' (multiple options should be
separated by comma, values are separated from options by `:').
Accepted options:
@@ -276,16 +276,16 @@ And following misfeatures:
+ color keying is not supported
+ feature connector of Mystique and Gx00 is set to VGA mode (it is disabled
by BIOS)
- + DCC (monitor detection) protocol is not implemented
+ + DDC (monitor detection) is supported through dualhead driver
+ some check for input values are not so strict how it should be (you can
specify vslen=4000 and so on).
+ maybe more...
And following features:
+ 4bpp is available only on Millennium I and Millennium II. It is hardware
limitation.
- + current fbset is not able to set 15bpp videomode: you must specify
- depth==16 and green.length==5. fbset does not allow you to set
- green.length.
+ + selection between 1:5:5:5 and 5:6:5 16bpp videomode is done by -rgba
+ option of fbset: "fbset -depth 16 -rgba 5,5,5" selects 1:5:5:5, anything
+ else selects 5:6:5 mode.
+ text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors
instead of one of 16M colors). It is due to hardware limitation of
Millennium I/II and SVGALib compatibility.
@@ -330,6 +330,27 @@ TEXT
Millennium I G200
TEXT 3.29 1.50
+
+Dualhead G400
+=============
+Driver supports dualhead G400 with some limitations:
+ + secondary head shares videomemory with primary head. It is not problem
+ if you have 32MB of videoram, but if you have only 16MB, you may have
+ to think twice before choosing videomode (for example twice 1880x1440x32bpp
+ is not possible).
+ + due to hardware limitation, secondary head can use only 16 and 32bpp
+ videomodes.
+ + secondary head is not accelerated. There were bad problems with accelerated
+ XFree when secondary head used to use acceleration.
+ + secondary head always powerups in 640x480@60-32 videomode. You have to use
+ fbset to change this mode.
+ + secondary head always powerups in monitor mode. You have to use matroxset
+ to change it to TV mode. Also, you must select at least 525 lines for
+ NTSC output and 625 lines for PAL output.
+ + kernel is not fully multihead ready. So some things are impossible to do.
+ + if you compiled it as module, you must insert i2c-matroxfb, matroxfb_maven
+ and matroxfb_crtc2 into kernel.
+
* Yes, it is slower than Millennium I.
--
diff --git a/drivers/block/README.fd b/Documentation/floppy.txt
index 38f0b85a5..7bd117ee8 100644
--- a/drivers/block/README.fd
+++ b/Documentation/floppy.txt
@@ -1,4 +1,4 @@
-This Readme file describes the floppy driver.
+This file describes the floppy driver.
FAQ list:
=========
diff --git a/Documentation/ide.txt b/Documentation/ide.txt
index 74e56b75f..7352528bd 100644
--- a/Documentation/ide.txt
+++ b/Documentation/ide.txt
@@ -38,7 +38,7 @@ NEW! - support for IDE ATAPI *floppy* drives
- interface PIO timing & prefetch parameter support
- experimental support for UMC 8672 interfaces
- support for secondary interface on the FGI/Holtek HT-6560B VLB i/f
- - use kernel command line option: ide0=ht6560
+ - use kernel command line option: ide0=ht6560b
- experimental support for various IDE chipsets
- use appropriate kernel command line option from list below
- support for drives with a stuck WRERR_STAT bit
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index c2a1b0025..29a11c3a8 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -128,7 +128,8 @@ Code Seq# Include File Comments
'm' all linux/soundcard.h conflict!
'm' all linux/synclink.h conflict!
'm' 00-1F net/irda/irmod.h conflict!
-'n' all linux/ncp_fs.h
+'n' 00-7F linux/ncp_fs.h
+'n' E0-FF video/matrox.h matroxfb
'p' 00-3F linux/mc146818rtc.h
'p' 40-7F linux/nvram.h
'p' 80-9F user-space parport
diff --git a/drivers/block/README.buddha b/Documentation/m68k/README.buddha
index d3b7bc73f..d3b7bc73f 100644
--- a/drivers/block/README.buddha
+++ b/Documentation/m68k/README.buddha
diff --git a/Documentation/networking/8139too.txt b/Documentation/networking/8139too.txt
new file mode 100644
index 000000000..6a75c7338
--- /dev/null
+++ b/Documentation/networking/8139too.txt
@@ -0,0 +1,194 @@
+
+ "8139too" Fast Ethernet driver for Linux
+ Improved support for RTL-8139 Fast Ethernet adapters
+
+ Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+
+ Architectures supported (all PCI platforms):
+ x86, Alpha AXP, PowerPC, Sparc64
+
+
+
+
+Disclaimer
+----------
+
+THIS DRIVER IS A DEVELOPMENT RELEASE FOR A DEVELOPMENT KERNEL. DO NOT
+USE IN A PRODUCTION ENVIRONMENT.
+
+DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is
+completely different and maintained independently of the 8139too code base.
+
+
+
+Requirements
+------------
+Kernel 2.3.41 or later.
+A Fast Ethernet adapter containing an RTL8139-based chip.
+
+
+
+Introduction
+------------
+
+The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial
+modification of the experimental rtl8139 driver from Donald Becker,
+some versions of which appeared in 2.2.x and 2.3.x kernels. The
+RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very
+popular.
+
+The step from 2.2.x to 2.4.x kernels brings many new features to Linux
+device drivers. Features for MMIO resources, a standard hot-plug API,
+and other interfaces are now becoming requirements, as drivers move
+off the x86 platform. With that in mind, I have begun updating the
+RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and
+fixing the problems that users have been encountering.
+
+
+
+Features of 8139too
+-------------------
+[note - this list intended for people familiar with kernel drivers]
+
+** 100% MMIO, for full speed operation. All users (so far) have
+reported performance increases over their existing RTL drivers.
+
+** Multi-platform support: x86, Alpha, PPC, ...
+
+** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the
+driver portable to non-x86 SMP platforms in the process.
+
+** Use new PCI driver API for seamless, low-maintenance hot-plug support
+
+** Several bugs fixes from original rtl8139 1.08r (October 5, 1999),
+including the very common "transmit timeout" problem.
+
+* Use new resource allocation API, required for hot-plug support
+* Use new register read/write macros
+* initcall support (module_init/exit)
+* vastly improved debug tracing support
+* code formatting in many places for readability
+* use new init_etherdev() facilities
+
+...and probably some other less important changes which I forgot.
+
+
+
+Installation
+------------
+
+OPTION 1: Build inside kernel tree (into kernel image, or as module)
+
+ (overwrite 8139too driver in kernel tree with different version)
+ 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c
+
+OPTION 2: Build outside kernel tree
+
+ Use the included Makefile.
+
+
+
+Tested Adapters
+---------------
+AOpen ALN-325C
+KTI KF-230TX
+KTI KF-230TX/2
+
+(please add your adapter model to this list)
+
+
+
+Status of Platform Support
+--------------------------
+
+(see errata below for details)
+
+x86: tested, stable
+Alpha AXP: tested, stable
+PowerPC: tested, unstable
+Sparc64: not tested
+
+
+
+Special Thanks
+--------------
+The following people contributed invaluable testing time, feedback
+and/or patches during the development of this driver. Thanks to all
+of them.
+
+Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration
+
+Alan Cox, Gerard Roudier - insight on posted MMIO writes
+
+Martin Mares - code review
+
+Tigran Aivazian - testing, code review, and a bug fix
+
+Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin,
+James Fidell, Taso Hatzi, Peter K - intrepid test team
+
+And thanks to every supporter free software.
+
+
+
+Known Bugs / Errata / To-Do
+---------------------------
+The following issues are known, and are actively being pursued. Patches
+to resolve these issues is welcome. If a problem occurs which is not in
+the list, please report it. That's why we do beta releases, after all...
+
+
+
+1) Work with Donald to merge fixes and updates into his driver.
+
+2) 2.2.x COMPATIBILITY SUPPORT IS BROKEN. DO NOT USE IT.
+It is included only for enterprising hackers willing to help fix it.
+
+3) PPC platform has stability problems.
+
+4) Sparc64 platform not tested at all.
+
+5) Identify and fix "rx wedge" when ping flooded.
+
+7) N-Way auto-negotiation is known to fail in some cases. This problem
+also occurs in the rtl8139 driver in kernels 2.2.x/2.3.x. Solution:
+Following technique in sunhme and sunbmac, use a kernel timer to
+manually perform autonegotiation in case the network or card cannot do
+it automatically. (patches welcome)
+
+8) Much improved command line / module parameter setup. (patches and
+suggestions welcome)
+
+9) Better documentation. (patches welcome)
+
+10) User-mode (or maybe optional /proc) diagnostics program.
+
+
+
+
+Change History
+--------------
+Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release
+
+* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now)
+* Softnet logic updates to fix bugs and improve performance
+* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones)
+* Remove bogus SiS entries from PCI probe table
+* Add support for cards
+ "Delta Electronics 8139 10/100BaseTX"
+ "Addtron Technolgy 8139 10/100BaseTX"
+* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r)
+* PCI DMA mapping by Dave Miller
+* Complete rewrite of SMP locking logic
+* Hotplug support
+* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code
+ from rtl8139_open
+* Reset NWay registers to sane defaults on rtl8139_open/hw_start
+* Miscellaneous code cleanup
+
+Version 0.7.0 - Feb 7, 2000 - first public beta release
+
+
+[EOF]
+
diff --git a/Documentation/networking/fore200e.txt b/Documentation/networking/fore200e.txt
new file mode 100644
index 000000000..13ee5327e
--- /dev/null
+++ b/Documentation/networking/fore200e.txt
@@ -0,0 +1,55 @@
+
+Fore PCA-200E/SBA-200E ATM NIC Firmware Copyright Notice
+--------------------------------------------------------
+
+Please read the fore200e_firmware_copyright file present
+in the linux/drivers/atm directory for details and restrictions.
+
+
+Firmware Updates
+----------------
+
+The FORE Systems 200E-series driver is shipped with firmware data being
+uploaded to the ATM adapters at system boot time or at module loading time.
+The supplied firmware images should work with all adapters.
+
+However, if you encounter problems (firmware doesn't start or the driver
+is unable to read PROM data), you may consider trying another firmware
+version. Alternative binary firmware images can be found somewhere on the
+ForeThough CD-ROM supplied with your adapter by FORE Systems.
+
+You can also get the latest firmware images from FORE Systems at
+http://www.fore.com. Register TACTics Online and go to
+the 'software updates' pages. The firmware binaries are part of
+the various ForeThough software distributions.
+
+Notice that different versions of the PCA-200E firmware exist, depending
+on the endianess of the host architecture. The driver is shipped with
+both little and big endian PCA firmware images.
+
+Name and location of the new firmware images can be set at kernel
+configuration time.
+
+
+Driver Rebuilding
+-----------------
+
+1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix)
+ to some directory, such as linux/drivers/atm.
+
+2. Reconfigure your kernel to set the new firmware name and location.
+ Expected pathnames are absolute or relative to the drivers/atm directory.
+
+3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co]
+ to ensure that the new firmware will be used when rebuilding the kernel or
+ the module.
+
+4. Rebuild and re-install your kernel or your module.
+
+
+Feedback
+--------
+
+Feedback is welcome. Please send success stories/bug reports/
+patches/improvement/comments/flames to <lizzi@cnam.fr>.
+
diff --git a/Documentation/networking/tulip.txt b/Documentation/networking/tulip.txt
index 4a83d1bf2..ecef178b0 100644
--- a/Documentation/networking/tulip.txt
+++ b/Documentation/networking/tulip.txt
@@ -1,110 +1,144 @@
Tulip Ethernet Card Driver
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
The Tulip driver is developed by Donald Becker and changed by
-Takashi Manabe. This driver is designed to work with PCI Ethernet
-cards which use the DECchip DC21x4x family. This driver hopefully
-works with all of 1.2.x and 1.3.x kernels, but I tested only
-with 1.2.13, 1.3.39, 1.3.49, 1.3.52, 1.3.57 and later.
-
-Hopefully, the de4x5.c driver will support all cards supported
-by the tulip.c driver. However, the SMC's 9332dst card and some
-cards do not work with the de4x5.c driver. So, if your card is
-not a 9332dst, please try the de4x5.c driver first.
-
-Success List
-============
-
-+-------------------------------------+-----------+-------------+
-|vendor/card |chip |system |
-+-------------------------------------+-----------+-------------+
-|SMC | | |
-| EtherPower 10 PCI(8432T/8432BT) |21040/21041|Pentium |
-+-------------------------------------+-----------+-------------+
-|SMC | | |
-| EtherPower 10/100 PCI(9332DST) |21140 |Pentium/UDB |
-+-------------------------------------+-----------+-------------+
-|DEC | | |
-| EtherWorks 100/10 PCI(DE500-XA) |21140 |Pentium |
-+-------------------------------------+-----------+-------------+
-|DEC | | |
-| EtherWorks 10 PCI(DE450) |21041 |Pentium |
-+-------------------------------------+-----------+-------------+
-|DEC | | |
-| QSILVER's |21040 |UDB |
-+-------------------------------------+-----------+-------------+
-|ZNYX | | |
-| 312 etherarray |21040 |Pentium |
-+-------------------------------------+-----------+-------------+
-|Allied Telesis | | |
-| LA100PCI-T |21140 |Pentium/UDB |
-+-------------------------------------+-----------+-------------+
-|Danpex ('Planet Japan' in Japan?) | | |
-| EN-9400 |21040 |Pentium |
-+-------------------------------------+-----------+-------------+
-|Cogent | | |
-| EM110 |21140 |Pentium |
-+-------------------------------------+-----------+-------------+
-
-Pentium: PCI machine with Pentium CPU
-UDB: Universal Desktop Box(aka Multia) with Alpha 21066 CPU
-
-Known bug(s)
-============
-This driver's media detection is very simple and sometimes
-it causes serious problem. The driver automatically switches
-media when it causes timeout. If you want to specify or to fix
-a media;
-
-- Modify TULIP_PORT in tulip.c, line 33.
-- Uncomment the definition of TULIP_FIX_PORT in tulip.c, line 40.
-
-or
-
-- Use patched ifconfig command and specify 'link='. The patch
- against ifconfig.c in net-tools-1.3.50-BETA6e is included in
- this file.
-
-Thanks
+Takashi Manabe and a cast of thousands.
+
+ This driver is for the Digital "Tulip" Ethernet adapter interface.
+ It should work with most DEC 21*4*-based chips/ethercards, as well as
+ with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
+
+ The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ Center of Excellence in Space Data and Information Sciences
+ Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+ Additional information available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+
+ Theory of Operation
+
+Board Compatibility
+===================
+
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI. Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported.
+
+These chips are used on at least 140 unique PCI board designs. The great
+number of chips and board designs supported is the reason for the
+driver size and complexity. Almost of the increasing complexity is in the
+board configuration and media selection code. There is very little
+increasing in the operational critical path length.
+
+Board-specific settings
+=======================
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board. The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+Some boards have EEPROMs tables with default media entry. The factory default
+is usually "autoselect". This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation.
+
+Driver operation
+================
+
+Ring buffers
+------------
+
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers. When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff. When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames. For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information). For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data. A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+Synchronization
+---------------
+The driver runs as two independent, single-threaded flows of control. One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag. The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.) After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+Notes
+=====
+
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
+
+References
+==========
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
+
+Errata
======
-o becker@CESDIS.gsfc.nasa.gov (author of the tulip.c driver)
-o davies@wanton.lkg.dec.com (author of the de4x5.c driver)
-
-o siekas@mailhost.tcs.tulane.edu
-
-o jheiss@calvin.caltech.edu (providing information about smc8432 card)
-o goto@plathome.co.jp (lending me a DE450 card)
-o ted@physics.ucsb.edu
-o pmheuvel@xs4all.nl
-o hjl@lucon.org (EN-9400)
-o niles@axp745.gsfc.nasa.gov (ZNYX312)
-o pkc@scs.carleton.ca (EM110)
-o and testers...
-
------------------------------------------------------------------------
-*** ifconfig.c-dist Wed Jan 17 07:25:36 1996
---- ifconfig.c Tue Apr 9 15:24:25 1996
-***************
-*** 765,770 ****
---- 766,786 ----
- continue;
- }
- ifr.ifr_map.irq = atoi(*spp);
-+ if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
-+ fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno));
-+ goterr = 1;
-+ }
-+ spp++;
-+ continue;
-+ }
-+
-+ if (!strcmp(*spp, "link")) {
-+ if (*++spp == NULL) usage();
-+ if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) {
-+ goterr = 1;
-+ continue;
-+ }
-+ ifr.ifr_map.port = atoi(*spp);
- if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) {
- fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno));
- goterr = 1;
+The old DEC databooks were light on details.
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written. Hmmm, now how is that possible?
+
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below. Some boards do not have EEPROM
+media tables and need to be patched up. Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
+
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them. The MII transceiver status is polled using an kernel timer.
+
+
+Source tree tour
+----------------
+The following is a list of files comprising the Tulip ethernet driver in
+drivers/net/tulip subdirectory.
+
+21142.c - 21142-specific h/w interaction
+eeprom.c - EEPROM reading and parsing
+interrupt.c - Interrupt handler
+media.c - Media selection and MII support
+pnic.c - PNIC-specific h/w interaction
+timer.c - Main driver timer, and misc h/w timers
+tulip.h - Private driver header
+tulip_core.c - Driver core (a.k.a. where "everything else" goes)
+
+
+
+[EOF]
+
diff --git a/Documentation/networking/wavelan.txt b/Documentation/networking/wavelan.txt
index a4a1f7921..82006e55d 100644
--- a/Documentation/networking/wavelan.txt
+++ b/Documentation/networking/wavelan.txt
@@ -1,41 +1,73 @@
-Sun Jul 2 01:38:33 EST 1995
-
- As the date above certify, this ``readme'' is mostly
-obsolete. Please read release notes and change list in
-driver/net/wavelan.p.h, and consult my web page at :
- http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
-
- Jean <jt@hpl.hp.com>
-
-1. At present the driver autoprobes for a WaveLAN card only at I/O address
- 0x390. The version of the card that I use (NCR) supports four I/O addresses
- (selectable via a pair of DIP switches). If you want the driver to
- autoprobe a different subset of the four valid addresses then you will need
- to edit .../drivers/net/wavelan.c (near line 714) and change the
- initialisation of the `iobase[]' array. Normally, I use a LILO
- configuration file directive to obviate the need for autoprobing entirely,
- a course of action I heartily recommend.
-
-2. By default, the driver uses the Network ID (NWID) stored in the card's
- Parameter Storage Area (PSA). However, the PSA NWID can be overridden by a
- value passed explicitly as the third numeric argument to LILO's "ether="
- directive, either at the LILO prompt at boot time or within LILO's
- configuration file.
- For example, the following line from such a LILO configuration file would
- auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to
- 0x4321, all on a WaveLAN card labelled "eth0":
-
- ..
- append ="ether=0,0x390,0x4321,eth0"
- ..
-
-3. The driver uses the IRQ stored in the card's PSA.
- To change this you will need to use the configuration/setup software that
- accompanies each WaveLAN device. Yes, the driver should use the value passed
- in via LILO and it will, just as soon as I can work out why that part of the
- code doesn't work :-(.
-
-4. If you encounter any problems send me some email.
-
-Good luck,
-Bruce Janson (bruce@cs.usyd.edu.au)
+ The Wavelan drivers saga
+ ------------------------
+
+ By Jean Tourrilhes <jt@hpl.hp.com>
+
+ The Wavelan is a Radio network adapter designed by
+Lucent. Under this generic name is hidden quite a variety of hardware,
+and many Linux driver to support it.
+ The get the full story on Wireless LANs, please consult :
+ http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
+
+"wavelan" driver (old ISA Wavelan)
+----------------
+ o Config : Network device -> Wireless LAN -> AT&T WaveLAN
+ o Location : .../drivers/net/wavelan*
+ o in-line doc : .../drivers/net/wavelan.p.h
+ o on-line doc :
+ http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+
+ This is the driver for the ISA version of the first generation
+of the Wavelan, now discontinued. The device is 2 Mb/s, composed of a
+Intel 82586 controler and a Lucent Modem, and is NOT 802.11 compliant.
+ The driver has been tested with the following hardware :
+ o Wavelan ISA 915 MHz (full length ISA card)
+ o Wavelan ISA 915 MHz 2.0 (half length ISA card)
+ o Wavelan ISA 2.4 GHz (full length ISA card, fixed frequency)
+ o Wavelan ISA 2.4 GHz 2.0 (half length ISA card, frequency selectable)
+ o Above cards with the optional DES encryption feature
+
+"wavelan_cs" driver (old Pcmcia Wavelan)
+-------------------
+ o Config : Network device -> PCMCIA network ->
+ Pcmcia Wireless LAN -> AT&T/Lucent WaveLAN
+ o Location : .../drivers/net/pcmcia/wavelan*
+ o in-line doc : .../drivers/net/pcmcia/wavelan_cs.h
+ o on-line doc :
+ http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+
+ This is the driver for the PCMCIA version of the first
+generation of the Wavelan, now discontinued. The device is 2 Mb/s,
+composed of a Intel 82593 controler (totally different from the 82586)
+and a Lucent Modem, and NOT 802.11 compatible.
+ The driver has been tested with the following hardware :
+ o Wavelan Pcmcia 915 MHz 2.0 (Pcmcia card + separate
+ modem/antenna block)
+ o Wavelan Pcmcia 2.4 GHz 2.0 (Pcmcia card + separate
+ modem/antenna block)
+
+"wvlan_cs" driver (Wavelan IEEE, GPL)
+-----------------
+ o Config : Not yet in kernel
+ o Location : Pcmcia package 3.1.10+
+ o on-line doc : http://www.fasta.fh-dortmund.de/users/andy/wvlan/
+
+ This is the driver for the current generation of Wavelan IEEE,
+which is 802.11 compatible. Depending on version, it is 2 Mb/s or 11
+Mb/s, with or without encryption, all implemented in Lucent specific
+DSP (the Hermes).
+ This is a GPL full source PCMCIA driver (ISA is just a Pcmcia
+card with ISA-Pcmcia bridge).
+
+"wavelan2_cs" driver (Wavelan IEEE, binary)
+--------------------
+ o Config : Not yet in kernel
+ o Location : ftp://sourceforge.org/pcmcia/contrib/
+
+ This driver support exactly the same hardware as the previous
+driver, the main difference is that it is based on a binary library
+and supported by Lucent.
+
+ I hope it clears the confusion ;-)
+
+ Jean
diff --git a/Documentation/parport-lowlevel.txt b/Documentation/parport-lowlevel.txt
new file mode 100644
index 000000000..1d40008a1
--- /dev/null
+++ b/Documentation/parport-lowlevel.txt
@@ -0,0 +1,1490 @@
+PARPORT interface documentation
+-------------------------------
+
+Time-stamp: <2000-02-24 13:30:20 twaugh>
+
+Described here are the following functions:
+
+Global functions:
+ parport_register_driver
+ parport_unregister_driver
+ parport_enumerate
+ parport_register_device
+ parport_unregister_device
+ parport_claim
+ parport_claim_or_block
+ parport_release
+ parport_yield
+ parport_yield_blocking
+ parport_wait_peripheral
+ parport_poll_peripheral
+ parport_wait_event
+ parport_negotiate
+ parport_read
+ parport_write
+ parport_open
+ parport_close
+ parport_device_id
+ parport_device_num
+ parport_device_coords
+ parport_find_class
+ parport_find_device
+ parport_set_timeout
+
+Port functions (can be overridden by low-level drivers):
+ SPP:
+ port->ops->read_data
+ port->ops->write_data
+ port->ops->read_status
+ port->ops->read_control
+ port->ops->write_control
+ port->ops->frob_control
+ port->ops->enable_irq
+ port->ops->disable_irq
+ port->ops->data_forward
+ port->ops->data_reverse
+
+ EPP:
+ port->ops->epp_write_data
+ port->ops->epp_read_data
+ port->ops->epp_write_addr
+ port->ops->epp_read_addr
+
+ ECP:
+ port->ops->ecp_write_data
+ port->ops->ecp_read_data
+ port->ops->ecp_write_addr
+
+ Other:
+ port->ops->nibble_read_data
+ port->ops->byte_read_data
+ port->ops->compat_write_data
+
+The parport subsystem comprises 'parport' (the core port-sharing
+code), and a variety of low-level drivers that actually do the port
+accesses. Each low-level driver handles a particular style of port
+(PC, Amiga, and so on).
+
+The parport interface to the device driver author can be broken down
+into global functions and port functions.
+
+The global functions are mostly for communicating between the device
+driver and the parport subsystem: acquiring a list of available ports,
+claiming a port for exclusive use, and so on. They also include
+'generic' functions for doing standard things that will work on any
+IEEE 1284-capable architecture.
+
+The port functions are provided by the low-level drivers, although the
+core parport module provides generic 'defaults' for some routines.
+The port functions can be split into three groups: SPP, EPP, and ECP.
+
+SPP (Standard Parallel Port) functions modify so-called 'SPP'
+registers: data, status, and control. The hardware may not actually
+have registers exactly like that, but the PC does and this interface is
+modelled after common PC implementations. Other low-level drivers may
+be able to emulate most of the functionality.
+
+EPP (Enhanced Parallel Port) functions are provided for reading and
+writing in IEEE 1284 EPP mode, and ECP (Extended Capabilities Port)
+functions are used for IEEE 1284 ECP mode. (What about BECP? Does
+anyone care?)
+
+Hardware assistance for EPP and/or ECP transfers may or may not be
+available, and if it is available it may or may not be used. If
+hardware is not used, the transfer will be software-driven. In order
+to cope with peripherals that only tenuously support IEEE 1284, a
+low-level driver specific function is provided, for altering 'fudge
+factors'.
+
+GLOBAL FUNCTIONS
+----------------
+
+parport_register_driver - register a device driver with parport
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_driver {
+ const char *name;
+ void (*attach) (struct parport *);
+ void (*detach) (struct parport *);
+ struct parport_driver *next;
+};
+int parport_register_driver (struct parport_driver *driver);
+
+DESCRIPTION
+
+In order to be notified about parallel ports when they are detected,
+parport_register_driver should be called. Your driver will
+immediately be notified of all ports that have already been detected,
+and of each new port as low-level drivers are loaded.
+
+A 'struct parport_driver' contains the textual name of your driver,
+a pointer to a function to handle new ports, and a pointer to a
+function to handle ports going away due to a low-level driver
+unloading. Ports will only be detached if they are not being used
+(i.e. there are no devices registered on them).
+
+The visible parts of the 'struct parport *' argument given to
+attach/detach are:
+
+struct parport
+{
+ struct parport *next; /* next parport in list */
+ const char *name; /* port's name */
+ unsigned int modes; /* bitfield of hardware modes */
+ struct parport_device_info probe_info;
+ /* IEEE1284 info */
+ int number; /* parport index */
+ struct parport_operations *ops;
+ ...
+};
+
+There are other members of the structure, but they should not be
+touched.
+
+The 'modes' member summarises the capabilities of the underlying
+hardware. It consists of flags which may be bitwise-ored together:
+
+ PARPORT_MODE_PCSPP IBM PC registers are available,
+ i.e. functions that act on data,
+ control and status registers are
+ probably writing directly to the
+ hardware.
+ PARPORT_MODE_TRISTATE The data drivers may be turned off.
+ This allows the data lines to be used
+ for reverse (peripheral to host)
+ transfers.
+ PARPORT_MODE_COMPAT The hardware can assist with
+ compatibility-mode (printer)
+ transfers, i.e. compat_write_block.
+ PARPORT_MODE_EPP The hardware can assist with EPP
+ transfers.
+ PARPORT_MODE_ECP The hardware can assist with ECP
+ transfers.
+ PARPORT_MODE_DMA The hardware can use DMA, so you might
+ want to pass ISA DMA-able memory
+ (i.e. memory allocated using the
+ GFP_DMA flag with kmalloc) to the
+ low-level driver in order to take
+ advantage of it.
+
+There may be other flags in 'modes' as well.
+
+The contents of 'modes' is advisory only. For example, if the
+hardware is capable of DMA, and PARPORT_MODE_DMA is in 'modes', it
+doesn't necessarily mean that DMA will always be used when possible.
+Similarly, hardware that is capable of assisting ECP transfers won't
+necessarily be used.
+
+RETURN VALUE
+
+Zero on success, otherwise an error code.
+
+ERRORS
+
+None. (Can it fail? Why return int?)
+
+EXAMPLE
+
+static void lp_attach (struct parport *port)
+{
+ ...
+ private = kmalloc (...);
+ dev[count++] = parport_register_device (...);
+ ...
+}
+
+static void lp_detach (struct parport *port)
+{
+ ...
+}
+
+static struct parport_driver lp_driver = {
+ "lp",
+ lp_attach,
+ lp_detach,
+ NULL /* always put NULL here */
+};
+
+int lp_init (void)
+{
+ ...
+ if (parport_register_driver (&lp_driver)) {
+ /* Failed; nothing we can do. */
+ return -EIO;
+ }
+ ...
+}
+
+SEE ALSO
+
+parport_unregister_driver, parport_register_device, parport_enumerate
+
+parport_unregister_driver - tell parport to forget about this driver
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_driver {
+ const char *name;
+ void (*attach) (struct parport *);
+ void (*detach) (struct parport *);
+ struct parport_driver *next;
+};
+void parport_unregister_driver (struct parport_driver *driver);
+
+DESCRIPTION
+
+This tells parport not to notify the device driver of new ports or of
+ports going away. Registered devices belonging to that driver are NOT
+unregistered: parport_unregister_device must be used for each one.
+
+EXAMPLE
+
+void cleanup_module (void)
+{
+ ...
+ /* Stop notifications. */
+ parport_unregister_driver (&lp_driver);
+
+ /* Unregister devices. */
+ for (i = 0; i < NUM_DEVS; i++)
+ parport_unregister_device (dev[i]);
+ ...
+}
+
+SEE ALSO
+
+parport_register_driver, parport_enumerate
+
+parport_enumerate - retrieve a list of parallel ports (DEPRECATED)
+-----------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport *parport_enumerate (void);
+
+DESCRIPTION
+
+Retrieve the first of a list of valid parallel ports for this machine.
+Successive parallel ports can be found using the 'struct parport
+*next' element of the 'struct parport *' that is returned. If 'next'
+is NULL, there are no more parallel ports in the list. The number of
+ports in the list will not exceed PARPORT_MAX.
+
+RETURN VALUE
+
+A 'struct parport *' describing a valid parallel port for the machine,
+or NULL if there are none.
+
+ERRORS
+
+This function can return NULL to indicate that there are no parallel
+ports to use.
+
+EXAMPLE
+
+int detect_device (void)
+{
+ struct parport *port;
+
+ for (port = parport_enumerate ();
+ port != NULL;
+ port = port->next) {
+ /* Try to detect a device on the port... */
+ ...
+ }
+ }
+
+ ...
+}
+
+NOTES
+
+parport_enumerate is deprecated; parport_register_driver should be
+used instead.
+
+SEE ALSO
+
+parport_register_driver, parport_unregister_driver
+
+parport_register_device - register to use a port
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+typedef int (*preempt_func) (void *handle);
+typedef void (*wakeup_func) (void *handle);
+typedef int (*irq_func) (int irq, void *handle, struct pt_regs *);
+
+struct pardevice *parport_register_device(struct parport *port,
+ const char *name,
+ preempt_func preempt,
+ wakeup_func wakeup,
+ irq_func irq,
+ int flags,
+ void *handle);
+
+DESCRIPTION
+
+Use this function to register your device driver on a parallel port
+('port'). Once you have done that, you will be able to use
+parport_claim and parport_release in order to use the port.
+
+This function will register three callbacks into your driver:
+'preempt', 'wakeup' and 'irq'. Each of these may be NULL in order to
+indicate that you do not want a callback.
+
+When the 'preempt' function is called, it is because another driver
+wishes to use the parallel port. The 'preempt' function should return
+non-zero if the parallel port cannot be released yet -- if zero is
+returned, the port is lost to another driver and the port must be
+re-claimed before use.
+
+The 'wakeup' function is called once another driver has released the
+port and no other driver has yet claimed it. You can claim the
+parallel port from within the 'wakeup' function (in which case the
+claim is guaranteed to succeed), or choose not to if you don't need it
+now.
+
+If an interrupt occurs on the parallel port your driver has claimed,
+the 'irq' function will be called. (Write something about shared
+interrupts here.)
+
+The 'handle' is a pointer to driver-specific data, and is passed to
+the callback functions.
+
+'flags' may be a bitwise combination of the following flags:
+
+ Flag Meaning
+ PARPORT_DEV_EXCL The device cannot share the parallel port at all.
+ Use this only when absolutely necessary.
+
+The typedefs are not actually defined -- they are only shown in order
+to make the function prototype more readable.
+
+The visible parts of the returned 'struct pardevice' are:
+
+struct pardevice {
+ struct parport *port; /* Associated port */
+ void *private; /* Device driver's 'handle' */
+ ...
+};
+
+RETURN VALUE
+
+A 'struct pardevice *': a handle to the registered parallel port
+device that can be used for parport_claim, parport_release, etc.
+
+ERRORS
+
+A return value of NULL indicates that there was a problem registering
+a device on that port.
+
+EXAMPLE
+
+static int preempt (void *handle)
+{
+ if (busy_right_now)
+ return 1;
+
+ must_reclaim_port = 1;
+ return 0;
+}
+
+static void wakeup (void *handle)
+{
+ struct toaster *private = handle;
+ struct pardevice *dev = private->dev;
+ if (!dev) return; /* avoid races */
+
+ if (want_port)
+ parport_claim (dev);
+}
+
+static int toaster_detect (struct toaster *private, struct parport *port)
+{
+ private->dev = parport_register_device (port, "toaster", preempt,
+ wakeup, NULL, 0,
+ private);
+ if (!private->dev)
+ /* Couldn't register with parport. */
+ return -EIO;
+
+ must_reclaim_port = 0;
+ busy_right_now = 1;
+ parport_claim_or_block (private->dev);
+ ...
+ /* Don't need the port while the toaster warms up. */
+ busy_right_now = 0;
+ ...
+ busy_right_now = 1;
+ if (must_reclaim_port) {
+ parport_claim_or_block (private->dev);
+ must_reclaim_port = 0;
+ }
+ ...
+}
+
+SEE ALSO
+
+parport_unregister_device, parport_claim
+
+parport_unregister_device - finish using a port
+-------------------------
+
+SYNPOPSIS
+
+#include <linux/parport.h>
+
+void parport_unregister_device (struct pardevice *dev);
+
+DESCRIPTION
+
+This function is the opposite of parport_register_device. After using
+parport_unregister_device, 'dev' is no longer a valid device handle.
+
+You should not unregister a device that is currently claimed, although
+if you do it will be released automatically.
+
+EXAMPLE
+
+ ...
+ kfree (dev->private); /* before we lose the pointer */
+ parport_unregister_device (dev);
+ ...
+
+SEE ALSO
+
+parport_unregister_driver
+
+parport_claim, parport_claim_or_block - claim the parallel port for a device
+-------------------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_claim (struct pardevice *dev);
+int parport_claim_or_block (struct pardevice *dev);
+
+DESCRIPTION
+
+These functions attempt to gain control of the parallel port on which
+'dev' is registered. 'parport_claim' does not block, but
+'parport_claim_or_block' may do. (Put something here about blocking
+interruptibly or non-interruptibly.)
+
+You should not try to claim a port that you have already claimed.
+
+RETURN VALUE
+
+A return value of zero indicates that the port was successfully
+claimed, and the caller now has possession of the parallel port.
+
+If 'parport_claim_or_block' blocks before returning successfully, the
+return value is positive.
+
+ERRORS
+
+ -EAGAIN The port is unavailable at the moment, but another attempt
+ to claim it may succeed.
+
+SEE ALSO
+
+parport_release
+
+parport_release - release the parallel port
+---------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+void parport_release (struct pardevice *dev);
+
+DESCRIPTION
+
+Once a parallel port device has been claimed, it can be released using
+'parport_release'. It cannot fail, but you should not release a
+device that you do not have possession of.
+
+EXAMPLE
+
+static size_t write (struct pardevice *dev, const void *buf,
+ size_t len)
+{
+ ...
+ written = dev->port->ops->write_ecp_data (dev->port, buf,
+ len);
+ parport_release (dev);
+ ...
+}
+
+
+SEE ALSO
+
+change_mode, parport_claim, parport_claim_or_block, parport_yield
+
+parport_yield, parport_yield_blocking - temporarily release a parallel port
+-------------------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_yield (struct pardevice *dev)
+int parport_yield_blocking (struct pardevice *dev);
+
+DESCRIPTION
+
+When a driver has control of a parallel port, it may allow another
+driver to temporarily 'borrow' it. 'parport_yield' does not block;
+'parport_yield_blocking' may do.
+
+RETURN VALUE
+
+A return value of zero indicates that the caller still owns the port
+and the call did not block.
+
+A positive return value from 'parport_yield_blocking' indicates that
+the caller still owns the port and the call blocked.
+
+A return value of -EAGAIN indicates that the caller no longer owns the
+port, and it must be re-claimed before use.
+
+ERRORS
+
+ -EAGAIN Ownership of the parallel port was given away.
+
+SEE ALSO
+
+parport_release
+
+parport_wait_peripheral - wait for status lines, up to 35ms
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_wait_peripheral (struct parport *port,
+ unsigned char mask,
+ unsigned char val);
+
+DESCRIPTION
+
+Wait for the status lines in mask to match the values in val.
+
+RETURN VALUE
+
+ -EINTR a signal is pending
+ 0 the status lines in mask have values in val
+ 1 timed out while waiting (35ms elapsed)
+
+SEE ALSO
+
+parport_poll_peripheral
+
+parport_poll_peripheral - wait for status lines, in usec
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_poll_peripheral (struct parport *port,
+ unsigned char mask,
+ unsigned char val,
+ int usec);
+
+DESCRIPTION
+
+Wait for the status lines in mask to match the values in val.
+
+RETURN VALUE
+
+ -EINTR a signal is pending
+ 0 the status lines in mask have values in val
+ 1 timed out while waiting (usec microseconds have elapsed)
+
+SEE ALSO
+
+parport_wait_peripheral
+
+parport_wait_event - wait for an event on a port
+------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_wait_event (struct parport *port, signed long timeout)
+
+DESCRIPTION
+
+Wait for an event (e.g. interrupt) on a port. The timeout is in
+jiffies.
+
+RETURN VALUE
+
+ 0 success
+ <0 error (exit as soon as possible)
+ >0 timed out
+
+parport_negotiate - perform IEEE 1284 negotiation
+-----------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_negotiate (struct parport *, int mode);
+
+DESCRIPTION
+
+Perform IEEE 1284 negotiation.
+
+RETURN VALUE
+
+ 0 handshake OK; IEEE 1284 peripheral and mode available
+ -1 handshake failed; peripheral not compliant (or none present)
+ 1 handshake OK; IEEE 1284 peripheral present but mode not
+ available
+
+SEE ALSO
+
+parport_read, parport_write
+
+parport_read - read data from device
+------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+ssize_t parport_read (struct parport *, void *buf, size_t len);
+
+DESCRIPTION
+
+Read data from device in current IEEE 1284 transfer mode. This only
+works for modes that support reverse data transfer.
+
+RETURN VALUE
+
+If negative, an error code; otherwise the number of bytes transferred.
+
+SEE ALSO
+
+parport_write, parport_negotiate
+
+parport_write - write data to device
+-------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+ssize_t parport_write (struct parport *, const void *buf, size_t len);
+
+DESCRIPTION
+
+Write data to device in current IEEE 1284 transfer mode. This only
+works for modes that support forward data transfer.
+
+RETURN VALUE
+
+If negative, an error code; otherwise the number of bytes transferred.
+
+SEE ALSO
+
+parport_read, parport_negotiate
+
+parport_open - register device for particular device number
+------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct pardevice *parport_open (int devnum, const char *name,
+ int (*pf) (void *),
+ void (*kf) (void *),
+ void (*irqf) (int, void *,
+ struct pt_regs *),
+ int flags, void *handle);
+
+DESCRIPTION
+
+This is like parport_register_device but takes a device number instead
+of a pointer to a struct parport.
+
+RETURN VALUE
+
+See parport_register_device. If no device is associated with devnum,
+NULL is returned.
+
+SEE ALSO
+
+parport_register_device, parport_device_num
+
+parport_close - unregister device for particular device number
+-------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+void parport_close (struct pardevice *dev);
+
+DESCRIPTION
+
+This is the equivalent of parport_unregister_device for parport_open.
+
+SEE ALSO
+
+parport_unregister_device, parport_open
+
+parport_device_id - obtain IEEE 1284 Device ID
+-----------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+
+DESCRIPTION
+
+Obtains the IEEE 1284 Device ID associated with a given device.
+
+RETURN VALUE
+
+If negative, an error code; otherwise, the number of bytes of buffer
+that contain the device ID. The format of the device ID is as
+follows:
+
+[length][ID]
+
+The first two bytes indicate the inclusive length of the entire Device
+ID, and are in big-endian order. The ID is a sequence of pairs of the
+form:
+
+key:value;
+
+NOTES
+
+Many devices have ill-formed IEEE 1284 Device IDs.
+
+SEE ALSO
+
+parport_find_class, parport_find_device, parport_device_num
+
+parport_device_num - convert device coordinates to device number
+------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_device_num (int parport, int mux, int daisy);
+
+DESCRIPTION
+
+Convert between device coordinates (port, multiplexor, daisy chain
+address) and device number (zero-based).
+
+RETURN VALUE
+
+Device number, or -1 if no device at given coordinates.
+
+SEE ALSO
+
+parport_device_coords, parport_open, parport_device_id
+
+parport_device_coords - convert device number to device coordinates
+------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_device_coords (int devnum, int *parport, int *mux,
+ int *daisy);
+
+DESCRIPTION
+
+Convert between device number (zero-based) and device coordinates
+(port, multiplexor, daisy chain address).
+
+RETURN VALUE
+
+Zero on success, in which case the coordinates are (*parport, *mux,
+*daisy).
+
+SEE ALSO
+
+parport_device_num, parport_open, parport_device_id
+
+parport_find_class - find a device by its class
+------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+typedef enum {
+ PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */
+ PARPORT_CLASS_PRINTER,
+ PARPORT_CLASS_MODEM,
+ PARPORT_CLASS_NET,
+ PARPORT_CLASS_HDC, /* Hard disk controller */
+ PARPORT_CLASS_PCMCIA,
+ PARPORT_CLASS_MEDIA, /* Multimedia device */
+ PARPORT_CLASS_FDC, /* Floppy disk controller */
+ PARPORT_CLASS_PORTS,
+ PARPORT_CLASS_SCANNER,
+ PARPORT_CLASS_DIGCAM,
+ PARPORT_CLASS_OTHER, /* Anything else */
+ PARPORT_CLASS_UNSPEC, /* No CLS field in ID */
+ PARPORT_CLASS_SCSIADAPTER
+} parport_device_class;
+
+int parport_find_class (parport_device_class cls, int from);
+
+DESCRIPTION
+
+Find a device by class. The search starts from device number from+1.
+
+RETURN VALUE
+
+The device number of the next device in that class, or -1 if no such
+device exists.
+
+NOTES
+
+Example usage:
+
+int devnum = -1;
+while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) {
+ struct pardevice *dev = parport_open (devnum, ...);
+ ...
+}
+
+SEE ALSO
+
+parport_find_device, parport_open, parport_device_id
+
+parport_find_device - find a device by its class
+------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+int parport_find_device (const char *mfg, const char *mdl, int from);
+
+DESCRIPTION
+
+Find a device by vendor and model. The search starts from device
+number from+1.
+
+RETURN VALUE
+
+The device number of the next device matching the specifications, or
+-1 if no such device exists.
+
+NOTES
+
+Example usage:
+
+int devnum = -1;
+while ((devnum = parport_find_device ("IOMEGA", "ZIP+", devnum)) != -1) {
+ struct pardevice *dev = parport_open (devnum, ...);
+ ...
+}
+
+SEE ALSO
+
+parport_find_class, parport_open, parport_device_id
+
+parport_set_timeout - set the inactivity timeout
+-------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+long parport_set_timeout (struct pardevice *dev, long inactivity);
+
+DESCRIPTION
+
+Set the inactivity timeout, in jiffies, for a registered device. The
+previous timeout is returned.
+
+RETURN VALUE
+
+The previous timeout, in jiffies.
+
+NOTES
+
+Some of the port->ops functions for a parport may take time, owing to
+delays at the peripheral. After the peripheral has not responded for
+'inactivity' jiffies, a timeout will occur and the blocking function
+will return.
+
+A timeout of 0 jiffies is a special case: the function must do as much
+as it can without blocking or leaving the hardware in an unknown
+state. If port operations are performed from within an interrupt
+handler, for instance, a timeout of 0 jiffies should be used.
+
+Once set for a registered device, the timeout will remain at the set
+value until set again.
+
+SEE ALSO
+
+port->ops->xxx_read/write_yyy
+
+PORT FUNCTIONS
+--------------
+
+The functions in the port->ops structure (struct parport_operations)
+are provided by the low-level driver responsible for that port.
+
+port->ops->read_data - read the data register
+--------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ unsigned char (*read_data) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+If port->modes contains the PARPORT_MODE_TRISTATE flag and the
+PARPORT_CONTROL_DIRECTION bit in the control register is set, this
+returns the value on the data pins. If port->modes contains the
+PARPORT_MODE_TRISTATE flag and the PARPORT_CONTROL_DIRECTION bit is
+not set, the return value _may_ be the last value written to the data
+register. Otherwise the return value is undefined.
+
+SEE ALSO
+
+write_data, read_status, write_control
+
+port->ops->write_data - write the data register
+---------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*write_data) (struct parport *port, unsigned char d);
+ ...
+};
+
+DESCRIPTION
+
+Writes to the data register. May have side-effects (a STROBE pulse,
+for instance).
+
+SEE ALSO
+
+read_data, read_status, write_control
+
+port->ops->read_status - read the status register
+----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ unsigned char (*read_status) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+Reads from the status register. This is a bitmask:
+
+- PARPORT_STATUS_ERROR (printer fault, "nFault")
+- PARPORT_STATUS_SELECT (on-line, "Select")
+- PARPORT_STATUS_PAPEROUT (no paper, "PError")
+- PARPORT_STATUS_ACK (handshake, "nAck")
+- PARPORT_STATUS_BUSY (busy, "Busy")
+
+There may be other bits set.
+
+SEE ALSO
+
+read_data, write_data, write_control
+
+port->ops->read_control - read the control register
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ unsigned char (*read_control) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+Returns the last value written to the control register (either from
+write_control or frob_control). No port access is performed.
+
+SEE ALSO
+
+read_data, write_data, read_status, write_control
+
+port->ops->write_control - write the control register
+------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*write_status) (struct parport *port, unsigned char s);
+ ...
+};
+
+DESCRIPTION
+
+Writes to the control register. This is a bitmask:
+ _______
+- PARPORT_CONTROL_STROBE (nStrobe)
+ _______
+- PARPORT_CONTROL_AUTOFD (nAutoFd)
+ _____
+- PARPORT_CONTROL_INIT (nInit)
+ _________
+- PARPORT_CONTROL_SELECT (nSelectIn)
+
+SEE ALSO
+
+read_data, write_data, read_status, frob_control
+
+port->ops->frob_control - write control register bits
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*frob_control) (struct parport *port,
+ unsigned char mask,
+ unsigned char val);
+ ...
+};
+
+DESCRIPTION
+
+This is equivalent to reading from the control register, masking out
+the bits in mask, exclusive-or'ing with the bits in val, and writing
+the result to the control register.
+
+As some ports don't allow reads from the control port, a software copy
+of its contents is maintained, so frob_control is in fact only one
+port access.
+
+SEE ALSO
+
+read_data, write_data, read_status, write_control
+
+port->ops->enable_irq - enable interrupt generation
+---------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*enable_irq) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+The parallel port hardware is instructed to generate interrupts at
+appropriate moments, although those moments are
+architecture-specific. For the PC architecture, interrupts are
+commonly generated on the rising edge of nAck.
+
+SEE ALSO
+
+disable_irq
+
+port->ops->disable_irq - disable interrupt generation
+----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*disable_irq) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+The parallel port hardware is instructed not to generate interrupts.
+The interrupt itself is not masked.
+
+SEE ALSO
+
+enable_irq
+
+port->ops->data_forward - enable data drivers
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*data_forward) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+Enables the data line drivers, for 8-bit host-to-peripheral
+communications.
+
+SEE ALSO
+
+data_reverse
+
+port->ops->data_reverse - tristate the buffer
+-----------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ void (*data_reverse) (struct parport *port);
+ ...
+};
+
+DESCRIPTION
+
+Places the data bus in a high impedance state, if port->modes has the
+PARPORT_MODE_TRISTATE bit set.
+
+SEE ALSO
+
+data_forward
+
+port->ops->epp_write_data - write EPP data
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*epp_write_data) (struct parport *port, const void *buf,
+ size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Writes data in EPP mode, and returns the number of bytes written.
+
+The 'flags' parameter may be one or more of the following,
+bitwise-or'ed together:
+
+PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and
+ 32-bit registers. However, if a transfer
+ times out, the return value may be unreliable.
+
+SEE ALSO
+
+epp_read_data, epp_write_addr, epp_read_addr
+
+port->ops->epp_read_data - read EPP data
+------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*epp_read_data) (struct parport *port, void *buf,
+ size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Reads data in EPP mode, and returns the number of bytes read.
+
+The 'flags' parameter may be one or more of the following,
+bitwise-or'ed together:
+
+PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and
+ 32-bit registers. However, if a transfer
+ times out, the return value may be unreliable.
+
+SEE ALSO
+
+epp_write_data, epp_write_addr, epp_read_addr
+
+port->ops->epp_write_addr - write EPP address
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*epp_write_addr) (struct parport *port,
+ const void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Writes EPP addresses (8 bits each), and returns the number written.
+
+The 'flags' parameter may be one or more of the following,
+bitwise-or'ed together:
+
+PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and
+ 32-bit registers. However, if a transfer
+ times out, the return value may be unreliable.
+
+(Does PARPORT_EPP_FAST make sense for this function?)
+
+SEE ALSO
+
+epp_write_data, epp_read_data, epp_read_addr
+
+port->ops->epp_read_addr - read EPP address
+------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*epp_read_addr) (struct parport *port, void *buf,
+ size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Reads EPP addresses (8 bits each), and returns the number read.
+
+The 'flags' parameter may be one or more of the following,
+bitwise-or'ed together:
+
+PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and
+ 32-bit registers. However, if a transfer
+ times out, the return value may be unreliable.
+
+(Does PARPORT_EPP_FAST make sense for this function?)
+
+SEE ALSO
+
+epp_write_data, epp_read_data, epp_write_addr
+
+port->ops->ecp_write_data - write a block of ECP data
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*ecp_write_data) (struct parport *port,
+ const void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Writes a block of ECP data. The 'flags' parameter is ignored.
+
+RETURN VALUE
+
+The number of bytes written.
+
+SEE ALSO
+
+ecp_read_data, ecp_write_addr
+
+port->ops->ecp_read_data - read a block of ECP data
+------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*ecp_read_data) (struct parport *port,
+ void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Reads a block of ECP data. The 'flags' parameter is ignored.
+
+RETURN VALUE
+
+The number of bytes read. NB. There may be more unread data in a
+FIFO. Is there a way of stunning the FIFO to prevent this?
+
+SEE ALSO
+
+ecp_write_block, ecp_write_addr
+
+port->ops->ecp_write_addr - write a block of ECP addresses
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*ecp_write_addr) (struct parport *port,
+ const void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Writes a block of ECP addresses. The 'flags' parameter is ignored.
+
+RETURN VALUE
+
+The number of bytes written.
+
+NOTES
+
+This may use a FIFO, and if so shall not return until the FIFO is empty.
+
+SEE ALSO
+
+ecp_read_data, ecp_write_data
+
+port->ops->nibble_read_data - read a block of data in nibble mode
+---------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*nibble_read_data) (struct parport *port,
+ void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Reads a block of data in nibble mode. The 'flags' parameter is ignored.
+
+RETURN VALUE
+
+The number of whole bytes read.
+
+SEE ALSO
+
+byte_read_data, compat_write_data
+
+port->ops->byte_read_data - read a block of data in byte mode
+-------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*byte_read_data) (struct parport *port,
+ void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Reads a block of data in byte mode. The 'flags' parameter is ignored.
+
+RETURN VALUE
+
+The number of bytes read.
+
+SEE ALSO
+
+nibble_read_data, compat_write_data
+
+port->ops->compat_write_data - write a block of data in compatibility mode
+----------------------------
+
+SYNOPSIS
+
+#include <linux/parport.h>
+
+struct parport_operations {
+ ...
+ size_t (*compat_write_data) (struct parport *port,
+ const void *buf, size_t len, int flags);
+ ...
+};
+
+DESCRIPTION
+
+Writes a block of data in compatibility mode. The 'flags' parameter
+is ignored.
+
+RETURN VALUE
+
+The number of bytes written.
+
+SEE ALSO
+
+nibble_read_data, byte_read_data
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index d1211c512..f09ece79a 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -174,6 +174,8 @@ pci_find_slot() Find pci_dev corresponding to given bus and
pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3)
pci_find_capability() Find specified capability in device's capability
list.
+pci_module_init() Inline helper function for ensuring correct
+ pci_driver initialization and error handling.
7. Miscellaneous hints
diff --git a/Documentation/pm.txt b/Documentation/pm.txt
index eb7a819b6..1e78926cd 100644
--- a/Documentation/pm.txt
+++ b/Documentation/pm.txt
@@ -164,3 +164,154 @@ void pm_dev_idle(struct pm_dev *dev);
* access the device hardware until a call to "pm_access" is made.
*/
typedef int (*pm_callback)(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+Driver Details
+--------------
+This is just a quick Q&A as a stopgap until a real driver writers'
+power management guide is available.
+
+Q: When is a device suspended?
+
+Devices can be suspended based on direct user request (eg. laptop lid
+closes), system power policy (eg. sleep after 30 minutes of console
+inactivity), or device power policy (eg. power down device after 5
+minutes of inactivity)
+
+Q: Must a driver honor a suspend request?
+
+No, a driver can return -EBUSY from a suspend request and this
+will stop the system from suspending. When a suspend request
+fails, all suspended devices are resumed and the system continues
+to run. Suspend can be retried at a later time.
+
+Q: Can the driver block suspend/resume requests?
+
+Yes, a driver can delay its return from a suspend or resume
+request until the device is ready to handle requests. It
+is advantageous to return as quickly as possible from a
+request as suspend/resume are done serially.
+
+Q: What context is a suspend/resume initiated from?
+
+A suspend or resume is initiated from a kernel thread context.
+It is safe to block, allocate memory, initiate requests
+or anything else you can do within the kernel.
+
+Q: Will requests continue to arrive after a suspend?
+
+Possibly. It is the driver's responsibility to queue(*),
+fail, or drop any requests that arrive after returning
+success to a suspend request. It is important that the
+driver not access its device until after it receives
+a resume request as the device's bus may no longer
+be active.
+
+(*) If a driver queues requests for processing after
+ resume be aware that the device, network, etc.
+ might be in a different state than at suspend time.
+ It's probably better to drop requests unless
+ the driver is a storage device.
+
+Q: Do I have to manage bus-specific power management registers
+
+No. It is the responsibility of the bus driver to manage
+PCI, USB, etc. power management registers. The bus driver
+or the power management subsystem will also enable any
+wake-on functionality that the device has.
+
+Q: So, really, what do I need to do to support suspend/resume?
+
+You need to save any device context that would
+be lost if the device was powered off and then restore
+it at resume time. When ACPI is active, there are
+three levels of device suspend states; D1, D2, and D3.
+(The suspend state is passed as the "data" argument
+to the device callback.) With D3, the device is powered
+off and loses all context, D1 and D2 are shallower power
+states and require less device context to be saved. To
+play it safe, just save everything at suspend and restore
+everything at resume.
+
+Q: Where do I store device context for suspend?
+
+Anywhere in memory, kmalloc a buffer or store it
+in the device descriptor. You are guaranteed that the
+contents of memory will be restored and accessible
+before resume, even when the system suspends to disk.
+
+Q: What do I need to do for ACPI vs. APM vs. etc?
+
+Drivers need not be aware of the specific power management
+technology that is active. They just need to be aware
+of when the overlying power management system requests
+that they suspend or resume.
+
+Q: What about device dependencies?
+
+When a driver registers a device, the power management
+subsystem uses the information provided to build a
+tree of device dependencies (eg. USB device X is on
+USB controller Y which is on PCI bus Z) When power
+management wants to suspend a device, it first sends
+a suspend request to its driver, then the bus driver,
+and so on up to the system bus. Device resumes
+proceed in the opposite direction.
+
+Q: Who do I contact for additional information about
+ enabling power management for my specific driver/device?
+
+ACPI4Linux mailing list: acpi@phobos.fs.tum.de
+Linux ACPI maintainer: andy_henroid@yahoo.com
+
+System Interface
+----------------
+If you are providing new power management support to Linux (ie.
+adding support for something like APM or ACPI), you should
+communicate with drivers through the existing generic power
+management interface.
+
+/*
+ * Send a request to a single device
+ *
+ * Parameters:
+ * dev - PM device previously returned from pm_register or pm_find
+ * rqst - request type
+ * data - data, if any, associated with the request
+ *
+ * Returns: 0 if the request is successful
+ * See "pm_callback" return for errors
+ *
+ * Details: Forward request to device callback and, if a suspend
+ * or resume request, update the pm_dev "state" field
+ * appropriately
+ */
+int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+/*
+ * Send a request to all devices
+ *
+ * Parameters:
+ * rqst - request type
+ * data - data, if any, associated with the request
+ *
+ * Returns: 0 if the request is successful
+ * See "pm_callback" return for errors
+ *
+ * Details: Walk list of registered devices and call pm_send
+ * for each until complete or an error is encountered.
+ * If an error is encountered for a suspend request,
+ * return all devices to the state they were in before
+ * the suspend request.
+ */
+int pm_send_all(pm_request_t rqst, void *data);
+
+/*
+ * Find a matching device
+ *
+ * Parameters:
+ * type - device type (PCI device, system device, or 0 to match all devices)
+ * from - previous match or NULL to start from the beginning
+ *
+ * Returns: Matching device or NULL if none found
+ */
+struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from);
diff --git a/Documentation/vm/balance b/Documentation/vm/balance
index 6202e4291..bd3d31bc4 100644
--- a/Documentation/vm/balance
+++ b/Documentation/vm/balance
@@ -68,12 +68,24 @@ primarily needed in a situation where balancing can not be done,
probably because all allocation requests are coming from intr context
and all process contexts are sleeping. For 2.3, kswapd does not really
need to balance the highmem zone, since intr context does not request
-highmem pages. A zone aware kswapd still needs to be implemented.
+highmem pages. kswapd looks at the zone_wake_kswapd field in the zone
+structure to decide whether a zone needs balancing.
Page stealing from process memory and shm is done if stealing the page would
alleviate memory pressure on any zone in the page's node that has fallen below
its watermark.
+pages_min/pages_low/pages_high/low_on_memory/zone_wake_kswapd: These are
+per-zone fields, used to determine when a zone needs to be balanced. When
+the number of pages falls below pages_min, the hysteric field low_on_memory
+gets set. This stays set till the number of free pages becomes pages_high.
+When low_on_memory is set, page allocation requests will try to free some
+pages in the zone (providing GFP_WAIT is set in the request). Orthogonal
+to this, is the decision to poke kswapd to free some zone pages. That
+decision is not hysteresis based, and is done when the number of free
+pages is below pages_low; in which case zone_wake_kswapd is also set.
+
+
(Good) Ideas that I have heard:
1. Dynamic experience should influence balancing: number of failed requests
for a zone can be tracked and fed into the balancing scheme (jalvo@mbay.net)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7c0c56032..03d8e42ed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -726,6 +726,12 @@ M: emoenke@gwdg.de
L: linux-kernel@vger.rutgers.edu
S: Maintained
+NVIDIA (RIVA) FRAMEBUFFER DRIVER
+P: Jeff Garzik
+M: jgarzik@mandrakesoft.com
+L: linux-nvidia@lists.surfsouth.com
+S: Maintained
+
OLYMPIC NETWORK DRIVER
P: Peter De Shrijver
M: p2@ace.ulyssis.sutdent.kuleuven.ac.be
@@ -778,7 +784,7 @@ PCI SUBSYSTEM
P: Martin Mares
M: mj@suse.cz
L: linux-kernel@vger.rutgers.edu
-S: Maintained
+S: Supported
PCMCIA SUBSYSTEM
P: David Hinds
@@ -986,7 +992,7 @@ S: Maintained
SVGA HANDLING
P: Martin Mares
-M: mj@atrey.karlin.mff.cuni.cz
+M: mj@suse.cz
L: linux-video@atrey.karlin.mff.cuni.cz
S: Maintained
@@ -1021,6 +1027,12 @@ L: linux-tr@linuxtr.net
W: http://www.auk.cx/tms380tr/
S: Maintained
+TULIP NETWORK DRIVER
+P: Jeff Garzik
+M: jgarzik@mandrakesoft.com
+L: linux-tulip@cesdis.gsfc.nasa.gov
+S: Maintained
+
U14-34F SCSI DRIVER
P: Dario Ballabio
M: dario@milano.europe.dg.com
@@ -1112,6 +1124,7 @@ S: Maintained
VIA 82Cxxx AUDIO DRIVER
P: Jeff Garzik
M: jgarzik@mandrakesoft.com
+L: linux-via@gtf.org
S: Maintained
VIDEO FOR LINUX
diff --git a/Makefile b/Makefile
index 66627d6a3..9c6e47960 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 47
+SUBLEVEL = 48
EXTRAVERSION =
ARCH = mips
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 8e44bb0e2..1686fefbc 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -60,6 +60,7 @@ unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
unset CONFIG_ALPHA_IRONGATE
+unset CONFIG_ALPHA_BROKEN_IRQ_MASK
# Most of these machines have ISA slots; not exactly sure which don't,
# and this doesn't activate hordes of code, so do it always.
@@ -178,6 +179,10 @@ if [ "$CONFIG_ALPHA_XL" = "y" ]
then
define_bool CONFIG_ALPHA_AVANTI y
fi
+if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ]
+then
+ define_bool CONFIG_ALPHA_BROKEN_IRQ_MASK y
+fi
if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" ]
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 725dd4f51..25d9583dd 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -98,6 +98,8 @@ EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memsetw);
EXPORT_SYMBOL(__constant_c_memset);
+EXPORT_SYMBOL(__direct_map_base);
+EXPORT_SYMBOL(__direct_map_size);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
@@ -144,6 +146,10 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise);
EXPORT_SYMBOL(alpha_fp_emul);
#endif
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+EXPORT_SYMBOL(__min_ipl);
+#endif
+
/*
* The following are specially called from the uaccess assembly stubs.
*/
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index 5fa112173..1452b6336 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -24,7 +24,6 @@
#include "proto.h"
#include "pci_impl.h"
-int TSUNAMI_bootcpu;
static struct
{
@@ -210,17 +209,23 @@ void
tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
{
tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0;
-
- wmb();
+ volatile unsigned long *csr;
+ unsigned long value;
/* We can invalidate up to 8 tlb entries in a go. The flush
matches against <31:16> in the pci address. */
+ csr = &pchip->tlbia.csr;
if (((start ^ end) & 0xffff0000) == 0)
- pchip->tlbiv.csr = (start & 0xffff0000) >> 12;
- else
- pchip->tlbia.csr = 0;
+ csr = &pchip->tlbiv.csr;
+ /* For TBIA, it doesn't matter what value we write. For TBI,
+ it's the shifted tag bits. */
+ value = (start & 0xffff0000) >> 12;
+
+ wmb();
+ *csr = value;
mb();
+ *csr;
}
#ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI
@@ -229,7 +234,7 @@ tsunami_probe_read(volatile unsigned long *vaddr)
{
long dont_care, probe_result;
int cpu = smp_processor_id();
- int s = swpipl(6); /* Block everything but machine checks. */
+ int s = swpipl(IPL_MCHECK - 1);
mcheck_taken(cpu) = 0;
mcheck_expected(cpu) = 1;
@@ -338,9 +343,13 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
* because of an idiot-syncrasy of the CYPRESS chip. It may
* respond to a PCI bus address in the last 1MB of the 4GB
* address range.
+ *
+ * Note that the TLB lookup logic uses bitwise concatenation,
+ * not addition, so the required arena alignment is based on
+ * the size of the window.
*/
- hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE);
- hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, PAGE_SIZE);
+ hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 0x00800000>>10);
+ hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 0x08000000>>10);
__direct_map_base = 0x40000000;
__direct_map_size = 0x80000000;
@@ -399,8 +408,6 @@ tsunami_init_arch(void)
printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr);
printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr);
#endif
- TSUNAMI_bootcpu = __hard_smp_processor_id();
-
/* With multiple PCI busses, we play with I/O as physical addrs. */
ioport_resource.end = ~0UL;
iomem_resource.end = ~0UL;
@@ -444,12 +451,10 @@ tsunami_kill_arch(int mode)
static inline void
tsunami_pci_clr_err_1(tsunami_pchip *pchip)
{
- unsigned int jd;
-
- jd = pchip->perror.csr;
+ pchip->perror.csr;
pchip->perror.csr = 0x040;
mb();
- jd = pchip->perror.csr;
+ pchip->perror.csr;
}
static inline void
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 3d593acf3..613a633ba 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -48,6 +48,12 @@ unsigned long __irq_attempt[NR_IRQS];
#define ACTUAL_NR_IRQS NR_IRQS
#endif
+/* Hack minimum IPL during interupt processing for broken hardware. */
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+int __min_ipl;
+#endif
+
/*
* Performance counter hook. A module can override this to
* do something useful.
@@ -283,30 +289,32 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
struct irqaction *action)
{
int status, cpu = smp_processor_id();
- unsigned long ipl;
+ int old_ipl, ipl;
kstat.irqs[cpu][irq]++;
irq_enter(cpu, irq);
status = 1; /* Force the "do bottom halves" bit */
- ipl = rdps() & 7;
+ old_ipl = ipl = getipl();
do {
- unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0);
- if (newipl != ipl) {
- swpipl(newipl);
- ipl = newipl;
+ int new_ipl = IPL_MIN;
+ if (action->flags & SA_INTERRUPT)
+ new_ipl = IPL_MAX;
+ if (new_ipl != ipl) {
+ setipl(new_ipl);
+ ipl = new_ipl;
}
status |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
+ if (ipl != old_ipl)
+ setipl(old_ipl);
+
if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
- if (ipl == 0)
- __cli();
-
irq_exit(cpu, irq);
return status;
@@ -325,7 +333,7 @@ disable_irq_nosync(unsigned int irq)
spin_lock_irqsave(&irq_controller_lock, flags);
if (!irq_desc[irq].depth++) {
- irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].status |= IRQ_DISABLED | IRQ_MASKED;
irq_desc[irq].handler->disable(irq);
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
@@ -356,14 +364,15 @@ enable_irq(unsigned int irq)
switch (irq_desc[irq].depth) {
case 1:
{
- unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
- irq_desc[irq].status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- irq_desc[irq].status = status | IRQ_REPLAY;
+ unsigned int status = irq_desc[irq].status;
+ status &= ~(IRQ_DISABLED | IRQ_MASKED);
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ status |= IRQ_REPLAY;
/* ??? We can't re-send on (most?) alpha hw.
hw_resend_irq(irq_desc[irq].handler,irq); */
}
+ irq_desc[irq].status = status;
irq_desc[irq].handler->enable(irq);
/* fall-through */
}
@@ -425,7 +434,7 @@ setup_irq(unsigned int irq, struct irqaction * new)
if (!shared) {
irq_desc[irq].depth = 0;
- irq_desc[irq].status &= ~IRQ_DISABLED;
+ irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_MASKED);
irq_desc[irq].handler->startup(irq);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -500,7 +509,7 @@ free_irq(unsigned int irq, void *dev_id)
/* Found - now remove it from the list of entries. */
*pp = action->next;
if (!irq_desc[irq].action) {
- irq_desc[irq].status |= IRQ_DISABLED;
+ irq_desc[irq].status |= IRQ_DISABLED|IRQ_MASKED;
irq_desc[irq].handler->shutdown(irq);
}
spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -669,7 +678,7 @@ __global_cli(void)
* Maximize ipl. If ipl was previously 0 and if this thread
* is not in an irq, then take global_irq_lock.
*/
- if (swpipl(7) == 0 && !local_irq_count(cpu))
+ if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu))
get_irqlock(cpu, where);
}
@@ -841,13 +850,25 @@ handle_irq(int irq, struct pt_regs * regs)
desc = irq_desc + irq;
spin_lock_irq(&irq_controller_lock); /* mask also the RTC */
desc->handler->ack(irq);
+ status = desc->status;
+
+#ifndef CONFIG_SMP
+ /* Look for broken irq masking. */
+ if (status & IRQ_MASKED) {
+ static unsigned long last_printed;
+ if (time_after(jiffies, last_printed+HZ)) {
+ printk(KERN_CRIT "Mask didn't work for irq %d!\n", irq);
+ last_printed = jiffies;
+ }
+ }
+#endif
/*
* REPLAY is when Linux resends an IRQ that was dropped earlier.
* WAITING is used by probe to mark irqs that are being tested.
*/
- status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
- status |= IRQ_PENDING; /* we _want_ to handle it */
+ status &= ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING | IRQ_MASKED; /* we _want_ to handle it */
/*
* If the IRQ is disabled for whatever reason, we cannot
@@ -890,9 +911,12 @@ handle_irq(int irq, struct pt_regs * regs)
desc->status &= ~IRQ_PENDING;
spin_unlock(&irq_controller_lock);
}
- desc->status &= ~IRQ_INPROGRESS;
- if (!(desc->status & IRQ_DISABLED))
+ status = desc->status & ~IRQ_INPROGRESS;
+ if (!(status & IRQ_DISABLED)) {
+ status &= ~IRQ_MASKED;
desc->handler->end(irq);
+ }
+ desc->status = status;
spin_unlock(&irq_controller_lock);
}
@@ -1056,7 +1080,7 @@ do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
#ifdef CONFIG_SMP
cpu_data[smp_processor_id()].smp_local_irq_count++;
smp_percpu_timer_interrupt(&regs);
- if (smp_processor_id() == smp_boot_cpuid)
+ if (smp_processor_id() == boot_cpuid)
#endif
handle_irq(RTC_IRQ, &regs);
return;
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 72ce8bcb6..f5a9bd990 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -133,6 +133,9 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
unsigned long paddr;
dma_addr_t ret;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
paddr = virt_to_phys(cpu_addr);
/* First check to see if we can use the direct map window. */
@@ -186,12 +189,15 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
wrote there. */
void
-pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction)
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
+ int direction)
{
struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
struct pci_iommu_arena *arena;
long dma_ofs, npages;
+ if (direction == PCI_DMA_NONE)
+ BUG();
if (dma_addr >= __direct_map_base
&& dma_addr < __direct_map_base + __direct_map_size) {
@@ -247,7 +253,8 @@ pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
}
memset(cpu_addr, 0, size);
- *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL);
+ *dma_addrp = pci_map_single(pdev, cpu_addr, size,
+ PCI_DMA_BIDIRECTIONAL);
if (*dma_addrp == 0) {
free_pages((unsigned long)cpu_addr, order);
return NULL;
@@ -424,13 +431,17 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end,
}
int
-pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
{
struct scatterlist *start, *end, *out;
struct pci_controler *hose;
struct pci_iommu_arena *arena;
dma_addr_t max_dma;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg->dma_length = sg->length;
@@ -499,7 +510,8 @@ error:
above. */
void
-pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction)
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+ int direction)
{
struct pci_controler *hose;
struct pci_iommu_arena *arena;
@@ -507,6 +519,9 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct
dma_addr_t max_dma;
dma_addr_t fstart, fend;
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
if (! alpha_mv.mv_pci_tbi)
return;
@@ -555,3 +570,33 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direct
DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg));
}
+
+/* Return whether the given PCI device DMA address mask can be
+ supported properly. */
+
+int
+pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask)
+{
+ struct pci_controler *hose;
+ struct pci_iommu_arena *arena;
+
+ /* If there exists a direct map, and the mask fits either
+ MAX_DMA_ADDRESS defined such that GFP_DMA does something
+ useful, or the total system memory as shifted by the
+ map base. */
+ if (__direct_map_size != 0
+ && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask
+ || __direct_map_base + (max_low_pfn<<PAGE_SHIFT)-1 <= mask))
+ return 1;
+
+ /* Check that we have a scatter-gather arena that fits. */
+ hose = pdev ? pdev->sysdata : pci_isa_hose;
+ arena = hose->sg_isa;
+ if (arena && arena->dma_base + arena->size <= mask)
+ return 1;
+ arena = hose->sg_pci;
+ if (arena && arena->dma_base + arena->size <= mask)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 31a818209..2e462550f 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -90,55 +90,82 @@ cpu_idle(void)
}
}
+
+struct halt_info {
+ int mode;
+ char *restart_cmd;
+};
+
static void
-common_shutdown(int mode, char *restart_cmd)
+common_shutdown_1(void *generic_ptr)
{
- /* The following currently only has any effect on SRM. We should
- fix MILO to understand it. Should be pretty easy. Also we can
- support RESTART2 via the ipc_buffer machinations pictured below,
- which SRM ignores. */
+ struct halt_info *how = (struct halt_info *)generic_ptr;
+ struct percpu_struct *cpup;
+ unsigned long *pflags, flags;
+ int cpuid = smp_processor_id();
- if (alpha_using_srm) {
- struct percpu_struct *cpup;
- unsigned long flags;
-
- cpup = (struct percpu_struct *)
- ((unsigned long)hwrpb + hwrpb->processor_offset);
-
- flags = cpup->flags;
-
- /* Clear reason to "default"; clear "bootstrap in progress". */
- flags &= ~0x00ff0001UL;
-
- if (mode == LINUX_REBOOT_CMD_RESTART) {
- if (!restart_cmd) {
- flags |= 0x00020000UL; /* "cold bootstrap" */
- cpup->ipc_buffer[0] = 0;
- } else {
- flags |= 0x00030000UL; /* "warm bootstrap" */
- strncpy((char *)cpup->ipc_buffer, restart_cmd,
- sizeof(cpup->ipc_buffer));
- }
+ /* No point in taking interrupts anymore. */
+ __cli();
+
+ cpup = (struct percpu_struct *)
+ ((unsigned long)hwrpb + hwrpb->processor_offset
+ + hwrpb->processor_size * cpuid);
+ pflags = &cpup->flags;
+ flags = *pflags;
+
+ /* Clear reason to "default"; clear "bootstrap in progress". */
+ flags &= ~0x00ff0001UL;
+
+#ifdef __SMP__
+ /* Secondaries halt here. */
+ if (cpuid != boot_cpuid) {
+ flags |= 0x00040000UL; /* "remain halted" */
+ *pflags = flags;
+ clear_bit(cpuid, &cpu_present_mask);
+ halt();
+ }
+#endif
+
+ if (how->mode == LINUX_REBOOT_CMD_RESTART) {
+ if (!how->restart_cmd) {
+ flags |= 0x00020000UL; /* "cold bootstrap" */
} else {
- flags |= 0x00040000UL; /* "remain halted" */
+ /* For SRM, we could probably set environment
+ variables to get this to work. We'd have to
+ delay this until after srm_paging_stop unless
+ we ever got srm_fixup working.
+
+ At the moment, SRM will use the last boot device,
+ but the file and flags will be the defaults, when
+ doing a "warm" bootstrap. */
+ flags |= 0x00030000UL; /* "warm bootstrap" */
}
-
- cpup->flags = flags;
- mb();
+ } else {
+ flags |= 0x00040000UL; /* "remain halted" */
+ }
+ *pflags = flags;
- /* reset_for_srm(); */
- set_hae(srm_hae);
+#ifdef __SMP__
+ /* Wait for the secondaries to halt. */
+ clear_bit(boot_cpuid, &cpu_present_mask);
+ while (cpu_present_mask)
+ barrier();
+#endif
+ /* If booted from SRM, reset some of the original environment. */
+ if (alpha_using_srm) {
#ifdef CONFIG_DUMMY_CONSOLE
- /* This has the effect of reseting the VGA video origin. */
+ /* This has the effect of resetting the VGA video origin. */
take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1);
#endif
+ /* reset_for_srm(); */
+ set_hae(srm_hae);
}
if (alpha_mv.kill_arch)
- alpha_mv.kill_arch(mode);
+ alpha_mv.kill_arch(how->mode);
- if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) {
+ if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) {
/* Unfortunately, since MILO doesn't currently understand
the hwrpb bits above, we can't reliably halt the
processor and keep it halted. So just loop. */
@@ -151,6 +178,18 @@ common_shutdown(int mode, char *restart_cmd)
halt();
}
+static void
+common_shutdown(int mode, char *restart_cmd)
+{
+ struct halt_info args;
+ args.mode = mode;
+ args.restart_cmd = restart_cmd;
+#ifdef __SMP__
+ smp_call_function(common_shutdown_1, &args, 1, 0);
+#endif
+ common_shutdown_1(&args);
+}
+
void
machine_restart(char *restart_cmd)
{
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index dd63de4d2..a8859059b 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -74,13 +74,14 @@ extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
/* setup.c */
extern unsigned long srm_hae;
+extern int boot_cpuid;
/* smp.c */
extern void setup_smp(void);
extern int smp_info(char *buffer);
extern void handle_ipi(struct pt_regs *);
extern void smp_percpu_timer_interrupt(struct pt_regs *);
-extern int smp_boot_cpuid;
+extern unsigned long cpu_present_mask;
/* bios32.c */
/* extern void reset_for_srm(void); */
diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c
index d4793ecb4..dc5209531 100644
--- a/arch/alpha/kernel/semaphore.c
+++ b/arch/alpha/kernel/semaphore.c
@@ -173,7 +173,7 @@ __down_read(struct rw_semaphore *sem, int count)
" subl %0,1,%0\n"
" stl_c %2,%1\n"
" bne %2,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=r"(count), "=m"(sem->count), "=r"(tmp)
@@ -226,7 +226,7 @@ __down_write(struct rw_semaphore *sem, int count)
" ldah %0,%3(%0)\n"
" stl_c %2,%1\n"
" bne %2,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=r"(count), "=m"(sem->count), "=r"(tmp)
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 112976bcb..1311d939b 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -50,6 +50,9 @@
struct hwrpb_struct *hwrpb;
unsigned long srm_hae;
+/* Which processor we booted from. */
+int boot_cpuid;
+
#ifdef CONFIG_ALPHA_GENERIC
struct alpha_machine_vector alpha_mv;
int alpha_using_srm;
@@ -351,6 +354,7 @@ setup_arch(char **cmdline_p)
char *type_name, *var_name, *p;
hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
+ boot_cpuid = hard_smp_processor_id();
/*
* Locate the command line.
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index e3ae30973..be1a6440e 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -62,11 +62,13 @@ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
/* Set to a secondary's cpuid when it comes online. */
static unsigned long smp_secondary_alive;
-unsigned long cpu_present_mask; /* Which cpus ids came online. */
-static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */
+/* Which cpus ids came online. */
+unsigned long cpu_present_mask;
+
+/* cpus reported in the hwrpb */
+static unsigned long hwrpb_cpu_present_mask __initdata = 0;
static int max_cpus = -1; /* Command-line limitation. */
-int smp_boot_cpuid; /* Which processor we booted from. */
int smp_num_probed; /* Internal processor count */
int smp_num_cpus = 1; /* Number that came online. */
int smp_threads_ready; /* True once the per process idle is forked. */
@@ -486,10 +488,9 @@ setup_smp(void)
struct percpu_struct *cpubase, *cpu;
int i;
- smp_boot_cpuid = hard_smp_processor_id();
- if (smp_boot_cpuid != 0) {
+ if (boot_cpuid != 0) {
printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n",
- smp_boot_cpuid);
+ boot_cpuid);
}
if (hwrpb->nr_processors > 1) {
@@ -508,7 +509,7 @@ setup_smp(void)
if ((cpu->flags & 0x1cc) == 0x1cc) {
smp_num_probed++;
/* Assume here that "whami" == index */
- __cpu_present_mask |= (1L << i);
+ hwrpb_cpu_present_mask |= (1L << i);
cpu->pal_revision = boot_cpu_palrev;
}
@@ -519,12 +520,12 @@ setup_smp(void)
}
} else {
smp_num_probed = 1;
- __cpu_present_mask = (1L << smp_boot_cpuid);
+ hwrpb_cpu_present_mask = (1L << boot_cpuid);
}
- cpu_present_mask = 1L << smp_boot_cpuid;
+ cpu_present_mask = 1L << boot_cpuid;
printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n",
- smp_num_probed, __cpu_present_mask);
+ smp_num_probed, hwrpb_cpu_present_mask);
}
/*
@@ -541,13 +542,13 @@ smp_boot_cpus(void)
memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map));
memset(ipi_data, 0, sizeof(ipi_data));
- __cpu_number_map[smp_boot_cpuid] = 0;
- __cpu_logical_map[0] = smp_boot_cpuid;
- current->processor = smp_boot_cpuid;
+ __cpu_number_map[boot_cpuid] = 0;
+ __cpu_logical_map[0] = boot_cpuid;
+ current->processor = boot_cpuid;
- smp_store_cpu_info(smp_boot_cpuid);
+ smp_store_cpu_info(boot_cpuid);
smp_tune_scheduling();
- smp_setup_percpu_timer(smp_boot_cpuid);
+ smp_setup_percpu_timer(boot_cpuid);
init_idle();
@@ -565,10 +566,10 @@ smp_boot_cpus(void)
cpu_count = 1;
for (i = 0; i < NR_CPUS; i++) {
- if (i == smp_boot_cpuid)
+ if (i == boot_cpuid)
continue;
- if (((__cpu_present_mask >> i) & 1) == 0)
+ if (((hwrpb_cpu_present_mask >> i) & 1) == 0)
continue;
if (smp_boot_one_cpu(i, cpu_count))
@@ -1023,7 +1024,7 @@ debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
" stl_c %0,%1\n"
" beq %0,3f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: ldl %0,%1\n"
" subq %2,1,%2\n"
"3: blt %2,4b\n"
@@ -1097,7 +1098,7 @@ void write_lock(rwlock_t * lock)
" stl_c %1,%0\n"
" beq %1,6f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: blt %3,4b # debug\n"
" subl %3,1,%3 # debug\n"
" ldl %1,%0\n"
@@ -1140,7 +1141,7 @@ void read_lock(rwlock_t * lock)
" stl_c %1,%0;"
" beq %1,6f;"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: ldl %1,%0;"
" blt %2,4b # debug\n"
" subl %2,1,%2 # debug\n"
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 1432496d8..acea58d1e 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -126,6 +126,30 @@ cabriolet_init_irq(void)
setup_irq(16+4, &isa_cascade_irqaction);
}
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
+static void
+pc164_device_interrupt(unsigned long v, struct pt_regs *r)
+{
+ /* In theory, the PC164 has the same interrupt hardware as
+ the other Cabriolet based systems. However, something
+ got screwed up late in the development cycle which broke
+ the interrupt masking hardware. Repeat, it is not
+ possible to mask and ack interrupts. At all.
+
+ In an attempt to work around this, while processing
+ interrupts, we do not allow the IPL to drop below what
+ it is currently. This prevents the possibility of
+ recursion.
+
+ ??? Another option might be to force all PCI devices
+ to use edge triggered rather than level triggered
+ interrupts. That might be too invasive though. */
+
+ __min_ipl = getipl();
+ cabriolet_device_interrupt(v, r);
+ __min_ipl = 0;
+}
+#endif
/*
* The EB66+ is very similar to the EB66 except that it does not have
@@ -379,7 +403,7 @@ struct alpha_machine_vector pc164_mv __initmv = {
min_mem_address: CIA_DEFAULT_MEM_BASE,
nr_irqs: 35,
- device_interrupt: cabriolet_device_interrupt,
+ device_interrupt: pc164_device_interrupt,
init_arch: cia_init_arch,
init_irq: cabriolet_init_irq,
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index fbebdd5a5..7414b8cc2 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -33,94 +33,80 @@
#include "machvec_impl.h"
+/* Note mask bit is true for ENABLED irqs. */
static unsigned long cached_irq_mask;
-
-#define TSUNAMI_SET_IRQ_MASK(cpu, value) \
-do { \
- volatile unsigned long *csr; \
- csr = &TSUNAMI_cchip->dim##cpu##.csr; \
- *csr = (value); \
- mb(); \
- *csr; \
-} while(0)
-
-static inline void
-do_flush_irq_mask(unsigned long value)
-{
- switch (TSUNAMI_bootcpu) {
- case 0:
- TSUNAMI_SET_IRQ_MASK(0, value);
- break;
- case 1:
- TSUNAMI_SET_IRQ_MASK(1, value);
- break;
- case 2:
- TSUNAMI_SET_IRQ_MASK(2, value);
- break;
- case 3:
- TSUNAMI_SET_IRQ_MASK(3, value);
- break;
- }
-}
-
-#ifdef CONFIG_SMP
-static inline void
-do_flush_smp_irq_mask(unsigned long value)
-{
- extern unsigned long cpu_present_mask;
- unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu);
-
- if (other_cpus & 1)
- TSUNAMI_SET_IRQ_MASK(0, value);
- if (other_cpus & 2)
- TSUNAMI_SET_IRQ_MASK(1, value);
- if (other_cpus & 4)
- TSUNAMI_SET_IRQ_MASK(2, value);
- if (other_cpus & 8)
- TSUNAMI_SET_IRQ_MASK(3, value);
-}
-#endif
-
static void
-dp264_flush_irq_mask(unsigned long mask)
+tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable)
{
- unsigned long value;
+ register tsunami_cchip *cchip = TSUNAMI_cchip;
+ register int bcpu = boot_cpuid;
#ifdef CONFIG_SMP
- do_flush_smp_irq_mask(mask);
+ register unsigned long cpm = cpu_present_mask;
+ volatile unsigned long *dim0, *dim1, *dim2, *dim3;
+ unsigned long mask0, mask1, mask2, mask3, maskB, dummy;
+
+ mask0 = mask1 = mask2 = mask3 = mask;
+ maskB = mask | isa_enable;
+ if (bcpu == 0) mask0 = maskB;
+ if (bcpu == 1) mask1 = maskB;
+ if (bcpu == 2) mask2 = maskB;
+ if (bcpu == 3) mask3 = maskB;
+
+ dim0 = &cchip->dim0.csr;
+ dim1 = &cchip->dim1.csr;
+ dim2 = &cchip->dim2.csr;
+ dim3 = &cchip->dim3.csr;
+ if ((cpm & 1) == 0) dim0 = &dummy;
+ if ((cpm & 2) == 0) dim1 = &dummy;
+ if ((cpm & 4) == 0) dim2 = &dummy;
+ if ((cpm & 8) == 0) dim3 = &dummy;
+
+ *dim0 = mask0;
+ *dim1 = mask1;
+ *dim2 = mask2;
+ *dim3 = mask3;
+ mb();
+ *dim0;
+ *dim1;
+ *dim2;
+ *dim3;
+#else
+ volatile unsigned long *dimB = &cchip->dim1.csr;
+ if (bcpu == 0) dimB = &cchip->dim0.csr;
+ if (bcpu == 2) dimB = &cchip->dim2.csr;
+ if (bcpu == 3) dimB = &cchip->dim3.csr;
+ *dimB = mask | isa_enable;
+ mb();
+ *dimB;
#endif
-
- value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */
- do_flush_irq_mask(value);
}
-static void
-clipper_flush_irq_mask(unsigned long mask)
+static inline void
+dp264_update_irq_hw(unsigned long mask)
{
- unsigned long value;
-
- value = mask >> 16;
-#ifdef CONFIG_SMP
- do_flush_smp_irq_mask(value);
-#endif
+ tsunami_update_irq_hw(mask, (1UL << 55) | 0xffff);
+}
- value = value | (1UL << 55); /* master ISA enable */
- do_flush_irq_mask(value);
+static inline void
+clipper_update_irq_hw(unsigned long mask)
+{
+ tsunami_update_irq_hw(mask, 1UL << 55);
}
static inline void
dp264_enable_irq(unsigned int irq)
{
cached_irq_mask |= 1UL << irq;
- dp264_flush_irq_mask(cached_irq_mask);
+ dp264_update_irq_hw(cached_irq_mask);
}
static void
dp264_disable_irq(unsigned int irq)
{
cached_irq_mask &= ~(1UL << irq);
- dp264_flush_irq_mask(cached_irq_mask);
+ dp264_update_irq_hw(cached_irq_mask);
}
static unsigned int
@@ -134,14 +120,14 @@ static inline void
clipper_enable_irq(unsigned int irq)
{
cached_irq_mask |= 1UL << irq;
- clipper_flush_irq_mask(cached_irq_mask);
+ clipper_update_irq_hw(cached_irq_mask);
}
static void
clipper_disable_irq(unsigned int irq)
{
cached_irq_mask &= ~(1UL << irq);
- clipper_flush_irq_mask(cached_irq_mask);
+ clipper_update_irq_hw(cached_irq_mask);
}
static unsigned int
@@ -271,7 +257,7 @@ dp264_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = dp264_srm_device_interrupt;
- dp264_flush_irq_mask(0UL);
+ dp264_update_irq_hw(0UL);
init_i8259a_irqs();
init_rtc_irq();
@@ -289,7 +275,7 @@ clipper_init_irq(void)
if (alpha_using_srm)
alpha_mv.device_interrupt = clipper_srm_device_interrupt;
- clipper_flush_irq_mask(0UL);
+ clipper_update_irq_hw(0UL);
init_i8259a_irqs();
init_rtc_irq();
diff --git a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
index ccdcf3bdb..0230ec6d9 100644
--- a/arch/alpha/kernel/sys_sio.c
+++ b/arch/alpha/kernel/sys_sio.c
@@ -391,7 +391,7 @@ struct alpha_machine_vector xl_mv __initmv = {
nr_irqs: 16,
device_interrupt: isa_device_interrupt,
- init_arch: lca_init_arch,
+ init_arch: apecs_init_arch,
init_irq: sio_init_irq,
init_rtc: common_init_rtc,
init_pci: noname_init_pci,
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 8211045e8..d7b5cee8c 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -22,7 +22,6 @@
* fixed algorithm in do_gettimeofday() for calculating the precise time
* from processor cycle counter (now taking lost_ticks into account)
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 36b0cc43a..828044b24 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -215,8 +215,10 @@ do_entIF(unsigned long type, unsigned long a1,
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
- if (alpha_fp_emul(regs.pc - 4))
+ if (alpha_fp_emul(regs.pc)) {
+ regs.pc += 4;
return;
+ }
}
send_sig(SIGILL, current, 1);
break;
diff --git a/arch/alpha/vmlinux.lds b/arch/alpha/vmlinux.lds
index 4b49a5369..4eaac4e42 100644
--- a/arch/alpha/vmlinux.lds
+++ b/arch/alpha/vmlinux.lds
@@ -5,7 +5,6 @@ SECTIONS
. = 0xfffffc0000310000;
_text = .;
.text : { *(.text) }
- .text2 : { *(.text2) }
_etext = .;
/* Exception table */
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 63d4631a4..c445daeee 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -165,7 +165,6 @@ EXPORT_SYMBOL_NOVERS(strncmp);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strlen);
EXPORT_SYMBOL_NOVERS(strnlen);
-EXPORT_SYMBOL_NOVERS(strspn);
EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strrchr);
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 8673d6c1d..7101b2936 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -23,7 +23,6 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
{
int order;
unsigned long page;
- struct vm_struct *area;
void *ret;
if (in_interrupt())
@@ -40,15 +39,10 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
*dma_handle = virt_to_bus((void *)page);
- area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */
- if (!area)
- goto no_area;
-
ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0);
if (ret)
return ret;
-no_area:
free_pages(page, order);
no_page:
BUG();
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 4ca545255..34b453c2c 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -109,10 +109,12 @@ CONFIG_BLK_DEV_CMD640=y
# CONFIG_BLK_DEV_ISAPNP is not set
CONFIG_BLK_DEV_RZ1000=y
CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
# CONFIG_BLK_DEV_IDEDMA_PCI is not set
# CONFIG_BLK_DEV_OFFBOARD is not set
# CONFIG_BLK_DEV_AEC6210 is not set
# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_CPQ_DA is not set
@@ -393,6 +395,7 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
#
# Video For Linux
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index 9bdd111d1..6228805db 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -34,6 +34,7 @@
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -379,13 +380,14 @@ static struct acpi_table *__init acpi_map_table(u32 addr)
ioremap((unsigned long) addr, table_size);
}
- if (!table) {
- /* ioremap is a pain, it returns NULL if the
- * table starts within mapped physical memory.
- * Hopefully, no table straddles a mapped/unmapped
- * physical memory boundary, ugh
+ if (!table && addr < virt_to_phys(high_memory)) {
+ /* sometimes we see ACPI tables in low memory
+ * and not reserved by the memory map (E820) code,
+ * who is at fault for this? BIOS?
*/
- table = (struct acpi_table*) phys_to_virt(addr);
+ printk(KERN_ERR
+ "ACPI: unreserved table memory @ 0x%p!\n",
+ (void*) addr);
}
}
return table;
@@ -933,9 +935,9 @@ static int acpi_enter_dx(acpi_dstate_t state)
int status = 0;
if (state == ACPI_D0)
- status = pm_send_request(PM_RESUME, (void*) state);
+ status = pm_send_all(PM_RESUME, (void*) state);
else
- status = pm_send_request(PM_SUSPEND, (void*) state);
+ status = pm_send_all(PM_SUSPEND, (void*) state);
return status;
}
@@ -1333,10 +1335,7 @@ static int __init acpi_init(void)
if (acpi_claim_ioports(acpi_facp)) {
printk(KERN_ERR "ACPI: I/O port allocation failed\n");
- if (pci_driver_registered)
- pci_unregister_driver(&acpi_driver);
- acpi_destroy_tables();
- return -ENODEV;
+ goto err_out;
}
if (acpi_facp->sci_int
@@ -1347,12 +1346,7 @@ static int __init acpi_init(void)
acpi_facp)) {
printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n",
acpi_facp->sci_int);
-
- if (pci_driver_registered)
- pci_unregister_driver(&acpi_driver);
- acpi_destroy_tables();
-
- return -ENODEV;
+ goto err_out;
}
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
@@ -1379,6 +1373,13 @@ static int __init acpi_init(void)
pm_idle = acpi_idle;
return 0;
+
+err_out:
+ if (pci_driver_registered)
+ pci_unregister_driver(&acpi_driver);
+ acpi_destroy_tables();
+
+ return -ENODEV;
}
/*
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 4ec5e7993..3d403b93c 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -333,7 +333,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
static struct apm_user * user_list = NULL;
-static char driver_version[] = "1.12"; /* no spaces */
+static char driver_version[] = "1.13"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
@@ -590,7 +590,11 @@ static void apm_cpu_idle(void)
continue;
if (hlt_counter)
continue;
- asm volatile("sti ; hlt" : : : "memory");
+ asm volatile("cli" : : : "memory");
+ if (!current->need_resched)
+ asm volatile("sti ; hlt" : : : "memory");
+ else
+ asm volatile("sti" : : : "memory");
continue;
}
@@ -635,7 +639,7 @@ static void apm_power_off(void)
*/
#ifdef CONFIG_SMP
/* Some bioses don't like being called from CPU != 0 */
- while (cpu_number_map[smp_processor_id()] != 0) {
+ while (cpu_number_map(smp_processor_id()) != 0) {
kernel_thread(apm_magic, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
schedule();
@@ -916,7 +920,7 @@ static int send_event(apm_event_t event, struct apm_user *sender)
case APM_CRITICAL_SUSPEND:
case APM_USER_SUSPEND:
/* map all suspends to ACPI D3 */
- if (pm_send_request(PM_SUSPEND, (void *)3)) {
+ if (pm_send_all(PM_SUSPEND, (void *)3)) {
if (apm_bios_info.version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
return 0;
@@ -925,7 +929,7 @@ static int send_event(apm_event_t event, struct apm_user *sender)
case APM_NORMAL_RESUME:
case APM_CRITICAL_RESUME:
/* map all resumes to ACPI D0 */
- (void) pm_send_request(PM_RESUME, (void *)0);
+ (void) pm_send_all(PM_RESUME, (void *)0);
break;
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index bcca244c1..0c3cae5d9 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -181,6 +181,8 @@ ret_from_fork:
call SYMBOL_NAME(schedule_tail)
addl $4, %esp
GET_CURRENT(%ebx)
+ testb $0x20,flags(%ebx) # PF_TRACESYS
+ jne tracesys_exit
jmp ret_from_sys_call
/*
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index cad6ceb17..a3389c5f0 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -144,6 +144,4 @@ EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(get_wchan);
-
-EXPORT_SYMBOL(local_bh_count);
-EXPORT_SYMBOL(local_irq_count);
+EXPORT_SYMBOL(irq_stat);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index d54f9b503..ec33f2269 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -127,11 +127,14 @@ void (*interrupt[NR_IRQS])(void) = {
* moves to arch independent land
*/
-void enable_8259A_irq(unsigned int irq);
-void disable_8259A_irq(unsigned int irq);
+static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
+
+static void end_8259A_irq (unsigned int irq)
+{
+ if (!(irq_desc[irq].status & IRQ_DISABLED))
+ enable_8259A_irq(irq);
+}
-/* shutdown is same as "disable" */
-#define end_8259A_irq enable_8259A_irq
#define shutdown_8259A_irq disable_8259A_irq
void mask_and_ack_8259A(unsigned int);
@@ -149,7 +152,8 @@ static struct hw_interrupt_type i8259A_irq_type = {
enable_8259A_irq,
disable_8259A_irq,
mask_and_ack_8259A,
- end_8259A_irq
+ end_8259A_irq,
+ NULL
};
/*
@@ -183,30 +187,45 @@ unsigned long io_apic_irqs = 0;
void disable_8259A_irq(unsigned int irq)
{
unsigned int mask = 1 << irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask |= mask;
if (irq & 8)
outb(cached_A1,0xA1);
else
outb(cached_21,0x21);
+ spin_unlock_irqrestore(&i8259A_lock, flags);
}
void enable_8259A_irq(unsigned int irq)
{
unsigned int mask = ~(1 << irq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask &= mask;
if (irq & 8)
outb(cached_A1,0xA1);
else
outb(cached_21,0x21);
+ spin_unlock_irqrestore(&i8259A_lock, flags);
}
int i8259A_irq_pending(unsigned int irq)
{
unsigned int mask = 1<<irq;
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&i8259A_lock, flags);
if (irq < 8)
- return (inb(0x20) & mask);
- return (inb(0xA0) & (mask >> 8));
+ ret = inb(0x20) & mask;
+ else
+ ret = inb(0xA0) & (mask >> 8);
+ spin_unlock_irqrestore(&i8259A_lock, flags);
+
+ return ret;
}
void make_8259A_irq(unsigned int irq)
@@ -247,7 +266,9 @@ static inline int i8259A_irq_real(unsigned int irq)
void mask_and_ack_8259A(unsigned int irq)
{
unsigned int irqmask = 1 << irq;
+ unsigned long flags;
+ spin_lock_irqsave(&i8259A_lock, flags);
/*
* Lightweight spurious IRQ detection. We do not want
* to overdo spurious IRQ handling - it's usually a sign
@@ -278,6 +299,7 @@ handle_real_irq:
outb(cached_21,0x21);
outb(0x20,0x20); /* 'generic EOI' to master */
}
+ spin_unlock_irqrestore(&i8259A_lock, flags);
return;
spurious_8259A_irq:
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 75b2bfb9f..129a587f0 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -28,6 +28,8 @@
#include <asm/smp.h>
#include <asm/desc.h>
+static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
+
/*
* # of IO-APICs and # of IRQ routing registers
*/
@@ -87,9 +89,8 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry->pin = pin;
}
-#define DO_ACTION(name,R,ACTION, FINAL) \
+#define __DO_ACTION(name,R,ACTION, FINAL) \
\
-static void name##_IO_APIC_irq(unsigned int irq) \
{ \
int pin; \
struct irq_pin_list *entry = irq_2_pin + irq; \
@@ -109,8 +110,31 @@ static void name##_IO_APIC_irq(unsigned int irq) \
FINAL; \
}
-DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
-DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */
+#define DO_ACTION(name,R,ACTION, FINAL) \
+ \
+static void name##_IO_APIC_irq(unsigned int irq) \
+__DO_ACTION(name,R,ACTION, FINAL)
+
+DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
+DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */
+
+static void mask_IO_APIC_irq (unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __mask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void unmask_IO_APIC_irq (unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __unmask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{
@@ -537,7 +561,7 @@ void __init setup_IO_APIC_irqs(void)
entry.delivery_mode = dest_LowestPrio;
entry.dest_mode = 1; /* logical delivery */
entry.mask = 0; /* enable IRQ */
- entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */
+ entry.dest.logical.logical_dest = APIC_ALL_CPUS;
idx = find_irq_entry(apic,pin,mp_INT);
if (idx == -1) {
@@ -1026,16 +1050,16 @@ extern atomic_t nmi_counter[NR_CPUS];
static int __init nmi_irq_works(void)
{
- atomic_t tmp[NR_CPUS];
+ irq_cpustat_t tmp[NR_CPUS];
int j, cpu;
- memcpy(tmp, nmi_counter, sizeof(tmp));
+ memcpy(tmp, irq_stat, sizeof(tmp));
sti();
mdelay(50);
for (j = 0; j < smp_num_cpus; j++) {
cpu = cpu_logical_map(j);
- if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) {
+ if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) {
printk("CPU#%d NMI appears to be stuck.\n", cpu);
return 0;
}
@@ -1055,14 +1079,9 @@ static int __init nmi_irq_works(void)
* that was delayed but this is now handled in the device
* independent code.
*/
-static void enable_edge_ioapic_irq(unsigned int irq)
-{
- unmask_IO_APIC_irq(irq);
-}
+#define enable_edge_ioapic_irq unmask_IO_APIC_irq
-static void disable_edge_ioapic_irq(unsigned int irq)
-{
-}
+static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ }
/*
* Starting up a edge-triggered IO-APIC interrupt is
@@ -1077,12 +1096,17 @@ static void disable_edge_ioapic_irq(unsigned int irq)
static unsigned int startup_edge_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
if (irq < 16) {
disable_8259A_irq(irq);
if (i8259A_irq_pending(irq))
was_pending = 1;
}
- enable_edge_ioapic_irq(irq);
+ __unmask_IO_APIC_irq(irq);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
return was_pending;
}
@@ -1093,14 +1117,15 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
* interrupt for real. This prevents IRQ storms from unhandled
* devices.
*/
-void static ack_edge_ioapic_irq(unsigned int irq)
+static void ack_edge_ioapic_irq(unsigned int irq)
{
if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
== (IRQ_PENDING | IRQ_DISABLED))
mask_IO_APIC_irq(irq);
ack_APIC_irq();
}
-void static end_edge_ioapic_irq(unsigned int i){}
+
+static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ }
/*
@@ -1108,23 +1133,46 @@ void static end_edge_ioapic_irq(unsigned int i){}
* and shutting down and starting up the interrupt
* is the same as enabling and disabling them -- except
* with a startup need to return a "was pending" value.
+ *
+ * Level triggered interrupts are special because we
+ * do not touch any IO-APIC register while handling
+ * them. We ack the APIC in the end-IRQ handler, not
+ * in the start-IRQ-handler. Protection against reentrance
+ * from the same interrupt is still provided, both by the
+ * generic IRQ layer and by the fact that an unacked local
+ * APIC does not accept IRQs.
*/
-static unsigned int startup_level_ioapic_irq(unsigned int irq)
+static unsigned int startup_level_ioapic_irq (unsigned int irq)
{
unmask_IO_APIC_irq(irq);
+
return 0; /* don't check for pending */
}
#define shutdown_level_ioapic_irq mask_IO_APIC_irq
#define enable_level_ioapic_irq unmask_IO_APIC_irq
#define disable_level_ioapic_irq mask_IO_APIC_irq
-#define end_level_ioapic_irq unmask_IO_APIC_irq
-void static mask_and_ack_level_ioapic_irq(unsigned int i)
+
+static void end_level_ioapic_irq (unsigned int i)
{
- mask_IO_APIC_irq(i);
ack_APIC_irq();
}
+static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ }
+
+static void set_ioapic_affinity (unsigned int irq, unsigned int mask)
+{
+ unsigned long flags;
+ /*
+ * Only the first 8 bits are valid.
+ */
+ mask = mask << 24;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ __DO_ACTION( target, 1, = mask, )
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
/*
* Level and edge triggered IO-APIC interrupts need different handling,
* so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -1141,7 +1189,8 @@ static struct hw_interrupt_type ioapic_edge_irq_type = {
enable_edge_ioapic_irq,
disable_edge_ioapic_irq,
ack_edge_ioapic_irq,
- end_edge_ioapic_irq
+ end_edge_ioapic_irq,
+ set_ioapic_affinity,
};
static struct hw_interrupt_type ioapic_level_irq_type = {
@@ -1151,7 +1200,8 @@ static struct hw_interrupt_type ioapic_level_irq_type = {
enable_level_ioapic_irq,
disable_level_ioapic_irq,
mask_and_ack_level_ioapic_irq,
- end_level_ioapic_irq
+ end_level_ioapic_irq,
+ set_ioapic_affinity,
};
static inline void init_IO_APIC_traps(void)
@@ -1185,12 +1235,12 @@ static inline void init_IO_APIC_traps(void)
}
}
-void static ack_lapic_irq (unsigned int irq)
+static void ack_lapic_irq (unsigned int irq)
{
ack_APIC_irq();
}
-void static end_lapic_irq (unsigned int i) { /* nothing */ }
+static void end_lapic_irq (unsigned int i) { /* nothing */ }
static struct hw_interrupt_type lapic_irq_type = {
"local-APIC-edge",
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 9d4a81041..7054249e6 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -31,21 +31,20 @@
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/system.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/delay.h>
#include <asm/desc.h>
#include <asm/irq.h>
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-
-extern atomic_t nmi_counter[NR_CPUS];
/*
* Linux has a controller-independent x86 interrupt architecture.
@@ -63,17 +62,15 @@ extern atomic_t nmi_counter[NR_CPUS];
* interrupt controllers, without having to do assembly magic.
*/
-/*
- * Micro-access to controllers is serialized over the whole
- * system. We never hold this lock when we call the actual
- * IRQ handler.
- */
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
+irq_cpustat_t irq_stat [NR_CPUS];
+
/*
* Controller mappings for all interrupt sources:
*/
irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
- { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }};
+ { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
+
+static void register_irq_proc (unsigned int irq);
/*
* Special irq handlers.
@@ -164,7 +161,7 @@ int get_irq_list(char *buf)
p += sprintf(p, "NMI: ");
for (j = 0; j < smp_num_cpus; j++)
p += sprintf(p, "%10u ",
- atomic_read(nmi_counter+cpu_logical_map(j)));
+ atomic_read(&nmi_counter(cpu_logical_map(j))));
p += sprintf(p, "\n");
#if CONFIG_SMP
p += sprintf(p, "LOC: ");
@@ -186,7 +183,6 @@ int get_irq_list(char *buf)
#ifdef CONFIG_SMP
unsigned char global_irq_holder = NO_PROC_ID;
unsigned volatile int global_irq_lock;
-atomic_t global_irq_count;
static void show(char * str)
{
@@ -196,9 +192,9 @@ static void show(char * str)
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d %d]\n",
- atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+ irqs_running(), local_irq_count(0), local_irq_count(1));
printk("bh: %d [%d %d]\n",
- spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count[0], local_bh_count[1]);
+ spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count(0), local_bh_count(1));
stack = (unsigned long *) &stack;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
@@ -248,10 +244,9 @@ static inline void wait_on_irq(int cpu)
* for bottom half handlers unless we're
* already executing in one..
*/
- if (!atomic_read(&global_irq_count)) {
- if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock))
+ if (!irqs_running())
+ if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
break;
- }
/* Duh, we have to loop. Release the lock to avoid deadlocks */
clear_bit(0,&global_irq_lock);
@@ -264,11 +259,11 @@ static inline void wait_on_irq(int cpu)
__sti();
SYNC_OTHER_CORES(cpu);
__cli();
- if (atomic_read(&global_irq_count))
+ if (irqs_running())
continue;
if (global_irq_lock)
continue;
- if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock))
+ if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
continue;
if (!test_and_set_bit(0,&global_irq_lock))
break;
@@ -285,7 +280,7 @@ static inline void wait_on_irq(int cpu)
*/
void synchronize_irq(void)
{
- if (atomic_read(&global_irq_count)) {
+ if (irqs_running()) {
/* Stupid approach */
cli();
sti();
@@ -338,7 +333,7 @@ void __global_cli(void)
if (flags & (1 << EFLAGS_IF_SHIFT)) {
int cpu = smp_processor_id();
__cli();
- if (!local_irq_count[cpu])
+ if (!local_irq_count(cpu))
get_irqlock(cpu);
}
}
@@ -347,7 +342,7 @@ void __global_sti(void)
{
int cpu = smp_processor_id();
- if (!local_irq_count[cpu])
+ if (!local_irq_count(cpu))
release_irqlock(cpu);
__sti();
}
@@ -364,6 +359,7 @@ unsigned long __global_save_flags(void)
int retval;
int local_enabled;
unsigned long flags;
+ int cpu = smp_processor_id();
__save_flags(flags);
local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
@@ -371,10 +367,10 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
- if (!local_irq_count[smp_processor_id()]) {
+ if (!local_irq_count(cpu)) {
if (local_enabled)
retval = 1;
- if (global_irq_holder == (unsigned char) smp_processor_id())
+ if (global_irq_holder == cpu)
retval = 0;
}
return retval;
@@ -442,16 +438,17 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction *
* hardware disable after having gotten the irq
* controller lock.
*/
-void disable_irq_nosync(unsigned int irq)
+void inline disable_irq_nosync(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- spin_lock_irqsave(&irq_controller_lock, flags);
- if (!irq_desc[irq].depth++) {
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->disable(irq);
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
@@ -462,7 +459,7 @@ void disable_irq(unsigned int irq)
{
disable_irq_nosync(irq);
- if (!local_irq_count[smp_processor_id()]) {
+ if (!local_irq_count(smp_processor_id())) {
do {
barrier();
} while (irq_desc[irq].status & IRQ_INPROGRESS);
@@ -471,28 +468,29 @@ void disable_irq(unsigned int irq)
void enable_irq(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- spin_lock_irqsave(&irq_controller_lock, flags);
- switch (irq_desc[irq].depth) {
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
case 1: {
- unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
- irq_desc[irq].status = status;
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- irq_desc[irq].status = status | IRQ_REPLAY;
- hw_resend_irq(irq_desc[irq].handler,irq);
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
}
- irq_desc[irq].handler->enable(irq);
+ desc->handler->enable(irq);
/* fall-through */
}
default:
- irq_desc[irq].depth--;
+ desc->depth--;
break;
case 0:
printk("enable_irq() unbalanced from %p\n",
__builtin_return_address(0));
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
@@ -514,13 +512,12 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs)
*/
int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */
int cpu = smp_processor_id();
- irq_desc_t *desc;
+ irq_desc_t *desc = irq_desc + irq;
struct irqaction * action;
unsigned int status;
kstat.irqs[cpu][irq]++;
- desc = irq_desc + irq;
- spin_lock(&irq_controller_lock);
+ spin_lock(&desc->lock);
desc->handler->ack(irq);
/*
REPLAY is when Linux resends an IRQ that was dropped earlier
@@ -540,7 +537,6 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs)
status |= IRQ_INPROGRESS; /* we are handling it */
}
desc->status = status;
- spin_unlock(&irq_controller_lock);
/*
* If there is no IRQ handler or it was disabled, exit early.
@@ -549,7 +545,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs)
will take care of it.
*/
if (!action)
- return 1;
+ goto out;
/*
* Edge triggered interrupts need to remember
@@ -562,20 +558,24 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs)
* SMP environment.
*/
for (;;) {
+ spin_unlock(&desc->lock);
handle_IRQ_event(irq, &regs, action);
- spin_lock(&irq_controller_lock);
+ spin_lock(&desc->lock);
if (!(desc->status & IRQ_PENDING))
break;
desc->status &= ~IRQ_PENDING;
- spin_unlock(&irq_controller_lock);
}
desc->status &= ~IRQ_INPROGRESS;
- if (!(desc->status & IRQ_DISABLED))
- desc->handler->end(irq);
- spin_unlock(&irq_controller_lock);
+out:
+ /*
+ * The ->end() handler has to deal with interrupts which got
+ * disabled while the handler was running.
+ */
+ desc->handler->end(irq);
+ spin_unlock(&desc->lock);
- if (softirq_state[cpu].active&softirq_state[cpu].mask)
+ if (softirq_state[cpu].active & softirq_state[cpu].mask)
do_softirq();
return 1;
}
@@ -627,14 +627,16 @@ int request_irq(unsigned int irq,
void free_irq(unsigned int irq, void *dev_id)
{
+ irq_desc_t *desc;
struct irqaction **p;
unsigned long flags;
if (irq >= NR_IRQS)
return;
- spin_lock_irqsave(&irq_controller_lock,flags);
- p = &irq_desc[irq].action;
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
for (;;) {
struct irqaction * action = *p;
if (action) {
@@ -645,22 +647,22 @@ void free_irq(unsigned int irq, void *dev_id)
/* Found it - now remove it from the list of entries */
*pp = action->next;
- if (!irq_desc[irq].action) {
- irq_desc[irq].status |= IRQ_DISABLED;
- irq_desc[irq].handler->shutdown(irq);
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->shutdown(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
#ifdef CONFIG_SMP
/* Wait to make sure it's not being used on another CPU */
- while (irq_desc[irq].status & IRQ_INPROGRESS)
+ while (desc->status & IRQ_INPROGRESS)
barrier();
#endif
kfree(action);
return;
}
printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
return;
}
}
@@ -676,21 +678,43 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long probe_irq_on(void)
{
unsigned int i;
- unsigned long delay;
+ irq_desc_t *desc;
unsigned long val;
+ unsigned long delay;
+
+ /*
+ * something may have generated an irq long ago and we want to
+ * flush such a longstanding irq before considering it as spurious.
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!irq_desc[i].action)
+ irq_desc[i].handler->startup(i);
+ spin_unlock_irq(&desc->lock);
+ }
+
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ synchronize_irq();
/*
- * first, enable any unassigned irqs
+ * enable any unassigned irqs
+ * (we must startup again here because if a longstanding irq
+ * happened in the previous stage, it may have masked itself)
*/
- spin_lock_irq(&irq_controller_lock);
for (i = NR_IRQS-1; i > 0; i--) {
- if (!irq_desc[i].action) {
- irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
- if(irq_desc[i].handler->startup(i))
- irq_desc[i].status |= IRQ_PENDING;
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action) {
+ desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if (desc->handler->startup(i))
+ desc->status |= IRQ_PENDING;
}
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
/*
* Wait for spurious interrupts to trigger
@@ -702,24 +726,24 @@ unsigned long probe_irq_on(void)
* Now filter out any obviously spurious interrupts
*/
val = 0;
- spin_lock_irq(&irq_controller_lock);
- for (i=0; i<NR_IRQS; i++) {
- unsigned int status = irq_desc[i].status;
-
- if (!(status & IRQ_AUTODETECT))
- continue;
-
- /* It triggered already - consider it spurious. */
- if (!(status & IRQ_WAITING)) {
- irq_desc[i].status = status & ~IRQ_AUTODETECT;
- irq_desc[i].handler->shutdown(i);
- continue;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ } else
+ if (i < 32)
+ val |= 1 << i;
}
-
- if (i < 32)
- val |= 1 << i;
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
return val;
}
@@ -734,20 +758,22 @@ unsigned int probe_irq_mask(unsigned long val)
unsigned int mask;
mask = 0;
- spin_lock_irq(&irq_controller_lock);
for (i = 0; i < 16; i++) {
- unsigned int status = irq_desc[i].status;
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
- if (!(status & IRQ_AUTODETECT))
- continue;
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
- if (!(status & IRQ_WAITING))
- mask |= 1 << i;
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING))
+ mask |= 1 << i;
- irq_desc[i].status = status & ~IRQ_AUTODETECT;
- irq_desc[i].handler->shutdown(i);
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
return mask & val;
}
@@ -762,22 +788,24 @@ int probe_irq_off(unsigned long val)
nr_irqs = 0;
irq_found = 0;
- spin_lock_irq(&irq_controller_lock);
- for (i=0; i<NR_IRQS; i++) {
- unsigned int status = irq_desc[i].status;
-
- if (!(status & IRQ_AUTODETECT))
- continue;
-
- if (!(status & IRQ_WAITING)) {
- if (!nr_irqs)
- irq_found = i;
- nr_irqs++;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
}
- irq_desc[i].status = status & ~IRQ_AUTODETECT;
- irq_desc[i].handler->shutdown(i);
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
if (nr_irqs > 1)
irq_found = -irq_found;
@@ -788,8 +816,9 @@ int probe_irq_off(unsigned long val)
int setup_irq(unsigned int irq, struct irqaction * new)
{
int shared = 0;
- struct irqaction *old, **p;
unsigned long flags;
+ struct irqaction *old, **p;
+ irq_desc_t *desc = irq_desc + irq;
/*
* Some drivers like serial.c use request_irq() heavily,
@@ -811,12 +840,12 @@ int setup_irq(unsigned int irq, struct irqaction * new)
/*
* The following block of code has to be executed atomically
*/
- spin_lock_irqsave(&irq_controller_lock,flags);
- p = &irq_desc[irq].action;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
return -EBUSY;
}
@@ -831,11 +860,171 @@ int setup_irq(unsigned int irq, struct irqaction * new)
*p = new;
if (!shared) {
- irq_desc[irq].depth = 0;
- irq_desc[irq].status &= ~IRQ_DISABLED;
- irq_desc[irq].handler->startup(irq);
+ desc->depth = 0;
+ desc->status &= ~IRQ_DISABLED;
+ desc->handler->startup(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock,flags);
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ register_irq_proc(irq);
return 0;
}
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff};
+
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08x\n", irq_affinity[(int)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+ unsigned long count, unsigned long *ret)
+{
+ unsigned char hexnum [HEX_DIGITS];
+ unsigned long value;
+ int i;
+
+ if (!count)
+ return -EINVAL;
+ if (count > HEX_DIGITS)
+ count = HEX_DIGITS;
+ if (copy_from_user(hexnum, buffer, count))
+ return -EFAULT;
+
+ /*
+ * Parse the first 8 characters as a hex string, any non-hex char
+ * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+ */
+ value = 0;
+
+ for (i = 0; i < count; i++) {
+ unsigned int c = hexnum[i];
+
+ switch (c) {
+ case '0' ... '9': c -= '0'; break;
+ case 'a' ... 'f': c -= 'a'-10; break;
+ case 'A' ... 'F': c -= 'A'-10; break;
+ default:
+ goto out;
+ }
+ value = (value << 4) | c;
+ }
+out:
+ *ret = value;
+ return 0;
+}
+
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (int) data, full_count = count, err;
+ unsigned long new_value;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
+ */
+ if (!(new_value & cpu_online_map))
+ return -EINVAL;
+#endif
+
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq, new_value);
+
+ return full_count;
+}
+
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long *mask = (unsigned long *) data;
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08lx\n", *mask);
+}
+
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ unsigned long *mask = (unsigned long *) data, full_count = count, err;
+ unsigned long new_value;
+
+ err = parse_hex_value(buffer, count, &new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
+}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+ struct proc_dir_entry *entry;
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type))
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+
+ entry->nlink = 1;
+ entry->data = (void *)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+
+ smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", 0);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++) {
+ if (irq_desc[i].handler == &no_irq_type)
+ continue;
+ register_irq_proc(i);
+ }
+}
+
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 26b6525d8..84490b40b 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -20,6 +20,9 @@
* Initial release.
* 1.01 18 February 2000, Tigran Aivazian <tigran@sco.com>
* Added read() support + cleanups.
+ * 1.02 21 February 2000, Tigran Aivazian <tigran@sco.com>
+ * Added 'device trimming' support. open(O_WRONLY) zeroes
+ * and frees the saved copy of applied microcode.
*/
#include <linux/init.h>
@@ -33,7 +36,7 @@
#include <asm/uaccess.h>
#include <asm/processor.h>
-#define MICROCODE_VERSION "1.01"
+#define MICROCODE_VERSION "1.02"
MODULE_DESCRIPTION("CPU (P6) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
@@ -53,7 +56,7 @@ static void do_update_one(void *);
/*
* Bits in microcode_status. (31 bits of room for future expansion)
*/
-#define MICROCODE_IS_OPEN 0 /* set if /dev/microcode is in use */
+#define MICROCODE_IS_OPEN 0 /* set if device is in use */
static unsigned long microcode_status = 0;
/* the actual array of microcode blocks, each 2048 bytes */
@@ -68,31 +71,16 @@ static struct file_operations microcode_fops = {
release: microcode_release,
};
-static struct inode_operations microcode_inops = {
- default_file_ops: &microcode_fops,
-};
-
static struct proc_dir_entry *proc_microcode;
static int __init microcode_init(void)
{
- int size;
-
proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver);
if (!proc_microcode) {
printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n");
return -ENOMEM;
}
- proc_microcode->ops = &microcode_inops;
- size = smp_num_cpus * sizeof(struct microcode);
- mc_applied = kmalloc(size, GFP_KERNEL);
- if (!mc_applied) {
- remove_proc_entry("microcode", proc_root_driver);
- printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
- return -ENOMEM;
- }
- memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed
- update makes this obvious */
+ proc_microcode->proc_fops = &microcode_fops;
printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
return 0;
}
@@ -100,7 +88,8 @@ static int __init microcode_init(void)
static void __exit microcode_exit(void)
{
remove_proc_entry("microcode", proc_root_driver);
- kfree(mc_applied);
+ if (mc_applied)
+ kfree(mc_applied);
printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
}
@@ -119,6 +108,15 @@ static int microcode_open(struct inode *inode, struct file *file)
if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
return -EBUSY;
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ proc_microcode->size = 0;
+ if (mc_applied) {
+ memset(mc_applied, 0, smp_num_cpus * sizeof(struct microcode));
+ kfree(mc_applied);
+ mc_applied = NULL;
+ }
+ }
+
MOD_INC_USE_COUNT;
return 0;
@@ -243,6 +241,16 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l
sizeof(struct microcode));
return -EINVAL;
}
+ if (!mc_applied) {
+ int size = smp_num_cpus * sizeof(struct microcode);
+ mc_applied = kmalloc(size, GFP_KERNEL);
+ if (!mc_applied) {
+ printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
+ return -ENOMEM;
+ }
+ memset(mc_applied, 0, size);
+ }
+
lock_kernel();
microcode_num = len/sizeof(struct microcode);
microcode = vmalloc(len);
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 81685d2f5..030b31647 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -316,11 +316,14 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
return num_processors;
}
+static struct intel_mp_floating *mpf_found;
+
/*
* Scan the memory blocks for an SMP configuration block.
*/
-static int __init smp_get_mpf(struct intel_mp_floating *mpf)
+void __init get_smp_config (void)
{
+ struct intel_mp_floating *mpf = mpf_found;
printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
if (mpf->mpf_feature2 & (1<<7)) {
printk(" IMCR and PIC compatibility mode.\n");
@@ -329,7 +332,6 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf)
printk(" Virtual Wire compatibility mode.\n");
pic_mode = 0;
}
- smp_found_config = 1;
/*
* default CPU id - if it's different in the mptable
* then we change it before first using it.
@@ -388,7 +390,7 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf)
default:
printk("???\nUnknown standard configuration %d\n",
mpf->mpf_feature1);
- return 1;
+ return;
}
if (mpf->mpf_feature1 > 4) {
printk("Bus #1 is PCI\n");
@@ -412,10 +414,9 @@ static int __init smp_get_mpf(struct intel_mp_floating *mpf)
/*
* Only use the first configuration found.
*/
- return 1;
}
-static int __init smp_scan_config(unsigned long base, unsigned long length)
+static int __init smp_scan_config (unsigned long base, unsigned long length)
{
unsigned long *bp = phys_to_virt(base);
struct intel_mp_floating *mpf;
@@ -432,9 +433,13 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
((mpf->mpf_specification == 1)
|| (mpf->mpf_specification == 4)) ) {
- printk("found SMP MP-table at %08ld\n",
+ smp_found_config = 1;
+ printk("found SMP MP-table at %08lx\n",
virt_to_phys(mpf));
- smp_get_mpf(mpf);
+ reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE);
+ if (mpf->mpf_physptr)
+ reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE);
+ mpf_found = mpf;
return 1;
}
bp += 4;
@@ -443,7 +448,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
return 0;
}
-void __init init_intel_smp (void)
+void __init find_intel_smp (void)
{
unsigned int address;
@@ -488,7 +493,7 @@ void __init init_intel_smp (void)
* sense, but it doesnt have a BIOS(-configuration table).
* No problem for Linux.
*/
-void __init init_visws_smp(void)
+void __init find_visws_smp(void)
{
smp_found_config = 1;
@@ -505,13 +510,13 @@ void __init init_visws_smp(void)
* - Intel MP Configuration Table
* - or SGI Visual Workstation configuration
*/
-void __init init_smp_config (void)
+void __init find_smp_config (void)
{
#ifdef CONFIG_X86_IO_APIC
- init_intel_smp();
+ find_intel_smp();
#endif
#ifdef CONFIG_VISWS
- init_visws_smp();
+ find_visws_smp();
#endif
}
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index a0a4ab851..cc9c7eafe 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -1507,11 +1507,6 @@ static struct file_operations mtrr_fops =
# ifdef CONFIG_PROC_FS
-static struct inode_operations proc_mtrr_inode_operations =
-{
- &mtrr_fops, /* default property file-ops */
-};
-
static struct proc_dir_entry *proc_root_mtrr;
# endif /* CONFIG_PROC_FS */
@@ -1836,9 +1831,9 @@ int __init mtrr_init(void)
#ifdef CONFIG_PROC_FS
proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root);
- proc_root_mtrr->ops = &proc_mtrr_inode_operations;
+ proc_root_mtrr->proc_fops = &mtrr_fops;
#endif
-#ifdev CONFIG_DEVFS_FS
+#ifdef CONFIG_DEVFS_FS
devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0,
S_IFREG | S_IRUGO | S_IWUSR, 0, 0,
&mtrr_fops, NULL);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 0f61ca543..19f7022a4 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -74,8 +74,13 @@ void enable_hlt(void)
*/
static void default_idle(void)
{
- if (current_cpu_data.hlt_works_ok && !hlt_counter)
- asm volatile("sti ; hlt" : : : "memory");
+ if (current_cpu_data.hlt_works_ok && !hlt_counter) {
+ asm volatile("cli" : : : "memory");
+ if (!current->need_resched)
+ asm volatile("sti ; hlt" : : : "memory");
+ else
+ asm volatile("sti" : : : "memory");
+ }
}
/*
diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c
index c530eece0..febc592ae 100644
--- a/arch/i386/kernel/semaphore.c
+++ b/arch/i386/kernel/semaphore.c
@@ -150,8 +150,9 @@ int __down_interruptible(struct semaphore * sem)
int __down_trylock(struct semaphore * sem)
{
int sleepers;
+ unsigned long flags;
- spin_lock_irq(&semaphore_lock);
+ spin_lock_irqsave(&semaphore_lock, flags);
sleepers = sem->sleepers + 1;
sem->sleepers = 0;
@@ -162,7 +163,7 @@ int __down_trylock(struct semaphore * sem)
if (!atomic_add_negative(sleepers, &sem->count))
wake_up(&sem->wait);
- spin_unlock_irq(&semaphore_lock);
+ spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index cd2a3d8af..b5602ebec 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -119,7 +119,7 @@ extern int rd_image_start; /* starting block # of image */
#endif
extern int root_mountflags;
-extern int _text, _etext, _edata, _end;
+extern char _text, _etext, _edata, _end;
extern unsigned long cpu_hz;
/*
@@ -709,9 +709,20 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_X86_IO_APIC
/*
- * Save possible boot-time SMP configuration:
+ * Find and reserve possible boot-time SMP configuration:
*/
- init_smp_config();
+ find_smp_config();
+#endif
+ paging_init();
+#ifdef CONFIG_X86_IO_APIC
+ /*
+ * get boot-time SMP configuration:
+ */
+ if (smp_found_config)
+ get_smp_config();
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+ init_apic_mappings();
#endif
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 07797e760..7400b628b 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -360,8 +360,6 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
printk("Do you have a strange power saving mode enabled?\n");
}
-atomic_t nmi_counter[NR_CPUS];
-
#if CONFIG_X86_IO_APIC
int nmi_watchdog = 1;
@@ -437,7 +435,8 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
unsigned char reason = inb(0x61);
- atomic_inc(nmi_counter+smp_processor_id());
+
+ atomic_inc(&nmi_counter(smp_processor_id()));
if (!(reason & 0xc0)) {
#if CONFIG_X86_IO_APIC
/*
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index c3991b056..8b1324520 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -438,10 +438,6 @@ void __init paging_init(void)
__flush_tlb_all();
-#ifdef CONFIG_X86_LOCAL_APIC
- init_apic_mappings();
-#endif
-
#ifdef CONFIG_HIGHMEM
kmap_init();
#endif
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
index 685d85b20..af51038e5 100644
--- a/arch/ia64/ia32/binfmt_elf32.c
+++ b/arch/ia64/ia32/binfmt_elf32.c
@@ -82,6 +82,8 @@ void ia64_elf32_init(struct pt_regs *regs)
/* Do all the IA-32 setup here */
+ current->thread.map_base = 0x40000000;
+
/* CS descriptor */
__asm__("mov ar.csd = %0" : /* no outputs */
: "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L,
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index 82ba58129..bd7b0517b 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -75,7 +75,7 @@ ia32_syscall_table:
data8 sys_unlink /* 10 */
data8 sys32_execve
data8 sys_chdir
- data8 sys_ni_syscall /* sys_time is not supported on ia64 */
+ data8 sys32_time
data8 sys_mknod
data8 sys_chmod /* 15 */
data8 sys_lchown
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index d61f1cfe5..8d4e4a8fd 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -278,7 +278,7 @@ do_mmap_fake(struct file *file, unsigned long addr, unsigned long len,
if (!file)
return -EINVAL;
inode = file->f_dentry->d_inode;
- if (!inode->i_op || !inode->i_op->default_file_ops)
+ if (!inode->i_fop)
return -EINVAL;
if (!file->f_op->read)
return -EINVAL;
@@ -1930,6 +1930,25 @@ out:
return err;
}
+/*
+ * sys_time() can be implemented in user-level using
+ * sys_gettimeofday(). IA64 did this but i386 Linux did not
+ * so we have to implement this system call here.
+ */
+asmlinkage long sys32_time(int * tloc)
+{
+ int i;
+
+ /* SMP: This is fairly trivial. We grab CURRENT_TIME and
+ stuff it to user space. No side effects */
+ i = CURRENT_TIME;
+ if (tloc) {
+ if (put_user(i,tloc))
+ i = -EFAULT;
+ }
+ return i;
+}
+
#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */
/* In order to reduce some races, while at the same time doing additional
diff --git a/arch/ia64/kdb/kdbsupport.c b/arch/ia64/kdb/kdbsupport.c
index 0b574ae6e..d074a01a3 100644
--- a/arch/ia64/kdb/kdbsupport.c
+++ b/arch/ia64/kdb/kdbsupport.c
@@ -28,9 +28,10 @@
#include <linux/stddef.h>
#include <linux/vmalloc.h>
-#include <asm/uaccess.h>
+#include <asm/delay.h>
#include <asm/kdbsupport.h>
#include <asm/rse.h>
+#include <asm/uaccess.h>
extern kdb_state_t kdb_state ;
k_machreg_t dbregs[KDB_DBREGS];
@@ -45,6 +46,21 @@ kdb_setup (char *str)
__setup("kdb", kdb_setup);
static int
+kdb_ia64_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+ int diag;
+ unsigned long val;
+
+ diag = kdbgetularg(argv[1], &val);
+ if (diag)
+ return diag;
+ kdb_printf("new itm=%0xlx\n", val);
+
+ ia64_set_itm(val);
+ return 0;
+}
+
+static int
kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs)
{
u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv;
@@ -53,15 +69,17 @@ kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *re
asm ("mov %0=cr.tpr" : "=r"(tpr));
asm ("mov %0=cr.lrr0" : "=r"(lrr0));
asm ("mov %0=cr.lrr1" : "=r"(lrr1));
- printk ("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1);
+ printk("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1);
asm ("mov %0=cr.itv" : "=r"(itv));
asm ("mov %0=cr.pmv" : "=r"(pmv));
asm ("mov %0=cr.cmcv" : "=r"(cmcv));
- printk ("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv);
+ printk("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv);
- printk ("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n",
+ printk("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n",
ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3());
+
+ printk("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm());
return 0;
}
@@ -90,6 +108,7 @@ kdb_init (void)
kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ;
kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0);
+ kdb_register("itm", kdb_ia64_itm, "", "Set new ITM value", 0);
}
/*
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 5efe50164..6059e41c6 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -158,6 +158,9 @@ ia64_handle_irq (unsigned long irq, struct pt_regs *regs)
unsigned long eoi_ptr;
# ifdef CONFIG_USB
+ extern void reenable_usb (void);
+ extern void disable_usb (void);
+
if (usbfix)
disable_usb();
# endif
diff --git a/arch/ia64/kernel/irq_internal.c b/arch/ia64/kernel/irq_internal.c
index 1ae904fe8..cc59e0c72 100644
--- a/arch/ia64/kernel/irq_internal.c
+++ b/arch/ia64/kernel/irq_internal.c
@@ -60,7 +60,7 @@ internal_noop (unsigned int irq)
}
struct hw_interrupt_type irq_type_ia64_internal = {
- "IA64 internal",
+ "IA64-internal",
(void (*)(unsigned long)) internal_noop, /* init */
internal_noop, /* startup */
internal_noop, /* shutdown */
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 4c3ac242a..b4592999f 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -1026,7 +1026,7 @@ dispatch_to_fault_handler:
// 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49)
mov r16=cr.ifa
rsm psr.dt
-#if 0
+#if 1
// If you disable this, you MUST re-enable to update_mmu_cache() code in pgtable.h
mov r17=_PAGE_SIZE_4K<<2
;;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 5b6deb5f5..cc26b8760 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -97,6 +97,14 @@ cpu_idle (void *unused)
check_pgt_cache();
if (pm_idle)
(*pm_idle)();
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+ if (ia64_get_itm() < ia64_get_itc()) {
+ extern void ia64_reset_itm();
+
+ printk("cpu_idle: ITM in past, resetting it...\n");
+ ia64_reset_itm();
+ }
+#endif
}
}
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 7c5ace740..cfcff3063 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -21,6 +21,10 @@
#include <asm/ptrace.h>
#include <asm/sal.h>
#include <asm/system.h>
+#ifdef CONFIG_KDB
+# include <linux/kdb.h>
+#endif
+
extern rwlock_t xtime_lock;
extern volatile unsigned long lost_ticks;
@@ -61,7 +65,7 @@ do_profile (unsigned long ip)
* update to jiffy. The xtime_lock must be at least read-locked when
* calling this routine.
*/
-static inline unsigned long
+static /*inline*/ unsigned long
gettimeoffset (void)
{
unsigned long now = ia64_get_itc();
@@ -186,6 +190,20 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_unlock(&xtime_lock);
}
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+
+void
+ia64_reset_itm (void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ timer_interrupt(0, 0, current);
+ local_irq_restore(flags);
+}
+
+#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+
/*
* Encapsulate access to the itm structure for SMP.
*/
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index c242622ec..1f5106036 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -110,15 +110,75 @@ void
ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
{
siginfo_t siginfo;
+ int sig, code;
- /* gdb uses a break number of 0xccccc for debug breakpoints: */
- if (break_num != 0xccccc)
- die_if_kernel("Bad break", regs, break_num);
+ /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
+ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ siginfo.si_imm = break_num;
- siginfo.si_signo = SIGTRAP;
- siginfo.si_errno = break_num; /* XXX is it legal to abuse si_errno like this? */
- siginfo.si_code = TRAP_BRKPT;
- send_sig_info(SIGTRAP, &siginfo, current);
+ switch (break_num) {
+ case 0: /* unknown error */
+ sig = SIGILL; code = ILL_ILLOPC;
+ break;
+
+ case 1: /* integer divide by zero */
+ sig = SIGFPE; code = FPE_INTDIV;
+ break;
+
+ case 2: /* integer overflow */
+ sig = SIGFPE; code = FPE_INTOVF;
+ break;
+
+ case 3: /* range check/bounds check */
+ sig = SIGFPE; code = FPE_FLTSUB;
+ break;
+
+ case 4: /* null pointer dereference */
+ sig = SIGSEGV; code = SEGV_MAPERR;
+ break;
+
+ case 5: /* misaligned data */
+ sig = SIGSEGV; code = BUS_ADRALN;
+ break;
+
+ case 6: /* decimal overflow */
+ sig = SIGFPE; code = __FPE_DECOVF;
+ break;
+
+ case 7: /* decimal divide by zero */
+ sig = SIGFPE; code = __FPE_DECDIV;
+ break;
+
+ case 8: /* packed decimal error */
+ sig = SIGFPE; code = __FPE_DECERR;
+ break;
+
+ case 9: /* invalid ASCII digit */
+ sig = SIGFPE; code = __FPE_INVASC;
+ break;
+
+ case 10: /* invalid decimal digit */
+ sig = SIGFPE; code = __FPE_INVDEC;
+ break;
+
+ case 11: /* paragraph stack overflow */
+ sig = SIGSEGV; code = __SEGV_PSTKOVF;
+ break;
+
+ default:
+ if (break_num < 0x40000 || break_num > 0x100000)
+ die_if_kernel("Bad break", regs, break_num);
+
+ if (break_num < 0x80000) {
+ sig = SIGILL; code = __ILL_BREAK;
+ } else {
+ sig = SIGTRAP; code = TRAP_BRKPT;
+ }
+ }
+ siginfo.si_signo = sig;
+ siginfo.si_errno = 0;
+ siginfo.si_code = code;
+ send_sig_info(sig, &siginfo, current);
}
/*
@@ -240,6 +300,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
{
long exception, bundle[2];
unsigned long fault_ip;
+ struct siginfo siginfo;
static int fpu_swa_count = 0;
static unsigned long last_time;
@@ -265,21 +326,41 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
ia64_increment_ip(regs);
} else if (exception == -1) {
printk("handle_fpu_swa: fp_emulate() returned -1\n");
- return -2;
+ return -1;
} else {
/* is next instruction a trap? */
if (exception & 2) {
ia64_increment_ip(regs);
}
- return -1;
+ siginfo.si_signo = SIGFPE;
+ siginfo.si_errno = 0;
+ siginfo.si_code = 0;
+ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ if (isr & 0x11) {
+ siginfo.si_code = FPE_FLTINV;
+ } else if (isr & 0x44) {
+ siginfo.si_code = FPE_FLTDIV;
+ }
+ send_sig_info(SIGFPE, &siginfo, current);
}
} else {
if (exception == -1) {
printk("handle_fpu_swa: fp_emulate() returned -1\n");
- return -2;
+ return -1;
} else if (exception != 0) {
/* raise exception */
- return -1;
+ siginfo.si_signo = SIGFPE;
+ siginfo.si_errno = 0;
+ siginfo.si_code = 0;
+ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
+ if (isr & 0x880) {
+ siginfo.si_code = FPE_FLTOVF;
+ } else if (isr & 0x1100) {
+ siginfo.si_code = FPE_FLTUND;
+ } else if (isr & 0x2200) {
+ siginfo.si_code = FPE_FLTRES;
+ }
+ send_sig_info(SIGFPE, &siginfo, current);
}
}
return 0;
@@ -369,22 +450,19 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
return;
case 30: /* Unaligned fault */
- sprintf(buf, "Unaligned access in kernel mode---don't do this!");
+ sprintf(buf, "Kernel unaligned trap accessing %016lx (ip=%016lx)!",
+ ifa, regs->cr_iip + ia64_psr(regs)->ri);
break;
case 32: /* fp fault */
case 33: /* fp trap */
- result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
+ result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, &isr);
if (result < 0) {
siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0;
- siginfo.si_code = 0; /* XXX fix me */
+ siginfo.si_code = FPE_FLTINV;
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
- send_sig_info(SIGFPE, &siginfo, current);
- if (result == -1)
- send_sig_info(SIGFPE, &siginfo, current);
- else
- force_sig(SIGFPE, current);
+ force_sig(SIGFPE, current);
}
return;
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index 0bd213f6b..014adcf35 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -1384,30 +1384,33 @@ ia64_handle_unaligned(unsigned long ifa, struct pt_regs *regs)
load_store_t *insn;
int ret = -1;
- /*
- * We flag unaligned references while in kernel as
- * errors: the kernel must be fixed. The switch code
- * is in ivt.S at entry 30.
- *
- * So here we keep a simple sanity check.
- */
- if ( !user_mode(regs) ) {
- die_if_kernel("Unaligned reference while in kernel\n", regs, 30);
- /* NOT_REACHED */
+ if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) {
+ struct siginfo si;
+
+ si.si_signo = SIGBUS;
+ si.si_errno = 0;
+ si.si_code = BUS_ADRALN;
+ si.si_addr = (void *) ifa;
+ send_sig_info (SIGBUS, &si, current);
+ return;
}
- /*
- * Make sure we log the unaligned access, so that user/sysadmin can notice it
- * and eventually fix the program.
- *
- * We don't want to do that for every access so we pace it with jiffies.
- */
- if ( unalign_count > 5 && jiffies - last_time > 5*HZ ) unalign_count = 0;
- if ( ++unalign_count < 5 ) {
- last_time = jiffies;
- printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n",
- current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
-
+ if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) {
+ /*
+ * Make sure we log the unaligned access, so that
+ * user/sysadmin can notice it and eventually fix the
+ * program.
+ *
+ * We don't want to do that for every access so we
+ * pace it with jiffies.
+ */
+ if (unalign_count > 5 && jiffies - last_time > 5*HZ)
+ unalign_count = 0;
+ if (++unalign_count < 5) {
+ last_time = jiffies;
+ printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n",
+ current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri);
+ }
}
DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr));
diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S
index 03a540a80..58c92876f 100644
--- a/arch/ia64/lib/copy_user.S
+++ b/arch/ia64/lib/copy_user.S
@@ -1,71 +1,375 @@
-/*
- * This routine copies a linear memory buffer across the user/kernel boundary. When
- * reading a byte from the source causes a fault, the remainder of the destination
- * buffer is zeroed out. Note that this can happen only when copying from user
- * to kernel memory and we do this to absolutely guarantee that the
- * kernel doesn't operate on random data.
- *
- * This file is derived from arch/alpha/lib/copy_user.S.
- *
- * Inputs:
- * in0: address of destination buffer
- * in1: address of source buffer
- * in2: length of buffer in bytes
- * Outputs:
- * r8: number of bytes that didn't get copied due to a fault
- *
- * Copyright (C) 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#define EXI(x...) \
-99: x; \
+// The label comes first because our store instruction contains a comma
+// and confuse the preprocessor otherwise
+//
+#undef DEBUG
+#ifdef DEBUG
+#define EX(y,x...) \
+99: x
+#else
+#define EX(y,x...) \
.section __ex_table,"a"; \
- data4 @gprel(99b); \
- data4 .Lexit_in-99b; \
- .previous
+ data4 @gprel(99f); \
+ data4 y-99f; \
+ .previous; \
+99: x
+#endif
-#define EXO(x...) \
-99: x; \
- .section __ex_table,"a"; \
- data4 @gprel(99b); \
- data4 .Lexit_out-99b; \
- .previous
-
- .text
- .psr abi64
- .psr lsb
- .lsb
-
- .align 32
- .global __copy_user
- .proc __copy_user
+//
+// Tuneable parameters
+//
+#define COPY_BREAK 16 // we do byte copy below (must be >=16)
+#define PIPE_DEPTH 4 // pipe depth
+
+#define EPI p[PIPE_DEPTH-1] // PASTE(p,16+PIPE_DEPTH-1)
+
+//
+// arguments
+//
+#define dst in0
+#define src in1
+#define len in2
+
+//
+// local registers
+//
+#define cnt r18
+#define len2 r19
+#define saved_lc r20
+#define saved_pr r21
+#define tmp r22
+#define val r23
+#define src1 r24
+#define dst1 r25
+#define src2 r26
+#define dst2 r27
+#define len1 r28
+#define enddst r29
+#define endsrc r30
+#define saved_pfs r31
+ .text
+ .psr abi64
+ .psr lsb
+
+ .align 16
+ .global __copy_user
+ .proc __copy_user
__copy_user:
- alloc r10=ar.pfs,3,0,0,0
- mov r9=ar.lc // save ar.lc
- mov ar.lc=in2 // set ar.lc to length of buffer
- br.sptk.few .Lentr
-
- // XXX braindead copy loop---this needs to be optimized
-.Loop1:
- EXI(ld1 r8=[in1],1)
- ;;
- EXO(st1 [in0]=r8,1)
-.Lentr: br.cloop.dptk.few .Loop1 // repeat unless ar.lc--==0
- ;; // avoid RAW on ar.lc
-.Lexit_out:
- mov r8=ar.lc // return how many bytes we _didn't_ copy
- mov ar.lc=r9
- br.ret.sptk.few rp
-
-.Lexit_in:
- // clear the remainder of the buffer:
- mov r8=ar.lc // return how many bytes we _didn't_ copy
-.Loop2:
- st1 [in0]=r0,1 // this cannot fault because we get here only on user->kernel copies
- br.cloop.dptk.few .Loop2
- ;; // avoid RAW on ar.lc
- mov ar.lc=r9
- br.ret.sptk.few rp
-
- .endp __copy_user
+ alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7)
+
+ .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH]
+ .rotp p[PIPE_DEPTH]
+
+ adds len2=-1,len // br.ctop is repeat/until
+ mov ret0=r0
+
+ ;; // RAW of cfm when len=0
+ cmp.eq p8,p0=r0,len // check for zero length
+ mov saved_lc=ar.lc // preserve ar.lc (slow)
+(p8) br.ret.spnt.few rp // empty mempcy()
+ ;;
+ add enddst=dst,len // first byte after end of source
+ add endsrc=src,len // first byte after end of destination
+ mov saved_pr=pr // preserve predicates
+
+ mov dst1=dst // copy because of rotation
+ mov ar.ec=PIPE_DEPTH
+ mov pr.rot=1<<16 // p16=true all others are false
+
+ mov src1=src // copy because of rotation
+ mov ar.lc=len2 // initialize lc for small count
+ cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy
+
+ xor tmp=src,dst // same alignment test prepare
+(p10) br.cond.dptk.few long_memcpy
+ ;; // RAW pr.rot/p16 ?
+ //
+ // Now we do the byte by byte loop with software pipeline
+ //
+ // p7 is necessarily false by now
+1:
+ EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1)
+
+ EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1)
+ br.ctop.dptk.few 1b
+ ;;
+ mov ar.lc=saved_lc
+ mov pr=saved_pr,0xffffffffffff0000
+ mov ar.pfs=saved_pfs // restore ar.ec
+ br.ret.sptk.few rp // end of short memcpy
+
+ //
+ // Beginning of long mempcy (i.e. > 16 bytes)
+ //
+long_memcpy:
+ tbit.nz p6,p7=src1,0 // odd alignement
+ and tmp=7,tmp
+ ;;
+ cmp.eq p10,p8=r0,tmp
+ mov len1=len // copy because of rotation
+(p8) br.cond.dpnt.few 1b // XXX Fixme. memcpy_diff_align
+ ;;
+ // At this point we know we have more than 16 bytes to copy
+ // and also that both src and dest have the same alignment
+ // which may not be the one we want. So for now we must move
+ // forward slowly until we reach 16byte alignment: no need to
+ // worry about reaching the end of buffer.
+ //
+ EX(failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned
+(p6) adds len1=-1,len1;;
+ tbit.nz p7,p0=src1,1
+ ;;
+ EX(failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned
+(p7) adds len1=-2,len1;;
+ tbit.nz p8,p0=src1,2
+ ;;
+ //
+ // Stop bit not required after ld4 because if we fail on ld4
+ // we have never executed the ld1, therefore st1 is not executed.
+ //
+ EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned
+ EX(failure_out,(p6) st1 [dst1]=val1[0],1)
+ tbit.nz p9,p0=src1,3
+ ;;
+ //
+ // Stop bit not required after ld8 because if we fail on ld8
+ // we have never executed the ld2, therefore st2 is not executed.
+ //
+ EX(failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned
+ EX(failure_out,(p7) st2 [dst1]=val1[1],2)
+(p8) adds len1=-4,len1
+ ;;
+ EX(failure_out, (p8) st4 [dst1]=val2[0],4)
+(p9) adds len1=-8,len1;;
+ shr.u cnt=len1,4 // number of 128-bit (2x64bit) words
+ ;;
+ EX(failure_out, (p9) st8 [dst1]=val2[1],8)
+ tbit.nz p6,p0=len1,3
+ cmp.eq p7,p0=r0,cnt
+ adds tmp=-1,cnt // br.ctop is repeat/until
+(p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left
+ ;;
+ adds src2=8,src1
+ adds dst2=8,dst1
+ mov ar.lc=tmp
+ ;;
+ //
+ // 16bytes/iteration
+ //
+2:
+ EX(failure_in3,(p16) ld8 val1[0]=[src1],16)
+(p16) ld8 val2[0]=[src2],16
+
+ EX(failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16)
+(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16
+ br.ctop.dptk.few 2b
+ ;; // RAW on src1 when fall through from loop
+ //
+ // Tail correction based on len only
+ //
+ // No matter where we come from (loop or test) the src1 pointer
+ // is 16 byte aligned AND we have less than 16 bytes to copy.
+ //
+.dotail:
+ EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes
+ tbit.nz p7,p0=len1,2
+ ;;
+ EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes
+ tbit.nz p8,p0=len1,1
+ ;;
+ EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes
+ tbit.nz p9,p0=len1,0
+ ;;
+ EX(failure_out, (p6) st8 [dst1]=val1[0],8)
+ ;;
+ EX(failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left
+ mov ar.lc=saved_lc
+ ;;
+ EX(failure_out,(p7) st4 [dst1]=val1[1],4)
+ mov pr=saved_pr,0xffffffffffff0000
+ ;;
+ EX(failure_out, (p8) st2 [dst1]=val2[0],2)
+ mov ar.pfs=saved_pfs
+ ;;
+ EX(failure_out, (p9) st1 [dst1]=val2[1])
+ br.ret.dptk.few rp
+
+
+
+ //
+ // Here we handle the case where the byte by byte copy fails
+ // on the load.
+ // Several factors make the zeroing of the rest of the buffer kind of
+ // tricky:
+ // - the pipeline: loads/stores are not in sync (pipeline)
+ //
+ // In the same loop iteration, the dst1 pointer does not directly
+ // reflect where the faulty load was.
+ //
+ // - pipeline effect
+ // When you get a fault on load, you may have valid data from
+ // previous loads not yet store in transit. Such data must be
+ // store normally before moving onto zeroing the rest.
+ //
+ // - single/multi dispersal independence.
+ //
+ // solution:
+ // - we don't disrupt the pipeline, i.e. data in transit in
+ // the software pipeline will be eventually move to memory.
+ // We simply replace the load with a simple mov and keep the
+ // pipeline going. We can't really do this inline because
+ // p16 is always reset to 1 when lc > 0.
+ //
+failure_in_pipe1:
+ sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied
+1:
+(p16) mov val1[0]=r0
+(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1
+ br.ctop.dptk.few 1b
+ ;;
+ mov pr=saved_pr,0xffffffffffff0000
+ mov ar.lc=saved_lc
+ mov ar.pfs=saved_pfs
+ br.ret.dptk.few rp
+
+
+ //
+ // Here we handle the head & tail part when we check for alignment.
+ // The following code handles only the load failures. The
+ // main diffculty comes from the fact that loads/stores are
+ // scheduled. So when you fail on a load, the stores corresponding
+ // to previous successful loads must be executed.
+ //
+ // However some simplifications are possible given the way
+ // things work.
+ //
+ // 1) HEAD
+ // Theory of operation:
+ //
+ // Page A | Page B
+ // ---------|-----
+ // 1|8 x
+ // 1 2|8 x
+ // 4|8 x
+ // 1 4|8 x
+ // 2 4|8 x
+ // 1 2 4|8 x
+ // |1
+ // |2 x
+ // |4 x
+ //
+ // page_size >= 4k (2^12). (x means 4, 2, 1)
+ // Here we suppose Page A exists and Page B does not.
+ //
+ // As we move towards eight byte alignment we may encounter faults.
+ // The numbers on each page show the size of the load (current alignment).
+ //
+ // Key point:
+ // - if you fail on 1, 2, 4 then you have never executed any smaller
+ // size loads, e.g. failing ld4 means no ld1 nor ld2 executed
+ // before.
+ //
+ // This allows us to simplify the cleanup code, because basically you
+ // only have to worry about "pending" stores in the case of a failing
+ // ld8(). Given the way the code is written today, this means only
+ // worry about st2, st4. There we can use the information encapsulated
+ // into the predicates.
+ //
+ // Other key point:
+ // - if you fail on the ld8 in the head, it means you went straight
+ // to it, i.e. 8byte alignment within an unexisting page.
+ // Again this comes from the fact that if you crossed just for the the ld8 then
+ // you are 8byte aligned but also 16byte align, therefore you would
+ // either go for the 16byte copy loop OR the ld8 in the tail part.
+ // The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible
+ // because it would mean you had 15bytes to copy in which case you
+ // would have defaulted to the byte by byte copy.
+ //
+ //
+ // 2) TAIL
+ // Here we now we have less than 16 bytes AND we are either 8 or 16 byte
+ // aligned.
+ //
+ // Key point:
+ // This means that we either:
+ // - are right on a page boundary
+ // OR
+ // - are at more than 16 bytes from a page boundary with
+ // at most 15 bytes to copy: no chance of crossing.
+ //
+ // This allows us to assume that if we fail on a load we haven't possibly
+ // executed any of the previous (tail) ones, so we don't need to do
+ // any stores. For instance, if we fail on ld2, this means we had
+ // 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4.
+ //
+ // This means that we are in a situation similar the a fault in the
+ // head part. That's nice!
+ //
+failure_in1:
+// sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied
+// sub len=enddst,dst1,1
+ sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied
+ sub len=endsrc,src1,1
+ //
+ // we know that ret0 can never be zero at this point
+ // because we failed why trying to do a load, i.e. there is still
+ // some work to do.
+ // The failure_in1bis and length problem is taken care of at the
+ // calling side.
+ //
+ ;;
+failure_in1bis: // from (failure_in3)
+ mov ar.lc=len // Continue with a stupid byte store.
+ ;;
+5:
+ st1 [dst1]=r0,1
+ br.cloop.dptk.few 5b
+ ;;
+skip_loop:
+ mov pr=saved_pr,0xffffffffffff0000
+ mov ar.lc=saved_lc
+ mov ar.pfs=saved_pfs
+ br.ret.dptk.few rp
+
+ //
+ // Here we simply restart the loop but instead
+ // of doing loads we fill the pipeline with zeroes
+ // We can't simply store r0 because we may have valid
+ // data in transit in the pipeline.
+ // ar.lc and ar.ec are setup correctly at this point
+ //
+ // we MUST use src1/endsrc here and not dst1/enddst because
+ // of the pipeline effect.
+ //
+failure_in3:
+ sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied
+ ;;
+2:
+(p16) mov val1[0]=r0
+(p16) mov val2[0]=r0
+(EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16
+(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16
+ br.ctop.dptk.few 2b
+ ;;
+ cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ?
+ sub len=enddst,dst1,1 // precompute len
+(p6) br.cond.dptk.few failure_in1bis
+ ;;
+ mov pr=saved_pr,0xffffffffffff0000
+ mov ar.lc=saved_lc
+ mov ar.pfs=saved_pfs
+ br.ret.dptk.few rp
+
+ //
+ // handling of failures on stores: that's the easy part
+ //
+failure_out:
+ sub ret0=enddst,dst1
+ mov pr=saved_pr,0xffffffffffff0000
+ mov ar.lc=saved_lc
+
+ mov ar.pfs=saved_pfs
+ br.ret.dptk.few rp
+
+
+ .endp __copy_user
+
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 5516700c1..bec96e794 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -176,6 +176,8 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
CONFIG_SCSI_SGIWD93=y
+CONFIG_SCSI_SGIWD93=y
+# 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
@@ -210,7 +212,6 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
#
# I2O device support
@@ -269,6 +270,7 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
#
# Video For Linux
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index b0225f750..41ea11b98 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -1,4 +1,4 @@
-/* $Id: irixelf.c,v 1.23 2000/01/29 01:41:59 ralf Exp $
+/* $Id: irixelf.c,v 1.24 2000/02/04 07:40:23 ralf Exp $
*
* irixelf.c: Code to load IRIX ELF executables which conform to
* the MIPS ABI.
@@ -257,11 +257,11 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
#endif
/* First of all, some simple consistency checks */
- if((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_dentry->d_inode->i_op ||
- !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) {
+ if ((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ !elf_check_arch(interp_elf_ex->e_machine) ||
+ (!interpreter_dentry->d_inode->i_fop ||
+ !interpreter_dentry->d_inode->i_fop->mmap)) {
printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
return 0xffffffff;
}
@@ -410,9 +410,8 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
/* First of all, some simple consistency checks */
if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
!elf_check_arch(ehp->e_machine) ||
- (!bprm->dentry->d_inode->i_op ||
- !bprm->dentry->d_inode->i_op->default_file_ops ||
- !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
+ (!bprm->dentry->d_inode->i_fop ||
+ !bprm->dentry->d_inode->i_fop->mmap)) {
return -ENOEXEC;
}
@@ -877,8 +876,8 @@ static inline int do_load_irix_library(struct file *file)
/* First of all, some simple consistency checks. */
if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
!elf_check_arch(elf_ex.e_machine) ||
- (!dentry->d_inode->i_op ||
- !dentry->d_inode->i_op->default_file_ops->mmap))
+ (!dentry->d_inode->i_fop ||
+ !dentry->d_inode->i_fop->mmap))
return -ENOEXEC;
/* Now read in all of the header information. */
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 4e3ba5ad9..239576e4e 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.19 2000/02/04 07:40:23 ralf Exp $
+/* $Id: irq.c,v 1.20 2000/02/23 00:41:00 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
@@ -32,6 +32,24 @@
#include <asm/nile4.h>
/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
+/*
* This contains the irq mask for both 8259A irq controllers, it's an
* int so we can deal with the third PIC in some systems like the RM300.
* (XXX This is broken for big endian.)
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index f1c65805f..b8e1e6ec2 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: mips_ksyms.c,v 1.24 2000/02/04 07:40:23 ralf Exp $
+/* $Id: mips_ksyms.c,v 1.25 2000/02/24 00:12:40 ralf Exp $
*
* Export MIPS-specific functions needed for loadable modules.
*
@@ -56,8 +56,6 @@ EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL(_clear_page);
-EXPORT_SYMBOL(local_bh_count);
-EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index c2ee57b86..9bffcdc96 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -83,3 +83,8 @@ int get_cpuinfo(char *buffer)
return len;
}
+
+void init_irq_proc(void)
+{
+ /* Nothing, for now. */
+}
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 43cf5ad74..f6209461f 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.21 2000/01/26 00:07:44 ralf Exp $
+/* $Id: setup.c,v 1.22 2000/01/27 01:05:23 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
@@ -220,4 +220,6 @@ void __init setup_arch(char **cmdline_p)
*memory_start_p = initrd_end;
}
#endif
+
+ paging_init();
}
diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c
index 916b0873a..cab112c29 100644
--- a/arch/mips/sgi/kernel/indy_int.c
+++ b/arch/mips/sgi/kernel/indy_int.c
@@ -1,4 +1,4 @@
-/* $Id: indy_int.c,v 1.16 1999/12/04 03:59:00 ralf Exp $
+/* $Id: indy_int.c,v 1.17 2000/02/04 07:40:23 ralf Exp $
*
* indy_int.c: Routines for generic manipulation of the INT[23] ASIC
* found on INDY workstations..
@@ -40,6 +40,24 @@
#include <asm/sgialib.h>
#include <asm/gdb-stub.h>
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
/* #define DEBUG_SGINT */
struct sgi_int2_regs *sgi_i2regs;
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 039ffd84f..c4f4ba27a 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -305,6 +305,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
#
# Video For Linux
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index 9c6687735..b40469cfc 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -224,6 +224,7 @@ CONFIG_VT_CONSOLE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
#
# Video For Linux
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 039ffd84f..c4f4ba27a 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -305,6 +305,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+# CONFIG_EFI_RTC is not set
#
# Video For Linux
diff --git a/arch/mips64/kernel/proc.c b/arch/mips64/kernel/proc.c
index 6fba1b756..063ac5d88 100644
--- a/arch/mips64/kernel/proc.c
+++ b/arch/mips64/kernel/proc.c
@@ -1,4 +1,4 @@
-/* $Id: proc.c,v 1.1 1999/09/27 16:01:37 ralf Exp $
+/* $Id: proc.c,v 1.1 1999/09/28 22:25:51 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
@@ -69,3 +69,8 @@ int get_cpuinfo(char *buffer)
return len;
}
+
+void init_irq_proc(void)
+{
+ /* Nothing, for now. */
+}
diff --git a/arch/mips64/kernel/setup.c b/arch/mips64/kernel/setup.c
index b42271b47..2a7d8a894 100644
--- a/arch/mips64/kernel/setup.c
+++ b/arch/mips64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.6 2000/01/27 01:05:24 ralf Exp $
+/* $Id: setup.c,v 1.7 2000/02/04 07:40:24 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
@@ -183,4 +183,6 @@ void __init setup_arch(char **cmdline_p)
*memory_start_p = initrd_end;
}
#endif
+
+ paging_init();
}
diff --git a/arch/mips64/sgi-ip22/ip22-int.c b/arch/mips64/sgi-ip22/ip22-int.c
index 420e47fc7..a26ad631d 100644
--- a/arch/mips64/sgi-ip22/ip22-int.c
+++ b/arch/mips64/sgi-ip22/ip22-int.c
@@ -1,4 +1,4 @@
-/* $Id: ip22-int.c,v 1.3 1999/12/04 03:59:01 ralf Exp $
+/* $Id: ip22-int.c,v 1.4 2000/02/04 07:40:24 ralf Exp $
*
* indy_int.c: Routines for generic manipulation of the INT[23] ASIC
* found on INDY workstations..
@@ -37,6 +37,24 @@
#include <asm/sgi/sgint23.h>
#include <asm/sgialib.h>
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
struct sgi_int2_regs *sgi_i2regs;
struct sgi_int3_regs *sgi_i3regs;
struct sgi_ioc_ints *ioc_icontrol;
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index 7f5a36f97..c9e6fe150 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -1,4 +1,4 @@
-/* $Id: ip27-irq.c,v 1.5 2000/02/04 07:40:24 ralf Exp $
+/* $Id: ip27-irq.c,v 1.6 2000/02/10 05:58:56 dagum Exp $
*
* ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
*
@@ -35,6 +35,24 @@
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/arch.h>
+/*
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
+ */
+
+irq_cpustat_t irq_stat [NR_CPUS];
+
extern asmlinkage void ip27_irq(void);
int (*irq_cannonicalize)(int irq);
@@ -255,7 +273,7 @@ void irq_debug(void)
printk("PI_INT_MASK0_A = 0x%x\n", LOCAL_HUB_L(PI_INT_MASK0_A));
}
-int setup_irq(int irq, struct irqaction *new)
+int setup_irq(unsigned int irq, struct irqaction *new)
{
int shared = 0;
struct irqaction *old, **p;
diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c
index d54a429a9..91bf4d8c4 100644
--- a/arch/ppc/chrpboot/main.c
+++ b/arch/ppc/chrpboot/main.c
@@ -10,7 +10,6 @@
#include "../coffboot/zlib.h"
#include <asm/bootinfo.h>
#include <asm/processor.h>
-#define __KERNEL__
#include <asm/page.h>
extern void *finddevice(const char *);
@@ -49,17 +48,8 @@ chrpboot(int a1, int a2, void *prom)
printf("chrpboot starting: loaded at 0x%x\n\r", &_start);
- if (initrd_len) {
- initrd_size = initrd_len;
- initrd_start = (RAM_END - initrd_size) & ~0xFFF;
- a1 = initrd_start;
- a2 = initrd_size;
- printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start,
- initrd_data,initrd_size);
- memcpy((char *)initrd_start, initrd_data, initrd_size);
- end_avail = (char *)initrd_start;
- } else
- end_avail = (char *) RAM_END;
+ end_avail = (char *) RAM_END;
+
im = image_data;
len = image_len;
dst = (void *) PROG_START;
@@ -98,7 +88,7 @@ chrpboot(int a1, int a2, void *prom)
rec = (struct bi_record *)((unsigned long)rec + rec->size);
rec->tag = BI_SYSMAP;
- rec->data[0] = sysmap_data;
+ rec->data[0] = (unsigned long)sysmap_data;
rec->data[1] = sysmap_len;
rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
rec = (struct bi_record *)((unsigned long)rec + rec->size);
@@ -129,6 +119,10 @@ void *zalloc(void *x, unsigned items, unsigned size)
void zfree(void *x, void *addr, unsigned nb)
{
+ nb = (nb + 7) & -8;
+ if (addr == (avail_ram - nb)) {
+ avail_ram -= nb;
+ }
}
#define HEAD_CRC 2
diff --git a/arch/ppc/chrpboot/piggyback.c b/arch/ppc/chrpboot/piggyback.c
index 172025802..304bc8f11 100644
--- a/arch/ppc/chrpboot/piggyback.c
+++ b/arch/ppc/chrpboot/piggyback.c
@@ -1,8 +1,9 @@
#include <stdio.h>
+#include <unistd.h>
extern long ce_exec_config[];
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
int i, cnt, pos, len;
unsigned int cksum, val;
diff --git a/arch/ppc/coffboot/piggyback.c b/arch/ppc/coffboot/piggyback.c
index 172025802..304bc8f11 100644
--- a/arch/ppc/coffboot/piggyback.c
+++ b/arch/ppc/coffboot/piggyback.c
@@ -1,8 +1,9 @@
#include <stdio.h>
+#include <unistd.h>
extern long ce_exec_config[];
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
int i, cnt, pos, len;
unsigned int cksum, val;
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 8bb23afa2..7d0ab5fa0 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -47,12 +47,9 @@ if [ "$CONFIG_8xx" = "y" ]; then
fi
if [ "$CONFIG_6xx" = "y" ]; then
choice 'Machine Type' \
- "PowerMac CONFIG_PMAC \
- PReP/MTX CONFIG_PREP \
- CHRP CONFIG_CHRP \
- PowerMac/PReP/CHRP CONFIG_ALL_PPC \
+ "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \
Gemini CONFIG_GEMINI \
- APUS CONFIG_APUS" PowerMac
+ APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP
fi
if [ "$CONFIG_PPC64" = "y" ]; then
diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
index 17217702f..4ba96bde9 100644
--- a/arch/ppc/configs/common_defconfig
+++ b/arch/ppc/configs/common_defconfig
@@ -17,9 +17,6 @@ CONFIG_6xx=y
# CONFIG_PPC64 is not set
# CONFIG_82xx is not set
# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
-# CONFIG_PREP is not set
-# CONFIG_CHRP is not set
CONFIG_ALL_PPC=y
# CONFIG_GEMINI is not set
# CONFIG_APUS is not set
@@ -286,30 +283,29 @@ CONFIG_GMAC=y
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_DM9102 is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
+# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
# CONFIG_LNE390 is not set
# CONFIG_NE3210 is not set
# CONFIG_NE2K_PCI is not set
+# CONFIG_RTL8129 is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_ES3210 is not set
# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
#
@@ -499,6 +495,7 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
#
# USB HID
@@ -508,13 +505,15 @@ CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
# CONFIG_USB_GRAPHIRE is not set
# CONFIG_USB_WMFORCE is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_MIX is not set
+# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
@@ -535,6 +534,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index 17217702f..4ba96bde9 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -17,9 +17,6 @@ CONFIG_6xx=y
# CONFIG_PPC64 is not set
# CONFIG_82xx is not set
# CONFIG_8xx is not set
-# CONFIG_PMAC is not set
-# CONFIG_PREP is not set
-# CONFIG_CHRP is not set
CONFIG_ALL_PPC=y
# CONFIG_GEMINI is not set
# CONFIG_APUS is not set
@@ -286,30 +283,29 @@ CONFIG_GMAC=y
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_RTL8139 is not set
-# CONFIG_DM9102 is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
-CONFIG_NET_EISA=y
+CONFIG_NET_PCI=y
CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
-# CONFIG_DEC_ELCP is not set
+# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
-# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
# CONFIG_LNE390 is not set
# CONFIG_NE3210 is not set
# CONFIG_NE2K_PCI is not set
+# CONFIG_RTL8129 is not set
+# CONFIG_8139TOO is not set
# CONFIG_SIS900 is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_ES3210 is not set
# CONFIG_EPIC100 is not set
-# CONFIG_ZNET is not set
# CONFIG_NET_POCKET is not set
#
@@ -499,6 +495,7 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PLUSB is not set
#
# USB HID
@@ -508,13 +505,15 @@ CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
# CONFIG_USB_GRAPHIRE is not set
# CONFIG_USB_WMFORCE is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_MIX is not set
+# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
@@ -535,6 +534,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_NTFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index ea7c7c6e7..0f7167622 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -88,24 +88,14 @@ endif
ifeq ($(CONFIG_NVRAM),y)
O_OBJS += pmac_nvram.o
endif
-ifeq ($(CONFIG_6xx),y)
- O_OBJS += open_pic.o indirect_pci.o
-endif
-ifeq ($(CONFIG_PPC64),y)
- O_OBJS += open_pic.o indirect_pci.o
-endif
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o
endif
-ifeq ($(CONFIG_PMAC),y)
- O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o
-endif
-ifeq ($(CONFIG_CHRP),y)
- O_OBJS += chrp_pci.o pmac_pci.o chrp_setup.o i8259.o \
- chrp_time.o pmac_time.o prom.o
-endif
-ifeq ($(CONFIG_PREP),y)
- O_OBJS += prep_pci.o i8259.o prep_setup.o prep_nvram.o prep_time.o residual.o
+ifeq ($(CONFIG_ALL_PPC),y)
+ O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \
+ chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \
+ prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o
+ OX_OBJS += prep_setup.o
endif
ifeq ($(CONFIG_GEMINI),y)
O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o
diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c
index 5f0c4b06e..a54efc6fd 100644
--- a/arch/ppc/kernel/apus_setup.c
+++ b/arch/ppc/kernel/apus_setup.c
@@ -10,7 +10,7 @@
* TODO:
* This file needs a *really* good cleanup. Restructure and optimize.
* Make sure it can be compiled for non-APUS configs. Begin to move
- * Amiga specific stuff into linux/machine/amiga.
+ * Amiga specific stuff into mach/amiga.
*/
#include <linux/config.h>
@@ -27,6 +27,10 @@
#include <asm/logging.h>
#endif
+/* Needs INITSERIAL call in head.S! */
+#undef APUS_DEBUG
+
+
#include <linux/ide.h>
#define T_CHAR (0x0000) /* char: don't touch */
#define T_SHORT (0x4000) /* short: 12 -> 21 */
@@ -60,37 +64,6 @@ static u_short driveid_types[] = {
#define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types))
-#if 0 /* Get rid of this crud */
-/* Get the IDE stuff from the 68k file */
-#define ide_init_hwif_ports m68k_ide_init_hwif_ports
-#define ide_default_irq m68k_ide_default_irq
-#undef ide_request_irq
-#define ide_request_irq m68k_ide_request_irq
-#undef ide_free_irq
-#define ide_free_irq m68k_ide_free_irq
-#define ide_default_io_base m68k_ide_default_io_base
-#define ide_check_region m68k_ide_check_region
-#define ide_request_region m68k_ide_request_region
-#define ide_release_region m68k_ide_release_region
-#define ide_fix_driveid m68k_ide_fix_driveid
-#define ide_init_default_hwifs m68k_ide_init_default_hwifs
-#define select_t m68k_select_t
-//#include <asm/hdreg.h>
-#include <asm-m68k/ide.h>
-#undef ide_free_irq
-#undef select_t
-#undef ide_request_irq
-#undef ide_init_default_hwifs
-#undef ide_init_hwif_ports
-#undef ide_default_irq
-#undef ide_default_io_base
-#undef ide_check_region
-#undef ide_request_region
-#undef ide_release_region
-#undef ide_fix_driveid
-/*-------------------------------------------*/
-#endif
-
#include <asm/bootinfo.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
@@ -764,6 +737,12 @@ void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
/****************************************************** IRQ stuff */
__apus
+static unsigned int apus_irq_cannonicalize(unsigned int irq)
+{
+ return irq;
+}
+
+__apus
int apus_get_irq_list(char *buf)
{
#ifdef CONFIG_APUS
@@ -922,6 +901,114 @@ static void apus_kbd_init_hw(void)
}
+/****************************************************** debugging */
+
+/* some serial hardware definitions */
+#define SDR_OVRUN (1<<15)
+#define SDR_RBF (1<<14)
+#define SDR_TBE (1<<13)
+#define SDR_TSRE (1<<12)
+
+#define AC_SETCLR (1<<15)
+#define AC_UARTBRK (1<<11)
+
+#define SER_DTR (1<<7)
+#define SER_RTS (1<<6)
+#define SER_DCD (1<<5)
+#define SER_CTS (1<<4)
+#define SER_DSR (1<<3)
+
+static __inline__ void ser_RTSon(void)
+{
+ ciab.pra &= ~SER_RTS; /* active low */
+}
+
+__apus
+int __debug_ser_out( unsigned char c )
+{
+ custom.serdat = c | 0x100;
+ mb();
+ while (!(custom.serdatr & 0x2000))
+ barrier();
+ return 1;
+}
+
+__apus
+unsigned char __debug_ser_in( void )
+{
+ unsigned char c;
+
+ /* XXX: is that ok?? derived from amiga_ser.c... */
+ while( !(custom.intreqr & IF_RBF) )
+ barrier();
+ c = custom.serdatr;
+ /* clear the interrupt, so that another character can be read */
+ custom.intreq = IF_RBF;
+ return c;
+}
+
+__apus
+int __debug_serinit( void )
+{
+ unsigned long flags;
+
+ save_flags (flags);
+ cli();
+
+ /* turn off Rx and Tx interrupts */
+ custom.intena = IF_RBF | IF_TBE;
+
+ /* clear any pending interrupt */
+ custom.intreq = IF_RBF | IF_TBE;
+
+ restore_flags (flags);
+
+ /*
+ * set the appropriate directions for the modem control flags,
+ * and clear RTS and DTR
+ */
+ ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */
+ ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */
+
+#ifdef CONFIG_KGDB
+ /* turn Rx interrupts on for GDB */
+ custom.intena = IF_SETCLR | IF_RBF;
+ ser_RTSon();
+#endif
+
+ return 0;
+}
+
+__apus
+void __debug_print_hex(unsigned long x)
+{
+ int i;
+ char hexchars[] = "0123456789ABCDEF";
+
+ for (i = 0; i < 8; i++) {
+ __debug_ser_out(hexchars[(x >> 28) & 15]);
+ x <<= 4;
+ }
+ __debug_ser_out('\n');
+ __debug_ser_out('\r');
+}
+
+__apus
+void __debug_print_string(char* s)
+{
+ unsigned char c;
+ while((c = *s++))
+ __debug_ser_out(c);
+ __debug_ser_out('\n');
+ __debug_ser_out('\r');
+}
+
+__apus
+static void apus_progress(char *s, unsigned short value)
+{
+ __debug_print_string(s);
+}
+
/****************************************************** init */
/* The number of spurious interrupts */
@@ -970,7 +1057,7 @@ void apus_init_IRQ(void)
int i;
for ( i = 0 ; i < NR_IRQS ; i++ )
- irq_desc[i].ctl = &amiga_irqctrl;
+ irq_desc[i].handler = &amiga_irqctrl;
for (i = 0; i < NUM_IRQ_NODES; i++)
nodes[i].handler = NULL;
@@ -1015,7 +1102,7 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.setup_arch = apus_setup_arch;
ppc_md.setup_residual = NULL;
ppc_md.get_cpuinfo = apus_get_cpuinfo;
- ppc_md.irq_cannonicalize = NULL;
+ ppc_md.irq_cannonicalize = apus_irq_cannonicalize;
ppc_md.init_IRQ = apus_init_IRQ;
ppc_md.get_irq = apus_get_irq;
ppc_md.post_irq = apus_post_irq;
@@ -1023,6 +1110,10 @@ void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.heartbeat = apus_heartbeat;
ppc_md.heartbeat_count = 1;
#endif
+#ifdef APUS_DEBUG
+ __debug_serinit();
+ ppc_md.progress = apus_progress;
+#endif
ppc_md.init = NULL;
ppc_md.restart = apus_restart;
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 013812afc..cc647a58b 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -435,7 +435,7 @@ _GLOBAL(fake_interrupt)
* here so it's easy to add arch-specific sections later.
* -- Cort
*/
-#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
/*
* On CHRP, the Run-Time Abstraction Services (RTAS) have to be
* called with the MMU off.
@@ -475,4 +475,4 @@ enter_rtas:
mtspr SRR0,r8
mtspr SRR1,r9
rfi /* return to caller */
-#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */
+#endif /* CONFIG_ALL_PPC */
diff --git a/arch/ppc/kernel/hashtable.S b/arch/ppc/kernel/hashtable.S
index c87385c53..5593ebe18 100644
--- a/arch/ppc/kernel/hashtable.S
+++ b/arch/ppc/kernel/hashtable.S
@@ -115,11 +115,6 @@ hash_page:
stw r6,0(r2) /* update PTE (accessed/dirty bits) */
/* Convert linux-style PTE to low word of PPC-style PTE */
-#ifdef CONFIG_PPC64
- /* clear the high 32 bits just in case */
- clrldi r6,r6,32
- clrldi r4,r4,32
-#endif /* CONFIG_PPC64 */
rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
ori r4,r4,0xe04 /* clear out reserved bits */
@@ -151,10 +146,6 @@ hash_page:
.globl hash_page_patch_A
hash_page_patch_A:
lis r4,Hash_base@h /* base address of hash table */
-#ifdef CONFIG_PPC64
- /* just in case */
- clrldi r4,r4,32
-#endif
rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */
rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */
xor r4,r4,r0 /* make primary hash */
@@ -169,43 +160,89 @@ hash_page_patch_A:
/* Search the primary PTEG for a PTE whose 1st word matches r5 */
mtctr r2
addi r3,r4,-8
-1: lwzu r0,8(r3) /* get next PTE */
+1:
+#ifdef CONFIG_PPC64
+ lwzu r0,16(r3) /* get next PTE */
+#else
+ lwzu r0,8(r3) /* get next PTE */
+#endif
cmp 0,r0,r5
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ found_slot
/* Search the secondary PTEG for a matching PTE */
+#ifdef CONFIG_PPC64
+ ori r5,r5,0x2 /* set H (secondary hash) bit */
+#else
ori r5,r5,0x40 /* set H (secondary hash) bit */
+#endif
.globl hash_page_patch_B
hash_page_patch_B:
xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
xori r3,r3,0xffc0
+#ifdef CONFIG_PPC64
+ addi r3,r3,-16
+#else
addi r3,r3,-8
+#endif
mtctr r2
-2: lwzu r0,8(r3)
+2:
+#ifdef CONFIG_PPC64
+ lwzu r0,16(r3)
+#else
+ lwzu r0,8(r3)
+#endif
cmp 0,r0,r5
bdnzf 2,2b
beq+ found_slot
+#ifdef CONFIG_PPC64
+ xori r5,r5,0x2 /* clear H bit again */
+#else
xori r5,r5,0x40 /* clear H bit again */
+#endif
/* Search the primary PTEG for an empty slot */
10: mtctr r2
+#ifdef CONFIG_PPC64
+ addi r3,r4,-16 /* search primary PTEG */
+#else
addi r3,r4,-8 /* search primary PTEG */
-1: lwzu r0,8(r3) /* get next PTE */
+#endif
+1:
+#ifdef CONFIG_PPC64
+ lwzu r0,16(r3) /* get next PTE */
+ andi. r0,r0,1
+#else
+ lwzu r0,8(r3) /* get next PTE */
rlwinm. r0,r0,0,0,0 /* only want to check valid bit */
+#endif
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ found_empty
/* Search the secondary PTEG for an empty slot */
+#ifdef CONFIG_PPC64
+ ori r5,r5,0x2 /* set H (secondary hash) bit */
+#else
ori r5,r5,0x40 /* set H (secondary hash) bit */
+#endif
.globl hash_page_patch_C
hash_page_patch_C:
xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
xori r3,r3,0xffc0
+#ifdef CONFIG_PPC64
+ addi r3,r3,-16
+#else
addi r3,r3,-8
+#endif
mtctr r2
-2: lwzu r0,8(r3)
+2:
+#ifdef CONFIG_PPC64
+ lwzu r0,16(r3)
+ andi. r0,r0,1
+#else
+ lwzu r0,8(r3)
rlwinm. r0,r0,0,0,0 /* only want to check valid bit */
+#endif
bdnzf 2,2b
beq+ found_empty
@@ -218,12 +255,21 @@ hash_page_patch_C:
* advantage to putting the PTE in the primary PTEG, we always
* put the PTE in the primary PTEG.
*/
+#ifdef CONFIG_PPC64
+ xori r5,r5,0x2 /* clear H bit again */
+#else
xori r5,r5,0x40 /* clear H bit again */
+#endif
lis r3,next_slot@ha
tophys(r3,r3)
lwz r2,next_slot@l(r3)
+#ifdef CONFIG_PPC64
+ addi r2,r2,16
+ andi. r2,r2,0x78
+#else
addi r2,r2,8
andi. r2,r2,0x38
+#endif
stw r2,next_slot@l(r3)
add r3,r4,r2
11:
@@ -237,9 +283,17 @@ hash_page_patch_C:
#ifndef __SMP__
/* Store PTE in PTEG */
found_empty:
+#ifdef CONFIG_PPC64
+ std r5,0(r3)
+#else
stw r5,0(r3)
+#endif
found_slot:
+#ifdef CONFIG_PPC64
+ std r6,8(r3)
+#else
stw r6,4(r3)
+#endif
sync
#else /* __SMP__ */
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index dd16b8c27..b6d44ecb3 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1328,18 +1328,15 @@ load_up_mmu:
/* Load the SDR1 register (hash table base & size) */
lis r6,_SDR1@ha
tophys(r6,r6)
-#ifdef CONFIG_PPC64
- ld r6,_SDR1@l(r6)
+ lwz r6,_SDR1@l(r6)
mtspr SDR1,r6
+#ifdef CONFIG_PPC64
/* clear the v bit in the ASR so we can
* behave as if we have segment registers
* -- Cort
*/
clrldi r6,r6,63
mtasr r6
-#else
- lwz r6,_SDR1@l(r6)
- mtspr SDR1,r6
#endif /* CONFIG_PPC64 */
li r0,16 /* load up segment register values */
mtctr r0 /* for context 0 */
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index fd77fbc36..ffac1871a 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -70,8 +70,6 @@ volatile unsigned char *chrp_int_ack_special;
#define MAXCOUNT 10000000
-#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
-
irq_desc_t irq_desc[NR_IRQS];
int ppc_spurious_interrupts = 0;
unsigned int local_bh_count[NR_CPUS];
@@ -81,7 +79,6 @@ unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
atomic_t ppc_n_lost_interrupts;
-
/* nasty hack for shared irq's since we need to do kmalloc calls but
* can't very early in the boot when we need to do a request irq.
* this needs to be removed.
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 50f63eeb4..8444bb4a0 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -241,12 +241,21 @@ _GLOBAL(__flush_page_to_ram)
rlwinm r5,r5,16,16,31
cmpi 0,r5,1
beqlr /* for 601, do nothing */
+ li r4,0x0FFF
+ andc r3,r3,r4 /* Get page base address */
li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
mtctr r4
+ mr r6,r3
0: dcbst 0,r3 /* Write line to ram */
addi r3,r3,CACHE_LINE_SIZE
bdnz 0b
sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
blr
/*
@@ -270,7 +279,7 @@ _GLOBAL(__flush_icache_page)
sync
isync
blr
-
+
/*
* Clear a page using the dcbz instruction, which doesn't cause any
* memory traffic (except to write out any cache lines which get
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 4f3c6834d..c381ea073 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -99,6 +99,7 @@ main(void)
DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+ DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq));
DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
index d13875c9f..b0276ca2c 100644
--- a/arch/ppc/kernel/pmac_pic.c
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -39,6 +39,17 @@ extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn
extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
unsigned char offset, unsigned short val);
+/*
+ * Mark an irq as "lost". This is only used on the pmac
+ * since it can lose interrupts (see pmac_set_irq_mask).
+ * -- Cort
+ */
+void __pmac __no_use_set_lost(unsigned long irq_nr)
+{
+ if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
+ atomic_inc(&ppc_n_lost_interrupts);
+}
+
static void pmac_openpic_mask_irq(unsigned int irq_nr)
{
openpic_disable_irq(irq_nr);
@@ -105,10 +116,8 @@ static void __pmac pmac_set_irq_mask(unsigned int irq_nr)
*/
if ((bit & ppc_cached_irq_mask[i])
&& (ld_le32(&pmac_irq_hw[i]->level) & bit)
- && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
- if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
- atomic_inc(&ppc_n_lost_interrupts);
- }
+ && !(ld_le32(&pmac_irq_hw[i]->flag) & bit))
+ __set_lost((ulong)irq_nr);
}
static void __pmac pmac_mask_irq(unsigned int irq_nr)
@@ -174,6 +183,8 @@ pmac_get_irq(struct pt_regs *regs)
unsigned long bits = 0;
#ifdef __SMP__
+ void pmac_smp_message_recv(void);
+
/* IPI's are a hack on the powersurge -- Cort */
if ( smp_processor_id() != 0 )
{
@@ -182,12 +193,12 @@ pmac_get_irq(struct pt_regs *regs)
if (xmon_2nd)
xmon(regs);
#endif
- smp_message_recv();
+ pmac_smp_message_recv();
return -2; /* ignore, already handled */
}
#endif /* __SMP__ */
- /* Yeah, I know, this could be a separate do_IRQ function */
+ /* Yeah, I know, this could be a separate get_irq function */
if (has_openpic)
{
irq = openpic_irq(smp_processor_id());
@@ -376,6 +387,7 @@ pmac_pic_init(void)
irqctrler = NULL;
}
+ int_control.int_set_lost = __no_use_set_lost;
/*
* G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
* 1998 G3 Series PowerBooks have 128,
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 264a24d48..da46f3c1c 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -44,19 +44,12 @@ extern unsigned long htab_evicts;
extern unsigned long pte_misses;
extern unsigned long pte_errors;
-static struct file_operations ppc_htab_operations = {
+struct file_operations ppc_htab_operations = {
llseek: ppc_htab_lseek,
read: ppc_htab_read,
write: ppc_htab_write,
};
-/*
- * proc files can do almost nothing..
- */
-struct inode_operations proc_ppc_htab_inode_operations = {
- &ppc_htab_operations, /* default proc file-ops */
-};
-
/* these will go into processor.h when I'm done debugging -- Cort */
#define MMCR0 952
#define MMCR0_PMC1_CYCLES (0x1<<7)
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 757715512..87c8d4082 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -34,6 +34,7 @@
#include <asm/feature.h>
#include <asm/dma.h>
#include <asm/machdep.h>
+#include <asm/hw_irq.h>
#ifdef __SMP__
#include <asm/smplock.h>
#endif /* __SMP__ */
@@ -50,7 +51,6 @@ extern void AlignmentException(struct pt_regs *regs);
extern void ProgramCheckException(struct pt_regs *regs);
extern void SingleStepException(struct pt_regs *regs);
extern int sys_sigreturn(struct pt_regs *regs);
-extern atomic_t ppc_n_lost_interrupts;
extern void do_lost_interrupts(unsigned long);
extern int do_signal(sigset_t *, struct pt_regs *);
@@ -69,6 +69,7 @@ EXPORT_SYMBOL(ProgramCheckException);
EXPORT_SYMBOL(SingleStepException);
EXPORT_SYMBOL(sys_sigreturn);
EXPORT_SYMBOL(ppc_n_lost_interrupts);
+EXPORT_SYMBOL(ppc_lost_interrupts);
EXPORT_SYMBOL(do_lost_interrupts);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
@@ -88,7 +89,7 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
#ifndef CONFIG_8xx
-#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(_prep_type);
EXPORT_SYMBOL(ucSystemType);
#endif
@@ -125,7 +126,6 @@ EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strspn);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strncmp);
@@ -227,7 +227,7 @@ EXPORT_SYMBOL(pmu_register_sleep_notifier);
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
EXPORT_SYMBOL(pmu_enable_irled);
#endif CONFIG_PMAC_PBOOK
-#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(find_devices);
EXPORT_SYMBOL(find_type_devices);
EXPORT_SYMBOL(find_compatible_devices);
@@ -243,8 +243,8 @@ EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
-#endif /* defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) */
-#if defined(CONFIG_SCSI) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC))
+#endif /* defined(CONFIG_ALL_PPC) */
+#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(note_scsi_host);
#endif
EXPORT_SYMBOL(kd_mksound);
@@ -270,7 +270,6 @@ EXPORT_SYMBOL(screen_info);
EXPORT_SYMBOL(int_control);
EXPORT_SYMBOL(timer_interrupt_intercept);
EXPORT_SYMBOL(timer_interrupt);
-extern unsigned long do_IRQ_intercept;
EXPORT_SYMBOL(do_IRQ_intercept);
EXPORT_SYMBOL(irq_desc);
void ppc_irq_dispatch_handler(struct pt_regs *, int);
@@ -278,3 +277,7 @@ EXPORT_SYMBOL(ppc_irq_dispatch_handler);
EXPORT_SYMBOL(decrementer_count);
EXPORT_SYMBOL(get_wchan);
EXPORT_SYMBOL(console_drivers);
+#ifdef CONFIG_XMON
+EXPORT_SYMBOL(xmon);
+#endif
+EXPORT_SYMBOL(down_read_failed);
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index 41382b2d7..5c01d3c72 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -158,7 +158,7 @@ enable_kernel_altivec(void)
if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
giveup_altivec(current);
else
- giveup_altivec(NULL): /* just enable AltiVec for kernel - force */
+ giveup_altivec(NULL); /* just enable AltiVec for kernel - force */
#else
giveup_altivec(last_task_used_altivec);
#endif /* __SMP __ */
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index b86e2a153..4ee638f62 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -604,7 +604,6 @@ prom_init(int r3, int r4, prom_entry pp)
/* XXX: hack - don't start cpu 0, this cpu -- Cort */
if ( smp_chrp_cpu_nr++ == 0 )
continue;
- RELOC(smp_ibm_chrp_hack) = 1;
prom_print(RELOC("starting cpu "));
prom_print(path);
*(unsigned long *)(0x4) = 0;
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 7502ad08e..5a57ba8a2 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -733,17 +733,13 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
id->eide_pio = __le16_to_cpu(id->eide_pio);
id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
- id->word69 = __le16_to_cpu(id->word69);
- id->word70 = __le16_to_cpu(id->word70);
- id->word71 = __le16_to_cpu(id->word71);
- id->word72 = __le16_to_cpu(id->word72);
- id->word73 = __le16_to_cpu(id->word73);
- id->word74 = __le16_to_cpu(id->word74);
+ for (i=0; i<2 i++)
+ id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+ for (i=0; i<4 i++)
+ id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
id->queue_depth = __le16_to_cpu(id->queue_depth);
- id->word76 = __le16_to_cpu(id->word76);
- id->word77 = __le16_to_cpu(id->word77);
- id->word78 = __le16_to_cpu(id->word78);
- id->word79 = __le16_to_cpu(id->word79);
+ for (i=0; i<4 i++)
+ id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
id->major_rev_num = __le16_to_cpu(id->major_rev_num);
id->minor_rev_num = __le16_to_cpu(id->minor_rev_num);
id->command_set_1 = __le16_to_cpu(id->command_set_1);
@@ -758,40 +754,14 @@ void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
id->word92 = __le16_to_cpu(id->word92);
id->hw_config = __le16_to_cpu(id->hw_config);
- id->word94 = __le16_to_cpu(id->word94);
- id->word95 = __le16_to_cpu(id->word95);
- id->word96 = __le16_to_cpu(id->word96);
- id->word97 = __le16_to_cpu(id->word97);
- id->word98 = __le16_to_cpu(id->word98);
- id->word99 = __le16_to_cpu(id->word99);
- id->word100 = __le16_to_cpu(id->word100);
- id->word101 = __le16_to_cpu(id->word101);
- id->word102 = __le16_to_cpu(id->word102);
- id->word103 = __le16_to_cpu(id->word103);
- id->word104 = __le16_to_cpu(id->word104);
- id->word105 = __le16_to_cpu(id->word105);
- id->word106 = __le16_to_cpu(id->word106);
- id->word107 = __le16_to_cpu(id->word107);
- id->word108 = __le16_to_cpu(id->word108);
- id->word109 = __le16_to_cpu(id->word109);
- id->word110 = __le16_to_cpu(id->word110);
- id->word111 = __le16_to_cpu(id->word111);
- id->word112 = __le16_to_cpu(id->word112);
- id->word113 = __le16_to_cpu(id->word113);
- id->word114 = __le16_to_cpu(id->word114);
- id->word115 = __le16_to_cpu(id->word115);
- id->word116 = __le16_to_cpu(id->word116);
- id->word117 = __le16_to_cpu(id->word117);
- id->word118 = __le16_to_cpu(id->word118);
- id->word119 = __le16_to_cpu(id->word119);
- id->word120 = __le16_to_cpu(id->word120);
- id->word121 = __le16_to_cpu(id->word121);
- id->word122 = __le16_to_cpu(id->word122);
- id->word123 = __le16_to_cpu(id->word123);
- id->word124 = __le16_to_cpu(id->word124);
- id->word125 = __le16_to_cpu(id->word125);
- id->word126 = __le16_to_cpu(id->word126);
+ for (i=0; i<34; i++)
+ id->words94_125[i] = __le16_to_cpu(id->words94_125[i]);
+ id->last_lun = __le16_to_cpu(id->last_lun);
id->word127 = __le16_to_cpu(id->word127);
- for (i=0; i<127; i++)
- id->reserved[i] = __le16_to_cpu(id->reserved[i]);
+ id->dlf = __le16_to_cpu(id->dlf);
+ id->csfo = __le16_to_cpu(id->csfo);
+ for (i=0; i<31; i++)
+ id->words130_159[i] = __le16_to_cpu(id->words130_159[i]);
+ for (i=0; i<97; i++)
+ id->words160_255[i] = __le16_to_cpu(id->words160_255[i]);
}
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 83dff9246..97543348b 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -12,6 +12,7 @@
* (troy@microux.com, hozer@drgw.net)
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
@@ -445,8 +446,10 @@ void __init smp_callin(void)
*/
if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
do_openpic_setup_cpu();
+#ifdef CONFIG_GEMINI
if ( _machine == _MACH_gemini )
gemini_init_l2();
+#endif
while(!smp_commenced)
barrier();
__sti();
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 25d728fdd..2faccd042 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -115,11 +115,7 @@ extern struct task_struct *current_set[NR_CPUS];
PTE *Hash, *Hash_end;
unsigned long Hash_size, Hash_mask;
#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-#ifdef CONFIG_PPC64
-unsigned long long _SDR1;
-#else
unsigned long _SDR1;
-#endif
static void hash_init(void);
union ubat { /* BAT register values to be loaded */
@@ -423,10 +419,9 @@ __ioremap(unsigned long addr, unsigned long size, unsigned long flags)
/*
* Is it a candidate for a BAT mapping?
*/
-
for (i = 0; i < size; i += PAGE_SIZE)
map_page(v+i, p+i, flags);
-out:
+out:
return (void *) (v + (addr & ~PAGE_MASK));
}
@@ -593,7 +588,7 @@ mmu_context_overflow(void)
#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
static void get_mem_prop(char *, struct mem_pieces *);
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
/*
* Read in a property describing some pieces of memory.
*/
@@ -616,7 +611,7 @@ static void __init get_mem_prop(char *name, struct mem_pieces *mp)
mem_pieces_sort(mp);
mem_pieces_coalesce(mp);
}
-#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */
+#endif /* CONFIG_ALL_PPC */
/*
* Set up one of the I/D BAT (block address translation) register pairs.
@@ -921,10 +916,11 @@ void __init MMU_init(void)
if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300);
hash_init();
#ifdef CONFIG_PPC64
- _SDR1 = 0; /* temporary hack to just use bats -- Cort */
-#else
+ _SDR1 = __pa(Hash) | (ffz(~Hash_size) - 7)-11;
+#else
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#endif
+#endif
+
ioremap_base = 0xf8000000;
if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301);
@@ -947,7 +943,7 @@ void __init MMU_init(void)
setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE);
#ifdef CONFIG_PPC64
/* temporary hack to get working until page tables are stable -- Cort*/
- setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE);
+/* setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE);*/
setbat(3, 0xd0000000, 0xd0000000, 0x10000000, IO_PAGE);
#else
setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
@@ -1118,7 +1114,7 @@ void __init paging_init(void)
/*
* All pages are DMA-able so we put them all in the DMA zone.
*/
- zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT;
+ zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT;
for (i = 1; i < MAX_NR_ZONES; i++)
zones_size[i] = 0;
free_area_init(zones_size);
@@ -1132,9 +1128,9 @@ void __init mem_init(void)
int codepages = 0;
int datapages = 0;
int initpages = 0;
-#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
extern unsigned int rtas_data, rtas_size;
-#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
+#endif /* defined(CONFIG_ALL_PPC) */
max_mapnr = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
num_physpages = max_mapnr; /* RAM is assumed contiguous */
@@ -1150,13 +1146,13 @@ void __init mem_init(void)
}
#endif /* CONFIG_BLK_DEV_INITRD */
-#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
/* mark the RTAS pages as reserved */
if ( rtas_data )
for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ;
addr += PAGE_SIZE)
SetPageReserved(mem_map + MAP_NR(addr));
-#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */
+#endif /* defined(CONFIG_ALL_PPC) */
if ( sysmap_size )
for (addr = (unsigned long)sysmap;
addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ;
@@ -1178,13 +1174,14 @@ void __init mem_init(void)
printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
(unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
- codepages, datapages, initpages,
+ codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
+ initpages<< (PAGE_SHIFT-10),
PAGE_OFFSET, (unsigned long) end_of_DRAM);
mem_init_done = 1;
}
#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
/*
* On systems with Open Firmware, collect information about
* physical RAM and which pieces are already in use.
@@ -1195,9 +1192,13 @@ void __init mem_init(void)
unsigned long __init *pmac_find_end_of_memory(void)
{
unsigned long a, total;
-
- /* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (768<<20)
+ unsigned long ram_limit = 0xf0000000 - KERNELBASE;
+ /* allow 0x08000000 for IO space */
+ if ( _machine & (_MACH_prep|_MACH_Pmac) )
+ ram_limit = 0xd8000000 - KERNELBASE;
+#ifdef CONFIG_PPC64
+ ram_limit = 64<<20;
+#endif
memory_node = find_devices("memory");
if (memory_node == NULL) {
@@ -1222,16 +1223,8 @@ unsigned long __init *pmac_find_end_of_memory(void)
a = phys_mem.regions[0].address;
if (a != 0)
panic("RAM doesn't start at physical address 0");
- /*
- * XXX:
- * Make sure ram mappings don't stomp on IO space
- * This is a temporary hack to keep this from happening
- * until we move the KERNELBASE and can allocate RAM up
- * to our nearest IO area.
- * -- Cort
- */
- if (__max_memory == 0 || __max_memory > RAM_LIMIT)
- __max_memory = RAM_LIMIT;
+ if (__max_memory == 0 || __max_memory > ram_limit)
+ __max_memory = ram_limit;
if (phys_mem.regions[0].size >= __max_memory) {
phys_mem.regions[0].size = __max_memory;
phys_mem.n_regions = 1;
@@ -1247,12 +1240,11 @@ unsigned long __init *pmac_find_end_of_memory(void)
set_phys_avail(&phys_mem);
-#undef RAM_LIMIT
return __va(total);
}
-#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */
+#endif /* CONFIG_ALL_PPC */
-#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_ALL_PPC)
/*
* This finds the amount of physical ram and does necessary
* setup for prep. This is pretty architecture specific so
@@ -1279,7 +1271,7 @@ unsigned long __init *prep_find_end_of_memory(void)
return (__va(total));
}
-#endif /* defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) */
+#endif /* defined(CONFIG_ALL_PPC) */
#if defined(CONFIG_GEMINI)
@@ -1389,16 +1381,12 @@ static void __init hash_init(void)
* up to a maximum of 2MB.
*/
ramsize = (ulong)end_of_DRAM - KERNELBASE;
-#ifdef CONFIG_PPC64
- Hash_mask = 0;
- for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++)
- ;
- Hash_size = h;
- Hash_mask <<= 10; /* so setting _SDR1 works the same -- Cort */
-#else
for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2)
;
Hash_size = h;
+#ifdef CONFIG_PPC64
+ Hash_mask = (h >> 7) - 1;
+#else
Hash_mask = (h >> 6) - 1;
#endif
@@ -1433,7 +1421,11 @@ static void __init hash_init(void)
/*
* Patch up the instructions in head.S:hash_page
*/
+#ifdef CONFIG_PPC64
+ Hash_bits = ffz(~Hash_size) - 7;
+#else
Hash_bits = ffz(~Hash_size) - 6;
+#endif
hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
| (__pa(Hash) >> 16);
hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
@@ -1443,9 +1435,17 @@ static void __init hash_init(void)
hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
| ((26 - Hash_bits) << 6);
hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+#ifdef CONFIG_PPC64
+ | (Hash_mask >> 11);
+#else
| (Hash_mask >> 10);
+#endif
hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+#ifdef CONFIG_PPC64
+ | (Hash_mask >> 11);
+#else
| (Hash_mask >> 10);
+#endif
#if 0 /* see hash_page in head.S, note also patch_C ref below */
hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff)
| (Hash_mask >> 10);
diff --git a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c
index e695d5a0a..309a526f5 100644
--- a/arch/ppc/mm/mem_pieces.c
+++ b/arch/ppc/mm/mem_pieces.c
@@ -127,7 +127,7 @@ mem_pieces_print(struct mem_pieces *mp)
printk("\n");
}
-#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
+#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC)
/*
* Add some memory to an array of pieces
*/
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
index a0da2f1b4..d18d74dfd 100644
--- a/arch/ppc/xmon/xmon.c
+++ b/arch/ppc/xmon/xmon.c
@@ -75,11 +75,14 @@ static void take_input(char *);
static unsigned read_spr(int);
static void write_spr(int, unsigned);
static void super_regs(void);
+static void print_sysmap(void);
static void remove_bpts(void);
static void insert_bpts(void);
static struct bpt *at_breakpoint(unsigned pc);
static void bpt_cmds(void);
static void cacheflush(void);
+static char *pretty_lookup_name(unsigned long addr);
+static char *lookup_name(unsigned long addr);
extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
extern void printf(const char *fmt, ...);
@@ -101,6 +104,7 @@ Commands:\n\
mm move a block of memory\n\
ms set a block of memory\n\
md compare two blocks of memory\n\
+ M print System.map\n\
r print registers\n\
S print special registers\n\
t print backtrace\n\
@@ -337,6 +341,8 @@ cmds(struct pt_regs *excp)
else
excprint(excp);
break;
+ case 'M':
+ print_sysmap();
case 'S':
super_regs();
break;
@@ -514,8 +520,10 @@ getsp()
void
excprint(struct pt_regs *fp)
{
- printf("vector: %x at pc = %x, msr = %x, sp = %x [%x]\n",
- fp->trap, fp->nip, fp->msr, fp->gpr[1], fp);
+ printf("vector: %x at pc = %x %s",
+ fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/"");
+ printf(", msr = %x, sp = %x [%x]\n",
+ fp->msr, fp->gpr[1], fp);
if (fp->trap == 0x300 || fp->trap == 0x600)
printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
if (current)
@@ -597,6 +605,14 @@ extern char exc_prolog;
extern char dec_exc;
void
+print_sysmap(void)
+{
+ extern char *sysmap;
+ if ( sysmap )
+ printf("System.map: \n%s", sysmap);
+}
+
+void
super_regs()
{
int i, cmd;
@@ -1345,9 +1361,26 @@ char *str;
lineptr = str;
}
+/*
+ * We use this array a lot here. We assume we don't have multiple
+ * instances of xmon running and that we don't use the return value of
+ * any functions other than printing them.
+ * -- Cort
+ */
char last[64];
-char *
-lookup_addr(unsigned long addr)
+static char *pretty_lookup_name(unsigned long addr)
+{
+ if ( lookup_name(addr) )
+ {
+ sprintf(last, " (%s)", lookup_name(addr));
+ return last;
+ }
+ else
+ return NULL;
+}
+
+
+static char *lookup_name(unsigned long addr)
{
extern char *sysmap;
extern unsigned long sysmap_size;
@@ -1357,10 +1390,6 @@ lookup_addr(unsigned long addr)
if ( !sysmap || !sysmap_size )
return NULL;
- /* adjust if addr is relative to kernelbase */
- if ( addr < PAGE_OFFSET )
- addr += PAGE_OFFSET;
-
cmp = simple_strtoul(c, &c, 8);
strcpy( last, strsep( &c, "\n"));
while ( c < (sysmap+sysmap_size) )
@@ -1372,3 +1401,4 @@ lookup_addr(unsigned long addr)
}
return last;
}
+
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index b0f7f63ea..a7a562549 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $
+# $Id: Makefile,v 1.10 2000/02/23 08:17:46 jj Exp $
# Makefile for the Sparc boot stuff.
#
# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -22,16 +22,20 @@ btfixupprep: btfixupprep.c
clean:
rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s
-BTOBJS := $(HEAD) init/main.o init/version.o \
- $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
- $(NETWORKS) $(DRIVERS)
+BTOBJS := $(HEAD) init/main.o init/version.o
+BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
+ $(DRIVERS) $(NETWORKS)
# I wanted to make this depend upon BTOBJS so that a parallel
# build would work, but this fails because $(HEAD) cannot work
# properly as it will cause head.o to be built with the implicit
# rules not the ones in kernel/Makefile. Someone please fix. --DaveM
vmlinux.o: dummy
- $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
+ $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
+ --start-group \
+ $(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \
+ $(LIBS) \
+ --end-group -o vmlinux.o
btfix.s: btfixupprep vmlinux.o
$(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 8c8903d26..f0dbea065 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -695,42 +695,6 @@ _sparc_io_get_info(char *buf, char **start, off_t fpos, int length, int *eof,
return p-buf;
}
-static struct proc_dir_entry _sparc_iomap_proc_entry = {
- 0, /* Inode number - dynamic */
- 6, /* Length of the file name */
- "io_map", /* The file name */
- S_IFREG | S_IRUGO, /* File mode */
- 1, /* Number of links */
- 0, 0, /* The uid and gid for the file */
- 0, /* The size of the file reported by ls. */
- NULL, /* struct inode_operations * ops */
- NULL, /* get_info: backward compatibility */
- NULL, /* owner */
- NULL, NULL, NULL, /* linkage */
- &sparc_iomap,
- _sparc_io_get_info, /* The read function for this file */
- NULL,
- /* and more stuff */
-};
-
-static struct proc_dir_entry _sparc_dvma_proc_entry = {
- 0, /* Inode number - dynamic */
- 8, /* Length of the file name */
- "dvma_map", /* The file name */
- S_IFREG | S_IRUGO, /* File mode */
- 1, /* Number of links */
- 0, 0, /* The uid and gid for the file */
- 0, /* The size of the file reported by ls. */
- NULL, /* struct inode_operations * ops */
- NULL, /* get_info: backward compatibility */
- NULL, /* owner */
- NULL, NULL, NULL, /* linkage */
- &_sparc_dvma,
- _sparc_io_get_info,
- NULL,
- /* some more stuff */
-};
-
#endif CONFIG_PROC_FS
/*
@@ -782,7 +746,7 @@ void ioport_init(void)
};
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &_sparc_iomap_proc_entry);
- proc_register(&proc_root, &_sparc_dvma_proc_entry);
+ create_proc_read_entry("io_map",0,0,_sparc_io_get_info,&sparc_iomap);
+ create_proc_read_entry("dvma_map",0,0,_sparc_io_get_info,&_sparc_dvma);
#endif
}
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 471929a01..07aefa660 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.101 2000/02/09 11:15:03 davem Exp $
+/* $Id: irq.c,v 1.102 2000/02/25 05:44:35 davem Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -713,3 +713,8 @@ void __init init_IRQ(void)
}
btfixup();
}
+
+void init_irq_proc(void)
+{
+ /* For now, nothing... */
+}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 50d682929..d4ac34932 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.114 2000/01/29 01:08:57 anton Exp $
+/* $Id: setup.c,v 1.115 2000/02/26 04:24:31 davem Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -294,6 +294,8 @@ static struct console prom_console = {
"PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0
};
+extern void paging_init(void);
+
void __init setup_arch(char **cmdline_p)
{
int i;
@@ -478,6 +480,8 @@ void __init setup_arch(char **cmdline_p)
if (serial_console)
conswitchp = NULL;
+
+ paging_init();
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index cdc1f0751..d4585d9d5 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.91 2000/02/18 20:23:24 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.93 2000/02/26 11:02:45 anton Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -92,7 +92,6 @@ __attribute__((section("__ksymtab"))) = \
/* used by various drivers */
EXPORT_SYMBOL(sparc_cpu_model);
-EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
EXPORT_SYMBOL(kernel_thread);
#ifdef SPIN_LOCK_DEBUG
EXPORT_SYMBOL(_do_spin_lock);
@@ -246,7 +245,6 @@ EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strspn);
/* Special internal versions of library functions. */
EXPORT_SYMBOL(__copy_1page);
diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S
index 102541b18..e199f3813 100644
--- a/arch/sparc/lib/locks.S
+++ b/arch/sparc/lib/locks.S
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $
+/* $Id: locks.S,v 1.16 2000/02/26 11:02:47 anton Exp $
* locks.S: SMP low-level lock primitives on Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,25 +15,6 @@
.text
.align 4
- /* This is called when the initial acquisition attempt of a spin
- * lock fails. The calling convention is weird, return address
- * is in %o7 as usual but we agree with the caller to only touch
- * and use %g2 as a temporary. We are passed a ptr to the lock
- * itself in %g1, %g4 must be restored into %o7 when we return,
- * and the caller wants us to return to him at three instructions
- * previous to the call instruction which got us here. See how
- * this is used in asm/spinlock.h if what I just said confuses
- * you to no end.
- */
- .globl ___spinlock_waitfor
-___spinlock_waitfor:
-1: orcc %g2, 0x0, %g0
- bne,a 1b
- ldub [%g1], %g2
- ldstub [%g1], %g2
- jmpl %o7 - 12, %g0
- mov %g4, %o7
-
/* Read/writer locks, as usual this is overly clever to make it
* as fast as possible.
*/
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 6736dc9d3..3ac49a10b 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.80 2000/02/09 21:11:06 davem Exp $
+/* $Id: init.c,v 1.81 2000/02/26 11:59:31 anton Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -40,7 +40,7 @@ unsigned long phys_base;
struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
unsigned long sparc_unmapped_base;
-struct pgtable_cache_struct pgt_quicklists;
+struct pgtable_cache_struct pgt_quicklists = { 0, 0, 0, 0, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED };
/* References to section boundaries */
extern char __init_begin, __init_end, _start, end, etext , edata;
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 917bb5e74..12e9432a7 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -273,9 +273,9 @@ CONFIG_SUNBMAC=m
CONFIG_SUNQE=m
CONFIG_DE4X5=m
CONFIG_VORTEX=m
-CONFIG_RTL8139=m
+CONFIG_8139TOO=m
CONFIG_NE2K_PCI=m
-CONFIG_EEXPRESS_PRO100=m
+CONFIG_EEPRO100=m
CONFIG_ADAPTEC_STARFIRE=m
#
@@ -299,7 +299,7 @@ CONFIG_VIDEO_DEV=y
# CONFIG_VIDEO_BT848 is not set
#
-# Filesystems
+# File systems
#
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=m
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index cb659b655..ed9e49685 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.83 2000/02/11 06:57:17 jj Exp $
+/* $Id: irq.c,v 1.84 2000/02/25 05:44:41 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -1156,3 +1156,8 @@ void __init init_IRQ(void)
: "i" (PSTATE_IE)
: "g1");
}
+
+void init_irq_proc(void)
+{
+ /* For now, nothing... */
+}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 0f280f818..ed2e8bd81 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.50 1999/12/01 10:44:45 davem Exp $
+/* $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -451,6 +451,8 @@ void register_prom_callbacks(void)
"' linux-.soft2 to .soft2");
}
+extern void paging_init(void);
+
void __init setup_arch(char **cmdline_p)
{
extern int serial_console; /* in console.c, of course */
@@ -587,6 +589,8 @@ void __init setup_arch(char **cmdline_p)
#endif
if (serial_console)
conswitchp = NULL;
+
+ paging_init();
}
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index f226a8ae5..8df2116e7 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -1,4 +1,4 @@
-/* $Id: signal32.c,v 1.59 2000/01/21 11:38:52 jj Exp $
+/* $Id: signal32.c,v 1.60 2000/02/25 06:02:37 jj Exp $
* arch/sparc64/kernel/signal32.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -126,6 +126,8 @@ int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
break;
+ case SIGURG:
+ case SIGIO:
case SIGSEGV:
case SIGILL:
case SIGFPE:
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index ff3843651..f798358ce 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.74 2000/02/09 11:15:07 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.75 2000/02/21 15:50:08 davem Exp $
* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -261,7 +261,6 @@ EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strpbrk);
EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strspn);
#ifdef CONFIG_SOLARIS_EMUL_MODULE
EXPORT_SYMBOL(getname32);
diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S
index aad5d941a..9f77c8cb4 100644
--- a/arch/sparc64/lib/VIScsum.S
+++ b/arch/sparc64/lib/VIScsum.S
@@ -1,14 +1,15 @@
-/* $Id: VIScsum.S,v 1.5 1999/07/30 09:35:36 davem Exp $
+/* $Id: VIScsum.S,v 1.6 2000/02/20 23:21:39 davem Exp $
* VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
* Visual Instruction Set.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
*
* Based on older sparc32/sparc64 checksum.S, which is:
*
* Copyright(C) 1995 Linus Torvalds
* Copyright(C) 1995 Miguel de Icaza
- * Copyright(C) 1996,1997 David S. Miller
+ * Copyright(C) 1996, 1997 David S. Miller
* derived from:
* Linux/Alpha checksum c-code
* Linux/ix86 inline checksum assembly
@@ -38,290 +39,290 @@
* tricks are UltraLinux trade secrets :))
*/
-#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \
- fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \
- fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \
- fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \
- fcmpgt32 %fz, %f6, %g5 /* FPM Group */; \
- inc %g1 /* IEU0 */; \
- fcmpgt32 %fz, %f8, %g7 /* FPM Group */; \
- srl %g1, 1, %g1 /* IEU0 */; \
- inc %g2 /* IEU1 */; \
- fcmpgt32 %fz, %f10, %o3 /* FPM Group */; \
- srl %g2, 1, %g2 /* IEU0 */; \
- add %o2, %g1, %o2 /* IEU1 */; \
- add %g3, 1, %g3 /* IEU0 Group */; \
- srl %g3, 1, %g3 /* IEU0 Group */; \
- add %o2, %g2, %o2 /* IEU1 */; \
- inc %g5 /* IEU0 Group */; \
- add %o2, %g3, %o2 /* IEU1 */;
+#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \
+ fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \
+ fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \
+ fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \
+ inc %g1 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f6, %g5 /* FPM */; \
+ srl %g1, 1, %g1 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f8, %g7 /* FPM */; \
+ inc %g2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f10, %o3 /* FPM */; \
+ srl %g2, 1, %g2 /* IEU0 Group */; \
+ inc %g3 /* IEU1 */; \
+ srl %g3, 1, %g3 /* IEU0 Group */; \
+ add %o2, %g1, %o2 /* IEU1 */; \
+ add %o2, %g2, %o2 /* IEU0 Group */; \
+ inc %g5 /* IEU1 */; \
+ add %o2, %g3, %o2 /* IEU0 Group */;
-#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \
- fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \
- srl %g5, 1, %g5 /* IEU0 */; \
- inc %g7 /* IEU1 */; \
- fpadd32 %F0, %f0, %F0 /* FPA */; \
- fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \
- srl %g7, 1, %g7 /* IEU0 */; \
- add %o2, %g5, %o2 /* IEU1 */; \
- fpadd32 %F2, %f2, %F2 /* FPA */; \
- inc %o3 /* IEU0 Group */; \
- add %o2, %g7, %o2 /* IEU1 */; \
- fcmpgt32 %f0, %F0, %g1 /* FPM Group */; \
- srl %o3, 1, %o3 /* IEU0 */; \
- inc %o4 /* IEU1 */; \
- fpadd32 %F4, %f4, %F4 /* FPA */; \
- fcmpgt32 %f2, %F2, %g2 /* FPM Group */; \
- srl %o4, 1, %o4 /* IEU0 */; \
- add %o2, %o3, %o2 /* IEU1 */; \
- fpadd32 %F6, %f6, %F6 /* FPA */; \
- inc %o5 /* IEU0 Group */; \
- add %o2, %o4, %o2 /* IEU1 */; \
- fcmpgt32 %f4, %F4, %g3 /* FPM Group */; \
- srl %o5, 1, %o5 /* IEU0 */; \
- inc %g1 /* IEU1 */; \
- fpadd32 %F8, %f8, %F8 /* FPA */; \
- fcmpgt32 %f6, %F6, %g5 /* FPM Group */; \
- srl %g1, 1, %g1 /* IEU0 */; \
- add %o2, %o5, %o2 /* IEU1 */; \
- fpadd32 %F10, %f10, %F10 /* FPA */; \
- inc %g2 /* IEU0 Group */; \
- add %o2, %g1, %o2 /* IEU1 */; \
- fcmpgt32 %f8, %F8, %g7 /* FPM Group */; \
- srl %g2, 1, %g2 /* IEU0 */; \
- inc %g3 /* IEU1 */; \
- fpadd32 %F12, %f12, %F12 /* FPA */; \
- fcmpgt32 %f10, %F10, %o3 /* FPM Group */; \
- srl %g3, 1, %g3 /* IEU0 */; \
- add %o2, %g2, %o2 /* IEU1 */; \
- fpadd32 %F14, %f14, %F14 /* FPA */; \
- inc %g5 /* IEU0 Group */; \
- add %o2, %g3, %o2 /* IEU1 */;
+#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \
+ srl %g5, 1, %g5 /* IEU0 Group */; \
+ fpadd32 %F0, %f0, %F0 /* FPA */; \
+ fcmpgt32 %O12, %f12, %o4 /* FPM */; \
+ inc %g7 /* IEU0 Group */; \
+ fpadd32 %F2, %f2, %F2 /* FPA */; \
+ fcmpgt32 %O14, %f14, %o5 /* FPM */; \
+ add %o2, %g5, %o2 /* IEU1 Group */; \
+ fpadd32 %F4, %f4, %F4 /* FPA */; \
+ fcmpgt32 %f0, %F0, %g1 /* FPM */; \
+ srl %g7, 1, %g7 /* IEU0 Group */; \
+ fpadd32 %F6, %f6, %F6 /* FPA */; \
+ fcmpgt32 %f2, %F2, %g2 /* FPM */; \
+ add %o2, %g7, %o2 /* IEU0 Group */; \
+ fpadd32 %F8, %f8, %F8 /* FPA */; \
+ fcmpgt32 %f4, %F4, %g3 /* FPM */; \
+ inc %o3 /* IEU0 Group */; \
+ fpadd32 %F10, %f10, %F10 /* FPA */; \
+ fcmpgt32 %f6, %F6, %g5 /* FPM */; \
+ srl %o3, 1, %o3 /* IEU0 Group */; \
+ fpadd32 %F12, %f12, %F12 /* FPA */; \
+ fcmpgt32 %f8, %F8, %g7 /* FPM */; \
+ add %o2, %o3, %o2 /* IEU0 Group */; \
+ fpadd32 %F14, %f14, %F14 /* FPA */; \
+ fcmpgt32 %f10, %F10, %o3 /* FPM */; \
+ inc %o4 /* IEU0 Group */; \
+ inc %o5 /* IEU1 */; \
+ srl %o4, 1, %o4 /* IEU0 Group */; \
+ inc %g1 /* IEU1 */; \
+ srl %o5, 1, %o5 /* IEU0 Group */; \
+ add %o2, %o4, %o2 /* IEU1 */; \
+ srl %g1, 1, %g1 /* IEU0 Group */; \
+ add %o2, %o5, %o2 /* IEU1 */; \
+ inc %g2 /* IEU0 Group */; \
+ add %o2, %g1, %o2 /* IEU1 */; \
+ srl %g2, 1, %g2 /* IEU0 Group */; \
+ inc %g3 /* IEU1 */; \
+ srl %g3, 1, %g3 /* IEU0 Group */; \
+ add %o2, %g2, %o2 /* IEU1 */; \
+ inc %g5 /* IEU0 Group */; \
+ add %o2, %g3, %o2 /* IEU0 */;
-#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \
- fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \
- srl %g5, 1, %g5 /* IEU0 */; \
- inc %g7 /* IEU1 */; \
- fpadd32 %f2, %f0, %S0 /* FPA */; \
- fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \
- srl %g7, 1, %g7 /* IEU0 */; \
- add %o2, %g5, %o2 /* IEU1 */; \
- fpadd32 %f6, %f4, %S1 /* FPA */; \
- inc %o3 /* IEU0 Group */; \
- add %o2, %g7, %o2 /* IEU1 */; \
- fcmpgt32 %f0, %S0, %g1 /* FPM Group */; \
- srl %o3, 1, %o3 /* IEU0 */; \
- inc %o4 /* IEU1 */; \
- fpadd32 %f10, %f8, %S2 /* FPA */; \
- fcmpgt32 %f4, %S1, %g2 /* FPM Group */; \
- srl %o4, 1, %o4 /* IEU0 */; \
- add %o2, %o3, %o2 /* IEU1 */; \
- fpadd32 %f14, %f12, %S3 /* FPA */; \
- inc %o5 /* IEU0 Group */; \
- add %o2, %o4, %o2 /* IEU1 */; \
- fzero %fz /* FPA */; \
- fcmpgt32 %f8, %S2, %g3 /* FPM Group */; \
- srl %o5, 1, %o5 /* IEU0 */; \
- inc %g1 /* IEU1 */; \
- fpadd32 %S0, %S1, %T0 /* FPA */; \
- fcmpgt32 %f12, %S3, %g5 /* FPM Group */; \
- srl %g1, 1, %g1 /* IEU0 */; \
- add %o2, %o5, %o2 /* IEU1 */; \
- fpadd32 %S2, %S3, %T1 /* FPA */; \
- inc %g2 /* IEU0 Group */; \
- add %o2, %g1, %o2 /* IEU1 */; \
- fcmpgt32 %S0, %T0, %g7 /* FPM Group */; \
- srl %g2, 1, %g2 /* IEU0 */; \
- inc %g3 /* IEU1 */; \
- fcmpgt32 %S2, %T1, %o3 /* FPM Group */; \
- srl %g3, 1, %g3 /* IEU0 */; \
- add %o2, %g2, %o2 /* IEU1 */; \
- inc %g5 /* IEU0 Group */; \
- add %o2, %g3, %o2 /* IEU1 */; \
- fcmpgt32 %fz, %f2, %o4 /* FPM Group */; \
- srl %g5, 1, %g5 /* IEU0 */; \
- inc %g7 /* IEU1 */; \
- fpadd32 %T0, %T1, %U0 /* FPA */; \
- fcmpgt32 %fz, %f6, %o5 /* FPM Group */; \
- srl %g7, 1, %g7 /* IEU0 */; \
- add %o2, %g5, %o2 /* IEU1 */; \
- inc %o3 /* IEU0 Group */; \
- add %o2, %g7, %o2 /* IEU1 */; \
- fcmpgt32 %fz, %f10, %g1 /* FPM Group */; \
- srl %o3, 1, %o3 /* IEU0 */; \
- inc %o4 /* IEU1 */; \
- fcmpgt32 %fz, %f14, %g2 /* FPM Group */; \
- srl %o4, 1, %o4 /* IEU0 */; \
- add %o2, %o3, %o2 /* IEU1 */; \
- std %U0, [%sp + STACKOFF] /* Store Group */; \
- inc %o5 /* IEU0 */; \
- sub %o2, %o4, %o2 /* IEU1 */; \
- fcmpgt32 %fz, %S1, %g3 /* FPM Group */; \
- srl %o5, 1, %o5 /* IEU0 */; \
- inc %g1 /* IEU1 */; \
- fcmpgt32 %fz, %S3, %g5 /* FPM Group */; \
- srl %g1, 1, %g1 /* IEU0 */; \
- sub %o2, %o5, %o2 /* IEU1 */; \
- ldx [%sp + STACKOFF], %o5 /* Load Group */; \
- inc %g2 /* IEU0 */; \
- sub %o2, %g1, %o2 /* IEU1 */; \
- fcmpgt32 %fz, %T1, %g7 /* FPM Group */; \
- srl %g2, 1, %g2 /* IEU0 */; \
- inc %g3 /* IEU1 */; \
- fcmpgt32 %T0, %U0, %o3 /* FPM Group */; \
- srl %g3, 1, %g3 /* IEU0 */; \
- sub %o2, %g2, %o2 /* IEU1 */; \
- inc %g5 /* IEU0 Group */; \
- sub %o2, %g3, %o2 /* IEU1 */; \
- fcmpgt32 %fz, %U0, %o4 /* FPM Group */; \
- srl %g5, 1, %g5 /* IEU0 */; \
- inc %g7 /* IEU1 */; \
- srl %g7, 1, %g7 /* IEU0 Group */; \
- sub %o2, %g5, %o2 /* IEU1 */; \
- inc %o3 /* IEU0 Group */; \
- sub %o2, %g7, %o2 /* IEU1 */; \
- srl %o3, 1, %o3 /* IEU0 Group */; \
- inc %o4 /* IEU1 */; \
- srl %o4, 1, %o4 /* IEU0 Group */; \
- add %o2, %o3, %o2 /* IEU1 */; \
- sub %o2, %o4, %o2 /* IEU0 Group */; \
- addcc %o2, %o5, %o2 /* IEU1 Group */; \
- bcs,a,pn %xcc, 33f /* CTI */; \
- add %o2, 1, %o2 /* IEU0 */; \
-33: /* That's it */;
+#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \
+ srl %g5, 1, %g5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ fcmpgt32 %O12, %f12, %o4 /* FPM */; \
+ inc %g7 /* IEU0 Group */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ fcmpgt32 %O14, %f14, %o5 /* FPM */; \
+ srl %g7, 1, %g7 /* IEU0 Group */; \
+ fpadd32 %f10, %f8, %S2 /* FPA */; \
+ fcmpgt32 %f0, %S0, %g1 /* FPM */; \
+ inc %o3 /* IEU0 Group */; \
+ fpadd32 %f14, %f12, %S3 /* FPA */; \
+ fcmpgt32 %f4, %S1, %g2 /* FPM */; \
+ add %o2, %g5, %o2 /* IEU0 Group */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fcmpgt32 %f8, %S2, %g3 /* FPM */; \
+ add %o2, %g7, %o2 /* IEU0 Group */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f12, %S3, %g5 /* FPM */; \
+ srl %o3, 1, %o3 /* IEU0 Group */; \
+ fpadd32 %S2, %S3, %T1 /* FPA */; \
+ fcmpgt32 %S0, %T0, %g7 /* FPM */; \
+ add %o2, %o3, %o2 /* IEU0 Group */; \
+ fpadd32 %T0, %T1, %U0 /* FPA */; \
+ fcmpgt32 %S2, %T1, %o3 /* FPM */; \
+ inc %o4 /* IEU0 Group */; \
+ inc %o5 /* IEU1 */; \
+ srl %o4, 1, %o4 /* IEU0 Group */; \
+ inc %g1 /* IEU1 */; \
+ add %o2, %o4, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f2, %o4 /* FPM */; \
+ srl %o5, 1, %o5 /* IEU0 Group */; \
+ inc %g2 /* IEU1 */; \
+ add %o2, %o5, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f6, %o5 /* FPM */; \
+ srl %g1, 1, %g1 /* IEU0 Group */; \
+ inc %g3 /* IEU1 */; \
+ add %o2, %g1, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f10, %g1 /* FPM */; \
+ srl %g2, 1, %g2 /* IEU0 Group */; \
+ inc %g5 /* IEU1 */; \
+ add %o2, %g2, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f14, %g2 /* FPM */; \
+ srl %g3, 1, %g3 /* IEU0 Group */; \
+ inc %g7 /* IEU1 */; \
+ add %o2, %g3, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S1, %g3 /* FPM */; \
+ srl %g5, 1, %g5 /* IEU0 Group */; \
+ inc %o3 /* IEU1 */; \
+ add %o2, %g5, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S3, %g5 /* FPM */; \
+ srl %g7, 1, %g7 /* IEU0 Group */; \
+ inc %o4 /* IEU1 */; \
+ add %o2, %g7, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %T1, %g7 /* FPM */; \
+ srl %o3, 1, %o3 /* IEU0 Group */; \
+ inc %o5 /* IEU1 */; \
+ add %o2, %o3, %o2 /* IEU0 Group */; \
+ fcmpgt32 %T0, %U0, %o3 /* FPM */; \
+ srl %o4, 1, %o4 /* IEU0 Group */; \
+ inc %g1 /* IEU1 */; \
+ sub %o2, %o4, %o2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %U0, %o4 /* FPM */; \
+ srl %o5, 1, %o5 /* IEU0 Group */; \
+ inc %g2 /* IEU1 */; \
+ srl %g1, 1, %g1 /* IEU0 Group */; \
+ sub %o2, %o5, %o2 /* IEU1 */; \
+ std %U0, [%sp + STACKOFF] /* Store */; \
+ srl %g2, 1, %g2 /* IEU0 Group */; \
+ sub %o2, %g1, %o2 /* IEU1 */; \
+ inc %g3 /* IEU0 Group */; \
+ sub %o2, %g2, %o2 /* IEU1 */; \
+ srl %g3, 1, %g3 /* IEU0 Group */; \
+ inc %g5 /* IEU1 */; \
+ srl %g5, 1, %g5 /* IEU0 Group */; \
+ sub %o2, %g3, %o2 /* IEU1 */; \
+ ldx [%sp + STACKOFF], %o5 /* Load Group */; \
+ inc %g7 /* IEU0 */; \
+ sub %o2, %g5, %o2 /* IEU1 */; \
+ srl %g7, 1, %g7 /* IEU0 Group */; \
+ inc %o3 /* IEU1 */; \
+ srl %o3, 1, %o3 /* IEU0 Group */; \
+ sub %o2, %g7, %o2 /* IEU1 */; \
+ inc %o4 /* IEU0 Group */; \
+ add %o2, %o3, %o2 /* IEU1 */; \
+ srl %o4, 1, %o4 /* IEU0 Group */; \
+ sub %o2, %o4, %o2 /* IEU0 Group */; \
+ addcc %o2, %o5, %o2 /* IEU1 Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %o2, 1, %o2 /* IEU0 */; \
+33: /* That's it */;
-#define CSUM_LASTCHUNK(offset) \
- ldx [%o0 - offset - 0x10], %g2; \
- ldx [%o0 - offset - 0x08], %g3; \
- addcc %g2, %o2, %o2; \
- bcs,a,pn %xcc, 31f; \
- add %o2, 1, %o2; \
-31: addcc %g3, %o2, %o2; \
- bcs,a,pn %xcc, 32f; \
- add %o2, 1, %o2; \
+#define CSUM_LASTCHUNK(offset) \
+ ldx [%o0 - offset - 0x10], %g2; \
+ ldx [%o0 - offset - 0x08], %g3; \
+ addcc %g2, %o2, %o2; \
+ bcs,a,pn %xcc, 31f; \
+ add %o2, 1, %o2; \
+31: addcc %g3, %o2, %o2; \
+ bcs,a,pn %xcc, 32f; \
+ add %o2, 1, %o2; \
32:
.text
.globl csum_partial
.align 32
csum_partial:
- andcc %o0, 7, %g0 /* IEU1 Group */
- be,pt %icc, 4f /* CTI */
- andcc %o0, 0x38, %g3 /* IEU1 */
- mov 1, %g5 /* IEU0 Group */
- cmp %o1, 6 /* IEU1 */
- bl,pn %icc, 21f /* CTI */
- andcc %o0, 2, %g0 /* IEU1 Group */
- be,pt %icc, 1f /* CTI */
- and %o0, 4, %g7 /* IEU0 */
- lduh [%o0], %g2 /* Load */
- sub %o1, 2, %o1 /* IEU0 Group */
- add %o0, 2, %o0 /* IEU1 */
- andcc %o0, 4, %g7 /* IEU1 Group */
- sll %g5, 16, %g5 /* IEU0 */
- sll %g2, 16, %g2 /* IEU0 Group */
- addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */
- bcs,a,pn %icc, 1f /* CTI */
- add %o2, %g5, %o2 /* IEU0 */
-1: ld [%o0], %g2 /* Load */
- brz,a,pn %g7, 4f /* CTI+IEU1 Group */
- and %o0, 0x38, %g3 /* IEU0 */
- add %o0, 4, %o0 /* IEU0 Group */
- sub %o1, 4, %o1 /* IEU1 */
- addcc %g2, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %icc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: and %o0, 0x38, %g3 /* IEU1 Group */
-4: srl %o2, 0, %o2 /* IEU0 Group */
- mov 0x40, %g1 /* IEU1 */
- brz,pn %g3, 3f /* CTI+IEU1 Group */
- sub %g1, %g3, %g1 /* IEU0 */
- cmp %o1, 56 /* IEU1 Group */
- blu,pn %icc, 20f /* CTI */
- andcc %o0, 8, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- ldx [%o0], %g2 /* Load */
- add %o0, 8, %o0 /* IEU0 Group */
- sub %o1, 8, %o1 /* IEU1 */
- addcc %g2, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: andcc %g1, 0x10, %g0 /* IEU1 Group */
- be,pn %icc, 2f /* CTI */
- and %g1, 0x20, %g1 /* IEU0 */
- ldx [%o0], %g2 /* Load */
- ldx [%o0+8], %g3 /* Load Group */
- add %o0, 16, %o0 /* IEU0 */
- sub %o1, 16, %o1 /* IEU1 */
- addcc %g2, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: addcc %g3, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 2f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-2: brz,pn %g1, 3f /* CTI+IEU1 Group */
- ldx [%o0], %g2 /* Load */
- ldx [%o0+8], %g3 /* Load Group */
- ldx [%o0+16], %g5 /* Load Group */
- ldx [%o0+24], %g7 /* Load Group */
- add %o0, 32, %o0 /* IEU0 */
- sub %o1, 32, %o1 /* IEU1 */
- addcc %g2, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: addcc %g3, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: addcc %g5, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: addcc %g7, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 3f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-3: cmp %o1, 0xc0 /* IEU1 Group */
- blu,pn %icc, 20f /* CTI */
- sllx %o2, 32, %g5 /* IEU0 */
+ andcc %o0, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ andcc %o0, 0x38, %g3 /* IEU1 */
+ mov 1, %g5 /* IEU0 Group */
+ cmp %o1, 6 /* IEU1 */
+ bl,pn %icc, 21f /* CTI */
+ andcc %o0, 2, %g0 /* IEU1 Group */
+ be,pt %icc, 1f /* CTI */
+ and %o0, 4, %g7 /* IEU0 */
+ lduh [%o0], %g2 /* Load */
+ sub %o1, 2, %o1 /* IEU0 Group */
+ add %o0, 2, %o0 /* IEU1 */
+ andcc %o0, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sll %g2, 16, %g2 /* IEU0 Group */
+ addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %o2, %g5, %o2 /* IEU0 */
+1: ld [%o0], %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %o0, 0x38, %g3 /* IEU0 */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sub %o1, 4, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: and %o0, 0x38, %g3 /* IEU1 Group */
+4: srl %o2, 0, %o2 /* IEU0 Group */
+ mov 0x40, %g1 /* IEU1 */
+ brz,pn %g3, 3f /* CTI+IEU1 Group */
+ sub %g1, %g3, %g1 /* IEU0 */
+ cmp %o1, 56 /* IEU1 Group */
+ blu,pn %icc, 20f /* CTI */
+ andcc %o0, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ ldx [%o0], %g2 /* Load */
+ add %o0, 8, %o0 /* IEU0 Group */
+ sub %o1, 8, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 2f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ ldx [%o0], %g2 /* Load */
+ ldx [%o0+8], %g3 /* Load Group */
+ add %o0, 16, %o0 /* IEU0 */
+ sub %o1, 16, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 2f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+2: brz,pn %g1, 3f /* CTI+IEU1 Group */
+ ldx [%o0], %g2 /* Load */
+ ldx [%o0+8], %g3 /* Load Group */
+ ldx [%o0+16], %g5 /* Load Group */
+ ldx [%o0+24], %g7 /* Load Group */
+ add %o0, 32, %o0 /* IEU0 */
+ sub %o1, 32, %o1 /* IEU1 */
+ addcc %g2, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g5, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: addcc %g7, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 3f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+3: cmp %o1, 0xc0 /* IEU1 Group */
+ blu,pn %icc, 20f /* CTI */
+ sllx %o2, 32, %g5 /* IEU0 */
#ifdef __KERNEL__
VISEntry
#endif
- addcc %o2, %g5, %o2 /* IEU1 Group */
- sub %o1, 0xc0, %o1 /* IEU0 */
- wr %g0, ASI_BLK_P, %asi /* LSU Group */
- membar #StoreLoad /* LSU Group */
- srlx %o2, 32, %o2 /* IEU0 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU1 */
-1: andcc %o1, 0x80, %g0 /* IEU1 Group */
- bne,pn %icc, 7f /* CTI */
- andcc %o1, 0x40, %g0 /* IEU1 Group */
- be,pn %icc, 6f /* CTI */
- fzero %f12 /* FPA */
- fzero %f14 /* FPA Group */
+ addcc %o2, %g5, %o2 /* IEU1 Group */
+ sub %o1, 0xc0, %o1 /* IEU0 */
+ wr %g0, ASI_BLK_P, %asi /* LSU Group */
+ membar #StoreLoad /* LSU Group */
+ srlx %o2, 32, %o2 /* IEU0 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU1 */
+1: andcc %o1, 0x80, %g0 /* IEU1 Group */
+ bne,pn %icc, 7f /* CTI */
+ andcc %o1, 0x40, %g0 /* IEU1 Group */
+ be,pn %icc, 6f /* CTI */
+ fzero %f12 /* FPA */
+ fzero %f14 /* FPA Group */
ldda [%o0 + 0x000] %asi, %f16
ldda [%o0 + 0x040] %asi, %f32
ldda [%o0 + 0x080] %asi, %f48
START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
ba,a,pt %xcc, 3f
-6: sub %o0, 0x40, %o0 /* IEU0 Group */
- fzero %f28 /* FPA */
- fzero %f30 /* FPA Group */
+6: sub %o0, 0x40, %o0 /* IEU0 Group */
+ fzero %f28 /* FPA */
+ fzero %f30 /* FPA Group */
ldda [%o0 + 0x040] %asi, %f32
ldda [%o0 + 0x080] %asi, %f48
ldda [%o0 + 0x0c0] %asi, %f0
START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
ba,a,pt %xcc, 4f
-7: bne,pt %icc, 8f /* CTI */
- fzero %f44 /* FPA */
- add %o0, 0x40, %o0 /* IEU0 Group */
- fzero %f60 /* FPA */
- fzero %f62 /* FPA Group */
+7: bne,pt %icc, 8f /* CTI */
+ fzero %f44 /* FPA */
+ add %o0, 0x40, %o0 /* IEU0 Group */
+ fzero %f60 /* FPA */
+ fzero %f62 /* FPA Group */
ldda [%o0 - 0x040] %asi, %f0
ldda [%o0 + 0x000] %asi, %f16
ldda [%o0 + 0x040] %asi, %f32
START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
ba,a,pt %xcc, 2f
-8: add %o0, 0x80, %o0 /* IEU0 Group */
- fzero %f46 /* FPA */
+8: add %o0, 0x80, %o0 /* IEU0 Group */
+ fzero %f46 /* FPA */
ldda [%o0 - 0x080] %asi, %f48
ldda [%o0 - 0x040] %asi, %f0
ldda [%o0 + 0x000] %asi, %f16
@@ -333,36 +334,36 @@ csum_partial:
3: DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
ldda [%o0 + 0x0c0] %asi, %f0
4: DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
- add %o0, 0x100, %o0 /* IEU0 Group */
- subcc %o1, 0x100, %o1 /* IEU1 */
- bgeu,a,pt %icc, 1b /* CTI */
+ add %o0, 0x100, %o0 /* IEU0 Group */
+ subcc %o1, 0x100, %o1 /* IEU1 */
+ bgeu,a,pt %icc, 1b /* CTI */
ldda [%o0 + 0x000] %asi, %f16
- membar #Sync /* LSU Group */
+ membar #Sync /* LSU Group */
DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
#ifdef __KERNEL__
ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7
#endif
- and %o1, 0x3f, %o1 /* IEU0 Group */
+ and %o1, 0x3f, %o1 /* IEU0 Group */
#ifdef __KERNEL__
VISExit
wr %g7, %g0, %asi
#endif
-20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
- be,pn %icc, 23f /* CTI */
- and %o1, 0xf, %o3 /* IEU0 */
+20: andcc %o1, 0xf0, %g1 /* IEU1 Group */
+ be,pn %icc, 23f /* CTI */
+ and %o1, 0xf, %o3 /* IEU0 */
#ifdef __KERNEL__
-22: sll %g1, 1, %o4 /* IEU0 Group */
- sethi %hi(23f), %g7 /* IEU1 */
- sub %g7, %o4, %g7 /* IEU0 Group */
- jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */
- add %o0, %g1, %o0 /* IEU0 */
+22: sll %g1, 1, %o4 /* IEU0 Group */
+ sethi %hi(23f), %g7 /* IEU1 */
+ sub %g7, %o4, %g7 /* IEU0 Group */
+ jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced*/
+ add %o0, %g1, %o0 /* IEU0 */
#else
-22: rd %pc, %g7 /* LSU Group+4bubbles */
- sll %g1, 1, %o4 /* IEU0 Group */
- sub %g7, %o4, %g7 /* IEU0 Group (regdep) */
- jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */
- add %o0, %g1, %o0 /* IEU0 */
+22: rd %pc, %g7 /* LSU Group+4bubbles */
+ sll %g1, 1, %o4 /* IEU0 Group */
+ sub %g7, %o4, %g7 /* IEU0 Group (regdep) */
+ jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced*/
+ add %o0, %g1, %o0 /* IEU0 */
#endif
CSUM_LASTCHUNK(0xe0)
CSUM_LASTCHUNK(0xd0)
@@ -379,72 +380,72 @@ csum_partial:
CSUM_LASTCHUNK(0x20)
CSUM_LASTCHUNK(0x10)
CSUM_LASTCHUNK(0x00)
-23: brnz,pn %o3, 26f /* CTI+IEU1 Group */
-24: sllx %o2, 32, %g1 /* IEU0 */
-25: addcc %o2, %g1, %o0 /* IEU1 Group */
- srlx %o0, 32, %o0 /* IEU0 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o0, 1, %o0 /* IEU1 */
-1: retl /* CTI Group brk forced */
- srl %o0, 0, %o0 /* IEU0 */
-26: andcc %o1, 8, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- ldx [%o0], %g3 /* Load */
- add %o0, 8, %o0 /* IEU0 Group */
- addcc %g3, %o2, %o2 /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: andcc %o1, 4, %g0 /* IEU1 Group */
- be,a,pn %icc, 1f /* CTI */
- clr %g2 /* IEU0 */
- ld [%o0], %g2 /* Load */
- add %o0, 4, %o0 /* IEU0 Group */
- sllx %g2, 32, %g2 /* IEU0 Group */
-1: andcc %o1, 2, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o4 /* IEU0 Group */
- lduh [%o0], %o4 /* Load */
- add %o0, 2, %o0 /* IEU1 */
- sll %o4, 16, %o4 /* IEU0 Group */
-1: andcc %o1, 1, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o5 /* IEU0 Group */
- ldub [%o0], %o5 /* Load */
- sll %o5, 8, %o5 /* IEU0 Group */
-1: or %g2, %o4, %o4 /* IEU1 */
- or %o5, %o4, %o4 /* IEU0 Group (regdep) */
- addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: ba,pt %xcc, 25b /* CTI Group */
- sllx %o2, 32, %g1 /* IEU0 */
-21: srl %o2, 0, %o2 /* IEU0 Group */
- cmp %o1, 0 /* IEU1 */
- be,pn %icc, 24b /* CTI */
- andcc %o1, 4, %g0 /* IEU1 Group */
- be,a,pn %icc, 1f /* CTI */
- clr %g2 /* IEU0 */
- lduh [%o0], %g3 /* Load */
- lduh [%o0+2], %g2 /* Load Group */
- add %o0, 4, %o0 /* IEU0 Group */
- sllx %g3, 48, %g3 /* IEU0 Group */
- sllx %g2, 32, %g2 /* IEU0 Group */
- or %g3, %g2, %g2 /* IEU0 Group */
-1: andcc %o1, 2, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o4 /* IEU0 Group */
- lduh [%o0], %o4 /* Load */
- add %o0, 2, %o0 /* IEU1 */
- sll %o4, 16, %o4 /* IEU0 Group */
-1: andcc %o1, 1, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o5 /* IEU0 Group */
- ldub [%o0], %o5 /* Load */
- sll %o5, 8, %o5 /* IEU0 Group */
-1: or %g2, %o4, %o4 /* IEU1 */
- or %o5, %o4, %o4 /* IEU0 Group (regdep) */
- addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %o2, 1, %o2 /* IEU0 */
-1: ba,pt %xcc, 25b /* CTI Group */
- sllx %o2, 32, %g1 /* IEU0 */
+23: brnz,pn %o3, 26f /* CTI+IEU1 Group */
+24: sllx %o2, 32, %g1 /* IEU0 */
+25: addcc %o2, %g1, %o0 /* IEU1 Group */
+ srlx %o0, 32, %o0 /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o0, 1, %o0 /* IEU1 */
+1: retl /* CTI Group brk forced*/
+ srl %o0, 0, %o0 /* IEU0 */
+26: andcc %o1, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ ldx [%o0], %g3 /* Load */
+ add %o0, 8, %o0 /* IEU0 Group */
+ addcc %g3, %o2, %o2 /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: andcc %o1, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ ld [%o0], %g2 /* Load */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sllx %g2, 32, %g2 /* IEU0 Group */
+1: andcc %o1, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduh [%o0], %o4 /* Load */
+ add %o0, 2, %o0 /* IEU1 */
+ sll %o4, 16, %o4 /* IEU0 Group */
+1: andcc %o1, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ ldub [%o0], %o5 /* Load */
+ sll %o5, 8, %o5 /* IEU0 Group */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %o2, 32, %g1 /* IEU0 */
+21: srl %o2, 0, %o2 /* IEU0 Group */
+ cmp %o1, 0 /* IEU1 */
+ be,pn %icc, 24b /* CTI */
+ andcc %o1, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduh [%o0], %g3 /* Load */
+ lduh [%o0+2], %g2 /* Load Group */
+ add %o0, 4, %o0 /* IEU0 Group */
+ sllx %g3, 48, %g3 /* IEU0 Group */
+ sllx %g2, 32, %g2 /* IEU0 Group */
+ or %g3, %g2, %g2 /* IEU0 Group */
+1: andcc %o1, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o4 /* IEU0 Group */
+ lduh [%o0], %o4 /* Load */
+ add %o0, 2, %o0 /* IEU1 */
+ sll %o4, 16, %o4 /* IEU0 Group */
+1: andcc %o1, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ ldub [%o0], %o5 /* Load */
+ sll %o5, 8, %o5 /* IEU0 Group */
+1: or %g2, %o4, %o4 /* IEU1 */
+ or %o5, %o4, %o4 /* IEU0 Group (regdep) */
+ addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %o2, 1, %o2 /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %o2, 32, %g1 /* IEU0 */
diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S
index 3f89eea29..9b0193022 100644
--- a/arch/sparc64/lib/VIScsumcopy.S
+++ b/arch/sparc64/lib/VIScsumcopy.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsumcopy.S,v 1.7 2000/01/19 04:06:03 davem Exp $
+/* $Id: VIScsumcopy.S,v 1.8 2000/02/20 23:21:39 davem Exp $
* VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
* copying utilizing the UltraSparc Visual Instruction Set.
*
@@ -62,384 +62,386 @@
* per 64bytes checksummed/copied.
*/
-#define LDBLK(O0) \
- ldda [%src] %asi, %O0 /* Load Group */
+#define LDBLK(O0) \
+ ldda [%src] %asi, %O0 /* Load Group */
-#define STBLK \
- stda %f48, [%dst] ASI_BLK_P /* Store */
+#define STBLK \
+ stda %f48, [%dst] ASI_BLK_P /* Store */
-#define ST(fx,off) \
- std %fx, [%dst + off] /* Store */
+#define ST(fx,off) \
+ std %fx, [%dst + off] /* Store */
-#define SYNC \
+#define SYNC \
membar #Sync
#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
- LOAD /* Load Group */; \
- faligndata %A14, %F0, %A14 /* FPA Group */; \
- inc %x5 /* IEU0 */; \
- STORE1 /* Store (optional) */; \
- faligndata %F0, %F2, %A0 /* FPA Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- add %sum, %x4, %sum /* IEU1 */; \
- fpadd32 %F0, %f0, %F0 /* FPA Group */; \
- inc %x6 /* IEU0 */; \
- STORE2 /* Store (optional) */; \
- faligndata %F2, %F4, %A2 /* FPA Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fpadd32 %F2, %f2, %F2 /* FPA Group */; \
- add %src, 64, %src /* IEU0 */; \
- add %dst, 64, %dst /* IEU1 */; \
- fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \
- inc %x7 /* IEU0 */; \
- STORE3 /* Store (optional) */; \
- faligndata %F4, %F6, %A4 /* FPA */; \
- srl %x7, 1, %x7 /* IEU0 Group */; \
- add %sum, %x6, %sum /* IEU1 */; \
- fpadd32 %F4, %f4, %F4 /* FPA */; \
- fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \
- inc %x8 /* IEU0 */; \
- STORE4 /* Store (optional) */; \
- faligndata %F6, %F8, %A6 /* FPA */; \
- srl %x8, 1, %x8 /* IEU0 Group */; \
- add %sum, %x7, %sum /* IEU1 */; \
- fpadd32 %F6, %f6, %F6 /* FPA */; \
- fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \
- inc %x1 /* IEU0 */; \
- STORE5 /* Store (optional) */; \
- faligndata %F8, %F10, %A8 /* FPA */; \
- srl %x1, 1, %x1 /* IEU0 Group */; \
- add %sum, %x8, %sum /* IEU1 */; \
- fpadd32 %F8, %f8, %F8 /* FPA */; \
- fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \
- inc %x2 /* IEU0 */; \
- STORE6 /* Store (optional) */; \
- faligndata %F10, %F12, %A10 /* FPA */; \
- srl %x2, 1, %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- fpadd32 %F10, %f10, %F10 /* FPA */; \
- fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \
- inc %x3 /* IEU0 */; \
- STORE7 /* Store (optional) */; \
- faligndata %F12, %F14, %A12 /* FPA */; \
- srl %x3, 1, %x3 /* IEU0 Group */; \
- add %sum, %x2, %sum /* IEU1 */; \
- fpadd32 %F12, %f12, %F12 /* FPA */; \
- fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \
- inc %x4 /* IEU0 */; \
- STORE8 /* Store (optional) */; \
- fmovd %F14, %B14 /* FPA */; \
- srl %x4, 1, %x4 /* IEU0 Group */; \
- add %sum, %x3, %sum /* IEU1 */; \
- fpadd32 %F14, %f14, %F14 /* FPA */; \
- fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \
- subcc %len, 64, %len /* IEU1 */; \
- BRANCH /* CTI */; \
- fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \
+ LOAD /* Load (Group) */; \
+ faligndata %A14, %F0, %A14 /* FPA Group */; \
+ inc %x5 /* IEU0 */; \
+ STORE1 /* Store (optional) */; \
+ faligndata %F0, %F2, %A0 /* FPA Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA Group */; \
+ inc %x6 /* IEU0 */; \
+ STORE2 /* Store (optional) */; \
+ faligndata %F2, %F4, %A2 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA Group */; \
+ add %src, 64, %src /* IEU0 */; \
+ fcmpgt32 %f0, %F0, %x1 /* FPM */; \
+ add %dst, 64, %dst /* IEU1 Group */; \
+ inc %x7 /* IEU0 */; \
+ STORE3 /* Store (optional) */; \
+ faligndata %F4, %F6, %A4 /* FPA */; \
+ fpadd32 %F4, %f4, %F4 /* FPA Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fcmpgt32 %f2, %F2, %x2 /* FPM */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ inc %x8 /* IEU1 */; \
+ STORE4 /* Store (optional) */; \
+ faligndata %F6, %F8, %A6 /* FPA */; \
+ fpadd32 %F6, %f6, %F6 /* FPA Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ fcmpgt32 %f4, %F4, %x3 /* FPM */; \
+ add %sum, %x7, %sum /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ STORE5 /* Store (optional) */; \
+ faligndata %F8, %F10, %A8 /* FPA */; \
+ fpadd32 %F8, %f8, %F8 /* FPA Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ fcmpgt32 %f6, %F6, %x4 /* FPM */; \
+ add %sum, %x8, %sum /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ STORE6 /* Store (optional) */; \
+ faligndata %F10, %F12, %A10 /* FPA */; \
+ fpadd32 %F10, %f10, %F10 /* FPA Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ fcmpgt32 %f8, %F8, %x5 /* FPM */; \
+ add %sum, %x1, %sum /* IEU0 Group */; \
+ inc %x3 /* IEU1 */; \
+ STORE7 /* Store (optional) */; \
+ faligndata %F12, %F14, %A12 /* FPA */; \
+ fpadd32 %F12, %f12, %F12 /* FPA Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ fcmpgt32 %f10, %F10, %x6 /* FPM */; \
+ add %sum, %x2, %sum /* IEU0 Group */; \
+ inc %x4 /* IEU1 */; \
+ STORE8 /* Store (optional) */; \
+ fmovd %F14, %B14 /* FPA */; \
+ fpadd32 %F14, %f14, %F14 /* FPA Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ fcmpgt32 %f12, %F12, %x7 /* FPM */; \
+ add %sum, %x3, %sum /* IEU0 Group */; \
+ subcc %len, 64, %len /* IEU1 */; \
+ BRANCH /* CTI */; \
+ fcmpgt32 %f14, %F14, %x8 /* FPM Group */;
#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
- inc %x5 /* IEU0 Group */; \
- fpadd32 %f2, %f0, %S0 /* FPA */; \
- srl %x5, 1, %x5 /* IEU0 Group */; \
- add %sum, %x4, %sum /* IEU1 */; \
- fpadd32 %f6, %f4, %S1 /* FPA */; \
- inc %x6 /* IEU0 Group */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- inc %x7 /* IEU1 */; \
- fpadd32 %f10, %f8, %S2 /* FPA */; \
- fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \
- srl %x7, 1, %x7 /* IEU0 */; \
- add %sum, %x6, %sum /* IEU1 */; \
- fpadd32 %f14, %f12, %S3 /* FPA */; \
- inc %x8 /* IEU0 Group */; \
- add %sum, %x7, %sum /* IEU1 */; \
- fzero %fz /* FPA */; \
- fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \
- srl %x8, 1, %x8 /* IEU0 */; \
- inc %x1 /* IEU1 */; \
- fpadd32 %S0, %S1, %T0 /* FPA */; \
- fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \
- srl %x1, 1, %x1 /* IEU0 */; \
- add %sum, %x8, %sum /* IEU1 */; \
- fpadd32 %S2, %S3, %T1 /* FPA */; \
- inc %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \
- srl %x2, 1, %x2 /* IEU0 */; \
- inc %x3 /* IEU1 */; \
- fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \
- srl %x3, 1, %x3 /* IEU0 */; \
- add %sum, %x2, %sum /* IEU1 */; \
- inc %x4 /* IEU0 Group */; \
- add %sum, %x3, %sum /* IEU1 */; \
- fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \
- srl %x4, 1, %x4 /* IEU0 */; \
- inc %x5 /* IEU1 */; \
- fpadd32 %T0, %T1, %U0 /* FPA */; \
- fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- add %sum, %x4, %sum /* IEU1 */; \
- inc %x6 /* IEU0 Group */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- inc %x7 /* IEU1 */; \
- fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \
- ba,pt %xcc, ett /* CTI */; \
- fmovd %FA, %FB /* FPA */; \
+ inc %x5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %x6 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA Group */; \
+ add %sum, %x5, %sum /* IEU0 */; \
+ fcmpgt32 %f0, %S0, %x1 /* FPM */; \
+ fpadd32 %f14, %f12, %S3 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ fcmpgt32 %f4, %S1, %x2 /* FPM */; \
+ add %sum, %x6, %sum /* IEU0 Group */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %x3 /* FPM */; \
+ inc %x7 /* IEU0 Group */; \
+ inc %x8 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fpadd32 %S2, %S3, %T1 /* FPA Group */; \
+ add %sum, %x7, %sum /* IEU0 */; \
+ fcmpgt32 %f12, %S3, %x4 /* FPM */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ add %sum, %x1, %sum /* IEU0 Group */; \
+ fcmpgt32 %S0, %T0, %x5 /* FPM */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ fcmpgt32 %S2, %T1, %x6 /* FPM */; \
+ inc %x3 /* IEU0 Group */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ inc %x4 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA Group */; \
+ add %sum, %x3, %sum /* IEU0 */; \
+ fcmpgt32 %fz, %f2, %x7 /* FPM */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f6, %x8 /* FPM */; \
+ inc %x5 /* IEU0 Group */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f10, %x1 /* FPM */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fmovd %FA, %FB /* FPA Group */; \
+ fcmpgt32 %fz, %f14, %x2 /* FPM */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ ba,pt %xcc, ett /* CTI */; \
+ inc %x7 /* IEU1 */;
-#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
-#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
- fpadd32 %U0, %U1, %V0 /* FPA Group */; \
- srl %x7, 1, %x7 /* IEU0 */; \
- add %sum, %x6, %sum /* IEU1 */; \
- std %V0, [%sp + STACKOFF] /* Store Group */; \
- inc %x8 /* IEU0 */; \
- sub %sum, %x7, %sum /* IEU1 */; \
- fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \
- srl %x8, 1, %x8 /* IEU0 */; \
- inc %x1 /* IEU1 */; \
- fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \
- srl %x1, 1, %x1 /* IEU0 */; \
- sub %sum, %x8, %sum /* IEU1 */; \
- ldx [%sp + STACKOFF], %x8 /* Load Group */; \
- inc %x2 /* IEU0 */; \
- sub %sum, %x1, %sum /* IEU1 */; \
- fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \
- srl %x2, 1, %x2 /* IEU0 */; \
- inc %x3 /* IEU1 */; \
- fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \
- srl %x3, 1, %x3 /* IEU0 */; \
- sub %sum, %x2, %sum /* IEU1 */; \
- inc %x4 /* IEU0 Group */; \
- sub %sum, %x3, %sum /* IEU1 */; \
- fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \
- srl %x4, 1, %x4 /* IEU0 */; \
- inc %x5 /* IEU1 */; \
- fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- sub %sum, %x4, %sum /* IEU1 */; \
- fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \
- inc %x6 /* IEU0 */; \
- sub %sum, %x5, %sum /* IEU1 */; \
- srl %x6, 1, %x6 /* IEU0 Group */; \
- inc %x7 /* IEU1 */; \
- srl %x7, 1, %x7 /* IEU0 Group */; \
- add %sum, %x6, %sum /* IEU1 */; \
- inc %x1 /* IEU0 Group */; \
- sub %sum, %x7, %sum /* IEU1 */; \
- srl %x1, 1, %x1 /* IEU0 Group */; \
- inc %x2 /* IEU1 */; \
- srl %x2, 1, %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- sub %sum, %x2, %sum /* IEU0 Group */; \
- addcc %sum, %x8, %sum /* IEU Group */; \
- bcs,a,pn %xcc, 33f /* CTI */; \
- add %sum, 1, %sum /* IEU0 */; \
-33: /* That's it */;
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
+ fpadd32 %U0, %U1, %V0 /* FPA Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ std %V0, [%sp + STACKOFF] /* Store Group */; \
+ inc %x8 /* IEU0 */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S1, %x3 /* FPM */; \
+ inc %x1 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S3, %x4 /* FPM */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ sub %sum, %x8, %sum /* IEU1 */; \
+ ldx [%sp + STACKOFF], %x8 /* Load Group */; \
+ inc %x2 /* IEU0 */; \
+ sub %sum, %x1, %sum /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %T1, %x5 /* FPM */; \
+ inc %x3 /* IEU0 Group */; \
+ fcmpgt32 %T0, %U0, %x6 /* FPM */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ sub %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ sub %sum, %x3, %sum /* IEU1 */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ fcmpgt32 %fz, %U1, %x7 /* FPM */; \
+ inc %x5 /* IEU0 Group */; \
+ fcmpgt32 %U0, %V0, %x1 /* FPM */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ sub %sum, %x4, %sum /* IEU1 */; \
+ sub %sum, %x5, %sum /* IEU0 Group */; \
+ fcmpgt32 %fz, %V0, %x2 /* FPM */; \
+ inc %x6 /* IEU0 Group */; \
+ inc %x7 /* IEU1 */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ inc %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ sub %sum, %x2, %sum /* IEU0 Group */; \
+ addcc %sum, %x8, %sum /* IEU1 Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %sum, 1, %sum /* IEU0 (Group) */; \
+33: /* That's it */;
.text
.globl csum_partial_copy_vis
.align 32
-/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */
-/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp.
+ * csum_partial_copy_from_user
+ * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256
+ */
csum_partial_copy_vis:
- andcc %dst, 7, %g0 /* IEU1 Group */
- be,pt %icc, 4f /* CTI */
- and %dst, 0x38, %o4 /* IEU0 */
- mov 1, %g5 /* IEU0 Group */
- andcc %dst, 2, %g0 /* IEU1 */
- be,pt %icc, 1f /* CTI */
- and %dst, 4, %g7 /* IEU0 Group */
- lduha [%src] %asi, %g2 /* Load */
- sub %len, 2, %len /* IEU0 Group */
- add %dst, 2, %dst /* IEU1 */
- andcc %dst, 4, %g7 /* IEU1 Group */
- sll %g5, 16, %g5 /* IEU0 */
- sth %g2, [%dst - 2] /* Store Group */
- sll %g2, 16, %g2 /* IEU0 */
- add %src, 2, %src /* IEU1 */
- addcc %g2, %sum, %sum /* IEU1 Group */
- bcs,a,pn %icc, 1f /* CTI */
- add %sum, %g5, %sum /* IEU0 */
-1: lduwa [%src] %asi, %g2 /* Load */
- brz,a,pn %g7, 4f /* CTI+IEU1 Group */
- and %dst, 0x38, %o4 /* IEU0 */
- add %dst, 4, %dst /* IEU0 Group */
- sub %len, 4, %len /* IEU1 */
- addcc %g2, %sum, %sum /* IEU1 Group */
- bcs,a,pn %icc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: and %dst, 0x38, %o4 /* IEU0 Group */
- stw %g2, [%dst - 4] /* Store */
- add %src, 4, %src /* IEU1 */
+ andcc %dst, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ and %dst, 0x38, %o4 /* IEU0 */
+ mov 1, %g5 /* IEU0 Group */
+ andcc %dst, 2, %g0 /* IEU1 */
+ be,pt %icc, 1f /* CTI */
+ and %dst, 4, %g7 /* IEU0 Group */
+ lduha [%src] %asi, %g2 /* Load */
+ sub %len, 2, %len /* IEU0 Group */
+ add %dst, 2, %dst /* IEU1 */
+ andcc %dst, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ sth %g2, [%dst - 2] /* Store Group */
+ sll %g2, 16, %g2 /* IEU0 */
+ add %src, 2, %src /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, %g5, %sum /* IEU0 */
+1: lduwa [%src] %asi, %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %dst, 0x38, %o4 /* IEU0 */
+ add %dst, 4, %dst /* IEU0 Group */
+ sub %len, 4, %len /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: and %dst, 0x38, %o4 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ add %src, 4, %src /* IEU1 */
4:
#ifdef __KERNEL__
VISEntry
#endif
- mov %src, %g7 /* IEU1 Group */
- fzero %f48 /* FPA */
- alignaddr %src, %g0, %src /* Single Group */
- subcc %g7, %src, %g7 /* IEU1 Group */
- be,pt %xcc, 1f /* CTI */
- mov 0x40, %g1 /* IEU0 */
- lduwa [%src] %asi, %g2 /* Load Group */
- subcc %sum, %g2, %sum /* IEU1 Group+load stall */
- bcs,a,pn %icc, 1f /* CTI */
- sub %sum, 1, %sum /* IEU0 */
-1: srl %sum, 0, %sum /* IEU0 Group */
- clr %g5 /* IEU1 */
- brz,pn %o4, 3f /* CTI+IEU1 Group */
- sub %g1, %o4, %g1 /* IEU0 */
- ldda [%src] %asi, %f0 /* Load */
- clr %o4 /* IEU0 Group */
- andcc %dst, 8, %g0 /* IEU1 */
- be,pn %icc, 1f /* CTI */
- ldda [%src + 8] %asi, %f2 /* Load Group */
- add %src, 8, %src /* IEU0 */
- sub %len, 8, %len /* IEU1 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- addcc %dst, 8, %dst /* IEU1 Group */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %o4 /* FPM Group */
- fmovd %f2, %f0 /* FPA Group */
- ldda [%src + 8] %asi, %f2 /* Load */
- std %f16, [%dst - 8] /* Store */
- fmovd %f50, %f48 /* FPA */
-1: andcc %g1, 0x10, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- and %g1, 0x20, %g1 /* IEU0 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- ldda [%src + 16] %asi, %f4 /* Load Group */
- add %src, 16, %src /* IEU0 */
- add %dst, 16, %dst /* IEU1 */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %g5 /* FPM Group */
- sub %len, 16, %len /* IEU0 */
- inc %o4 /* IEU1 */
- std %f16, [%dst - 16] /* Store Group */
- fpadd32 %f2, %f50, %f48 /* FPA */
- srl %o4, 1, %o5 /* IEU0 */
- faligndata %f2, %f4, %f18 /* FPA Group */
- std %f18, [%dst - 8] /* Store */
- fcmpgt32 %f50, %f48, %o4 /* FPM Group */
- add %o5, %sum, %sum /* IEU0 */
- ldda [%src + 8] %asi, %f2 /* Load */
- fmovd %f4, %f0 /* FPA */
-1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
- rd %asi, %g2 /* LSU Group + 4 bubbles */
- inc %g5 /* IEU0 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- ldda [%src + 16] %asi, %f4 /* Load Group */
- srl %g5, 1, %g5 /* IEU0 */
- add %dst, 32, %dst /* IEU1 */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %o5 /* FPM Group */
- inc %o4 /* IEU0 */
- ldda [%src + 24] %asi, %f6 /* Load */
- srl %o4, 1, %o4 /* IEU0 Group */
- add %g5, %sum, %sum /* IEU1 */
- ldda [%src + 32] %asi, %f8 /* Load */
- fpadd32 %f2, %f50, %f48 /* FPA */
- faligndata %f2, %f4, %f18 /* FPA Group */
- sub %len, 32, %len /* IEU0 */
- std %f16, [%dst - 32] /* Store */
- fcmpgt32 %f50, %f48, %g3 /* FPM Group */
- inc %o5 /* IEU0 */
- add %o4, %sum, %sum /* IEU1 */
- fpadd32 %f4, %f48, %f50 /* FPA */
- faligndata %f4, %f6, %f20 /* FPA Group */
- srl %o5, 1, %o5 /* IEU0 */
- fcmpgt32 %f48, %f50, %g5 /* FPM Group */
- add %o5, %sum, %sum /* IEU0 */
- std %f18, [%dst - 24] /* Store */
- fpadd32 %f6, %f50, %f48 /* FPA */
- inc %g3 /* IEU0 Group */
- std %f20, [%dst - 16] /* Store */
- add %src, 32, %src /* IEU1 */
- faligndata %f6, %f8, %f22 /* FPA */
- fcmpgt32 %f50, %f48, %o4 /* FPM Group */
- srl %g3, 1, %g3 /* IEU0 */
- std %f22, [%dst - 8] /* Store */
- add %g3, %sum, %sum /* IEU0 Group */
-3: rd %asi, %g2 /* LSU Group + 4 bubbles */
+ mov %src, %g7 /* IEU1 Group */
+ fzero %f48 /* FPA */
+ alignaddr %src, %g0, %src /* Single Group */
+ subcc %g7, %src, %g7 /* IEU1 Group */
+ be,pt %xcc, 1f /* CTI */
+ mov 0x40, %g1 /* IEU0 */
+ lduwa [%src] %asi, %g2 /* Load Group */
+ subcc %sum, %g2, %sum /* IEU1 Group+load stall*/
+ bcs,a,pn %icc, 1f /* CTI */
+ sub %sum, 1, %sum /* IEU0 */
+1: srl %sum, 0, %sum /* IEU0 Group */
+ clr %g5 /* IEU1 */
+ brz,pn %o4, 3f /* CTI+IEU1 Group */
+ sub %g1, %o4, %g1 /* IEU0 */
+ ldda [%src] %asi, %f0 /* Load */
+ clr %o4 /* IEU0 Group */
+ andcc %dst, 8, %g0 /* IEU1 */
+ be,pn %icc, 1f /* CTI */
+ ldda [%src + 8] %asi, %f2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ sub %len, 8, %len /* IEU1 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ addcc %dst, 8, %dst /* IEU1 Group */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o4 /* FPM Group */
+ fmovd %f2, %f0 /* FPA Group */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ std %f16, [%dst - 8] /* Store */
+ fmovd %f50, %f48 /* FPA */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ add %src, 16, %src /* IEU0 */
+ add %dst, 16, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ sub %len, 16, %len /* IEU0 */
+ inc %o4 /* IEU1 */
+ std %f16, [%dst - 16] /* Store Group */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ srl %o4, 1, %o5 /* IEU0 */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ std %f18, [%dst - 8] /* Store */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ ldda [%src + 8] %asi, %f2 /* Load */
+ fmovd %f4, %f0 /* FPA */
+1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
+ rd %asi, %g2 /* LSU Group + 4 bubbles*/
+ inc %g5 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldda [%src + 16] %asi, %f4 /* Load Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ add %dst, 32, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o5 /* FPM Group */
+ inc %o4 /* IEU0 */
+ ldda [%src + 24] %asi, %f6 /* Load */
+ srl %o4, 1, %o4 /* IEU0 Group */
+ add %g5, %sum, %sum /* IEU1 */
+ ldda [%src + 32] %asi, %f8 /* Load */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ sub %len, 32, %len /* IEU0 */
+ std %f16, [%dst - 32] /* Store */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ inc %o5 /* IEU0 */
+ add %o4, %sum, %sum /* IEU1 */
+ fpadd32 %f4, %f48, %f50 /* FPA */
+ faligndata %f4, %f6, %f20 /* FPA Group */
+ srl %o5, 1, %o5 /* IEU0 */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ std %f18, [%dst - 24] /* Store */
+ fpadd32 %f6, %f50, %f48 /* FPA */
+ inc %g3 /* IEU0 Group */
+ std %f20, [%dst - 16] /* Store */
+ add %src, 32, %src /* IEU1 */
+ faligndata %f6, %f8, %f22 /* FPA */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ srl %g3, 1, %g3 /* IEU0 */
+ std %f22, [%dst - 8] /* Store */
+ add %g3, %sum, %sum /* IEU0 Group */
+3: rd %asi, %g2 /* LSU Group + 4 bubbles*/
#ifdef __KERNEL__
-4: sethi %hi(vis0s), %g7 /* IEU0 Group */
- or %g2, ASI_BLK_OR, %g2 /* IEU1 */
+4: sethi %hi(vis0s), %g7 /* IEU0 Group */
+ or %g2, ASI_BLK_OR, %g2 /* IEU1 */
#else
-4: rd %pc, %g7 /* LSU Group + 4 bubbles */
+4: rd %pc, %g7 /* LSU Group + 4 bubbles*/
#endif
- inc %g5 /* IEU0 Group */
- and %src, 0x38, %g3 /* IEU1 */
- membar #StoreLoad /* LSU Group */
- srl %g5, 1, %g5 /* IEU0 */
- inc %o4 /* IEU1 */
- sll %g3, 8, %g3 /* IEU0 Group */
- sub %len, 0xc0, %len /* IEU1 */
- addcc %g5, %sum, %sum /* IEU1 Group */
- srl %o4, 1, %o4 /* IEU0 */
- add %g7, %g3, %g7 /* IEU0 Group */
- add %o4, %sum, %sum /* IEU1 */
+ inc %g5 /* IEU0 Group */
+ and %src, 0x38, %g3 /* IEU1 */
+ membar #StoreLoad /* LSU Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ inc %o4 /* IEU1 */
+ sll %g3, 8, %g3 /* IEU0 Group */
+ sub %len, 0xc0, %len /* IEU1 */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ srl %o4, 1, %o4 /* IEU0 */
+ add %g7, %g3, %g7 /* IEU0 Group */
+ add %o4, %sum, %sum /* IEU1 */
#ifdef __KERNEL__
- jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
+ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
#else
- jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
+ jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
#endif
- fzero %f32 /* FPA */
+ fzero %f32 /* FPA */
.align 2048
-vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- add %src, 128, %src /* IEU0 Group */
- ldda [%src-128] %asi, %f0 /* Load Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f48, %f62 /* FPA Group f0 available */
- faligndata %f0, %f2, %f48 /* FPA Group f2 available */
- fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */
- fpadd32 %f0, %f62, %f0 /* FPA */
- fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */
- faligndata %f2, %f4, %f50 /* FPA */
- fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */
- faligndata %f4, %f6, %f52 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */
- inc %x1 /* IEU0 */
- faligndata %f6, %f8, %f54 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */
- srl %x1, 1, %x1 /* IEU0 */
- inc %x2 /* IEU1 */
- faligndata %f8, %f10, %f56 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */
- srl %x2, 1, %x2 /* IEU0 */
- add %sum, %x1, %sum /* IEU1 */
- faligndata %f10, %f12, %f58 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- add %sum, %x2, %sum /* IEU1 */
- faligndata %f12, %f14, %f60 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f62 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f62 /* FPA Group f0 available*/
+ faligndata %f0, %f2, %f48 /* FPA Group f2 available*/
+ fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/
+ fpadd32 %f0, %f62, %f0 /* FPA */
+ fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/
+ faligndata %f2, %f4, %f50 /* FPA */
+ fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/
+ faligndata %f4, %f6, %f52 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/
+ inc %x1 /* IEU0 */
+ faligndata %f6, %f8, %f54 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/
+ srl %x1, 1, %x1 /* IEU0 */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f56 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/
+ srl %x2, 1, %x2 /* IEU0 */
+ add %sum, %x1, %sum /* IEU1 */
+ faligndata %f10, %f12, %f58 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f60 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f62 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
- ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
- ,LDBLK(f32), STBLK,,,,,,,,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f32), STBLK,,,,,,,,
,bcs,pn %icc, vis0e1)
DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
- ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
- ,LDBLK(f0), STBLK,,,,,,,,
+ ,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+ ,LDBLK(f0), STBLK,,,,,,,,
,bcs,pn %icc, vis0e2)
- DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+ DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
,f48,f50,f52,f54,f56,f58,f60,f62,f62,
,LDBLK(f16), STBLK,,,,,,,,
,bcc,pt %icc, vis0)
-vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f48,f50,f52,f54,f56,f58,f60,f62,f32,
,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
@@ -447,39 +449,39 @@ vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f4
,f48,f50,f52,f54,f56,f58,f60,f62,f0,
,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
-vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
+vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,
,f48,f50,f52,f54,f56,f58,f60,f62,f16,
,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
.align 2048
-vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- add %src, 128 - 8, %src /* IEU0 Group */
- ldda [%src-128] %asi, %f0 /* Load Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f0, %f58 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- fcmpgt32 %f32, %f2, %x2 /* FPM Group */
- faligndata %f2, %f4, %f48 /* FPA */
- fcmpgt32 %f32, %f4, %x3 /* FPM Group */
- faligndata %f4, %f6, %f50 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f52 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- inc %x2 /* IEU1 */
- faligndata %f8, %f10, %f54 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- srl %x2, 1, %x2 /* IEU0 */
- faligndata %f10, %f12, %f56 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- add %sum, %x2, %sum /* IEU1 */
- faligndata %f12, %f14, %f58 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f60 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 8, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f0, %f58 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f48 /* FPA */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f50 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f52 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f54 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ faligndata %f10, %f12, %f56 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f58 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f60 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f62,f48,f50,f52,f54,f56,f58,f60,f60,
,LDBLK(f32), ,STBLK,,,,,,,
@@ -505,31 +507,31 @@ vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
.align 2048
-vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- add %src, 128 - 16, %src /* IEU0 Group */
- ldda [%src-128] %asi, %f0 /* Load Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f0, %f56 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fcmpgt32 %f32, %f4, %x3 /* FPM Group */
- faligndata %f4, %f6, %f48 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f50 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f52 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f54 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- faligndata %f12, %f14, %f56 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f58 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 16, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f0, %f56 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f48 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f50 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f52 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f54 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ faligndata %f12, %f14, %f56 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f58 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f60,f62,f48,f50,f52,f54,f56,f58,f58,
,LDBLK(f32), ,,STBLK,,,,,,
@@ -555,27 +557,27 @@ vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
.align 2048
-vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- add %src, 128 - 24, %src /* IEU0 Group */
- ldda [%src-128] %asi, %f0 /* Load Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f0, %f54 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fpsub32 %f4, %f4, %f4 /* FPA Group */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f48 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f50 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f52 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f54 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f56 /* FPA */
- inc %x4 /* IEU0 */
- srl %x4, 1, %x4 /* IEU0 Group */
+vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 24, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f0, %f54 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fpsub32 %f4, %f4, %f4 /* FPA Group */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f48 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f50 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f52 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f54 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f56 /* FPA */
+ inc %x4 /* IEU0 */
+ srl %x4, 1, %x4 /* IEU0 Group */
vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f58,f60,f62,f48,f50,f52,f54,f56,f56,
,LDBLK(f32), ,,,STBLK,,,,,
@@ -601,25 +603,25 @@ vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
.align 2048
-vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- add %src, 128 - 32, %src /* IEU0 Group */
- ldda [%src-128] %asi, %f0 /* Load Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f0, %f52 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fpsub32 %f4, %f4, %f4 /* FPA Group */
- fpsub32 %f6, %f6, %f6 /* FPA Group */
- clr %x4 /* IEU0 */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f48 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f50 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f52 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f54 /* FPA */
+vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ add %src, 128 - 32, %src /* IEU0 Group */
+ ldda [%src-128] %asi, %f0 /* Load Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f0, %f52 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fpsub32 %f4, %f4, %f4 /* FPA Group */
+ fpsub32 %f6, %f6, %f6 /* FPA Group */
+ clr %x4 /* IEU0 */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f48 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f50 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f52 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f54 /* FPA */
vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f56,f58,f60,f62,f48,f50,f52,f54,f54,
,LDBLK(f32), ,,,,STBLK,,,,
@@ -645,26 +647,26 @@ vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
.align 2048
-vis5s: add %src, 128 - 40, %src /* IEU0 Group */
- ldda [%src-88] %asi, %f10 /* Load Group */
- ldda [%src-80] %asi, %f12 /* Load Group */
- ldda [%src-72] %asi, %f14 /* Load Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- faligndata %f10, %f12, %f48 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f50 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f52 /* FPA */
+vis5s: add %src, 128 - 40, %src /* IEU0 Group */
+ ldda [%src-88] %asi, %f10 /* Load Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f10, %f12, %f48 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f50 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f52 /* FPA */
vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f54,f56,f58,f60,f62,f48,f50,f52,f52,
,LDBLK(f32), ,,,,,STBLK,,,
@@ -690,25 +692,25 @@ vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72),
,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
.align 2048
-vis6s: add %src, 128 - 48, %src /* IEU0 Group */
- ldda [%src-80] %asi, %f12 /* Load Group */
- ldda [%src-72] %asi, %f14 /* Load Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fmuld %f32, %f32, %f10 /* FPM */
- clr %x6 /* IEU0 */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- faligndata %f12, %f14, %f48 /* FPA */
- fmovd %f14, %f50 /* FPA Group */
+vis6s: add %src, 128 - 48, %src /* IEU0 Group */
+ ldda [%src-80] %asi, %f12 /* Load Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ faligndata %f12, %f14, %f48 /* FPA */
+ fmovd %f14, %f50 /* FPA Group */
vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f52,f54,f56,f58,f60,f62,f48,f50,f50,
,LDBLK(f32), ,,,,,,STBLK,,
@@ -734,24 +736,24 @@ vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,,,STBLK,ST(f48,64),
,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
.align 2048
-vis7s: add %src, 128 - 56, %src /* IEU0 Group */
- ldda [%src-72] %asi, %f14 /* Load Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src-64] %asi, %f16 /* Load Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fmuld %f32, %f32, %f10 /* FPM */
- clr %x6 /* IEU0 */
- faddd %f32, %f32, %f12 /* FPA Group */
- clr %x7 /* IEU0 */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- fmovd %f14, %f48 /* FPA */
+vis7s: add %src, 128 - 56, %src /* IEU0 Group */
+ ldda [%src-72] %asi, %f14 /* Load Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src-64] %asi, %f16 /* Load Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ faddd %f32, %f32, %f12 /* FPA Group */
+ clr %x7 /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fmovd %f14, %f48 /* FPA */
vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f50,f52,f54,f56,f58,f60,f62,f48,f48,
,LDBLK(f32), ,,,,,,,STBLK,
@@ -779,112 +781,112 @@ vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
-ett: rd %asi, %x4 /* LSU Group+4bubbles */
- rd %gsr, %x3 /* LSU Group+4bubbles */
+ett: rd %asi, %x4 /* LSU Group+4bubbles */
+ rd %gsr, %x3 /* LSU Group+4bubbles */
#ifdef __KERNEL__
- srl %x4, 3, %x5 /* IEU0 Group */
- xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */
- wr %x4, %x5, %asi /* LSU Group+4bubbles */
+ srl %x4, 3, %x5 /* IEU0 Group */
+ xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */
+ wr %x4, %x5, %asi /* LSU Group+4bubbles */
#else
- wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */
+ wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */
#endif
- andcc %x3, 7, %x3 /* IEU1 Group */
- add %dst, 8, %dst /* IEU0 */
- bne,pn %icc, 1f /* CTI */
- fzero %f10 /* FPA */
- brz,a,pn %len, 2f /* CTI+IEU1 Group */
- std %f6, [%dst - 8] /* Store */
-1: cmp %len, 8 /* IEU1 */
- blu,pn %icc, 3f /* CTI */
- sub %src, 64, %src /* IEU0 Group */
-1: ldda [%src] %asi, %f2 /* Load Group */
- fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */
- add %src, 8, %src /* IEU0 */
- add %dst, 8, %dst /* IEU1 */
- faligndata %f6, %f2, %f14 /* FPA Group */
- fcmpgt32 %f10, %f12, %x5 /* FPM Group */
- std %f14, [%dst - 16] /* Store */
- fmovd %f2, %f6 /* FPA */
- fmovd %f12, %f10 /* FPA Group */
- sub %len, 8, %len /* IEU1 */
- fzero %f16 /* FPA Group - FPU nop */
- fzero %f18 /* FPA Group - FPU nop */
- inc %x5 /* IEU0 */
- srl %x5, 1, %x5 /* IEU0 Group (regdep) */
- cmp %len, 8 /* IEU1 */
- bgeu,pt %icc, 1b /* CTI */
- add %x5, %sum, %sum /* IEU0 Group */
-3: brz,a,pt %x3, 2f /* CTI+IEU1 */
- std %f6, [%dst - 8] /* Store Group */
- st %f7, [%dst - 8] /* Store Group */
- sub %dst, 4, %dst /* IEU0 */
- add %len, 4, %len /* IEU1 */
+ andcc %x3, 7, %x3 /* IEU1 Group */
+ add %dst, 8, %dst /* IEU0 */
+ bne,pn %icc, 1f /* CTI */
+ fzero %f10 /* FPA */
+ brz,a,pn %len, 2f /* CTI+IEU1 Group */
+ std %f6, [%dst - 8] /* Store */
+1: cmp %len, 8 /* IEU1 */
+ blu,pn %icc, 3f /* CTI */
+ sub %src, 64, %src /* IEU0 Group */
+1: ldda [%src] %asi, %f2 /* Load Group */
+ fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ faligndata %f6, %f2, %f14 /* FPA Group */
+ fcmpgt32 %f10, %f12, %x5 /* FPM Group */
+ std %f14, [%dst - 16] /* Store */
+ fmovd %f2, %f6 /* FPA */
+ fmovd %f12, %f10 /* FPA Group */
+ sub %len, 8, %len /* IEU1 */
+ fzero %f16 /* FPA Group - FPU nop */
+ fzero %f18 /* FPA Group - FPU nop */
+ inc %x5 /* IEU0 */
+ srl %x5, 1, %x5 /* IEU0 Group (regdep) */
+ cmp %len, 8 /* IEU1 */
+ bgeu,pt %icc, 1b /* CTI */
+ add %x5, %sum, %sum /* IEU0 Group */
+3: brz,a,pt %x3, 2f /* CTI+IEU1 */
+ std %f6, [%dst - 8] /* Store Group */
+ st %f7, [%dst - 8] /* Store Group */
+ sub %dst, 4, %dst /* IEU0 */
+ add %len, 4, %len /* IEU1 */
2:
#ifdef __KERNEL__
- sub %sp, 8, %sp /* IEU0 Group */
+ sub %sp, 8, %sp /* IEU0 Group */
#endif
END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
- membar #Sync /* LSU Group */
+ membar #Sync /* LSU Group */
#ifdef __KERNEL__
VISExit
- add %sp, 8, %sp /* IEU0 Group */
+ add %sp, 8, %sp /* IEU0 Group */
#endif
-23: brnz,pn %len, 26f /* CTI+IEU1 Group */
-24: sllx %sum, 32, %g1 /* IEU0 */
-25: addcc %sum, %g1, %src /* IEU1 Group */
- srlx %src, 32, %src /* IEU0 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %src, 1, %src /* IEU1 */
+23: brnz,pn %len, 26f /* CTI+IEU1 Group */
+24: sllx %sum, 32, %g1 /* IEU0 */
+25: addcc %sum, %g1, %src /* IEU1 Group */
+ srlx %src, 32, %src /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %src, 1, %src /* IEU1 */
#ifndef __KERNEL__
-1: retl /* CTI Group brk forced */
- srl %src, 0, %src /* IEU0 */
+1: retl /* CTI Group brk forced*/
+ srl %src, 0, %src /* IEU0 */
#else
-1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
- retl /* CTI Group brk forced */
- sllx %g4, 32, %g4 /* IEU0 */
+1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
+ retl /* CTI Group brk forced*/
+ sllx %g4, 32, %g4 /* IEU0 */
#endif
-26: andcc %len, 8, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- lduwa [%src] %asi, %o4 /* Load */
- lduwa [%src+4] %asi, %g2 /* Load Group */
- add %src, 8, %src /* IEU0 */
- add %dst, 8, %dst /* IEU1 */
- sllx %o4, 32, %g5 /* IEU0 Group */
- stw %o4, [%dst - 8] /* Store */
- or %g5, %g2, %g5 /* IEU0 Group */
- stw %g2, [%dst - 4] /* Store */
- addcc %g5, %sum, %sum /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: andcc %len, 4, %g0 /* IEU1 Group */
- be,a,pn %icc, 1f /* CTI */
- clr %g2 /* IEU0 */
- lduwa [%src] %asi, %g7 /* Load */
- add %src, 4, %src /* IEU0 Group */
- add %dst, 4, %dst /* IEU1 */
- sllx %g7, 32, %g2 /* IEU0 Group */
- stw %g7, [%dst - 4] /* Store */
-1: andcc %len, 2, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %g3 /* IEU0 Group */
- lduha [%src] %asi, %g7 /* Load */
- add %src, 2, %src /* IEU1 */
- add %dst, 2, %dst /* IEU0 Group */
- sll %g7, 16, %g3 /* IEU0 Group */
- sth %g7, [%dst - 2] /* Store */
-1: andcc %len, 1, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o5 /* IEU0 Group */
- lduba [%src] %asi, %g7 /* Load */
- sll %g7, 8, %o5 /* IEU0 Group */
- stb %g7, [%dst] /* Store */
-1: or %g2, %g3, %g3 /* IEU1 */
- or %o5, %g3, %g3 /* IEU0 Group (regdep) */
- addcc %g3, %sum, %sum /* IEU1 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: ba,pt %xcc, 25b /* CTI Group */
- sllx %sum, 32, %g1 /* IEU0 */
+26: andcc %len, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ lduwa [%src] %asi, %o4 /* Load */
+ lduwa [%src+4] %asi, %g2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ sllx %o4, 32, %g5 /* IEU0 Group */
+ stw %o4, [%dst - 8] /* Store */
+ or %g5, %g2, %g5 /* IEU0 Group */
+ stw %g2, [%dst - 4] /* Store */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: andcc %len, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduwa [%src] %asi, %g7 /* Load */
+ add %src, 4, %src /* IEU0 Group */
+ add %dst, 4, %dst /* IEU1 */
+ sllx %g7, 32, %g2 /* IEU0 Group */
+ stw %g7, [%dst - 4] /* Store */
+1: andcc %len, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g3 /* IEU0 Group */
+ lduha [%src] %asi, %g7 /* Load */
+ add %src, 2, %src /* IEU1 */
+ add %dst, 2, %dst /* IEU0 Group */
+ sll %g7, 16, %g3 /* IEU0 Group */
+ sth %g7, [%dst - 2] /* Store */
+1: andcc %len, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ lduba [%src] %asi, %g7 /* Load */
+ sll %g7, 8, %o5 /* IEU0 Group */
+ stb %g7, [%dst] /* Store */
+1: or %g2, %g3, %g3 /* IEU1 */
+ or %o5, %g3, %g3 /* IEU0 Group (regdep) */
+ addcc %g3, %sum, %sum /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %sum, 32, %g1 /* IEU0 */
#ifdef __KERNEL__
end:
diff --git a/arch/sparc64/lib/VIScsumcopyusr.S b/arch/sparc64/lib/VIScsumcopyusr.S
index 17bbe78b1..4730a1c08 100644
--- a/arch/sparc64/lib/VIScsumcopyusr.S
+++ b/arch/sparc64/lib/VIScsumcopyusr.S
@@ -1,4 +1,4 @@
-/* $Id: VIScsumcopyusr.S,v 1.1 2000/01/19 04:06:04 davem Exp $
+/* $Id: VIScsumcopyusr.S,v 1.2 2000/02/20 23:21:40 davem Exp $
* VIScsumcopyusr.S: High bandwidth IP checksumming with simultaneous
* copying utilizing the UltraSparc Visual Instruction Set.
*
@@ -91,358 +91,360 @@
#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \
- LOAD /* Load Group */; \
- faligndata %A14, %F0, %A14 /* FPA Group */; \
- inc %x5 /* IEU0 */; \
- STORE1 /* Store (optional) */; \
- faligndata %F0, %F2, %A0 /* FPA Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- add %sum, %x4, %sum /* IEU1 */; \
- fpadd32 %F0, %f0, %F0 /* FPA Group */; \
- inc %x6 /* IEU0 */; \
- STORE2 /* Store (optional) */; \
- faligndata %F2, %F4, %A2 /* FPA Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fpadd32 %F2, %f2, %F2 /* FPA Group */; \
- add %src, 64, %src /* IEU0 */; \
- add %dst, 64, %dst /* IEU1 */; \
- fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \
- inc %x7 /* IEU0 */; \
- STORE3 /* Store (optional) */; \
- faligndata %F4, %F6, %A4 /* FPA */; \
- srl %x7, 1, %x7 /* IEU0 Group */; \
- add %sum, %x6, %sum /* IEU1 */; \
- fpadd32 %F4, %f4, %F4 /* FPA */; \
- fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \
- inc %x8 /* IEU0 */; \
- STORE4 /* Store (optional) */; \
- faligndata %F6, %F8, %A6 /* FPA */; \
- srl %x8, 1, %x8 /* IEU0 Group */; \
- add %sum, %x7, %sum /* IEU1 */; \
- fpadd32 %F6, %f6, %F6 /* FPA */; \
- fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \
- inc %x1 /* IEU0 */; \
- STORE5 /* Store (optional) */; \
- faligndata %F8, %F10, %A8 /* FPA */; \
- srl %x1, 1, %x1 /* IEU0 Group */; \
- add %sum, %x8, %sum /* IEU1 */; \
- fpadd32 %F8, %f8, %F8 /* FPA */; \
- fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \
- inc %x2 /* IEU0 */; \
- STORE6 /* Store (optional) */; \
- faligndata %F10, %F12, %A10 /* FPA */; \
- srl %x2, 1, %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- fpadd32 %F10, %f10, %F10 /* FPA */; \
- fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \
- inc %x3 /* IEU0 */; \
- STORE7 /* Store (optional) */; \
- faligndata %F12, %F14, %A12 /* FPA */; \
- srl %x3, 1, %x3 /* IEU0 Group */; \
- add %sum, %x2, %sum /* IEU1 */; \
- fpadd32 %F12, %f12, %F12 /* FPA */; \
- fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \
- inc %x4 /* IEU0 */; \
- STORE8 /* Store (optional) */; \
- fmovd %F14, %B14 /* FPA */; \
- srl %x4, 1, %x4 /* IEU0 Group */; \
- add %sum, %x3, %sum /* IEU1 */; \
- fpadd32 %F14, %f14, %F14 /* FPA */; \
- fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \
- subcc %len, 64, %len /* IEU1 */; \
- BRANCH /* CTI */; \
- fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \
+ LOAD /* Load (Group) */; \
+ faligndata %A14, %F0, %A14 /* FPA Group */; \
+ inc %x5 /* IEU0 */; \
+ STORE1 /* Store (optional) */; \
+ faligndata %F0, %F2, %A0 /* FPA Group */; \
+ srl %x5, 1, %x5 /* IEU0 */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ fpadd32 %F0, %f0, %F0 /* FPA Group */; \
+ inc %x6 /* IEU0 */; \
+ STORE2 /* Store (optional) */; \
+ faligndata %F2, %F4, %A2 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fpadd32 %F2, %f2, %F2 /* FPA Group */; \
+ add %src, 64, %src /* IEU0 */; \
+ fcmpgt32 %f0, %F0, %x1 /* FPM */; \
+ add %dst, 64, %dst /* IEU1 Group */; \
+ inc %x7 /* IEU0 */; \
+ STORE3 /* Store (optional) */; \
+ faligndata %F4, %F6, %A4 /* FPA */; \
+ fpadd32 %F4, %f4, %F4 /* FPA Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ fcmpgt32 %f2, %F2, %x2 /* FPM */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ inc %x8 /* IEU1 */; \
+ STORE4 /* Store (optional) */; \
+ faligndata %F6, %F8, %A6 /* FPA */; \
+ fpadd32 %F6, %f6, %F6 /* FPA Group */; \
+ srl %x8, 1, %x8 /* IEU0 */; \
+ fcmpgt32 %f4, %F4, %x3 /* FPM */; \
+ add %sum, %x7, %sum /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ STORE5 /* Store (optional) */; \
+ faligndata %F8, %F10, %A8 /* FPA */; \
+ fpadd32 %F8, %f8, %F8 /* FPA Group */; \
+ srl %x1, 1, %x1 /* IEU0 */; \
+ fcmpgt32 %f6, %F6, %x4 /* FPM */; \
+ add %sum, %x8, %sum /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ STORE6 /* Store (optional) */; \
+ faligndata %F10, %F12, %A10 /* FPA */; \
+ fpadd32 %F10, %f10, %F10 /* FPA Group */; \
+ srl %x2, 1, %x2 /* IEU0 */; \
+ fcmpgt32 %f8, %F8, %x5 /* FPM */; \
+ add %sum, %x1, %sum /* IEU0 Group */; \
+ inc %x3 /* IEU1 */; \
+ STORE7 /* Store (optional) */; \
+ faligndata %F12, %F14, %A12 /* FPA */; \
+ fpadd32 %F12, %f12, %F12 /* FPA Group */; \
+ srl %x3, 1, %x3 /* IEU0 */; \
+ fcmpgt32 %f10, %F10, %x6 /* FPM */; \
+ add %sum, %x2, %sum /* IEU0 Group */; \
+ inc %x4 /* IEU1 */; \
+ STORE8 /* Store (optional) */; \
+ fmovd %F14, %B14 /* FPA */; \
+ fpadd32 %F14, %f14, %F14 /* FPA Group */; \
+ srl %x4, 1, %x4 /* IEU0 */; \
+ fcmpgt32 %f12, %F12, %x7 /* FPM */; \
+ add %sum, %x3, %sum /* IEU0 Group */; \
+ subcc %len, 64, %len /* IEU1 */; \
+ BRANCH /* CTI */; \
+ fcmpgt32 %f14, %F14, %x8 /* FPM Group */;
#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
- inc %x5 /* IEU0 Group */; \
- fpadd32 %f2, %f0, %S0 /* FPA */; \
- srl %x5, 1, %x5 /* IEU0 Group */; \
- add %sum, %x4, %sum /* IEU1 */; \
- fpadd32 %f6, %f4, %S1 /* FPA */; \
- inc %x6 /* IEU0 Group */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- inc %x7 /* IEU1 */; \
- fpadd32 %f10, %f8, %S2 /* FPA */; \
- fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \
- srl %x7, 1, %x7 /* IEU0 */; \
- add %sum, %x6, %sum /* IEU1 */; \
- fpadd32 %f14, %f12, %S3 /* FPA */; \
- inc %x8 /* IEU0 Group */; \
- add %sum, %x7, %sum /* IEU1 */; \
- fzero %fz /* FPA */; \
- fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \
- srl %x8, 1, %x8 /* IEU0 */; \
- inc %x1 /* IEU1 */; \
- fpadd32 %S0, %S1, %T0 /* FPA */; \
- fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \
- srl %x1, 1, %x1 /* IEU0 */; \
- add %sum, %x8, %sum /* IEU1 */; \
- fpadd32 %S2, %S3, %T1 /* FPA */; \
- inc %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \
- srl %x2, 1, %x2 /* IEU0 */; \
- inc %x3 /* IEU1 */; \
- fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \
- srl %x3, 1, %x3 /* IEU0 */; \
- add %sum, %x2, %sum /* IEU1 */; \
- inc %x4 /* IEU0 Group */; \
- add %sum, %x3, %sum /* IEU1 */; \
- fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \
- srl %x4, 1, %x4 /* IEU0 */; \
- inc %x5 /* IEU1 */; \
- fpadd32 %T0, %T1, %U0 /* FPA */; \
- fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- add %sum, %x4, %sum /* IEU1 */; \
- inc %x6 /* IEU0 Group */; \
- add %sum, %x5, %sum /* IEU1 */; \
- fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \
- srl %x6, 1, %x6 /* IEU0 */; \
- inc %x7 /* IEU1 */; \
- fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \
- ba,pt %xcc, ett /* CTI */; \
- fmovd %FA, %FB /* FPA */; \
+ inc %x5 /* IEU0 Group */; \
+ fpadd32 %f2, %f0, %S0 /* FPA */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ fpadd32 %f6, %f4, %S1 /* FPA */; \
+ inc %x6 /* IEU1 */; \
+ fpadd32 %f10, %f8, %S2 /* FPA Group */; \
+ add %sum, %x5, %sum /* IEU0 */; \
+ fcmpgt32 %f0, %S0, %x1 /* FPM */; \
+ fpadd32 %f14, %f12, %S3 /* FPA Group */; \
+ srl %x6, 1, %x6 /* IEU0 */; \
+ fcmpgt32 %f4, %S1, %x2 /* FPM */; \
+ add %sum, %x6, %sum /* IEU0 Group */; \
+ fzero %fz /* FPA */; \
+ fcmpgt32 %f8, %S2, %x3 /* FPM */; \
+ inc %x7 /* IEU0 Group */; \
+ inc %x8 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ fpadd32 %S0, %S1, %T0 /* FPA */; \
+ fpadd32 %S2, %S3, %T1 /* FPA Group */; \
+ add %sum, %x7, %sum /* IEU0 */; \
+ fcmpgt32 %f12, %S3, %x4 /* FPM */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ inc %x2 /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ add %sum, %x8, %sum /* IEU1 */; \
+ add %sum, %x1, %sum /* IEU0 Group */; \
+ fcmpgt32 %S0, %T0, %x5 /* FPM */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ fcmpgt32 %S2, %T1, %x6 /* FPM */; \
+ inc %x3 /* IEU0 Group */; \
+ add %sum, %x2, %sum /* IEU1 */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ inc %x4 /* IEU1 */; \
+ fpadd32 %T0, %T1, %U0 /* FPA Group */; \
+ add %sum, %x3, %sum /* IEU0 */; \
+ fcmpgt32 %fz, %f2, %x7 /* FPM */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f6, %x8 /* FPM */; \
+ inc %x5 /* IEU0 Group */; \
+ add %sum, %x4, %sum /* IEU1 */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ fcmpgt32 %fz, %f10, %x1 /* FPM */; \
+ inc %x6 /* IEU0 Group */; \
+ add %sum, %x5, %sum /* IEU1 */; \
+ fmovd %FA, %FB /* FPA Group */; \
+ fcmpgt32 %fz, %f14, %x2 /* FPM */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ ba,pt %xcc, ett /* CTI */; \
+ inc %x7 /* IEU1 */;
-#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \
END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
-#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
- fpadd32 %U0, %U1, %V0 /* FPA Group */; \
- srl %x7, 1, %x7 /* IEU0 */; \
- add %sum, %x6, %sum /* IEU1 */; \
- std %V0, [%sp + STACKOFF] /* Store Group */; \
- inc %x8 /* IEU0 */; \
- sub %sum, %x7, %sum /* IEU1 */; \
- fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \
- srl %x8, 1, %x8 /* IEU0 */; \
- inc %x1 /* IEU1 */; \
- fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \
- srl %x1, 1, %x1 /* IEU0 */; \
- sub %sum, %x8, %sum /* IEU1 */; \
- ldx [%sp + STACKOFF], %x8 /* Load Group */; \
- inc %x2 /* IEU0 */; \
- sub %sum, %x1, %sum /* IEU1 */; \
- fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \
- srl %x2, 1, %x2 /* IEU0 */; \
- inc %x3 /* IEU1 */; \
- fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \
- srl %x3, 1, %x3 /* IEU0 */; \
- sub %sum, %x2, %sum /* IEU1 */; \
- inc %x4 /* IEU0 Group */; \
- sub %sum, %x3, %sum /* IEU1 */; \
- fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \
- srl %x4, 1, %x4 /* IEU0 */; \
- inc %x5 /* IEU1 */; \
- fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \
- srl %x5, 1, %x5 /* IEU0 */; \
- sub %sum, %x4, %sum /* IEU1 */; \
- fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \
- inc %x6 /* IEU0 */; \
- sub %sum, %x5, %sum /* IEU1 */; \
- srl %x6, 1, %x6 /* IEU0 Group */; \
- inc %x7 /* IEU1 */; \
- srl %x7, 1, %x7 /* IEU0 Group */; \
- add %sum, %x6, %sum /* IEU1 */; \
- inc %x1 /* IEU0 Group */; \
- sub %sum, %x7, %sum /* IEU1 */; \
- srl %x1, 1, %x1 /* IEU0 Group */; \
- inc %x2 /* IEU1 */; \
- srl %x2, 1, %x2 /* IEU0 Group */; \
- add %sum, %x1, %sum /* IEU1 */; \
- sub %sum, %x2, %sum /* IEU0 Group */; \
- addcc %sum, %x8, %sum /* IEU Group */; \
- bcs,a,pn %xcc, 33f /* CTI */; \
- add %sum, 1, %sum /* IEU0 */; \
-33: /* That's it */;
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \
+ fpadd32 %U0, %U1, %V0 /* FPA Group */; \
+ srl %x7, 1, %x7 /* IEU0 */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ std %V0, [%sp + STACKOFF] /* Store Group */; \
+ inc %x8 /* IEU0 */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ srl %x8, 1, %x8 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S1, %x3 /* FPM */; \
+ inc %x1 /* IEU0 Group */; \
+ fcmpgt32 %fz, %S3, %x4 /* FPM */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ sub %sum, %x8, %sum /* IEU1 */; \
+ ldx [%sp + STACKOFF], %x8 /* Load Group */; \
+ inc %x2 /* IEU0 */; \
+ sub %sum, %x1, %sum /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ fcmpgt32 %fz, %T1, %x5 /* FPM */; \
+ inc %x3 /* IEU0 Group */; \
+ fcmpgt32 %T0, %U0, %x6 /* FPM */; \
+ srl %x3, 1, %x3 /* IEU0 Group */; \
+ sub %sum, %x2, %sum /* IEU1 */; \
+ inc %x4 /* IEU0 Group */; \
+ sub %sum, %x3, %sum /* IEU1 */; \
+ srl %x4, 1, %x4 /* IEU0 Group */; \
+ fcmpgt32 %fz, %U1, %x7 /* FPM */; \
+ inc %x5 /* IEU0 Group */; \
+ fcmpgt32 %U0, %V0, %x1 /* FPM */; \
+ srl %x5, 1, %x5 /* IEU0 Group */; \
+ sub %sum, %x4, %sum /* IEU1 */; \
+ sub %sum, %x5, %sum /* IEU0 Group */; \
+ fcmpgt32 %fz, %V0, %x2 /* FPM */; \
+ inc %x6 /* IEU0 Group */; \
+ inc %x7 /* IEU1 */; \
+ srl %x6, 1, %x6 /* IEU0 Group */; \
+ inc %x1 /* IEU1 */; \
+ srl %x7, 1, %x7 /* IEU0 Group */; \
+ add %sum, %x6, %sum /* IEU1 */; \
+ srl %x1, 1, %x1 /* IEU0 Group */; \
+ sub %sum, %x7, %sum /* IEU1 */; \
+ inc %x2 /* IEU0 Group */; \
+ add %sum, %x1, %sum /* IEU1 */; \
+ srl %x2, 1, %x2 /* IEU0 Group */; \
+ sub %sum, %x2, %sum /* IEU0 Group */; \
+ addcc %sum, %x8, %sum /* IEU1 Group */; \
+ bcs,a,pn %xcc, 33f /* CTI */; \
+ add %sum, 1, %sum /* IEU0 (Group) */; \
+33: /* That's it */;
.text
.globl csum_partial_copy_user_vis
.align 32
-/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */
-/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp.
+ * csum_partial_copy_from_user
+ * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256
+ */
csum_partial_copy_user_vis:
- andcc %dst, 7, %g0 /* IEU1 Group */
- be,pt %icc, 4f /* CTI */
- and %dst, 0x38, %o4 /* IEU0 */
- mov 1, %g5 /* IEU0 Group */
- andcc %dst, 2, %g0 /* IEU1 */
- be,pt %icc, 1f /* CTI */
- and %dst, 4, %g7 /* IEU0 Group */
- lduh [%src], %g2 /* Load */
- sub %len, 2, %len /* IEU0 Group */
- add %dst, 2, %dst /* IEU1 */
- andcc %dst, 4, %g7 /* IEU1 Group */
- sll %g5, 16, %g5 /* IEU0 */
- stha %g2, [%dst - 2] %asi /* Store Group */
- sll %g2, 16, %g2 /* IEU0 */
- add %src, 2, %src /* IEU1 */
- addcc %g2, %sum, %sum /* IEU1 Group */
- bcs,a,pn %icc, 1f /* CTI */
- add %sum, %g5, %sum /* IEU0 */
-1: lduw [%src], %g2 /* Load */
- brz,a,pn %g7, 4f /* CTI+IEU1 Group */
- and %dst, 0x38, %o4 /* IEU0 */
- add %dst, 4, %dst /* IEU0 Group */
- sub %len, 4, %len /* IEU1 */
- addcc %g2, %sum, %sum /* IEU1 Group */
- bcs,a,pn %icc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: and %dst, 0x38, %o4 /* IEU0 Group */
- stwa %g2, [%dst - 4] %asi /* Store */
- add %src, 4, %src /* IEU1 */
+ andcc %dst, 7, %g0 /* IEU1 Group */
+ be,pt %icc, 4f /* CTI */
+ and %dst, 0x38, %o4 /* IEU0 */
+ mov 1, %g5 /* IEU0 Group */
+ andcc %dst, 2, %g0 /* IEU1 */
+ be,pt %icc, 1f /* CTI */
+ and %dst, 4, %g7 /* IEU0 Group */
+ lduh [%src], %g2 /* Load */
+ sub %len, 2, %len /* IEU0 Group */
+ add %dst, 2, %dst /* IEU1 */
+ andcc %dst, 4, %g7 /* IEU1 Group */
+ sll %g5, 16, %g5 /* IEU0 */
+ stha %g2, [%dst - 2] %asi /* Store Group */
+ sll %g2, 16, %g2 /* IEU0 */
+ add %src, 2, %src /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, %g5, %sum /* IEU0 */
+1: lduw [%src], %g2 /* Load */
+ brz,a,pn %g7, 4f /* CTI+IEU1 Group */
+ and %dst, 0x38, %o4 /* IEU0 */
+ add %dst, 4, %dst /* IEU0 Group */
+ sub %len, 4, %len /* IEU1 */
+ addcc %g2, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %icc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: and %dst, 0x38, %o4 /* IEU0 Group */
+ stwa %g2, [%dst - 4] %asi /* Store */
+ add %src, 4, %src /* IEU1 */
4:
#ifdef __KERNEL__
VISEntry
#endif
- mov %src, %g7 /* IEU1 Group */
- fzero %f48 /* FPA */
- alignaddr %src, %g0, %src /* Single Group */
- subcc %g7, %src, %g7 /* IEU1 Group */
- be,pt %xcc, 1f /* CTI */
- mov 0x40, %g1 /* IEU0 */
- lduw [%src], %g2 /* Load Group */
- subcc %sum, %g2, %sum /* IEU1 Group+load stall */
- bcs,a,pn %icc, 1f /* CTI */
- sub %sum, 1, %sum /* IEU0 */
-1: srl %sum, 0, %sum /* IEU0 Group */
- clr %g5 /* IEU1 */
- brz,pn %o4, 3f /* CTI+IEU1 Group */
- sub %g1, %o4, %g1 /* IEU0 */
- ldd [%src], %f0 /* Load */
- clr %o4 /* IEU0 Group */
- andcc %dst, 8, %g0 /* IEU1 */
- be,pn %icc, 1f /* CTI */
- ldd [%src + 8], %f2 /* Load Group */
- add %src, 8, %src /* IEU0 */
- sub %len, 8, %len /* IEU1 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- addcc %dst, 8, %dst /* IEU1 Group */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %o4 /* FPM Group */
- fmovd %f2, %f0 /* FPA Group */
- ldd [%src + 8], %f2 /* Load */
- stda %f16, [%dst - 8] %asi /* Store */
- fmovd %f50, %f48 /* FPA */
-1: andcc %g1, 0x10, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- and %g1, 0x20, %g1 /* IEU0 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- ldd [%src + 16], %f4 /* Load Group */
- add %src, 16, %src /* IEU0 */
- add %dst, 16, %dst /* IEU1 */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %g5 /* FPM Group */
- sub %len, 16, %len /* IEU0 */
- inc %o4 /* IEU1 */
- stda %f16, [%dst - 16] %asi /* Store Group */
- fpadd32 %f2, %f50, %f48 /* FPA */
- srl %o4, 1, %o5 /* IEU0 */
- faligndata %f2, %f4, %f18 /* FPA Group */
- stda %f18, [%dst - 8] %asi /* Store */
- fcmpgt32 %f50, %f48, %o4 /* FPM Group */
- add %o5, %sum, %sum /* IEU0 */
- ldd [%src + 8], %f2 /* Load */
- fmovd %f4, %f0 /* FPA */
-1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
- rd %asi, %g2 /* LSU Group + 4 bubbles */
- inc %g5 /* IEU0 */
- fpadd32 %f0, %f48, %f50 /* FPA */
- ldd [%src + 16], %f4 /* Load Group */
- srl %g5, 1, %g5 /* IEU0 */
- add %dst, 32, %dst /* IEU1 */
- faligndata %f0, %f2, %f16 /* FPA */
- fcmpgt32 %f48, %f50, %o5 /* FPM Group */
- inc %o4 /* IEU0 */
- ldd [%src + 24], %f6 /* Load */
- srl %o4, 1, %o4 /* IEU0 Group */
- add %g5, %sum, %sum /* IEU1 */
- ldd [%src + 32], %f8 /* Load */
- fpadd32 %f2, %f50, %f48 /* FPA */
- faligndata %f2, %f4, %f18 /* FPA Group */
- sub %len, 32, %len /* IEU0 */
- stda %f16, [%dst - 32] %asi /* Store */
- fcmpgt32 %f50, %f48, %g3 /* FPM Group */
- inc %o5 /* IEU0 */
- add %o4, %sum, %sum /* IEU1 */
- fpadd32 %f4, %f48, %f50 /* FPA */
- faligndata %f4, %f6, %f20 /* FPA Group */
- srl %o5, 1, %o5 /* IEU0 */
- fcmpgt32 %f48, %f50, %g5 /* FPM Group */
- add %o5, %sum, %sum /* IEU0 */
- stda %f18, [%dst - 24] %asi /* Store */
- fpadd32 %f6, %f50, %f48 /* FPA */
- inc %g3 /* IEU0 Group */
- stda %f20, [%dst - 16] %asi /* Store */
- add %src, 32, %src /* IEU1 */
- faligndata %f6, %f8, %f22 /* FPA */
- fcmpgt32 %f50, %f48, %o4 /* FPM Group */
- srl %g3, 1, %g3 /* IEU0 */
- stda %f22, [%dst - 8] %asi /* Store */
- add %g3, %sum, %sum /* IEU0 Group */
-3: rd %asi, %g2 /* LSU Group + 4 bubbles */
+ mov %src, %g7 /* IEU1 Group */
+ fzero %f48 /* FPA */
+ alignaddr %src, %g0, %src /* Single Group */
+ subcc %g7, %src, %g7 /* IEU1 Group */
+ be,pt %xcc, 1f /* CTI */
+ mov 0x40, %g1 /* IEU0 */
+ lduw [%src], %g2 /* Load Group */
+ subcc %sum, %g2, %sum /* IEU1 Group+load stall*/
+ bcs,a,pn %icc, 1f /* CTI */
+ sub %sum, 1, %sum /* IEU0 */
+1: srl %sum, 0, %sum /* IEU0 Group */
+ clr %g5 /* IEU1 */
+ brz,pn %o4, 3f /* CTI+IEU1 Group */
+ sub %g1, %o4, %g1 /* IEU0 */
+ ldd [%src], %f0 /* Load */
+ clr %o4 /* IEU0 Group */
+ andcc %dst, 8, %g0 /* IEU1 */
+ be,pn %icc, 1f /* CTI */
+ ldd [%src + 8], %f2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ sub %len, 8, %len /* IEU1 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ addcc %dst, 8, %dst /* IEU1 Group */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o4 /* FPM Group */
+ fmovd %f2, %f0 /* FPA Group */
+ ldd [%src + 8], %f2 /* Load */
+ stda %f16, [%dst - 8] %asi /* Store */
+ fmovd %f50, %f48 /* FPA */
+1: andcc %g1, 0x10, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ and %g1, 0x20, %g1 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldd [%src + 16], %f4 /* Load Group */
+ add %src, 16, %src /* IEU0 */
+ add %dst, 16, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ sub %len, 16, %len /* IEU0 */
+ inc %o4 /* IEU1 */
+ stda %f16, [%dst - 16] %asi /* Store Group */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ srl %o4, 1, %o5 /* IEU0 */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ stda %f18, [%dst - 8] %asi /* Store */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ ldd [%src + 8], %f2 /* Load */
+ fmovd %f4, %f0 /* FPA */
+1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */
+ rd %asi, %g2 /* LSU Group + 4 bubbles*/
+ inc %g5 /* IEU0 */
+ fpadd32 %f0, %f48, %f50 /* FPA */
+ ldd [%src + 16], %f4 /* Load Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ add %dst, 32, %dst /* IEU1 */
+ faligndata %f0, %f2, %f16 /* FPA */
+ fcmpgt32 %f48, %f50, %o5 /* FPM Group */
+ inc %o4 /* IEU0 */
+ ldd [%src + 24], %f6 /* Load */
+ srl %o4, 1, %o4 /* IEU0 Group */
+ add %g5, %sum, %sum /* IEU1 */
+ ldd [%src + 32], %f8 /* Load */
+ fpadd32 %f2, %f50, %f48 /* FPA */
+ faligndata %f2, %f4, %f18 /* FPA Group */
+ sub %len, 32, %len /* IEU0 */
+ stda %f16, [%dst - 32] %asi /* Store */
+ fcmpgt32 %f50, %f48, %g3 /* FPM Group */
+ inc %o5 /* IEU0 */
+ add %o4, %sum, %sum /* IEU1 */
+ fpadd32 %f4, %f48, %f50 /* FPA */
+ faligndata %f4, %f6, %f20 /* FPA Group */
+ srl %o5, 1, %o5 /* IEU0 */
+ fcmpgt32 %f48, %f50, %g5 /* FPM Group */
+ add %o5, %sum, %sum /* IEU0 */
+ stda %f18, [%dst - 24] %asi /* Store */
+ fpadd32 %f6, %f50, %f48 /* FPA */
+ inc %g3 /* IEU0 Group */
+ stda %f20, [%dst - 16] %asi /* Store */
+ add %src, 32, %src /* IEU1 */
+ faligndata %f6, %f8, %f22 /* FPA */
+ fcmpgt32 %f50, %f48, %o4 /* FPM Group */
+ srl %g3, 1, %g3 /* IEU0 */
+ stda %f22, [%dst - 8] %asi /* Store */
+ add %g3, %sum, %sum /* IEU0 Group */
+3: rd %asi, %g2 /* LSU Group + 4 bubbles*/
#ifdef __KERNEL__
-4: sethi %hi(vis0s), %g7 /* IEU0 Group */
- or %g2, ASI_BLK_OR, %g2 /* IEU1 */
+4: sethi %hi(vis0s), %g7 /* IEU0 Group */
+ or %g2, ASI_BLK_OR, %g2 /* IEU1 */
#else
-4: rd %pc, %g7 /* LSU Group + 4 bubbles */
+4: rd %pc, %g7 /* LSU Group + 4 bubbles*/
#endif
- inc %g5 /* IEU0 Group */
- and %src, 0x38, %g3 /* IEU1 */
- membar #StoreLoad /* LSU Group */
- srl %g5, 1, %g5 /* IEU0 */
- inc %o4 /* IEU1 */
- sll %g3, 8, %g3 /* IEU0 Group */
- sub %len, 0xc0, %len /* IEU1 */
- addcc %g5, %sum, %sum /* IEU1 Group */
- srl %o4, 1, %o4 /* IEU0 */
- add %g7, %g3, %g7 /* IEU0 Group */
- add %o4, %sum, %sum /* IEU1 */
+ inc %g5 /* IEU0 Group */
+ and %src, 0x38, %g3 /* IEU1 */
+ membar #StoreLoad /* LSU Group */
+ srl %g5, 1, %g5 /* IEU0 */
+ inc %o4 /* IEU1 */
+ sll %g3, 8, %g3 /* IEU0 Group */
+ sub %len, 0xc0, %len /* IEU1 */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ srl %o4, 1, %o4 /* IEU0 */
+ add %g7, %g3, %g7 /* IEU0 Group */
+ add %o4, %sum, %sum /* IEU1 */
#ifdef __KERNEL__
- jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
+ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */
#else
- jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
+ jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */
#endif
- fzero %f32 /* FPA */
+ fzero %f32 /* FPA */
.align 2048
-vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src] ASI_BLK_P, %f0 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f48, %f62 /* FPA Group f0 available */
- faligndata %f0, %f2, %f48 /* FPA Group f2 available */
- fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */
- fpadd32 %f0, %f62, %f0 /* FPA */
- fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */
- faligndata %f2, %f4, %f50 /* FPA */
- fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */
- faligndata %f4, %f6, %f52 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */
- inc %x1 /* IEU0 */
- faligndata %f6, %f8, %f54 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */
- srl %x1, 1, %x1 /* IEU0 */
- inc %x2 /* IEU1 */
- faligndata %f8, %f10, %f56 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */
- srl %x2, 1, %x2 /* IEU0 */
- add %sum, %x1, %sum /* IEU1 */
- faligndata %f10, %f12, %f58 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- add %sum, %x2, %sum /* IEU1 */
- faligndata %f12, %f14, %f60 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f62 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src] ASI_BLK_P, %f0 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f48, %f62 /* FPA Group f0 available*/
+ faligndata %f0, %f2, %f48 /* FPA Group f2 available*/
+ fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/
+ fpadd32 %f0, %f62, %f0 /* FPA */
+ fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/
+ faligndata %f2, %f4, %f50 /* FPA */
+ fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/
+ faligndata %f4, %f6, %f52 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/
+ inc %x1 /* IEU0 */
+ faligndata %f6, %f8, %f54 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/
+ srl %x1, 1, %x1 /* IEU0 */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f56 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/
+ srl %x2, 1, %x2 /* IEU0 */
+ add %sum, %x1, %sum /* IEU1 */
+ faligndata %f10, %f12, %f58 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f60 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f62 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f48,f50,f52,f54,f56,f58,f60,f62,f62,
,LDBLK(f32), STBLK,,,,,,,,
@@ -468,36 +470,36 @@ vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
.align 2048
-vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- sub %src, 8, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f0 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f0, %f58 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- fcmpgt32 %f32, %f2, %x2 /* FPM Group */
- faligndata %f2, %f4, %f48 /* FPA */
- fcmpgt32 %f32, %f4, %x3 /* FPM Group */
- faligndata %f4, %f6, %f50 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f52 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- inc %x2 /* IEU1 */
- faligndata %f8, %f10, %f54 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- srl %x2, 1, %x2 /* IEU0 */
- faligndata %f10, %f12, %f56 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- add %sum, %x2, %sum /* IEU1 */
- faligndata %f12, %f14, %f58 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f60 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ sub %src, 8, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f0 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f0, %f58 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fcmpgt32 %f32, %f2, %x2 /* FPM Group */
+ faligndata %f2, %f4, %f48 /* FPA */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f50 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f52 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ inc %x2 /* IEU1 */
+ faligndata %f8, %f10, %f54 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ srl %x2, 1, %x2 /* IEU0 */
+ faligndata %f10, %f12, %f56 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ add %sum, %x2, %sum /* IEU1 */
+ faligndata %f12, %f14, %f58 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f60 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f62,f48,f50,f52,f54,f56,f58,f60,f60,
,LDBLK(f32), ,STBLK,,,,,,,
@@ -523,33 +525,33 @@ vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
.align 2048
-vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- sub %src, 16, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f0 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f0, %f56 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fcmpgt32 %f32, %f4, %x3 /* FPM Group */
- faligndata %f4, %f6, %f48 /* FPA */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f50 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f52 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f54 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- inc %x3 /* IEU0 */
- faligndata %f12, %f14, %f56 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- srl %x3, 1, %x3 /* IEU0 */
- inc %x4 /* IEU1 */
- fmovd %f14, %f58 /* FPA */
- srl %x4, 1, %x4 /* IEU0 Group */
- add %sum, %x3, %sum /* IEU1 */
+vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ sub %src, 16, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f0 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f0, %f56 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fcmpgt32 %f32, %f4, %x3 /* FPM Group */
+ faligndata %f4, %f6, %f48 /* FPA */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f50 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f52 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f54 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ inc %x3 /* IEU0 */
+ faligndata %f12, %f14, %f56 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ srl %x3, 1, %x3 /* IEU0 */
+ inc %x4 /* IEU1 */
+ fmovd %f14, %f58 /* FPA */
+ srl %x4, 1, %x4 /* IEU0 Group */
+ add %sum, %x3, %sum /* IEU1 */
vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f60,f62,f48,f50,f52,f54,f56,f58,f58,
,LDBLK(f32), ,,STBLK,,,,,,
@@ -575,29 +577,29 @@ vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
.align 2048
-vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- sub %src, 24, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f0 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f0, %f54 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fpsub32 %f4, %f4, %f4 /* FPA Group */
- fcmpgt32 %f32, %f6, %x4 /* FPM Group */
- faligndata %f6, %f8, %f48 /* FPA */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f50 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f52 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f54 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f56 /* FPA */
- inc %x4 /* IEU0 */
- srl %x4, 1, %x4 /* IEU0 Group */
+vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ sub %src, 24, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f0 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f0, %f54 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fpsub32 %f4, %f4, %f4 /* FPA Group */
+ fcmpgt32 %f32, %f6, %x4 /* FPM Group */
+ faligndata %f6, %f8, %f48 /* FPA */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f50 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f52 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f54 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f56 /* FPA */
+ inc %x4 /* IEU0 */
+ srl %x4, 1, %x4 /* IEU0 Group */
vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f58,f60,f62,f48,f50,f52,f54,f56,f56,
,LDBLK(f32), ,,,STBLK,,,,,
@@ -623,27 +625,27 @@ vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
.align 2048
-vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- sub %src, 32, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f0 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f0, %f52 /* FPA Group */
- fmovd %f48, %f0 /* FPA Group */
- sub %dst, 64, %dst /* IEU0 */
- fpsub32 %f2, %f2, %f2 /* FPA Group */
- fpsub32 %f4, %f4, %f4 /* FPA Group */
- fpsub32 %f6, %f6, %f6 /* FPA Group */
- clr %x4 /* IEU0 */
- fcmpgt32 %f32, %f8, %x5 /* FPM Group */
- faligndata %f8, %f10, %f48 /* FPA */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- faligndata %f10, %f12, %f50 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f52 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f54 /* FPA */
+vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ sub %src, 32, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f0 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f0, %f52 /* FPA Group */
+ fmovd %f48, %f0 /* FPA Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fpsub32 %f2, %f2, %f2 /* FPA Group */
+ fpsub32 %f4, %f4, %f4 /* FPA Group */
+ fpsub32 %f6, %f6, %f6 /* FPA Group */
+ clr %x4 /* IEU0 */
+ fcmpgt32 %f32, %f8, %x5 /* FPM Group */
+ faligndata %f8, %f10, %f48 /* FPA */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ faligndata %f10, %f12, %f50 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f52 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f54 /* FPA */
vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f56,f58,f60,f62,f48,f50,f52,f54,f54,
,LDBLK(f32), ,,,,STBLK,,,,
@@ -669,27 +671,27 @@ vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80),
,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
.align 2048
-vis5s: ldd [%src+0], %f10 /* Load Group */
- ldd [%src+8], %f12 /* Load Group */
- ldd [%src+16], %f14 /* Load Group */
- add %src, 24, %src /* IEU0 Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fcmpgt32 %f32, %f10, %x6 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- faligndata %f10, %f12, %f48 /* FPA */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- faligndata %f12, %f14, %f50 /* FPA */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- fmovd %f14, %f52 /* FPA */
+vis5s: ldd [%src+0], %f10 /* Load Group */
+ ldd [%src+8], %f12 /* Load Group */
+ ldd [%src+16], %f14 /* Load Group */
+ add %src, 24, %src /* IEU0 Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fcmpgt32 %f32, %f10, %x6 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ faligndata %f10, %f12, %f48 /* FPA */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ faligndata %f12, %f14, %f50 /* FPA */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ fmovd %f14, %f52 /* FPA */
vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f54,f56,f58,f60,f62,f48,f50,f52,f52,
,LDBLK(f32), ,,,,,STBLK,,,
@@ -715,26 +717,26 @@ vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72),
,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
.align 2048
-vis6s: ldd [%src+0], %f12 /* Load Group */
- ldd [%src+8], %f14 /* Load Group */
- add %src, 16, %src /* IEU0 Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fmuld %f32, %f32, %f10 /* FPM */
- clr %x6 /* IEU0 */
- fcmpgt32 %f32, %f12, %x7 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- faligndata %f12, %f14, %f48 /* FPA */
- fmovd %f14, %f50 /* FPA Group */
+vis6s: ldd [%src+0], %f12 /* Load Group */
+ ldd [%src+8], %f14 /* Load Group */
+ add %src, 16, %src /* IEU0 Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ fcmpgt32 %f32, %f12, %x7 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ faligndata %f12, %f14, %f48 /* FPA */
+ fmovd %f14, %f50 /* FPA Group */
vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f52,f54,f56,f58,f60,f62,f48,f50,f50,
,LDBLK(f32), ,,,,,,STBLK,,
@@ -760,25 +762,25 @@ vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
,SYNC, ,,,,,,STBLK_XORASI(x6,x7),ST(f48,64),
,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
.align 2048
-vis7s: ldd [%src+0], %f14 /* Load Group */
- add %src, 8, %src /* IEU0 Group */
- wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
- ldda [%src] ASI_BLK_P, %f16 /* Load Group */
- add %src, 64, %src /* IEU0 Group */
- fmovd %f48, %f0 /* FPA Group */
- fmuld %f32, %f32, %f2 /* FPM */
- clr %x4 /* IEU0 */
- faddd %f32, %f32, %f4 /* FPA Group */
- fmuld %f32, %f32, %f6 /* FPM */
- clr %x5 /* IEU0 */
- faddd %f32, %f32, %f8 /* FPA Group */
- fmuld %f32, %f32, %f10 /* FPM */
- clr %x6 /* IEU0 */
- faddd %f32, %f32, %f12 /* FPA Group */
- clr %x7 /* IEU0 */
- fcmpgt32 %f32, %f14, %x8 /* FPM Group */
- sub %dst, 64, %dst /* IEU0 */
- fmovd %f14, %f48 /* FPA */
+vis7s: ldd [%src+0], %f14 /* Load Group */
+ add %src, 8, %src /* IEU0 Group */
+ wr %g2, ASI_BLK_XOR, %asi /* LSU Group */
+ ldda [%src] ASI_BLK_P, %f16 /* Load Group */
+ add %src, 64, %src /* IEU0 Group */
+ fmovd %f48, %f0 /* FPA Group */
+ fmuld %f32, %f32, %f2 /* FPM */
+ clr %x4 /* IEU0 */
+ faddd %f32, %f32, %f4 /* FPA Group */
+ fmuld %f32, %f32, %f6 /* FPM */
+ clr %x5 /* IEU0 */
+ faddd %f32, %f32, %f8 /* FPA Group */
+ fmuld %f32, %f32, %f10 /* FPM */
+ clr %x6 /* IEU0 */
+ faddd %f32, %f32, %f12 /* FPA Group */
+ clr %x7 /* IEU0 */
+ fcmpgt32 %f32, %f14, %x8 /* FPM Group */
+ sub %dst, 64, %dst /* IEU0 */
+ fmovd %f14, %f48 /* FPA */
vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
,f50,f52,f54,f56,f58,f60,f62,f48,f48,
,LDBLK(f32), ,,,,,,,STBLK,
@@ -806,104 +808,104 @@ vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14
e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
-ett: rd %gsr, %x3 /* LSU Group+4bubbles */
- andcc %x3, 7, %x3 /* IEU1 Group */
- add %dst, 8, %dst /* IEU0 */
- bne,pn %icc, 1f /* CTI */
- fzero %f10 /* FPA */
- brz,a,pn %len, 2f /* CTI+IEU1 Group */
- stda %f6, [%dst - 8] %asi /* Store */
-1: cmp %len, 8 /* IEU1 */
- blu,pn %icc, 3f /* CTI */
- sub %src, 64, %src /* IEU0 Group */
-1: ldd [%src], %f2 /* Load Group */
- fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */
- add %src, 8, %src /* IEU0 */
- add %dst, 8, %dst /* IEU1 */
- faligndata %f6, %f2, %f14 /* FPA Group */
- fcmpgt32 %f10, %f12, %x5 /* FPM Group */
- stda %f14, [%dst - 16] %asi /* Store */
- fmovd %f2, %f6 /* FPA */
- fmovd %f12, %f10 /* FPA Group */
- sub %len, 8, %len /* IEU1 */
- fzero %f16 /* FPA Group - FPU nop */
- fzero %f18 /* FPA Group - FPU nop */
- inc %x5 /* IEU0 */
- srl %x5, 1, %x5 /* IEU0 Group (regdep) */
- cmp %len, 8 /* IEU1 */
- bgeu,pt %icc, 1b /* CTI */
- add %x5, %sum, %sum /* IEU0 Group */
-3: brz,a,pt %x3, 2f /* CTI+IEU1 */
- stda %f6, [%dst - 8] %asi /* Store Group */
- sta %f7, [%dst - 8] %asi /* Store Group */
- sub %dst, 4, %dst /* IEU0 */
- add %len, 4, %len /* IEU1 */
+ett: rd %gsr, %x3 /* LSU Group+4bubbles */
+ andcc %x3, 7, %x3 /* IEU1 Group */
+ add %dst, 8, %dst /* IEU0 */
+ bne,pn %icc, 1f /* CTI */
+ fzero %f10 /* FPA */
+ brz,a,pn %len, 2f /* CTI+IEU1 Group */
+ stda %f6, [%dst - 8] %asi /* Store */
+1: cmp %len, 8 /* IEU1 */
+ blu,pn %icc, 3f /* CTI */
+ sub %src, 64, %src /* IEU0 Group */
+1: ldd [%src], %f2 /* Load Group */
+ fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ faligndata %f6, %f2, %f14 /* FPA Group */
+ fcmpgt32 %f10, %f12, %x5 /* FPM Group */
+ stda %f14, [%dst - 16] %asi /* Store */
+ fmovd %f2, %f6 /* FPA */
+ fmovd %f12, %f10 /* FPA Group */
+ sub %len, 8, %len /* IEU1 */
+ fzero %f16 /* FPA Group - FPU nop */
+ fzero %f18 /* FPA Group - FPU nop */
+ inc %x5 /* IEU0 */
+ srl %x5, 1, %x5 /* IEU0 Group (regdep) */
+ cmp %len, 8 /* IEU1 */
+ bgeu,pt %icc, 1b /* CTI */
+ add %x5, %sum, %sum /* IEU0 Group */
+3: brz,a,pt %x3, 2f /* CTI+IEU1 */
+ stda %f6, [%dst - 8] %asi /* Store Group */
+ sta %f7, [%dst - 8] %asi /* Store Group */
+ sub %dst, 4, %dst /* IEU0 */
+ add %len, 4, %len /* IEU1 */
2:
#ifdef __KERNEL__
- sub %sp, 8, %sp /* IEU0 Group */
+ sub %sp, 8, %sp /* IEU0 Group */
#endif
END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
- membar #Sync /* LSU Group */
+ membar #Sync /* LSU Group */
#ifdef __KERNEL__
VISExit
- add %sp, 8, %sp /* IEU0 Group */
+ add %sp, 8, %sp /* IEU0 Group */
#endif
-23: brnz,pn %len, 26f /* CTI+IEU1 Group */
-24: sllx %sum, 32, %g1 /* IEU0 */
-25: addcc %sum, %g1, %src /* IEU1 Group */
- srlx %src, 32, %src /* IEU0 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %src, 1, %src /* IEU1 */
+23: brnz,pn %len, 26f /* CTI+IEU1 Group */
+24: sllx %sum, 32, %g1 /* IEU0 */
+25: addcc %sum, %g1, %src /* IEU1 Group */
+ srlx %src, 32, %src /* IEU0 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %src, 1, %src /* IEU1 */
#ifndef __KERNEL__
-1: retl /* CTI Group brk forced */
- srl %src, 0, %src /* IEU0 */
+1: retl /* CTI Group brk forced*/
+ srl %src, 0, %src /* IEU0 */
#else
-1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
- retl /* CTI Group brk forced */
- sllx %g4, 32, %g4 /* IEU0 */
+1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */
+ retl /* CTI Group brk forced*/
+ sllx %g4, 32, %g4 /* IEU0 */
#endif
-26: andcc %len, 8, %g0 /* IEU1 Group */
- be,pn %icc, 1f /* CTI */
- lduw [%src], %o4 /* Load */
- lduw [%src+4], %g2 /* Load Group */
- add %src, 8, %src /* IEU0 */
- add %dst, 8, %dst /* IEU1 */
- sllx %o4, 32, %g5 /* IEU0 Group */
- stwa %o4, [%dst - 8] %asi /* Store */
- or %g5, %g2, %g5 /* IEU0 Group */
- stwa %g2, [%dst - 4] %asi /* Store */
- addcc %g5, %sum, %sum /* IEU1 Group */
- bcs,a,pn %xcc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: andcc %len, 4, %g0 /* IEU1 Group */
- be,a,pn %icc, 1f /* CTI */
- clr %g2 /* IEU0 */
- lduw [%src], %g7 /* Load */
- add %src, 4, %src /* IEU0 Group */
- add %dst, 4, %dst /* IEU1 */
- sllx %g7, 32, %g2 /* IEU0 Group */
- stwa %g7, [%dst - 4] %asi /* Store */
-1: andcc %len, 2, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %g3 /* IEU0 Group */
- lduh [%src], %g7 /* Load */
- add %src, 2, %src /* IEU1 */
- add %dst, 2, %dst /* IEU0 Group */
- sll %g7, 16, %g3 /* IEU0 Group */
- stha %g7, [%dst - 2] %asi /* Store */
-1: andcc %len, 1, %g0 /* IEU1 */
- be,a,pn %icc, 1f /* CTI */
- clr %o5 /* IEU0 Group */
- ldub [%src], %g7 /* Load */
- sll %g7, 8, %o5 /* IEU0 Group */
- stba %g7, [%dst] %asi /* Store */
-1: or %g2, %g3, %g3 /* IEU1 */
- or %o5, %g3, %g3 /* IEU0 Group (regdep) */
- addcc %g3, %sum, %sum /* IEU1 Group (regdep) */
- bcs,a,pn %xcc, 1f /* CTI */
- add %sum, 1, %sum /* IEU0 */
-1: ba,pt %xcc, 25b /* CTI Group */
- sllx %sum, 32, %g1 /* IEU0 */
+26: andcc %len, 8, %g0 /* IEU1 Group */
+ be,pn %icc, 1f /* CTI */
+ lduw [%src], %o4 /* Load */
+ lduw [%src+4], %g2 /* Load Group */
+ add %src, 8, %src /* IEU0 */
+ add %dst, 8, %dst /* IEU1 */
+ sllx %o4, 32, %g5 /* IEU0 Group */
+ stwa %o4, [%dst - 8] %asi /* Store */
+ or %g5, %g2, %g5 /* IEU0 Group */
+ stwa %g2, [%dst - 4] %asi /* Store */
+ addcc %g5, %sum, %sum /* IEU1 Group */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: andcc %len, 4, %g0 /* IEU1 Group */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g2 /* IEU0 */
+ lduw [%src], %g7 /* Load */
+ add %src, 4, %src /* IEU0 Group */
+ add %dst, 4, %dst /* IEU1 */
+ sllx %g7, 32, %g2 /* IEU0 Group */
+ stwa %g7, [%dst - 4] %asi /* Store */
+1: andcc %len, 2, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %g3 /* IEU0 Group */
+ lduh [%src], %g7 /* Load */
+ add %src, 2, %src /* IEU1 */
+ add %dst, 2, %dst /* IEU0 Group */
+ sll %g7, 16, %g3 /* IEU0 Group */
+ stha %g7, [%dst - 2] %asi /* Store */
+1: andcc %len, 1, %g0 /* IEU1 */
+ be,a,pn %icc, 1f /* CTI */
+ clr %o5 /* IEU0 Group */
+ ldub [%src], %g7 /* Load */
+ sll %g7, 8, %o5 /* IEU0 Group */
+ stba %g7, [%dst] %asi /* Store */
+1: or %g2, %g3, %g3 /* IEU1 */
+ or %o5, %g3, %g3 /* IEU0 Group (regdep) */
+ addcc %g3, %sum, %sum /* IEU1 Group (regdep) */
+ bcs,a,pn %xcc, 1f /* CTI */
+ add %sum, 1, %sum /* IEU0 */
+1: ba,pt %xcc, 25b /* CTI Group */
+ sllx %sum, 32, %g1 /* IEU0 */
#ifdef __KERNEL__
end:
diff --git a/drivers/Makefile b/drivers/Makefile
index 1c99a05a7..1d4653233 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -57,6 +57,11 @@ SUB_DIRS += macintosh
MOD_SUB_DIRS += macintosh
endif
+ifdef CONFIG_PPC
+SUB_DIRS += macintosh
+MOD_SUB_DIRS += macintosh
+endif
+
ifeq ($(CONFIG_USB),y)
SUB_DIRS += usb
MOD_SUB_DIRS += usb
diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in
index 07e712751..8fb55632a 100644
--- a/drivers/atm/Config.in
+++ b/drivers/atm/Config.in
@@ -51,4 +51,29 @@ if [ "$CONFIG_PCI" = "y" ]; then
bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG
fi
fi
+if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then
+ tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E
+ if [ "$CONFIG_ATM_FORE200E" != "n" ]; then
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y
+ if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then
+ bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW
+ if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then
+ string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW
+ fi
+ fi
+ fi
+ if [ "$CONFIG_SBUS" = "y" ]; then
+ bool ' SBA-200E support' CONFIG_ATM_FORE200E_SBA y
+ if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then
+ bool ' Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW
+ if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then
+ string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_SBA_FW ""
+ fi
+ fi
+ fi
+ int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16
+ int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0
+ fi
+fi
endmenu
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 25b57fdd4..f126bd232 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -100,6 +100,58 @@ else
LX_OBJS += $(NEED_IDT77105_LX)
endif
+ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
+FORE200E_FW_OBJS += fore200e_pca_fw.o
+ ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
+# guess the target endianess to choose the right PCA-200E firmware image
+ CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi)
+ endif
+endif
+ifeq ($(CONFIG_ATM_FORE200E_SBA),y)
+FORE200E_FW_OBJS += fore200e_sba_fw.o
+ ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y)
+ CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2
+ endif
+endif
+ifeq ($(CONFIG_ATM_FORE200E),y)
+L_OBJS += fore200e.o $(FORE200E_FW_OBJS)
+else
+ ifeq ($(CONFIG_ATM_FORE200E),m)
+ M_OBJS += fore_200e.o
+ endif
+endif
+
EXTRA_CFLAGS=-g
include $(TOPDIR)/Rules.make
+
+# FORE Systems 200E-series firmware magic
+fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \
+ fore200e_mkfirm
+ ./fore200e_mkfirm -k -b _fore200e_pca_fw \
+ -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@
+
+fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \
+ fore200e_mkfirm
+ ./fore200e_mkfirm -k -b _fore200e_sba_fw \
+ -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@
+
+fore200e_mkfirm: fore200e_mkfirm.c
+ $(HOSTCC) $(HOSTCFLAGS) $< -o $@
+
+# deal with the various suffixes of the firmware images
+%.bin: %.data
+ objcopy -Iihex $< -Obinary $@.gz
+ gzip -df $@.gz
+
+%.bin1: %.data
+ objcopy -Iihex $< -Obinary $@.gz
+ gzip -df $@.gz
+
+%.bin2: %.data
+ objcopy -Iihex $< -Obinary $@.gz
+ gzip -df $@.gz
+
+# module build
+fore_200e.o: fore200e.o $(FORE200E_FW_OBJS)
+ $(LD) -r -o $@ $< $(FORE200E_FW_OBJS)
diff --git a/drivers/atm/atmdev_init.c b/drivers/atm/atmdev_init.c
index 20fcaee4a..357cbdbe0 100644
--- a/drivers/atm/atmdev_init.c
+++ b/drivers/atm/atmdev_init.c
@@ -28,6 +28,9 @@ extern int hrz_detect(void);
#ifdef CONFIG_ATM_IA
extern int ia_detect(void);
#endif
+#ifdef CONFIG_ATM_FORE200E
+extern int fore200e_detect(void);
+#endif
int __init atmdev_init(void)
@@ -56,5 +59,8 @@ int __init atmdev_init(void)
#ifdef CONFIG_ATM_IA
devs += ia_detect();
#endif
+#ifdef CONFIG_ATM_FORE200E
+ devs += fore200e_detect();
+#endif
return devs;
}
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 1904b7e71..081fcdfed 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -156,7 +156,8 @@ static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0,
static struct atm_dev *eni_boards = NULL;
-static u32 *zeroes = NULL; /* aligned "magic" zeroes */
+static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */
+static dma_addr_t zeroes;
/* Read/write registers on card */
#define eni_in(r) readl(eni_dev->reg+(r)*4)
@@ -349,18 +350,21 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
struct eni_vcc *eni_vcc;
u32 dma_rd,dma_wr;
u32 dma[RX_DMA_BUF*2];
- unsigned long paddr,here;
+ dma_addr_t paddr;
+ unsigned long here;
int i,j;
eni_dev = ENI_DEV(vcc->dev);
eni_vcc = ENI_VCC(vcc);
paddr = 0; /* GCC, shut up */
if (skb) {
- paddr = (unsigned long) skb->data;
+ paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
+ PCI_DMA_FROMDEVICE);
+ ENI_PRV_PADDR(skb) = paddr;
if (paddr & 3)
printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has "
"mis-aligned RX data (0x%lx)\n",vcc->dev->number,
- vcc->vci,paddr);
+ vcc->vci,(unsigned long) paddr);
ENI_PRV_SIZE(skb) = size+skip;
/* PDU plus descriptor */
ATM_SKB(skb)->vcc = vcc;
@@ -390,7 +394,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (init > words) init = words;
dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |
(vcc->vci << MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += init << 2;
words -= init;
}
@@ -399,7 +403,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_16W | ((words >> 4) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~15) << 2;
words &= 15;
}
@@ -409,7 +413,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_8W | ((words >> 3) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~7) << 2;
words &= 7;
}
@@ -419,7 +423,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_4W | ((words >> 2) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~3) << 2;
words &= 3;
}
@@ -429,7 +433,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
dma[j++] = MID_DT_2W | ((words >> 1) <<
MID_DMA_COUNT_SHIFT) | (vcc->vci <<
MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
paddr += (words & ~1) << 2;
words &= 1;
}
@@ -437,7 +441,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (words) {
dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT)
| (vcc->vci << MID_DMA_VCI_SHIFT);
- dma[j++] = virt_to_bus((void *) paddr);
+ dma[j++] = paddr;
}
}
if (size != eff) {
@@ -447,8 +451,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
}
if (!j || j > 2*RX_DMA_BUF) {
printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n");
- if (skb) kfree_skb(skb);
- return -1;
+ goto trouble;
}
dma[j-2] |= MID_DMA_END;
j = j >> 1;
@@ -461,8 +464,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */
printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n",
vcc->dev->number);
- if (skb) kfree_skb(skb);
- return -1;
+ goto trouble;
}
for (i = 0; i < j; i++) {
writel(dma[i*2],eni_dev->rx_dma+dma_wr*8);
@@ -472,12 +474,19 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
if (skb) {
ENI_PRV_POS(skb) = eni_vcc->descr+size+1;
skb_queue_tail(&eni_dev->rx_queue,skb);
-eni_vcc->last = skb;
+ eni_vcc->last = skb;
rx_enqueued++;
}
eni_vcc->descr = here;
eni_out(dma_wr,MID_DMA_WR_RX);
return 0;
+
+trouble:
+ if (paddr)
+ pci_unmap_single(eni_dev->pci_dev,paddr,skb->len,
+ PCI_DMA_FROMDEVICE);
+ if (skb) dev_kfree_skb_irq(skb);
+ return -1;
}
@@ -747,7 +756,9 @@ rx_dequeued++;
}
eni_vcc->rxing--;
eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1);
- if (!skb->len) kfree_skb(skb);
+ pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
+ PCI_DMA_TODEVICE);
+ if (!skb->len) dev_kfree_skb_irq(skb);
else {
EVENT("pushing (len=%ld)\n",skb->len,0);
if (vcc->qos.aal == ATM_AAL0)
@@ -902,13 +913,13 @@ static int start_rx(struct atm_dev *dev)
enum enq_res { enq_ok,enq_next,enq_jam };
-static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
+static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr,
u32 size)
{
u32 init,words;
- DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size);
- EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size);
+ DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size);
+ EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size);
#if 0 /* don't complain anymore */
if (paddr & 3)
printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr);
@@ -918,10 +929,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
if (paddr & 3) {
init = 4-(paddr & 3);
if (init > size || size < 7) init = size;
- DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size);
+ DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",
+ (unsigned long) paddr,init,size);
dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += init;
size -= init;
}
@@ -930,10 +942,11 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
if (words && (paddr & 31)) {
init = 8-((paddr & 31) >> 2);
if (init > words) init = words;
- DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words);
+ DPRINTK("put_dma: %lx DMA: %d/%d words\n",
+ (unsigned long) paddr,init,words);
dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += init << 2;
words -= init;
}
@@ -943,18 +956,18 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~15) << 2;
words &= 15;
}
#endif
#ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */
if (words & ~7) {
- DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3,
- words);
+ DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",
+ (unsigned long) paddr,words >> 3,words);
dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~7) << 2;
words &= 7;
}
@@ -965,7 +978,7 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~3) << 2;
words &= 3;
}
@@ -976,23 +989,25 @@ static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr,
words);
dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT)
| (chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += (words & ~1) << 2;
words &= 1;
}
#endif
if (words) {
- DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words);
+ DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr,
+ words);
dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
paddr += words << 2;
}
if (size) {
- DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size);
+ DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr,
+ size);
dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) |
(chan << MID_DMA_CHAN_SHIFT);
- dma[(*j)++] = virt_to_bus((void *) paddr);
+ dma[(*j)++] = paddr;
}
}
@@ -1003,6 +1018,7 @@ static enum enq_res do_tx(struct sk_buff *skb)
struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
struct eni_tx *tx;
+ dma_addr_t paddr;
u32 dma_rd,dma_wr;
u32 size; /* in words */
int aal5,dma_size,i,j;
@@ -1079,6 +1095,9 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
vcc->dev->number);
return enq_jam;
}
+ paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
+ PCI_DMA_TODEVICE);
+ ENI_PRV_PADDR(skb) = paddr;
/* prepare DMA queue entries */
j = 0;
eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) <<
@@ -1086,21 +1105,17 @@ DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
MID_DT_JK;
j++;
if (!ATM_SKB(skb)->iovcnt)
- if (aal5)
- put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) skb->data,skb->len);
- else put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) skb->data+4,skb->len-4);
+ if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len);
+ else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4);
else {
-DPRINTK("doing direct send\n");
+DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
for (i = 0; i < ATM_SKB(skb)->iovcnt; i++)
put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
((struct iovec *) skb->data)[i].iov_base,
((struct iovec *) skb->data)[i].iov_len);
}
if (skb->len & 3)
- put_dma(tx->index,eni_dev->dma,&j,
- (unsigned long) zeroes,4-(skb->len & 3));
+ put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));
/* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */
eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) <<
MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |
@@ -1188,8 +1203,10 @@ static void dequeue_tx(struct atm_dev *dev)
break;
}
ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb);
+ pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
+ PCI_DMA_TODEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_irq(skb);
vcc->stats->tx++;
wake_up(&eni_dev->tx_wait);
dma_complete++;
@@ -1670,7 +1687,7 @@ static int __init eni_init(struct atm_dev *dev)
(eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory "
"(0x%02x)\n",dev->number,error);
- return error;
+ return -EIO;
}
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,",
dev->number,revision,real_base,eni_dev->irq);
@@ -2020,7 +2037,6 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!skb) {
printk(KERN_CRIT "!skb in eni_send ?\n");
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
return -EINVAL;
}
if (vcc->qos.aal == ATM_AAL0) {
@@ -2195,7 +2211,14 @@ int __init eni_detect(void)
struct atm_dev *dev;
struct eni_dev *eni_dev;
int devs,type;
+ struct sk_buff *skb;
+ DPRINTK("eni_detect\n");
+ if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) {
+ printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n",
+ sizeof(skb->cb),sizeof(struct eni_skb_prv));
+ return 0;
+ }
eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev),
GFP_KERNEL);
if (!eni_dev) return -ENOMEM;
@@ -2208,8 +2231,9 @@ int __init eni_detect(void)
PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA,
pci_dev))) {
if (!devs) {
- zeroes = kmalloc(4,GFP_KERNEL);
- if (!zeroes) {
+ cpu_zeroes = pci_alloc_consistent(pci_dev,
+ ENI_ZEROES_SIZE,&zeroes);
+ if (!cpu_zeroes) {
kfree(eni_dev);
return -ENOMEM;
}
@@ -2231,11 +2255,12 @@ int __init eni_detect(void)
if (!eni_dev) break;
}
}
- kfree(eni_dev);
- if (!devs && zeroes) {
- kfree(zeroes);
- zeroes = NULL;
+ if (!devs && cpu_zeroes) {
+ pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE,
+ cpu_zeroes,zeroes);
+ cpu_zeroes = NULL;
}
+ kfree(eni_dev);
return devs;
}
diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h
index ca1749f59..76d0dd482 100644
--- a/drivers/atm/eni.h
+++ b/drivers/atm/eni.h
@@ -27,6 +27,8 @@
#define DEFAULT_RX_MULT 300 /* max_sdu*3 */
#define DEFAULT_TX_MULT 300 /* max_sdu*3 */
+#define ENI_ZEROES_SIZE 4 /* need that many DMA-able zero bytes */
+
struct eni_free {
unsigned long start; /* counting in bytes */
@@ -113,9 +115,11 @@ struct eni_skb_prv {
struct atm_skb_data _; /* reserved */
unsigned long pos; /* position of next descriptor */
int size; /* PDU size in reassembly buffer */
+ dma_addr_t paddr; /* DMA handle */
};
#define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size)
#define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos)
+#define ENI_PRV_PADDR(skb) (((struct eni_skb_prv *) (skb)->cb)->paddr)
#endif
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
new file mode 100644
index 000000000..4c07f2e7f
--- /dev/null
+++ b/drivers/atm/fore200e.c
@@ -0,0 +1,2973 @@
+/*
+ $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $
+
+ A FORE Systems 200E-series driver for ATM on Linux.
+ Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000.
+
+ Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de).
+
+ This driver simultaneously supports PCA-200E and SBA-200E adapters
+ on i386, alpha (untested), powerpc, sparc and sparc64 architectures.
+
+ 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
+*/
+
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/atmdev.h>
+#include <linux/sonet.h>
+#include <linux/atm_suni.h>
+#include <asm/io.h>
+#include <asm/string.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_ATM_FORE200E_SBA
+#include <asm/idprom.h>
+#include <asm/sbus.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/pgtable.h>
+#endif
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include "fore200e.h"
+#include "suni.h"
+
+#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */
+#define FORE200E_52BYTE_AAL0_SDU
+#endif
+
+#define FORE200E_VERSION "0.2a"
+
+
+#define FORE200E "fore200e: "
+
+#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
+#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \
+ printk(FORE200E format, ##args); } while(0)
+#else
+#define DPRINTK(level, format, args...) while(0)
+#endif
+
+
+#define FORE200E_ALIGN(addr, alignment) \
+ ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr))
+
+#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type))
+
+#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ])
+
+#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo))
+
+
+#define MSECS(ms) (((ms)*HZ/1000)+1)
+
+
+extern const struct atmdev_ops fore200e_ops;
+extern const struct fore200e_bus fore200e_bus[];
+
+static struct fore200e* fore200e_boards = NULL;
+
+
+#ifdef MODULE
+MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");
+MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION);
+MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E");
+#endif
+
+
+static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = {
+ { BUFFER_S1_NBR, BUFFER_L1_NBR },
+ { BUFFER_S2_NBR, BUFFER_L2_NBR }
+};
+
+static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = {
+ { BUFFER_S1_SIZE, BUFFER_L1_SIZE },
+ { BUFFER_S2_SIZE, BUFFER_L2_SIZE }
+};
+
+
+#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
+static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" };
+#endif
+
+
+#if 0 /* currently unused */
+static int
+fore200e_fore2atm_aal(enum fore200e_aal aal)
+{
+ switch(aal) {
+ case FORE200E_AAL0: return ATM_AAL0;
+ case FORE200E_AAL34: return ATM_AAL34;
+ case FORE200E_AAL5: return ATM_AAL5;
+ }
+
+ return -EINVAL;
+}
+#endif
+
+
+static enum fore200e_aal
+fore200e_atm2fore_aal(int aal)
+{
+ switch(aal) {
+ case ATM_AAL0: return FORE200E_AAL0;
+ case ATM_AAL34: return FORE200E_AAL34;
+ case ATM_AAL1:
+ case ATM_AAL2:
+ case ATM_AAL5: return FORE200E_AAL5;
+ }
+
+ return -EINVAL;
+}
+
+
+static char*
+fore200e_irq_itoa(int irq)
+{
+#if defined(__sparc_v9__)
+ return __irq_itoa(irq);
+#else
+ static char str[8];
+ sprintf(str, "%d", irq);
+ return str;
+#endif
+}
+
+
+static void*
+fore200e_kmalloc(int size, int flags)
+{
+ void* chunk = kmalloc(size, flags);
+
+ if (chunk)
+ memset(chunk, 0x00, size);
+ else
+ printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags);
+
+ return chunk;
+}
+
+
+static void
+fore200e_kfree(void* chunk)
+{
+ kfree(chunk);
+}
+
+
+/* allocate and align a chunk of memory intended to hold the data behing exchanged
+ between the driver and the adapter (using streaming DVMA on SBUS hosts) */
+
+static int
+fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment)
+{
+ unsigned long offset = 0;
+
+ if (alignment <= sizeof(int))
+ alignment = 0;
+
+ chunk->alloc_size = size + alignment;
+ chunk->align_size = size;
+
+ chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA);
+ if (chunk->alloc_addr == NULL)
+ return -ENOMEM;
+
+ if (alignment > 0)
+ offset = FORE200E_ALIGN(chunk->alloc_addr, alignment);
+
+ chunk->align_addr = chunk->alloc_addr + offset;
+
+ chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size);
+
+ return 0;
+}
+
+
+/* free a chunk of memory */
+
+static void
+fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+{
+ fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
+
+ fore200e_kfree(chunk->alloc_addr);
+}
+
+
+
+#if 0 /* currently unused */
+static int
+fore200e_checkup(struct fore200e* fore200e)
+{
+ u32 hb1, hb2;
+
+ hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
+ fore200e_spin(10);
+ hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
+
+ if (hb2 <= hb1) {
+ printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n",
+ fore200e->name, hb1, hb2);
+ return -EIO;
+ }
+ printk(FORE200E "device %s heartbeat is ok\n", fore200e->name);
+
+ return 0;
+}
+#endif
+
+
+static void
+fore200e_spin(int msecs)
+{
+ unsigned long timeout = jiffies + MSECS(msecs);
+ while (jiffies < timeout);
+}
+
+
+static int
+fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
+{
+ unsigned long timeout = jiffies + MSECS(msecs);
+ int ok;
+
+ mb();
+ do {
+ if ((ok = (*addr == val)) || (*addr & STATUS_ERROR))
+ break;
+
+ } while (jiffies < timeout);
+
+#if 1
+ if (!ok) {
+ printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n",
+ *addr, val);
+ }
+#endif
+
+ return ok;
+}
+
+
+static int
+fore200e_io_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
+{
+ unsigned long timeout = jiffies + MSECS(msecs);
+ int ok;
+
+ do {
+ if ((ok = (fore200e->bus->read(addr) == val)))
+ break;
+
+ } while (jiffies < timeout);
+
+#if 1
+ if (!ok) {
+ printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n",
+ fore200e->bus->read(addr), val);
+ }
+#endif
+
+ return ok;
+}
+
+
+static void
+fore200e_free_rx_buf(struct fore200e* fore200e)
+{
+ int scheme, magn, nbr;
+ struct buffer* buffer;
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
+
+ if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) {
+
+ for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) {
+
+ struct chunk* data = &buffer[ nbr ].data;
+
+ if (data->alloc_addr != NULL)
+ fore200e_chunk_free(fore200e, data);
+ }
+ }
+ }
+ }
+}
+
+
+static void
+fore200e_uninit_bs_queue(struct fore200e* fore200e)
+{
+ int scheme, magn;
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
+
+ struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status;
+ struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block;
+
+ if (status->alloc_addr)
+ fore200e->bus->dma_chunk_free(fore200e, status);
+
+ if (rbd_block->alloc_addr)
+ fore200e->bus->dma_chunk_free(fore200e, rbd_block);
+ }
+ }
+}
+
+
+static int
+fore200e_reset(struct fore200e* fore200e, int diag)
+{
+ int ok;
+
+ fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET);
+
+ fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat);
+
+ fore200e->bus->reset(fore200e);
+
+ if (diag) {
+ ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000);
+ if (ok == 0) {
+
+ printk(FORE200E "device %s self-test failed\n", fore200e->name);
+ return -ENODEV;
+ }
+
+ printk(FORE200E "device %s self-test passed\n", fore200e->name);
+
+ fore200e->state = FORE200E_STATE_RESET;
+ }
+
+ return 0;
+}
+
+
+static void
+fore200e_shutdown(struct fore200e* fore200e)
+{
+ printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n",
+ fore200e->name, fore200e->phys_base,
+ fore200e_irq_itoa(fore200e->irq));
+
+ if (fore200e->state > FORE200E_STATE_RESET) {
+ /* first, reset the board to prevent further interrupts or data transfers */
+ fore200e_reset(fore200e, 0);
+ }
+
+ /* then, release all allocated resources */
+ switch(fore200e->state) {
+
+ case FORE200E_STATE_COMPLETE:
+ if (fore200e->stats)
+ kfree(fore200e->stats);
+
+ case FORE200E_STATE_IRQ:
+ free_irq(fore200e->irq, fore200e->atm_dev);
+
+ case FORE200E_STATE_ALLOC_BUF:
+ fore200e_free_rx_buf(fore200e);
+
+ case FORE200E_STATE_INIT_BSQ:
+ fore200e_uninit_bs_queue(fore200e);
+
+ case FORE200E_STATE_INIT_RXQ:
+ fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status);
+ fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd);
+
+ case FORE200E_STATE_INIT_TXQ:
+ fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status);
+ fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd);
+
+ case FORE200E_STATE_INIT_CMDQ:
+ fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status);
+
+ case FORE200E_STATE_INITIALIZE:
+ /* nothing to do for that state */
+
+ case FORE200E_STATE_START_FW:
+ /* nothing to do for that state */
+
+ case FORE200E_STATE_LOAD_FW:
+ /* nothing to do for that state */
+
+ case FORE200E_STATE_RESET:
+ /* nothing to do for that state */
+
+ case FORE200E_STATE_MAP:
+ fore200e->bus->unmap(fore200e);
+
+ case FORE200E_STATE_CONFIGURE:
+ /* nothing to do for that state */
+
+ case FORE200E_STATE_REGISTER:
+ /* XXX shouldn't we *start* by deregistering the device? */
+ atm_dev_deregister(fore200e->atm_dev);
+
+ case FORE200E_STATE_BLANK:
+ /* nothing to do for that state */
+ }
+}
+
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+
+static u32 fore200e_pca_read(volatile u32* addr)
+{
+ /* on big-endian hosts, the board is configured to convert
+ the endianess of slave RAM accesses */
+ return le32_to_cpu(readl(addr));
+}
+
+
+static void fore200e_pca_write(u32 val, volatile u32* addr)
+{
+ /* on big-endian hosts, the board is configured to convert
+ the endianess of slave RAM accesses */
+ writel(cpu_to_le32(val), addr);
+}
+
+
+static u32
+fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+{
+ u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL);
+
+ DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n",
+ virt_addr, size, dma_addr);
+
+ return dma_addr;
+}
+
+
+static void
+fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+{
+ DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+
+ pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
+ PCI_DMA_BIDIRECTIONAL);
+}
+
+
+static void
+fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+{
+ DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+
+ pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size,
+ PCI_DMA_BIDIRECTIONAL);
+}
+
+
+/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism
+ (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
+
+static int
+fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment)
+{
+#if defined(__sparc_v9__)
+ /* returned chunks are page-aligned */
+ chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev,
+ chunk->alloc_size,
+ &chunk->dma_addr);
+
+ if (chunk->alloc_addr == NULL || chunk->dma_addr == 0)
+ return -ENOMEM;
+
+ chunk->align_addr = chunk->alloc_addr;
+#else
+ if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0)
+ return -ENOMEM;
+
+ chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size);
+#endif
+
+ return 0;
+}
+
+
+/* free a DMA consistent chunk of memory */
+
+static void
+fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+{
+#if defined(__sparc_v9__)
+ pci_free_consistent((struct pci_dev*)fore200e->bus_dev,
+ chunk->alloc_size,
+ chunk->alloc_addr,
+ chunk->dma_addr);
+#else
+ fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size);
+
+ fore200e_chunk_free(fore200e, chunk);
+#endif
+}
+
+
+static int
+fore200e_pca_irq_check(struct fore200e* fore200e)
+{
+ /* this is a 1 bit register */
+ return readl(fore200e->regs.pca.psr);
+}
+
+
+static void
+fore200e_pca_irq_ack(struct fore200e* fore200e)
+{
+ writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr);
+}
+
+
+static void
+fore200e_pca_reset(struct fore200e* fore200e)
+{
+ writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr);
+ fore200e_spin(10);
+ writel(0, fore200e->regs.pca.hcr);
+}
+
+
+static int __init
+fore200e_pca_map(struct fore200e* fore200e)
+{
+ DPRINTK(2, "device %s being mapped in memory\n", fore200e->name);
+
+ fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH);
+
+ if (fore200e->virt_base == NULL) {
+ printk(FORE200E "can't map device %s\n", fore200e->name);
+ return -EFAULT;
+ }
+
+ DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
+
+ /* gain access to the PCA-200E specific registers */
+ fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET);
+ fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET);
+ fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET);
+
+ fore200e->state = FORE200E_STATE_MAP;
+ return 0;
+}
+
+
+static void
+fore200e_pca_unmap(struct fore200e* fore200e)
+{
+ DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name);
+
+ /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41),
+ this leads to a kernel panic if the module is loaded and unloaded several times */
+ if (fore200e->virt_base != NULL)
+ iounmap(fore200e->virt_base);
+}
+
+
+static int __init
+fore200e_pca_configure(struct fore200e* fore200e)
+{
+ struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
+ u8 master_ctrl;
+
+ DPRINTK(2, "device %s being configured\n", fore200e->name);
+
+ if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) {
+ printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n");
+ return -EIO;
+ }
+
+ pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl);
+
+ master_ctrl = master_ctrl
+#if 0
+ | PCA200E_CTRL_DIS_CACHE_RD
+ | PCA200E_CTRL_DIS_WRT_INVAL
+#endif
+#if defined(__BIG_ENDIAN)
+ /* request the PCA board to convert the endianess of slave RAM accesses */
+ | PCA200E_CTRL_CONVERT_ENDIAN
+#endif
+ | PCA200E_CTRL_LARGE_PCI_BURSTS;
+
+ pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl);
+
+ fore200e->state = FORE200E_STATE_CONFIGURE;
+ return 0;
+}
+
+
+static struct fore200e* __init
+fore200e_pca_detect(const struct fore200e_bus* bus, int index)
+{
+ struct fore200e* fore200e;
+ struct pci_dev* pci_dev = NULL;
+ int count = index;
+
+ if (pci_present() == 0) {
+ printk(FORE200E "no PCI subsystem\n");
+ return NULL;
+ }
+
+ do {
+ pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev);
+ if (pci_dev == NULL)
+ return NULL;
+ } while (count--);
+
+ fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+ if (fore200e == NULL)
+ return NULL;
+
+ fore200e->bus = bus;
+ fore200e->bus_dev = pci_dev;
+ fore200e->irq = pci_dev->irq;
+ fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK);
+
+#if defined(__powerpc__)
+ fore200e->phys_base += KERNELBASE;
+#endif
+
+ sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+
+ pci_set_master(pci_dev);
+
+ return fore200e;
+}
+
+
+static int __init
+fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
+ struct prom_opcode opcode;
+ int ok;
+ u32 prom_dma;
+
+ FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
+
+ opcode.opcode = OPCODE_GET_PROM;
+ opcode.pad = 0;
+
+ prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data));
+
+ fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr);
+
+ *entry->status = STATUS_PENDING;
+
+ fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode);
+
+ ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
+
+ *entry->status = STATUS_FREE;
+
+ fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data));
+
+ if (ok == 0) {
+ printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name);
+ return -EIO;
+ }
+
+#if defined(__BIG_ENDIAN)
+
+#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) ))
+
+ /* MAC address is stored as little-endian */
+ swap_here(&prom->mac_addr[0]);
+ swap_here(&prom->mac_addr[4]);
+#endif
+
+ return 0;
+}
+
+
+static int
+fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
+{
+ struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
+
+ return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n",
+ pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn));
+}
+
+#endif /* CONFIG_ATM_FORE200E_PCA */
+
+
+
+
+#ifdef CONFIG_ATM_FORE200E_SBA
+
+static u32
+fore200e_sba_read(volatile u32* addr)
+{
+ return sbus_readl(addr);
+}
+
+
+static void
+fore200e_sba_write(u32 val, volatile u32* addr)
+{
+ sbus_writel(val, addr);
+}
+
+
+static u32
+fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size)
+{
+ u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size);
+
+ DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr);
+
+ return dma_addr;
+}
+
+
+static void
+fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size)
+{
+ DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+
+ sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+}
+
+
+static void
+fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size)
+{
+ DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size);
+
+ sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size);
+}
+
+
+/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
+ (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
+
+static int
+fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment)
+{
+ chunk->alloc_size = chunk->align_size = size * nbr;
+
+ /* returned chunks are page-aligned */
+ chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
+ chunk->alloc_size,
+ &chunk->dma_addr);
+
+ if (chunk->alloc_addr == NULL || chunk->dma_addr == 0)
+ return -ENOMEM;
+
+ chunk->align_addr = chunk->alloc_addr;
+
+ return 0;
+}
+
+
+/* free a DVMA consistent chunk of memory */
+
+static void
+fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+{
+ sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev,
+ chunk->alloc_size,
+ chunk->alloc_addr,
+ chunk->dma_addr);
+}
+
+
+static void
+fore200e_sba_irq_enable(struct fore200e* fore200e)
+{
+ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+ fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
+}
+
+
+static int
+fore200e_sba_irq_check(struct fore200e* fore200e)
+{
+ return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
+}
+
+
+static void
+fore200e_sba_irq_ack(struct fore200e* fore200e)
+{
+ u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+ fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
+}
+
+
+static void
+fore200e_sba_reset(struct fore200e* fore200e)
+{
+ fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
+ fore200e_spin(10);
+ fore200e->bus->write(0, fore200e->regs.sba.hcr);
+}
+
+
+static int __init
+fore200e_sba_map(struct fore200e* fore200e)
+{
+ struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
+ unsigned int bursts;
+
+ /* gain access to the SBA-200E specific registers */
+
+ fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+ fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+ fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+ fore200e->virt_base = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+
+ if (fore200e->virt_base == NULL) {
+ printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+ return -EFAULT;
+ }
+
+ DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
+
+ fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
+
+ /* get the supported DVMA burst sizes */
+ bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
+
+ if (sbus_can_dma_64bit(sbus_dev))
+ sbus_set_sbus64(sbus_dev, bursts);
+
+#if 0
+ if (bursts & DMA_BURST16)
+ fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr);
+ else
+ if (bursts & DMA_BURST8)
+ fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr);
+ else
+ if (bursts & DMA_BURST4)
+ fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr);
+#endif
+
+ fore200e->state = FORE200E_STATE_MAP;
+ return 0;
+}
+
+
+static void
+fore200e_sba_unmap(struct fore200e* fore200e)
+{
+ sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+ sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+ sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+ sbus_iounmap((ulong)fore200e->virt_base, SBA200E_RAM_LENGTH);
+}
+
+
+static int __init
+fore200e_sba_configure(struct fore200e* fore200e)
+{
+ fore200e->state = FORE200E_STATE_CONFIGURE;
+ return 0;
+}
+
+
+static struct fore200e* __init
+fore200e_sba_detect(const struct fore200e_bus* bus, int index)
+{
+ struct fore200e* fore200e;
+ struct sbus_bus* sbus_bus;
+ struct sbus_dev* sbus_dev = NULL;
+
+ unsigned int count = 0;
+
+ for_each_sbus (sbus_bus) {
+ for_each_sbusdev (sbus_dev, sbus_bus) {
+ if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) {
+ if (count >= index)
+ goto found;
+ count++;
+ }
+ }
+ }
+ return NULL;
+
+ found:
+#if 1
+ if (sbus_dev->num_registers != 4) {
+ printk(FORE200E "this %s device has %d instead of 4 registers\n",
+ bus->model_name, sbus_dev->num_registers);
+ return NULL;
+ }
+#endif
+
+ fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
+ if (fore200e == NULL)
+ return NULL;
+
+ fore200e->bus = bus;
+ fore200e->bus_dev = sbus_dev;
+ fore200e->irq = sbus_dev->irqs[ 0 ];
+
+ fore200e->phys_base = (unsigned long)sbus_dev;
+
+ sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+
+ return fore200e;
+}
+
+
+static int __init
+fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+{
+ struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
+ int len;
+
+ len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4);
+ if (len < 0)
+ return -EBUSY;
+
+ len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4);
+ if (len < 0)
+ return -EBUSY;
+
+ prom_getproperty(sbus_dev->prom_node, "serialnumber",
+ (char*)&prom->serial_number, sizeof(prom->serial_number));
+
+ prom_getproperty(sbus_dev->prom_node, "promversion",
+ (char*)&prom->hw_revision, sizeof(prom->hw_revision));
+
+ return 0;
+}
+
+
+static int
+fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
+{
+ struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
+
+ return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+}
+#endif /* CONFIG_ATM_FORE200E_SBA */
+
+
+static void
+fore200e_irq_tx(struct fore200e* fore200e)
+{
+ struct host_txq_entry* entry;
+ int i;
+
+ entry = fore200e->host_txq.host_entry;
+
+ for (i = 0; i < QUEUE_SIZE_TX; i++) {
+
+ if (*entry->status & STATUS_COMPLETE) {
+
+ DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb);
+
+ /* free copy of misaligned data */
+ if (entry->data)
+ kfree(entry->data);
+
+ /* remove DMA mapping */
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+
+ /* notify tx completion */
+ if (entry->vcc->pop)
+ entry->vcc->pop(entry->vcc, entry->skb);
+ else
+ dev_kfree_skb_irq(entry->skb);
+
+ /* check error condition */
+ if (*entry->status & STATUS_ERROR)
+ entry->vcc->stats->tx_err++;
+ else
+ entry->vcc->stats->tx++;
+
+ *entry->status = STATUS_FREE;
+
+ fore200e->host_txq.txing--;
+ }
+ entry++;
+ }
+}
+
+
+static void
+fore200e_supply(struct fore200e* fore200e)
+{
+ int scheme, magn, i;
+
+ struct host_bsq* bsq;
+ struct host_bsq_entry* entry;
+ struct buffer* buffer;
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
+
+ bsq = &fore200e->host_bsq[ scheme ][ magn ];
+
+ if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) {
+
+ DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n",
+ scheme, magn, bsq->count);
+
+ entry = &bsq->host_entry[ bsq->head ];
+
+ FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
+
+ for (i = 0; i < RBD_BLK_SIZE; i++) {
+
+ buffer = &bsq->buffer[ bsq->free ];
+
+ FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]);
+
+ entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr;
+ entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer);
+ }
+
+ /* increase the number of supplied rx buffers */
+ bsq->count += RBD_BLK_SIZE;
+
+ *entry->status = STATUS_PENDING;
+ fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr);
+ }
+ }
+ }
+}
+
+
+
+static struct atm_vcc*
+fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
+{
+ struct atm_vcc* vcc;
+
+ for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+
+ if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
+ break;
+ }
+
+ return vcc;
+}
+
+
+static void
+fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
+{
+ struct atm_vcc* vcc;
+ struct sk_buff* skb;
+ struct buffer* buffer;
+ struct fore200e_vcc* fore200e_vcc;
+ int i, pdu_len = 0;
+#ifdef FORE200E_52BYTE_AAL0_SDU
+ u32 cell_header = 0;
+#endif
+
+ vcc = fore200e_find_vcc(fore200e, rpd);
+ if (vcc == NULL) {
+
+ printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n",
+ fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci);
+ return;
+ }
+
+ fore200e_vcc = FORE200E_VCC(vcc);
+
+#ifdef FORE200E_52BYTE_AAL0_SDU
+ if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) {
+
+ cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) |
+ (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) |
+ (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) |
+ (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) |
+ rpd->atm_header.clp;
+ pdu_len = 4;
+ }
+#endif
+
+ /* compute total PDU length */
+ for (i = 0; i < rpd->nseg; i++)
+ pdu_len += rpd->rsd[ i ].length;
+
+ skb = alloc_skb(pdu_len, GFP_ATOMIC);
+ if (skb == NULL) {
+
+ printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
+ vcc->stats->rx_drop++;
+ return;
+ }
+
+ skb->stamp = vcc->timestamp = xtime;
+
+#ifdef FORE200E_52BYTE_AAL0_SDU
+ if (cell_header) {
+ *((u32*)skb_put(skb, 4)) = cell_header;
+ }
+#endif
+
+ /* reassemble segments */
+ for (i = 0; i < rpd->nseg; i++) {
+
+ /* rebuild rx buffer address from rsd handle */
+ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
+
+ /* ensure DMA synchronisation */
+ fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length);
+
+ memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length);
+ }
+
+ DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize);
+
+ if (pdu_len < fore200e_vcc->rx_min_pdu)
+ fore200e_vcc->rx_min_pdu = pdu_len;
+ if (pdu_len > fore200e_vcc->rx_max_pdu)
+ fore200e_vcc->rx_max_pdu = pdu_len;
+
+ /* push PDU */
+ if (atm_charge(vcc, skb->truesize) == 0) {
+
+ DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n",
+ vcc->itf, vcc->vpi, vcc->vci);
+
+ dev_kfree_skb_irq(skb);
+ return;
+ }
+
+ vcc->push(vcc, skb);
+ vcc->stats->rx++;
+}
+
+
+static void
+fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd)
+{
+ struct buffer* buffer;
+ int i;
+
+ for (i = 0; i < rpd->nseg; i++) {
+
+ /* rebuild rx buffer address from rsd handle */
+ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
+
+ /* decrease the number of supplied rx buffers */
+ fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--;
+ }
+}
+
+
+static void
+fore200e_irq_rx(struct fore200e* fore200e)
+{
+ struct host_rxq* rxq = &fore200e->host_rxq;
+ struct host_rxq_entry* entry;
+
+ for (;;) {
+
+ entry = &rxq->host_entry[ rxq->head ];
+
+ /* no more received PDUs */
+ if ((*entry->status & STATUS_COMPLETE) == 0)
+ break;
+
+ FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
+
+ if ((*entry->status & STATUS_ERROR) == 0) {
+
+ fore200e_push_rpd(fore200e, entry->rpd);
+ }
+ else {
+ printk(FORE200E "damaged PDU on %d.%d.%d\n",
+ fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
+ }
+
+ fore200e_collect_rpd(fore200e, entry->rpd);
+
+ fore200e_supply(fore200e);
+
+ /* rewrite the rpd address to ack the received PDU */
+ fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr);
+ *entry->status = STATUS_FREE;
+ }
+}
+
+
+static void
+fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
+{
+ struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev);
+
+ if (fore200e->bus->irq_check(fore200e) == 0) {
+
+ DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]);
+ return;
+ }
+ DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]);
+
+ fore200e_irq_rx(fore200e);
+
+ if (fore200e->host_txq.txing)
+ fore200e_irq_tx(fore200e);
+
+ fore200e->bus->irq_ack(fore200e);
+}
+
+
+static int
+fore200e_select_scheme(struct atm_vcc* vcc)
+{
+ int scheme;
+
+#if 1
+ /* fairly balance VCs over (identical) buffer schemes */
+ scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
+#else
+ /* bit 7 of VPI magically selects the second buffer scheme */
+ if (vcc->vpi & (1<<7)) {
+ vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */
+ scheme = BUFFER_SCHEME_TWO;
+ }
+ else {
+ scheme = BUFFER_SCHEME_ONE;
+ }
+#endif
+
+ DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n",
+ vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second");
+
+ return scheme;
+}
+
+
+
+static int
+fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
+ struct activate_opcode activ_opcode;
+ struct deactivate_opcode deactiv_opcode;
+ struct vpvc vpvc;
+ int ok;
+ enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal);
+
+ FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
+
+ if (activate) {
+ FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc);
+
+ activ_opcode.opcode = OPCODE_ACTIVATE_VCIN;
+ activ_opcode.aal = aal;
+ activ_opcode.scheme = FORE200E_VCC(vcc)->scheme;
+ activ_opcode.pad = 0;
+ }
+ else {
+ deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN;
+ deactiv_opcode.pad = 0;
+ }
+
+ vpvc.vci = vcc->vci;
+ vpvc.vpi = vcc->vpi;
+
+ *entry->status = STATUS_PENDING;
+
+ if (activate) {
+
+#ifdef FORE200E_52BYTE_AAL0_SDU
+ mtu = 48;
+#endif
+ /* the MTU is unused by the cp, except in the case of AAL0 */
+ fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu);
+ fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc);
+ fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode);
+ }
+ else {
+ fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc);
+ fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode);
+ }
+
+ ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
+
+ *entry->status = STATUS_FREE;
+
+ if (ok == 0) {
+ printk(FORE200E "unable to %s vpvc %d.%d on device %s\n",
+ activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name);
+ return -EIO;
+ }
+
+ DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci,
+ activate ? "open" : "clos", fore200e->name);
+
+ return 0;
+}
+
+
+static int
+fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
+{
+ struct atm_vcc* walk;
+
+ /* find a free VPI */
+ if (*vpi == ATM_VPI_ANY) {
+
+ for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
+
+ if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
+ (*vpi)++;
+ walk = vcc->dev->vccs;
+ }
+ }
+ }
+
+ /* find a free VCI */
+ if (*vci == ATM_VCI_ANY) {
+
+ for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
+
+ if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
+ *vci = walk->vci + 1;
+ walk = vcc->dev->vccs;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */
+
+static void
+fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate)
+{
+ if (qos->txtp.max_pcr < ATM_OC3_PCR) {
+
+ /* compute the data cells to idle cells ratio from the PCR */
+ rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR;
+ rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells;
+ }
+ else {
+ /* disable rate control */
+ rate->data_cells = rate->idle_cells = 0;
+ }
+}
+
+
+static int
+fore200e_open(struct atm_vcc *vcc, short vpi, int vci)
+{
+ struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+ struct fore200e_vcc* fore200e_vcc;
+
+ /* find a free VPI/VCI */
+ fore200e_walk_vccs(vcc, &vpi, &vci);
+
+ vcc->vpi = vpi;
+ vcc->vci = vci;
+
+ /* ressource checking only? */
+ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
+ return 0;
+
+ vcc->flags |= ATM_VF_ADDR;
+ vcc->itf = vcc->dev->number;
+
+ DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
+ "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n",
+ vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
+ fore200e_traffic_class[ vcc->qos.txtp.traffic_class ],
+ vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu,
+ fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ],
+ vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu);
+
+ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
+
+ down(&fore200e->rate_sf);
+ if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
+ up(&fore200e->rate_sf);
+ return -EAGAIN;
+ }
+ /* reserving the pseudo-CBR bandwidth at this point grants us
+ to reduce the length of the critical section protected
+ by 'rate_sf'. in counterpart, we have to reset the available
+ bandwidth if we later encounter an error */
+
+ fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr;
+ up(&fore200e->rate_sf);
+ }
+
+ fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL);
+ if (fore200e_vcc == NULL) {
+ down(&fore200e->rate_sf);
+ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
+ up(&fore200e->rate_sf);
+ return -ENOMEM;
+ }
+
+ FORE200E_VCC(vcc) = fore200e_vcc;
+
+ if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) {
+ kfree(fore200e_vcc);
+ down(&fore200e->rate_sf);
+ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
+ up(&fore200e->rate_sf);
+ return -EBUSY;
+ }
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ /* compute rate control parameters */
+ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
+
+ fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate);
+
+ DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n",
+ vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
+ vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr,
+ fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells);
+ }
+
+ fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536;
+ fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
+
+ vcc->flags |= ATM_VF_READY;
+ return 0;
+}
+
+
+
+static void
+fore200e_close(struct atm_vcc* vcc)
+{
+ struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+
+ DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
+
+ fore200e_activate_vcin(fore200e, 0, vcc, 0);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ kfree(FORE200E_VCC(vcc));
+
+ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
+ down(&fore200e->rate_sf);
+ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
+ up(&fore200e->rate_sf);
+ }
+}
+
+
+#if 0
+#define FORE200E_SYNC_SEND /* wait tx completion before returning */
+#endif
+
+
+static int
+fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+ struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+ struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
+ struct host_txq* txq = &fore200e->host_txq;
+ struct host_txq_entry* entry;
+ struct tpd* tpd;
+ struct tpd_haddr tpd_haddr;
+ unsigned long flags;
+ int retry = CONFIG_ATM_FORE200E_TX_RETRY;
+ int tx_copy = 0;
+ int tx_len = skb->len;
+ u32* cell_header = NULL;
+ unsigned char* skb_data;
+ int skb_len;
+
+#ifdef FORE200E_52BYTE_AAL0_SDU
+ if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) {
+ cell_header = (u32*) skb->data;
+ skb_data = skb->data + 4; /* skip 4-byte cell header */
+ skb_len = tx_len = skb->len - 4;
+
+ DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header);
+ }
+ else
+#endif
+ {
+ skb_data = skb->data;
+ skb_len = skb->len;
+ }
+
+ retry_here:
+
+ spin_lock_irqsave(&fore200e->tx_lock, flags);
+
+ entry = &txq->host_entry[ txq->head ];
+
+ if (*entry->status != STATUS_FREE) {
+
+ /* try to free completed tx queue entries */
+ fore200e_irq_tx(fore200e);
+
+ if (*entry->status != STATUS_FREE) {
+
+ spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+
+ /* retry once again? */
+ if(--retry > 0)
+ goto retry_here;
+
+ vcc->stats->tx_err++;
+
+ printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
+ fore200e->name, fore200e->cp_queues->heartbeat);
+
+ return -EIO;
+ }
+ }
+
+ tpd = entry->tpd;
+
+ if (((unsigned long)skb_data) & 0x3) {
+
+ DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name);
+ tx_copy = 1;
+ tx_len = skb_len;
+ }
+
+ if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) {
+
+ /* this simply NUKES the PCA-200E board */
+ DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name);
+ tx_copy = 1;
+ tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD;
+ }
+
+ if (tx_copy) {
+
+ entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
+ if (entry->data == NULL) {
+
+ spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+ return -ENOMEM;
+ }
+
+ memcpy(entry->data, skb_data, skb_len);
+ if (skb_len < tx_len)
+ memset(entry->data + skb_len, 0x00, tx_len - skb_len);
+
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len);
+ }
+ else {
+ entry->data = NULL;
+ tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len);
+ }
+
+ tpd->tsd[ 0 ].length = tx_len;
+
+ FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
+ txq->txing++;
+
+ spin_unlock_irqrestore(&fore200e->tx_lock, flags);
+
+ /* ensure DMA synchronisation */
+ fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length);
+
+ DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n",
+ vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
+ tpd->tsd[0].length, skb_len);
+
+ if (skb_len < fore200e_vcc->tx_min_pdu)
+ fore200e_vcc->tx_min_pdu = skb_len;
+ if (skb_len > fore200e_vcc->tx_max_pdu)
+ fore200e_vcc->tx_max_pdu = skb_len;
+
+ entry->vcc = vcc;
+ entry->skb = skb;
+
+ /* set tx rate control information */
+ tpd->rate.data_cells = fore200e_vcc->rate.data_cells;
+ tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells;
+
+ if (cell_header) {
+ tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP);
+ tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
+ tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
+ tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
+ tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT;
+ }
+ else {
+ /* set the ATM header, common to all cells conveying the PDU */
+ tpd->atm_header.clp = 0;
+ tpd->atm_header.plt = 0;
+ tpd->atm_header.vci = vcc->vci;
+ tpd->atm_header.vpi = vcc->vpi;
+ tpd->atm_header.gfc = 0;
+ }
+
+ tpd->spec.length = tx_len;
+ tpd->spec.nseg = 1;
+ tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal);
+#ifdef FORE200E_SYNC_SEND
+ tpd->spec.intr = 0;
+#else
+ tpd->spec.intr = 1;
+#endif
+
+ tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */
+ tpd_haddr.pad = 0;
+ tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */
+
+ *entry->status = STATUS_PENDING;
+ fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr);
+
+
+#ifdef FORE200E_SYNC_SEND
+ {
+ int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
+
+ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length);
+
+ if (ok == 0) {
+ printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
+
+ entry->vcc->stats->tx_err++;
+ return -EIO;
+ }
+ entry->vcc->stats->tx++;
+
+ DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
+
+ /* free tmp copy of misaligned data */
+ if (entry->data)
+ kfree(entry->data);
+
+ /* notify tx completion */
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
+ }
+#endif
+
+ return 0;
+}
+
+
+static int
+fore200e_getstats(struct fore200e* fore200e)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
+ struct stats_opcode opcode;
+ int ok;
+ u32 stats_dma_addr;
+
+ if (fore200e->stats == NULL) {
+ fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA);
+ if (fore200e->stats == NULL)
+ return -ENOMEM;
+ }
+
+ stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats));
+
+ FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
+
+ opcode.opcode = OPCODE_GET_STATS;
+ opcode.pad = 0;
+
+ fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr);
+
+ *entry->status = STATUS_PENDING;
+
+ fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode);
+
+ ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
+
+ *entry->status = STATUS_FREE;
+
+ fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats));
+
+ if (ok == 0) {
+ printk(FORE200E "unable to get statistics from device %s\n", fore200e->name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static int
+fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
+{
+ // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+
+ DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
+ vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
+
+ return -EINVAL;
+}
+
+
+static int
+fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
+{
+ // struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+
+ DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
+ vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
+
+ return -EINVAL;
+}
+
+
+#if 0 /* currently unused */
+static int
+fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
+ struct oc3_opcode opcode;
+ int ok;
+ u32 oc3_regs_dma_addr;
+
+ oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs));
+
+ FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
+
+ opcode.opcode = OPCODE_GET_OC3;
+ opcode.reg = 0;
+ opcode.value = 0;
+ opcode.mask = 0;
+
+ fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr);
+
+ *entry->status = STATUS_PENDING;
+
+ fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode);
+
+ ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
+
+ *entry->status = STATUS_FREE;
+
+ fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs));
+
+ if (ok == 0) {
+ printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name);
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+
+static int
+fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
+ struct oc3_opcode opcode;
+ int ok;
+
+ FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
+
+ opcode.opcode = OPCODE_SET_OC3;
+ opcode.reg = reg;
+ opcode.value = value;
+ opcode.mask = mask;
+
+ fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr);
+
+ *entry->status = STATUS_PENDING;
+
+ fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode);
+
+ ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);
+
+ *entry->status = STATUS_FREE;
+
+ if (ok == 0) {
+ printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static int
+fore200e_setloop(struct fore200e* fore200e, int loop_mode)
+{
+ u32 mct_value, mct_mask;
+ int error;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch (loop_mode) {
+
+ case SUNI_LM_NONE:
+ mct_value = 0;
+ mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE;
+ break;
+
+ case SUNI_LM_DIAG:
+ mct_value = mct_mask = SUNI_MCT_DLE;
+ break;
+
+ case SUNI_LM_LOOP:
+ mct_value = mct_mask = SUNI_MCT_LLE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask);
+ if ( error == 0)
+ fore200e->loop_mode = loop_mode;
+
+ return error;
+}
+
+
+static inline unsigned int
+fore200e_swap(unsigned int in)
+{
+#if defined(__LITTLE_ENDIAN)
+ return swab32(in);
+#else
+ return in;
+#endif
+}
+
+
+static int
+fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg)
+{
+ struct sonet_stats tmp;
+
+ if (fore200e_getstats(fore200e) < 0)
+ return -EIO;
+
+ tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors);
+ tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors);
+ tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors);
+ tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors);
+ tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors);
+ tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors);
+ tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors);
+ tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) +
+ fore200e_swap(fore200e->stats->aal34.cells_transmitted) +
+ fore200e_swap(fore200e->stats->aal5.cells_transmitted);
+ tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) +
+ fore200e_swap(fore200e->stats->aal34.cells_received) +
+ fore200e_swap(fore200e->stats->aal5.cells_received);
+
+ if (arg)
+ return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0;
+
+ return 0;
+}
+
+
+static int
+fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg)
+{
+ struct fore200e* fore200e = FORE200E_DEV(dev);
+
+ DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg);
+
+ switch (cmd) {
+
+ case SONET_GETSTAT:
+ return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg);
+
+ case SONET_GETDIAG:
+ return put_user(0, (int*)arg) ? -EFAULT : 0;
+
+ case SUNI_SETLOOP:
+ return fore200e_setloop(fore200e, (int)(unsigned long)arg);
+
+ case SUNI_GETLOOP:
+ return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0;
+ }
+
+ return -ENOSYS; /* not implemented */
+}
+
+
+static int
+fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
+{
+ struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
+ struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
+
+ DPRINTK(2, "change_qos %d.%d.%d, "
+ "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
+ "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n"
+ "available_cell_rate = %u",
+ vcc->itf, vcc->vpi, vcc->vci,
+ fore200e_traffic_class[ qos->txtp.traffic_class ],
+ qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu,
+ fore200e_traffic_class[ qos->rxtp.traffic_class ],
+ qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu,
+ flags, fore200e->available_cell_rate);
+
+ if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) {
+
+ down(&fore200e->rate_sf);
+ if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) {
+ up(&fore200e->rate_sf);
+ return -EAGAIN;
+ }
+
+ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
+ fore200e->available_cell_rate -= qos->txtp.max_pcr;
+ up(&fore200e->rate_sf);
+
+ memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
+
+ /* update rate control parameters */
+ fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
+
+ vcc->flags |= ATM_VF_HASQOS;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+
+static int __init
+fore200e_irq_request(struct fore200e* fore200e)
+{
+ if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) {
+
+ printk(FORE200E "unable to reserve IRQ %s for device %s\n",
+ fore200e_irq_itoa(fore200e->irq), fore200e->name);
+ return -EBUSY;
+ }
+
+ printk(FORE200E "IRQ %s reserved for device %s\n",
+ fore200e_irq_itoa(fore200e->irq), fore200e->name);
+
+ fore200e->state = FORE200E_STATE_IRQ;
+ return 0;
+}
+
+
+static int __init
+fore200e_get_esi(struct fore200e* fore200e)
+{
+ struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
+ int ok, i;
+
+ ok = fore200e->bus->prom_read(fore200e, prom);
+ if (ok < 0)
+ return -EBUSY;
+
+ printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ fore200e->name,
+ (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */
+ prom->serial_number & 0xFFFF,
+ prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ],
+ prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]);
+
+ for (i = 0; i < ESI_LEN; i++) {
+ fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ];
+ }
+
+ fore200e_kfree(prom);
+
+ return 0;
+}
+
+
+static int __init
+fore200e_alloc_rx_buf(struct fore200e* fore200e)
+{
+ int scheme, magn, nbr, size, i;
+
+ struct host_bsq* bsq;
+ struct buffer* buffer;
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
+
+ bsq = &fore200e->host_bsq[ scheme ][ magn ];
+
+ nbr = fore200e_rx_buf_nbr[ scheme ][ magn ];
+ size = fore200e_rx_buf_size[ scheme ][ magn ];
+
+ DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn);
+
+ /* allocate the array of receive buffers */
+ buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL);
+
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < nbr; i++) {
+
+ buffer[ i ].scheme = scheme;
+ buffer[ i ].magn = magn;
+
+ /* allocate the receive buffer body */
+ if (fore200e_chunk_alloc(fore200e,
+ &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) {
+
+ while (i > 0)
+ fore200e_chunk_free(fore200e, &buffer[ --i ].data);
+ fore200e_kfree(buffer);
+
+ return -ENOMEM;
+ }
+ }
+ /* set next free buffer index */
+ bsq->free = 0;
+ }
+ }
+
+ fore200e->state = FORE200E_STATE_ALLOC_BUF;
+ return 0;
+}
+
+
+static int __init
+fore200e_init_bs_queue(struct fore200e* fore200e)
+{
+ int scheme, magn, i;
+
+ struct host_bsq* bsq;
+ struct cp_bsq_entry* cp_entry;
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) {
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) {
+
+ DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn);
+
+ bsq = &fore200e->host_bsq[ scheme ][ magn ];
+
+ /* allocate and align the array of status words */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &bsq->status,
+ sizeof(enum status),
+ QUEUE_SIZE_BS,
+ fore200e->bus->status_alignment) < 0) {
+ return -ENOMEM;
+ }
+
+ /* allocate and align the array of receive buffer descriptors */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &bsq->rbd_block,
+ sizeof(struct rbd_block),
+ QUEUE_SIZE_BS,
+ fore200e->bus->descr_alignment) < 0) {
+
+ fore200e->bus->dma_chunk_free(fore200e, &bsq->status);
+ return -ENOMEM;
+ }
+
+ /* get the base address of the cp resident buffer supply queue entries */
+ cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base +
+ fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ]));
+
+ /* fill the host resident and cp resident buffer supply queue entries */
+ for (i = 0; i < QUEUE_SIZE_BS; i++) {
+
+ bsq->host_entry[ i ].status =
+ FORE200E_INDEX(bsq->status.align_addr, enum status, i);
+ bsq->host_entry[ i ].rbd_block =
+ FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i);
+ bsq->host_entry[ i ].rbd_block_dma =
+ FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i);
+ bsq->host_entry[ i ].cp_entry = &cp_entry[ i ];
+
+ *bsq->host_entry[ i ].status = STATUS_FREE;
+
+ fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i),
+ &cp_entry[ i ].status_haddr);
+ }
+ }
+ }
+
+ fore200e->state = FORE200E_STATE_INIT_BSQ;
+ return 0;
+}
+
+
+static int __init
+fore200e_init_rx_queue(struct fore200e* fore200e)
+{
+ struct host_rxq* rxq = &fore200e->host_rxq;
+ struct cp_rxq_entry* cp_entry;
+ int i;
+
+ DPRINTK(2, "receive queue is being initialized\n");
+
+ /* allocate and align the array of status words */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &rxq->status,
+ sizeof(enum status),
+ QUEUE_SIZE_RX,
+ fore200e->bus->status_alignment) < 0) {
+ return -ENOMEM;
+ }
+
+ /* allocate and align the array of receive PDU descriptors */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &rxq->rpd,
+ sizeof(struct rpd),
+ QUEUE_SIZE_RX,
+ fore200e->bus->descr_alignment) < 0) {
+
+ fore200e->bus->dma_chunk_free(fore200e, &rxq->status);
+ return -ENOMEM;
+ }
+
+ /* get the base address of the cp resident rx queue entries */
+ cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base +
+ fore200e->bus->read(&fore200e->cp_queues->cp_rxq));
+
+ /* fill the host resident and cp resident rx entries */
+ for (i=0; i < QUEUE_SIZE_RX; i++) {
+
+ rxq->host_entry[ i ].status =
+ FORE200E_INDEX(rxq->status.align_addr, enum status, i);
+ rxq->host_entry[ i ].rpd =
+ FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i);
+ rxq->host_entry[ i ].rpd_dma =
+ FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i);
+ rxq->host_entry[ i ].cp_entry = &cp_entry[ i ];
+
+ *rxq->host_entry[ i ].status = STATUS_FREE;
+
+ fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i),
+ &cp_entry[ i ].status_haddr);
+
+ fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i),
+ &cp_entry[ i ].rpd_haddr);
+ }
+
+ /* set the head entry of the queue */
+ rxq->head = 0;
+
+ fore200e->state = FORE200E_STATE_INIT_RXQ;
+ return 0;
+}
+
+
+static int __init
+fore200e_init_tx_queue(struct fore200e* fore200e)
+{
+ struct host_txq* txq = &fore200e->host_txq;
+ struct cp_txq_entry* cp_entry;
+ int i;
+
+ DPRINTK(2, "transmit queue is being initialized\n");
+
+ /* allocate and align the array of status words */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &txq->status,
+ sizeof(enum status),
+ QUEUE_SIZE_TX,
+ fore200e->bus->status_alignment) < 0) {
+ return -ENOMEM;
+ }
+
+ /* allocate and align the array of transmit PDU descriptors */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &txq->tpd,
+ sizeof(struct tpd),
+ QUEUE_SIZE_TX,
+ fore200e->bus->descr_alignment) < 0) {
+
+ fore200e->bus->dma_chunk_free(fore200e, &txq->status);
+ return -ENOMEM;
+ }
+
+ /* get the base address of the cp resident tx queue entries */
+ cp_entry = (struct cp_txq_entry*)(fore200e->virt_base +
+ fore200e->bus->read(&fore200e->cp_queues->cp_txq));
+
+ /* fill the host resident and cp resident tx entries */
+ for (i=0; i < QUEUE_SIZE_TX; i++) {
+
+ txq->host_entry[ i ].status =
+ FORE200E_INDEX(txq->status.align_addr, enum status, i);
+ txq->host_entry[ i ].tpd =
+ FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i);
+ txq->host_entry[ i ].tpd_dma =
+ FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i);
+ txq->host_entry[ i ].cp_entry = &cp_entry[ i ];
+
+ *txq->host_entry[ i ].status = STATUS_FREE;
+
+ fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i),
+ &cp_entry[ i ].status_haddr);
+
+ /* although there is a one-to-one mapping of tx queue entries and tpds,
+ we do not write here the DMA (physical) base address of each tpd into
+ the related cp resident entry, because the cp relies on this write
+ operation to detect that a new pdu has been submitted for tx */
+}
+
+ /* set the head entry of the queue */
+ txq->head = 0;
+
+ fore200e->state = FORE200E_STATE_INIT_TXQ;
+ return 0;
+}
+
+
+static int __init
+fore200e_init_cmd_queue(struct fore200e* fore200e)
+{
+ struct host_cmdq* cmdq = &fore200e->host_cmdq;
+ struct cp_cmdq_entry* cp_entry;
+ int i;
+
+ DPRINTK(2, "command queue is being initialized\n");
+
+ /* allocate and align the array of status words */
+ if (fore200e->bus->dma_chunk_alloc(fore200e,
+ &cmdq->status,
+ sizeof(enum status),
+ QUEUE_SIZE_CMD,
+ fore200e->bus->status_alignment) < 0) {
+ return -ENOMEM;
+ }
+
+ /* get the base address of the cp resident cmd queue entries */
+ cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base +
+ fore200e->bus->read(&fore200e->cp_queues->cp_cmdq));
+
+ /* fill the host resident and cp resident cmd entries */
+ for (i=0; i < QUEUE_SIZE_CMD; i++) {
+
+ cmdq->host_entry[ i ].status =
+ FORE200E_INDEX(cmdq->status.align_addr, enum status, i);
+ cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ];
+
+ *cmdq->host_entry[ i ].status = STATUS_FREE;
+
+ fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i),
+ &cp_entry[ i ].status_haddr);
+ }
+
+ /* set the head entry of the queue */
+ cmdq->head = 0;
+
+ fore200e->state = FORE200E_STATE_INIT_CMDQ;
+ return 0;
+}
+
+
+static void __init
+fore200e_param_bs_queue(struct fore200e* fore200e,
+ enum buffer_scheme scheme, enum buffer_magn magn,
+ int queue_length, int pool_size, int supply_blksize)
+{
+ struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
+
+ /* dumb value; the firmware doesn't allow us to activate a VC while
+ selecting a buffer scheme with zero-sized rbd pools */
+
+ if (pool_size == 0)
+ pool_size = 64;
+
+ fore200e->bus->write(queue_length, &bs_spec->queue_length);
+ fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size);
+ fore200e->bus->write(pool_size, &bs_spec->pool_size);
+ fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize);
+}
+
+
+static int __init
+fore200e_initialize(struct fore200e* fore200e)
+{
+ struct cp_queues* cpq;
+ int ok, scheme, magn;
+
+ DPRINTK(2, "device %s being initialized\n", fore200e->name);
+
+ spin_lock_init(&fore200e->tx_lock);
+ init_MUTEX(&fore200e->rate_sf);
+
+ cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
+
+ /* enable cp to host interrupts */
+ fore200e->bus->write(1, &cpq->imask);
+
+ if (fore200e->bus->irq_enable)
+ fore200e->bus->irq_enable(fore200e);
+
+ fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect);
+
+ fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len);
+ fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len);
+ fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len);
+
+ fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension);
+ fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension);
+
+ for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++)
+ for (magn = 0; magn < BUFFER_MAGN_NBR; magn++)
+ fore200e_param_bs_queue(fore200e, scheme, magn,
+ QUEUE_SIZE_BS,
+ fore200e_rx_buf_nbr[ scheme ][ magn ],
+ RBD_BLK_SIZE);
+
+ /* issue the initialize command */
+ fore200e->bus->write(STATUS_PENDING, &cpq->init.status);
+ fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode);
+
+ ok = fore200e_io_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000);
+ if (ok == 0) {
+ printk(FORE200E "device %s initialization failed\n", fore200e->name);
+ return -ENODEV;
+ }
+
+ printk(FORE200E "device %s initialized\n", fore200e->name);
+
+ fore200e->state = FORE200E_STATE_INITIALIZE;
+ return 0;
+}
+
+
+static void __init
+fore200e_monitor_putc(struct fore200e* fore200e, char c)
+{
+ struct cp_monitor* monitor = fore200e->cp_monitor;
+
+#if 0
+ printk("%c", c);
+#endif
+ fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send);
+}
+
+
+static int __init
+fore200e_monitor_getc(struct fore200e* fore200e)
+{
+ struct cp_monitor* monitor = fore200e->cp_monitor;
+ unsigned long timeout = jiffies + MSECS(50);
+ int c;
+
+ while (jiffies < timeout) {
+
+ c = (int) fore200e->bus->read(&monitor->soft_uart.recv);
+
+ if (c & FORE200E_CP_MONITOR_UART_AVAIL) {
+
+ fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv);
+#if 0
+ printk("%c", c & 0xFF);
+#endif
+ return c & 0xFF;
+ }
+ }
+
+ return -1;
+}
+
+
+static void __init
+fore200e_monitor_puts(struct fore200e* fore200e, char* str)
+{
+ while(*str) {
+
+ /* the i960 monitor doesn't accept any new character if it has something to say */
+ while (fore200e_monitor_getc(fore200e) >= 0);
+
+ fore200e_monitor_putc(fore200e, *str++);
+ }
+
+ while (fore200e_monitor_getc(fore200e) >= 0);
+}
+
+
+static int __init
+fore200e_start_fw(struct fore200e* fore200e)
+{
+ int ok;
+ char cmd[ 48 ];
+ struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data;
+
+ DPRINTK(2, "device %s firmware being started\n", fore200e->name);
+
+ sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset));
+
+ fore200e_monitor_puts(fore200e, cmd);
+
+ ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000);
+ if (ok == 0) {
+ printk(FORE200E "device %s firmware didn't start\n", fore200e->name);
+ return -ENODEV;
+ }
+
+ printk(FORE200E "device %s firmware started\n", fore200e->name);
+
+ fore200e->state = FORE200E_STATE_START_FW;
+ return 0;
+}
+
+
+static int __init
+fore200e_load_fw(struct fore200e* fore200e)
+{
+ u32* fw_data = (u32*) fore200e->bus->fw_data;
+ u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32);
+
+ struct fw_header* fw_header = (struct fw_header*) fw_data;
+
+ u32* load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset);
+
+ DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n",
+ fore200e->name, load_addr, fw_size);
+
+#if 1
+ if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) {
+ printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name);
+ return -ENODEV;
+ }
+#endif
+
+ for (; fw_size--; fw_data++, load_addr++)
+ fore200e->bus->write(le32_to_cpu(*fw_data), load_addr);
+
+ fore200e->state = FORE200E_STATE_LOAD_FW;
+ return 0;
+}
+
+
+static int __init
+fore200e_register(struct fore200e* fore200e)
+{
+ struct atm_dev* atm_dev;
+
+ DPRINTK(2, "device %s being registered\n", fore200e->name);
+
+ atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0);
+ if (atm_dev == NULL) {
+ printk(FORE200E "unable to register device %s\n", fore200e->name);
+ return -ENODEV;
+ }
+
+ FORE200E_DEV(atm_dev) = fore200e;
+ fore200e->atm_dev = atm_dev;
+
+ atm_dev->ci_range.vpi_bits = 8;
+ atm_dev->ci_range.vci_bits = 10;
+
+ fore200e->available_cell_rate = ATM_OC3_PCR;
+
+ fore200e->state = FORE200E_STATE_REGISTER;
+ return 0;
+}
+
+
+static int __init
+fore200e_init(struct fore200e* fore200e)
+{
+ if (fore200e_register(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e->bus->configure(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e->bus->map(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e_reset(fore200e, 1) < 0)
+ return -ENODEV;
+
+ if (fore200e_load_fw(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e_start_fw(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e_initialize(fore200e) < 0)
+ return -ENODEV;
+
+ if (fore200e_init_cmd_queue(fore200e) < 0)
+ return -ENOMEM;
+
+ if (fore200e_init_tx_queue(fore200e) < 0)
+ return -ENOMEM;
+
+ if (fore200e_init_rx_queue(fore200e) < 0)
+ return -ENOMEM;
+
+ if (fore200e_init_bs_queue(fore200e) < 0)
+ return -ENOMEM;
+
+ if (fore200e_alloc_rx_buf(fore200e) < 0)
+ return -ENOMEM;
+
+ if (fore200e_get_esi(fore200e) < 0)
+ return -EIO;
+
+ if (fore200e_irq_request(fore200e) < 0)
+ return -EBUSY;
+
+ fore200e_supply(fore200e);
+
+ /* all done, board initialization is now complete */
+ fore200e->state = FORE200E_STATE_COMPLETE;
+ return 0;
+}
+
+
+int __init
+fore200e_detect(void)
+{
+ const struct fore200e_bus* bus;
+ struct fore200e* fore200e;
+ int index, link;
+
+ printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
+
+ /* for each configured bus interface */
+ for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
+
+ /* detect all boards present on that bus */
+ for (index = 0; (fore200e = bus->detect(bus, index)); index++) {
+
+ printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
+ fore200e->bus->model_name,
+ fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
+
+ sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+ if (fore200e_init(fore200e) < 0) {
+
+ fore200e_shutdown(fore200e);
+ break;
+ }
+
+ link++;
+
+ fore200e->next = fore200e_boards;
+ fore200e_boards = fore200e;
+ }
+ }
+
+#if 0 /* XXX uncomment this to forbid module unloading */
+#ifdef MODULE
+ if (link > 0)
+ MOD_INC_USE_COUNT;
+#endif
+#endif
+
+ return link;
+}
+
+
+#ifdef MODULE
+static void
+fore200e_cleanup(struct fore200e** head)
+{
+ struct fore200e* fore200e = *head;
+
+ fore200e_shutdown(fore200e);
+
+ *head = fore200e->next;
+
+ kfree(fore200e);
+}
+#endif
+
+
+static int
+fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
+{
+ struct fore200e* fore200e = FORE200E_DEV(dev);
+ int len, left = *pos;
+
+ if (!left--) {
+
+ if (fore200e_getstats(fore200e) < 0)
+ return -EIO;
+
+ len = sprintf(page,"\n"
+ " device:\n"
+ " internal name:\t\t%s\n", fore200e->name);
+
+ /* print bus-specific information */
+ if (fore200e->bus->proc_read)
+ len += fore200e->bus->proc_read(fore200e, page + len);
+
+ len += sprintf(page + len,
+ " interrupt line:\t\t%s\n"
+ " physical base address:\t0x%p\n"
+ " virtual base address:\t0x%p\n"
+ " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n"
+ " board serial number:\t\t%d\n\n",
+ fore200e_irq_itoa(fore200e->irq),
+ (void*)fore200e->phys_base,
+ (void*)fore200e->virt_base,
+ fore200e->esi[0], fore200e->esi[1], fore200e->esi[2],
+ fore200e->esi[3], fore200e->esi[4], fore200e->esi[5],
+ fore200e->esi[4] * 256 + fore200e->esi[5]);
+
+ return len;
+ }
+
+ if (!left--)
+ return sprintf(page,
+ " supplied small bufs (1):\t%d\n"
+ " supplied large bufs (1):\t%d\n"
+ " supplied small bufs (2):\t%d\n"
+ " supplied large bufs (2):\t%d\n",
+ fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count,
+ fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count,
+ fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count,
+ fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count);
+ if (!left--) {
+ u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
+
+ len = sprintf(page,"\n\n"
+ " cell processor:\n"
+ " heartbeat state:\t\t");
+
+ if (hb >> 16 != 0xDEAD)
+ len += sprintf(page + len, "0x%08x\n", hb);
+ else
+ len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF);
+
+ return len;
+ }
+
+ if (!left--) {
+ static const char* media_name[] = {
+ "unshielded twisted pair",
+ "multimode optical fiber ST",
+ "multimode optical fiber SC",
+ "single-mode optical fiber ST",
+ "single-mode optical fiber SC",
+ "unknown"
+ };
+
+ static const char* oc3_mode[] = {
+ "normal operation",
+ "diagnostic loopback",
+ "line loopback"
+ };
+
+ u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release);
+ u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release);
+ u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision);
+ u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
+
+ if (media_index < 0 || media_index > 4)
+ media_index = 5;
+
+ return sprintf(page,
+ " firmware release:\t\t%d.%d.%d\n"
+ " monitor release:\t\t%d.%d\n"
+ " media type:\t\t\t%s\n"
+ " OC-3 revision:\t\t0x%x\n"
+ " OC-3 mode:\t\t\t%s",
+ fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24,
+ mon960_release >> 16, mon960_release << 16 >> 16,
+ media_name[ media_index ],
+ oc3_revision,
+ oc3_mode[ fore200e->loop_mode ]);
+ }
+
+ if (!left--) {
+ struct cp_monitor* cp_monitor = fore200e->cp_monitor;
+
+ return sprintf(page,
+ "\n\n"
+ " monitor:\n"
+ " version number:\t\t%d\n"
+ " boot status word:\t\t0x%08x\n",
+ fore200e->bus->read(&cp_monitor->mon_version),
+ fore200e->bus->read(&cp_monitor->bstat));
+ }
+
+ if (!left--)
+ return sprintf(page,
+ "\n"
+ " device statistics:\n"
+ " 4b5b:\n"
+ " crc_header_errors:\t\t%10u\n"
+ " framing_errors:\t\t%10u\n",
+ fore200e_swap(fore200e->stats->phy.crc_header_errors),
+ fore200e_swap(fore200e->stats->phy.framing_errors));
+
+ if (!left--)
+ return sprintf(page, "\n"
+ " OC-3:\n"
+ " section_bip8_errors:\t%10u\n"
+ " path_bip8_errors:\t\t%10u\n"
+ " line_bip24_errors:\t\t%10u\n"
+ " line_febe_errors:\t\t%10u\n"
+ " path_febe_errors:\t\t%10u\n"
+ " corr_hcs_errors:\t\t%10u\n"
+ " ucorr_hcs_errors:\t\t%10u\n",
+ fore200e_swap(fore200e->stats->oc3.section_bip8_errors),
+ fore200e_swap(fore200e->stats->oc3.path_bip8_errors),
+ fore200e_swap(fore200e->stats->oc3.line_bip24_errors),
+ fore200e_swap(fore200e->stats->oc3.line_febe_errors),
+ fore200e_swap(fore200e->stats->oc3.path_febe_errors),
+ fore200e_swap(fore200e->stats->oc3.corr_hcs_errors),
+ fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " ATM:\t\t\t\t cells\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " vpi out of range:\t\t%10u\n"
+ " vpi no conn:\t\t%10u\n"
+ " vci out of range:\t\t%10u\n"
+ " vci no conn:\t\t%10u\n",
+ fore200e_swap(fore200e->stats->atm.cells_transmitted),
+ fore200e_swap(fore200e->stats->atm.cells_received),
+ fore200e_swap(fore200e->stats->atm.vpi_bad_range),
+ fore200e_swap(fore200e->stats->atm.vpi_no_conn),
+ fore200e_swap(fore200e->stats->atm.vci_bad_range),
+ fore200e_swap(fore200e->stats->atm.vci_no_conn));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " AAL0:\t\t\t cells\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " dropped:\t\t\t%10u\n",
+ fore200e_swap(fore200e->stats->aal0.cells_transmitted),
+ fore200e_swap(fore200e->stats->aal0.cells_received),
+ fore200e_swap(fore200e->stats->aal0.cells_dropped));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " AAL3/4:\n"
+ " SAR sublayer:\t\t cells\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " dropped:\t\t\t%10u\n"
+ " CRC errors:\t\t%10u\n"
+ " protocol errors:\t\t%10u\n\n"
+ " CS sublayer:\t\t PDUs\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " dropped:\t\t\t%10u\n"
+ " protocol errors:\t\t%10u\n",
+ fore200e_swap(fore200e->stats->aal34.cells_transmitted),
+ fore200e_swap(fore200e->stats->aal34.cells_received),
+ fore200e_swap(fore200e->stats->aal34.cells_dropped),
+ fore200e_swap(fore200e->stats->aal34.cells_crc_errors),
+ fore200e_swap(fore200e->stats->aal34.cells_protocol_errors),
+ fore200e_swap(fore200e->stats->aal34.cspdus_transmitted),
+ fore200e_swap(fore200e->stats->aal34.cspdus_received),
+ fore200e_swap(fore200e->stats->aal34.cspdus_dropped),
+ fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " AAL5:\n"
+ " SAR sublayer:\t\t cells\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " dropped:\t\t\t%10u\n"
+ " congestions:\t\t%10u\n\n"
+ " CS sublayer:\t\t PDUs\n"
+ " TX:\t\t\t%10u\n"
+ " RX:\t\t\t%10u\n"
+ " dropped:\t\t\t%10u\n"
+ " CRC errors:\t\t%10u\n"
+ " protocol errors:\t\t%10u\n",
+ fore200e_swap(fore200e->stats->aal5.cells_transmitted),
+ fore200e_swap(fore200e->stats->aal5.cells_received),
+ fore200e_swap(fore200e->stats->aal5.cells_dropped),
+ fore200e_swap(fore200e->stats->aal5.congestion_experienced),
+ fore200e_swap(fore200e->stats->aal5.cspdus_transmitted),
+ fore200e_swap(fore200e->stats->aal5.cspdus_received),
+ fore200e_swap(fore200e->stats->aal5.cspdus_dropped),
+ fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors),
+ fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " AUX:\t\t allocation failures\n"
+ " small b1:\t\t\t%10u\n"
+ " large b1:\t\t\t%10u\n"
+ " small b2:\t\t\t%10u\n"
+ " large b2:\t\t\t%10u\n"
+ " RX PDUs:\t\t\t%10u\n",
+ fore200e_swap(fore200e->stats->aux.small_b1_failed),
+ fore200e_swap(fore200e->stats->aux.large_b1_failed),
+ fore200e_swap(fore200e->stats->aux.small_b2_failed),
+ fore200e_swap(fore200e->stats->aux.large_b2_failed),
+ fore200e_swap(fore200e->stats->aux.rpd_alloc_failed));
+
+ if (!left--)
+ return sprintf(page,"\n"
+ " receive carrier:\t\t\t%s\n",
+ fore200e->stats->aux.receive_carrier ? "ON" : "OFF!");
+
+ if (!left--) {
+ struct atm_vcc *vcc;
+ struct fore200e_vcc* fore200e_vcc;
+
+ len = sprintf(page,"\n"
+ " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
+
+ for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
+
+ fore200e_vcc = FORE200E_VCC(vcc);
+
+ len += sprintf(page + len,
+ " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n",
+ (u32)(unsigned long)vcc,
+ vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
+ fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu,
+ fore200e_vcc->tx_max_pdu,
+ fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu,
+ fore200e_vcc->rx_max_pdu
+ );
+ }
+
+ return len;
+ }
+
+ return 0;
+}
+
+
+#ifdef MODULE
+unsigned int
+init_module(void)
+{
+ DPRINTK(1, "module loaded\n");
+ return fore200e_detect() == 0;
+}
+
+void
+cleanup_module(void)
+{
+ while (fore200e_boards) {
+ fore200e_cleanup(&fore200e_boards);
+ }
+ DPRINTK(1, "module being removed\n");
+}
+#endif
+
+
+static const struct atmdev_ops fore200e_ops =
+{
+ NULL, /* fore200e_dev_close */
+ fore200e_open,
+ fore200e_close,
+ fore200e_ioctl,
+ fore200e_getsockopt,
+ fore200e_setsockopt,
+ fore200e_send,
+ NULL, /* fore200e_sg_send, */
+ NULL, /* fore200e_send_oam, */
+ NULL, /* fore200e_phy_put, */
+ NULL, /* fore200e_phy_get, */
+ NULL, /* fore200e_feedback, */
+ fore200e_change_qos,
+ NULL, /* fore200e_free_rx_skb */
+ fore200e_proc_read
+};
+
+
+#ifdef CONFIG_ATM_FORE200E_PCA
+extern const unsigned char _fore200e_pca_fw_data[];
+extern const unsigned int _fore200e_pca_fw_size;
+#endif
+#ifdef CONFIG_ATM_FORE200E_SBA
+extern const unsigned char _fore200e_sba_fw_data[];
+extern const unsigned int _fore200e_sba_fw_size;
+#endif
+
+static const struct fore200e_bus fore200e_bus[] = {
+#ifdef CONFIG_ATM_FORE200E_PCA
+ { "PCA-200E", "pca200e", 32, 4, 32,
+ _fore200e_pca_fw_data, &_fore200e_pca_fw_size,
+ fore200e_pca_read,
+ fore200e_pca_write,
+ fore200e_pca_dma_map,
+ fore200e_pca_dma_unmap,
+ fore200e_pca_dma_sync,
+ fore200e_pca_dma_chunk_alloc,
+ fore200e_pca_dma_chunk_free,
+ fore200e_pca_detect,
+ fore200e_pca_configure,
+ fore200e_pca_map,
+ fore200e_pca_reset,
+ fore200e_pca_prom_read,
+ fore200e_pca_unmap,
+ NULL,
+ fore200e_pca_irq_check,
+ fore200e_pca_irq_ack,
+ fore200e_pca_proc_read,
+ },
+#endif
+#ifdef CONFIG_ATM_FORE200E_SBA
+ { "SBA-200E", "sba200e", 32, 64, 32,
+ _fore200e_sba_fw_data, &_fore200e_sba_fw_size,
+ fore200e_sba_read,
+ fore200e_sba_write,
+ fore200e_sba_dma_map,
+ fore200e_sba_dma_unmap,
+ fore200e_sba_dma_sync,
+ fore200e_sba_dma_chunk_alloc,
+ fore200e_sba_dma_chunk_free,
+ fore200e_sba_detect,
+ fore200e_sba_configure,
+ fore200e_sba_map,
+ fore200e_sba_reset,
+ fore200e_sba_prom_read,
+ fore200e_sba_unmap,
+ fore200e_sba_irq_enable,
+ fore200e_sba_irq_check,
+ fore200e_sba_irq_ack,
+ fore200e_sba_proc_read,
+ },
+#endif
+ {}
+};
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
new file mode 100644
index 000000000..eea20162b
--- /dev/null
+++ b/drivers/atm/fore200e.h
@@ -0,0 +1,952 @@
+#ifndef _FORE200E_H
+#define _FORE200E_H
+
+#ifdef __KERNEL__
+
+/* rx buffer sizes */
+
+#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */
+#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */
+
+
+#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */
+
+
+#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */
+
+
+#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */
+#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */
+
+#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */
+#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */
+
+#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2)
+#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2)
+
+#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2)
+#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2)
+
+
+#define QUEUE_SIZE_CMD 16 /* command queue capacity */
+#define QUEUE_SIZE_RX 64 /* receive queue capacity */
+#define QUEUE_SIZE_TX 256 /* transmit queue capacity */
+#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */
+
+#define NBR_CONNECT 1024 /* number of ATM connections */
+
+
+#define TSD_FIXED 2
+#define TSD_EXTENSION 0
+#define TSD_NBR (TSD_FIXED + TSD_EXTENSION)
+
+
+/* the cp starts putting a received PDU into one *small* buffer,
+ then it uses a number of *large* buffers for the trailing data.
+ we compute here the total number of receive segment descriptors
+ required to hold the largest possible PDU */
+
+#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1)
+
+#define RSD_FIXED 3
+
+/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU,
+ but we have to keep the size of the receive PDU descriptor multiple of 32 bytes,
+ so we add one extra RSD to RSD_EXTENSION
+ (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */
+
+#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1)
+#define RSD_NBR (RSD_FIXED + RSD_EXTENSION)
+
+
+#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data))
+#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data))
+
+/* bitfields endian games */
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+#define BITFIELD2(b1, b2) b1; b2;
+#define BITFIELD3(b1, b2, b3) b1; b2; b3;
+#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4;
+#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5;
+#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+#define BITFIELD2(b1, b2) b2; b1;
+#define BITFIELD3(b1, b2, b3) b3; b2; b1;
+#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1;
+#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1;
+#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1;
+#else
+#error unknown bitfield endianess
+#endif
+
+
+/* ATM cell header (minus HEC byte) */
+
+typedef struct atm_header {
+ BITFIELD5(
+ u32 clp : 1, /* cell loss priority */
+ u32 plt : 3, /* payload type */
+ u32 vci : 16, /* virtual channel identifier */
+ u32 vpi : 8, /* virtual path identifier */
+ u32 gfc : 4 /* generic flow control */
+ )
+} atm_header_t;
+
+
+/* ATM adaptation layer id */
+
+typedef enum fore200e_aal {
+ FORE200E_AAL0 = 0,
+ FORE200E_AAL34 = 4,
+ FORE200E_AAL5 = 5,
+} fore200e_aal_t;
+
+
+/* transmit PDU descriptor specification */
+
+typedef struct tpd_spec {
+ BITFIELD4(
+ u32 length : 16, /* total PDU length */
+ u32 nseg : 8, /* number of transmit segments */
+ enum fore200e_aal aal : 4, /* adaptation layer */
+ u32 intr : 4 /* interrupt requested */
+ )
+} tpd_spec_t;
+
+
+/* transmit PDU rate control */
+
+typedef struct tpd_rate
+{
+ BITFIELD2(
+ u32 idle_cells : 16, /* number of idle cells to insert */
+ u32 data_cells : 16 /* number of data cells to transmit */
+ )
+} tpd_rate_t;
+
+
+/* transmit segment descriptor */
+
+typedef struct tsd {
+ u32 buffer; /* transmit buffer DMA address */
+ u32 length; /* number of bytes in buffer */
+} tsd_t;
+
+
+/* transmit PDU descriptor */
+
+typedef struct tpd {
+ struct atm_header atm_header; /* ATM header minus HEC byte */
+ struct tpd_spec spec; /* tpd specification */
+ struct tpd_rate rate; /* tpd rate control */
+ u32 pad; /* reserved */
+ struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */
+} tpd_t;
+
+
+/* receive segment descriptor */
+
+typedef struct rsd {
+ u32 handle; /* host supplied receive buffer handle */
+ u32 length; /* number of bytes in buffer */
+} rsd_t;
+
+
+/* receive PDU descriptor */
+
+typedef struct rpd {
+ struct atm_header atm_header; /* ATM header minus HEC byte */
+ u32 nseg; /* number of receive segments */
+ struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */
+} rpd_t;
+
+
+/* buffer scheme */
+
+typedef enum buffer_scheme {
+ BUFFER_SCHEME_ONE,
+ BUFFER_SCHEME_TWO,
+ BUFFER_SCHEME_NBR /* always last */
+} buffer_scheme_t;
+
+
+/* buffer magnitude */
+
+typedef enum buffer_magn {
+ BUFFER_MAGN_SMALL,
+ BUFFER_MAGN_LARGE,
+ BUFFER_MAGN_NBR /* always last */
+} buffer_magn_t;
+
+
+/* receive buffer descriptor */
+
+typedef struct rbd {
+ u32 handle; /* host supplied handle */
+ u32 buffer_haddr; /* host DMA address of host buffer */
+} rbd_t;
+
+
+/* receive buffer descriptor block */
+
+typedef struct rbd_block {
+ struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */
+} rbd_block_t;
+
+
+/* tpd DMA address */
+
+typedef struct tpd_haddr {
+ BITFIELD3(
+ u32 size : 4, /* tpd size expressed in 32 byte blocks */
+ u32 pad : 1, /* reserved */
+ u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */
+ )
+} tpd_haddr_t;
+
+
+/* cp resident transmit queue entry */
+
+typedef struct cp_txq_entry {
+ struct tpd_haddr tpd_haddr; /* host DMA address of tpd */
+ u32 status_haddr; /* host DMA address of completion status */
+} cp_txq_entry_t;
+
+
+/* cp resident receive queue entry */
+
+typedef struct cp_rxq_entry {
+ u32 rpd_haddr; /* host DMA address of rpd */
+ u32 status_haddr; /* host DMA address of completion status */
+} cp_rxq_entry_t;
+
+
+/* cp resident buffer supply queue entry */
+
+typedef struct cp_bsq_entry {
+ u32 rbd_block_haddr; /* host DMA address of rbd block */
+ u32 status_haddr; /* host DMA address of completion status */
+} cp_bsq_entry_t;
+
+
+/* completion status */
+
+typedef volatile enum status {
+ STATUS_PENDING = (1<<0), /* initial status (written by host) */
+ STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */
+ STATUS_FREE = (1<<2), /* initial status (written by host) */
+ STATUS_ERROR = (1<<3) /* completion status (written by cp) */
+} status_t;
+
+
+/* cp operation code */
+
+typedef enum opcode {
+ OPCODE_INITIALIZE = 1, /* initialize board */
+ OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */
+ OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */
+ OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */
+ OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */
+ OPCODE_GET_STATS, /* get board statistics */
+ OPCODE_SET_OC3, /* set OC-3 registers */
+ OPCODE_GET_OC3, /* get OC-3 registers */
+ OPCODE_RESET_STATS, /* reset board statistics */
+ OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */
+ OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the
+ firmware to be low order bits from
+ the VPI field of the ATM cell header */
+ OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */
+} opcode_t;
+
+
+/* virtual path / virtual channel identifers */
+
+typedef struct vpvc {
+ BITFIELD3(
+ u32 vci : 16, /* virtual channel identifier */
+ u32 vpi : 8, /* virtual path identifier */
+ u32 pad : 8 /* reserved */
+ )
+} vpvc_t;
+
+
+/* activate VC command opcode */
+
+typedef struct activate_opcode {
+ BITFIELD4(
+ enum opcode opcode : 8, /* cp opcode */
+ enum fore200e_aal aal : 8, /* adaptation layer */
+ enum buffer_scheme scheme : 8, /* buffer scheme */
+ u32 pad : 8 /* reserved */
+ )
+} activate_opcode_t;
+
+
+/* activate VC command block */
+
+typedef struct activate_block {
+ struct activate_opcode opcode; /* activate VC command opcode */
+ struct vpvc vpvc; /* VPI/VCI */
+ u32 mtu; /* for AAL0 only */
+
+} activate_block_t;
+
+
+/* deactivate VC command opcode */
+
+typedef struct deactivate_opcode {
+ BITFIELD2(
+ enum opcode opcode : 8, /* cp opcode */
+ u32 pad : 24 /* reserved */
+ )
+} deactivate_opcode_t;
+
+
+/* deactivate VC command block */
+
+typedef struct deactivate_block {
+ struct deactivate_opcode opcode; /* deactivate VC command opcode */
+ struct vpvc vpvc; /* VPI/VCI */
+} deactivate_block_t;
+
+
+/* OC-3 registers */
+
+typedef struct oc3_regs {
+ u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite
+ Saturn User Network Interface documentation
+ for a description of the OC-3 chip registers */
+} oc3_regs_t;
+
+
+/* set/get OC-3 regs command opcode */
+
+typedef struct oc3_opcode {
+ BITFIELD4(
+ enum opcode opcode : 8, /* cp opcode */
+ u32 reg : 8, /* register index */
+ u32 value : 8, /* register value */
+ u32 mask : 8 /* register mask that specifies which
+ bits of the register value field
+ are significant */
+ )
+} oc3_opcode_t;
+
+
+/* set/get OC-3 regs command block */
+
+typedef struct oc3_block {
+ struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */
+ u32 regs_haddr; /* host DMA address of OC-3 regs buffer */
+} oc3_block_t;
+
+
+/* physical encoding statistics */
+
+typedef struct stats_phy {
+ u32 crc_header_errors; /* cells received with bad header CRC */
+ u32 framing_errors; /* cells received with bad framing */
+ u32 pad[ 2 ]; /* i960 padding */
+} stats_phy_t;
+
+
+/* OC-3 statistics */
+
+typedef struct stats_oc3 {
+ u32 section_bip8_errors; /* section 8 bit interleaved parity */
+ u32 path_bip8_errors; /* path 8 bit interleaved parity */
+ u32 line_bip24_errors; /* line 24 bit interleaved parity */
+ u32 line_febe_errors; /* line far end block errors */
+ u32 path_febe_errors; /* path far end block errors */
+ u32 corr_hcs_errors; /* correctable header check sequence */
+ u32 ucorr_hcs_errors; /* uncorrectable header check sequence */
+ u32 pad[ 1 ]; /* i960 padding */
+} stats_oc3_t;
+
+
+/* ATM statistics */
+
+typedef struct stats_atm {
+ u32 cells_transmitted; /* cells transmitted */
+ u32 cells_received; /* cells received */
+ u32 vpi_bad_range; /* cell drops: VPI out of range */
+ u32 vpi_no_conn; /* cell drops: no connection for VPI */
+ u32 vci_bad_range; /* cell drops: VCI out of range */
+ u32 vci_no_conn; /* cell drops: no connection for VCI */
+ u32 pad[ 2 ]; /* i960 padding */
+} stats_atm_t;
+
+/* AAL0 statistics */
+
+typedef struct stats_aal0 {
+ u32 cells_transmitted; /* cells transmitted */
+ u32 cells_received; /* cells received */
+ u32 cells_dropped; /* cells dropped */
+ u32 pad[ 1 ]; /* i960 padding */
+} stats_aal0_t;
+
+
+/* AAL3/4 statistics */
+
+typedef struct stats_aal34 {
+ u32 cells_transmitted; /* cells transmitted from segmented PDUs */
+ u32 cells_received; /* cells reassembled into PDUs */
+ u32 cells_crc_errors; /* payload CRC error count */
+ u32 cells_protocol_errors; /* SAR or CS layer protocol errors */
+ u32 cells_dropped; /* cells dropped: partial reassembly */
+ u32 cspdus_transmitted; /* CS PDUs transmitted */
+ u32 cspdus_received; /* CS PDUs received */
+ u32 cspdus_protocol_errors; /* CS layer protocol errors */
+ u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */
+ u32 pad[ 3 ]; /* i960 padding */
+} stats_aal34_t;
+
+
+/* AAL5 statistics */
+
+typedef struct stats_aal5 {
+ u32 cells_transmitted; /* cells transmitted from segmented SDUs */
+ u32 cells_received; /* cells reassembled into SDUs */
+ u32 cells_dropped; /* reassembled PDUs dropped (in cells) */
+ u32 congestion_experienced; /* CRC error and length wrong */
+ u32 cspdus_transmitted; /* CS PDUs transmitted */
+ u32 cspdus_received; /* CS PDUs received */
+ u32 cspdus_crc_errors; /* CS PDUs CRC errors */
+ u32 cspdus_protocol_errors; /* CS layer protocol errors */
+ u32 cspdus_dropped; /* reassembled PDUs dropped */
+ u32 pad[ 3 ]; /* i960 padding */
+} stats_aal5_t;
+
+
+/* auxiliary statistics */
+
+typedef struct stats_aux {
+ u32 small_b1_failed; /* receive BD allocation failures */
+ u32 large_b1_failed; /* receive BD allocation failures */
+ u32 small_b2_failed; /* receive BD allocation failures */
+ u32 large_b2_failed; /* receive BD allocation failures */
+ u32 rpd_alloc_failed; /* receive PDU allocation failures */
+ u32 receive_carrier; /* no carrier = 0, carrier = 1 */
+ u32 pad[ 2 ]; /* i960 padding */
+} stats_aux_t;
+
+
+/* whole statistics buffer */
+
+typedef struct stats {
+ struct stats_phy phy; /* physical encoding statistics */
+ struct stats_oc3 oc3; /* OC-3 statistics */
+ struct stats_atm atm; /* ATM statistics */
+ struct stats_aal0 aal0; /* AAL0 statistics */
+ struct stats_aal34 aal34; /* AAL3/4 statistics */
+ struct stats_aal5 aal5; /* AAL5 statistics */
+ struct stats_aux aux; /* auxiliary statistics */
+} stats_t;
+
+
+/* get statistics command opcode */
+
+typedef struct stats_opcode {
+ BITFIELD2(
+ enum opcode opcode : 8, /* cp opcode */
+ u32 pad : 24 /* reserved */
+ )
+} stats_opcode_t;
+
+
+/* get statistics command block */
+
+typedef struct stats_block {
+ struct stats_opcode opcode; /* get statistics command opcode */
+ u32 stats_haddr; /* host DMA address of stats buffer */
+} stats_block_t;
+
+
+/* expansion PROM data (PCI specific) */
+
+typedef struct prom_data {
+ u32 hw_revision; /* hardware revision */
+ u32 serial_number; /* board serial number */
+ u8 mac_addr[ 8 ]; /* board MAC address */
+} prom_data_t;
+
+
+/* get expansion PROM data command opcode */
+
+typedef struct prom_opcode {
+ BITFIELD2(
+ enum opcode opcode : 8, /* cp opcode */
+ u32 pad : 24 /* reserved */
+ )
+} prom_opcode_t;
+
+
+/* get expansion PROM data command block */
+
+typedef struct prom_block {
+ struct prom_opcode opcode; /* get PROM data command opcode */
+ u32 prom_haddr; /* host DMA address of PROM buffer */
+} prom_block_t;
+
+
+/* cp command */
+
+typedef union cmd {
+ enum opcode opcode; /* operation code */
+ struct activate_block activate_block; /* activate VC */
+ struct deactivate_block deactivate_block; /* deactivate VC */
+ struct stats_block stats_block; /* get statistics */
+ struct prom_block prom_block; /* get expansion PROM data */
+ struct oc3_block oc3_block; /* get/set OC-3 registers */
+ u32 pad[ 4 ]; /* i960 padding */
+} cmd_t;
+
+
+/* cp resident command queue */
+
+typedef struct cp_cmdq_entry {
+ union cmd cmd; /* command */
+ u32 status_haddr; /* host DMA address of completion status */
+ u32 pad[ 3 ]; /* i960 padding */
+} cp_cmdq_entry_t;
+
+
+/* host resident transmit queue entry */
+
+typedef struct host_txq_entry {
+ struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */
+ enum status* status; /* addr of host resident status */
+ struct tpd* tpd; /* addr of transmit PDU descriptor */
+ u32 tpd_dma; /* DMA address of tpd */
+ struct sk_buff* skb; /* related skb */
+ struct atm_vcc* vcc; /* related vcc */
+ void* data; /* copy of misaligned data */
+} host_txq_entry_t;
+
+
+/* host resident receive queue entry */
+
+typedef struct host_rxq_entry {
+ struct cp_rxq_entry* cp_entry; /* addr of cp resident rx queue entry */
+ enum status* status; /* addr of host resident status */
+ struct rpd* rpd; /* addr of receive PDU descriptor */
+ u32 rpd_dma; /* DMA address of rpd */
+} host_rxq_entry_t;
+
+
+/* host resident buffer supply queue entry */
+
+typedef struct host_bsq_entry {
+ struct cp_bsq_entry* cp_entry; /* addr of cp resident buffer supply queue entry */
+ enum status* status; /* addr of host resident status */
+ struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */
+ u32 rbd_block_dma; /* DMA address od rdb */
+} host_bsq_entry_t;
+
+
+/* host resident command queue entry */
+
+typedef struct host_cmdq_entry {
+ struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */
+ enum status* status; /* addr of host resident status */
+} host_cmdq_entry_t;
+
+
+/* chunk of memory */
+
+typedef struct chunk {
+ void* alloc_addr; /* base address of allocated chunk */
+ void* align_addr; /* base address of aligned chunk */
+ u32 dma_addr; /* DMA address of aligned chunk */
+ u32 alloc_size; /* length of allocated chunk */
+ u32 align_size; /* length of aligned chunk */
+} chunk_t;
+
+#define dma_size align_size /* DMA useable size */
+
+
+/* host resident receive buffer */
+
+typedef struct buffer {
+ struct buffer* next; /* next receive buffer */
+ enum buffer_scheme scheme; /* buffer scheme */
+ enum buffer_magn magn; /* buffer magnitude */
+ struct chunk data; /* data buffer */
+} buffer_t;
+
+
+#if (BITS_PER_LONG == 32)
+#define FORE200E_BUF2HDL(buffer) ((u32)(buffer))
+#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle))
+#else /* deal with 64 bit pointers */
+#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer)))
+#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET))
+#endif
+
+
+/* host resident command queue */
+
+typedef struct host_cmdq {
+ struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */
+ int head; /* head of cmd queue */
+ struct chunk status; /* array of completion status */
+} host_cmdq_t;
+
+
+/* host resident transmit queue */
+
+typedef struct host_txq {
+ struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */
+ int head; /* head of tx queue */
+ struct chunk tpd; /* array of tpds */
+ struct chunk status; /* arry of completion status */
+ int txing; /* number of pending PDUs in tx queue */
+} host_txq_t;
+
+
+/* host resident receive queue */
+
+typedef struct host_rxq {
+ struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */
+ int head; /* head of rx queue */
+ struct chunk rpd; /* array of rpds */
+ struct chunk status; /* array of completion status */
+} host_rxq_t;
+
+
+/* host resident buffer supply queues */
+
+typedef struct host_bsq {
+ struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */
+ int head; /* head of buffer supply queue */
+ struct chunk rbd_block; /* array of rbds */
+ struct chunk status; /* array of completion status */
+ struct buffer* buffer; /* array of rx buffers */
+ int free; /* index of first free rx buffer */
+ volatile int count; /* count of supplied rx buffers */
+} host_bsq_t;
+
+
+/* header of the firmware image */
+
+typedef struct fw_header {
+ u32 magic; /* magic number */
+ u32 version; /* firware version id */
+ u32 load_offset; /* fw load offset in board memory */
+ u32 start_offset; /* fw execution start address in board memory */
+} fw_header_t;
+
+#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */
+
+
+/* receive buffer supply queues scheme specification */
+
+typedef struct bs_spec {
+ u32 queue_length; /* queue capacity */
+ u32 buffer_size; /* host buffer size */
+ u32 pool_size; /* number of rbds */
+ u32 supply_blksize; /* num of rbds in I/O block (multiple
+ of 4 between 4 and 124 inclusive) */
+} bs_spec_t;
+
+
+/* initialization command block (one-time command, not in cmd queue) */
+
+typedef struct init_block {
+ enum opcode opcode; /* initialize command */
+ enum status status; /* related status word */
+ u32 receive_threshold; /* not used */
+ u32 num_connect; /* ATM connections */
+ u32 cmd_queue_len; /* length of command queue */
+ u32 tx_queue_len; /* length of transmit queue */
+ u32 rx_queue_len; /* length of receive queue */
+ u32 rsd_extension; /* number of extra 32 byte blocks */
+ u32 tsd_extension; /* number of extra 32 byte blocks */
+ u32 conless_vpvc; /* not used */
+ u32 pad[ 2 ]; /* force quad alignment */
+ struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */
+} init_block_t;
+
+
+typedef enum media_type {
+ MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */
+ MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */
+ MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */
+ MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */
+ MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */
+} media_type_t;
+
+#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4)
+
+
+/* cp resident queues */
+
+typedef struct cp_queues {
+ u32 cp_cmdq; /* command queue */
+ u32 cp_txq; /* transmit queue */
+ u32 cp_rxq; /* receive queue */
+ u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */
+ u32 imask; /* 1 enables cp to host interrupts */
+ u32 istat; /* 1 for interrupt posted */
+ u32 heap_base; /* offset form beginning of ram */
+ u32 heap_size; /* space available for queues */
+ u32 hlogger; /* non zero for host logging */
+ u32 heartbeat; /* cp heartbeat */
+ u32 fw_release; /* firmware version */
+ u32 mon960_release; /* i960 monitor version */
+ u32 tq_plen; /* transmit throughput measurements */
+ /* make sure the init block remains on a quad word boundary */
+ struct init_block init; /* one time cmd, not in cmd queue */
+ enum media_type media_type; /* media type id */
+ u32 oc3_revision; /* OC-3 revision number */
+} cp_queues_t;
+
+
+/* boot status */
+
+typedef enum boot_status {
+ BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */
+ BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */
+ BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */
+ BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */
+ BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */
+} boot_status_t;
+
+
+/* software UART */
+
+typedef struct soft_uart {
+ u32 send; /* write register */
+ u32 recv; /* read register */
+} soft_uart_t;
+
+#define FORE200E_CP_MONITOR_UART_FREE 0x00000000
+#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000
+
+
+/* i960 monitor */
+
+typedef struct cp_monitor {
+ struct soft_uart soft_uart; /* software UART */
+ enum boot_status bstat; /* boot status */
+ u32 app_base; /* application base offset */
+ u32 mon_version; /* i960 monitor version */
+} cp_monitor_t;
+
+
+/* device state */
+
+typedef enum fore200e_state {
+ FORE200E_STATE_BLANK, /* initial state */
+ FORE200E_STATE_REGISTER, /* device registered */
+ FORE200E_STATE_CONFIGURE, /* bus interface configured */
+ FORE200E_STATE_MAP, /* board space mapped in host memory */
+ FORE200E_STATE_RESET, /* board resetted */
+ FORE200E_STATE_LOAD_FW, /* firmware loaded */
+ FORE200E_STATE_START_FW, /* firmware started */
+ FORE200E_STATE_INITIALIZE, /* initialize command successful */
+ FORE200E_STATE_INIT_CMDQ, /* command queue initialized */
+ FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */
+ FORE200E_STATE_INIT_RXQ, /* receive queue initialized */
+ FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */
+ FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */
+ FORE200E_STATE_IRQ, /* host interrupt requested */
+ FORE200E_STATE_COMPLETE /* initialization completed */
+} fore200e_state;
+
+
+/* PCA-200E registers */
+
+typedef struct fore200e_pca_regs {
+ volatile u32* hcr; /* address of host control register */
+ volatile u32* imr; /* address of host interrupt mask register */
+ volatile u32* psr; /* address of PCI specific register */
+} fore200e_pca_regs_t;
+
+
+/* SBA-200E registers */
+
+typedef struct fore200e_sba_regs {
+ volatile u32* hcr; /* address of host control register */
+ volatile u32* bsr; /* address of burst transfer size register */
+ volatile u32* isr; /* address of interrupt level selection register */
+} fore200e_sba_regs_t;
+
+
+/* model-specific registers */
+
+typedef union fore200e_regs {
+ struct fore200e_pca_regs pca; /* PCA-200E registers */
+ struct fore200e_sba_regs sba; /* SBA-200E registers */
+} fore200e_regs;
+
+
+struct fore200e;
+
+/* bus-dependent data */
+
+typedef struct fore200e_bus {
+ char* model_name; /* board model name */
+ char* proc_name; /* board name under /proc/atm */
+ int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */
+ int buffer_alignment; /* rx buffers DMA alignment requirement */
+ int status_alignment; /* status words DMA alignment requirement */
+ const unsigned char* fw_data; /* address of firmware data start */
+ const unsigned int* fw_size; /* address of firmware data size */
+ u32 (*read)(volatile u32*);
+ void (*write)(u32, volatile u32*);
+ u32 (*dma_map)(struct fore200e*, void*, int);
+ void (*dma_unmap)(struct fore200e*, u32, int);
+ void (*dma_sync)(struct fore200e*, u32, int);
+ int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
+ void (*dma_chunk_free)(struct fore200e*, struct chunk*);
+ struct fore200e* (*detect)(const struct fore200e_bus*, int);
+ int (*configure)(struct fore200e*);
+ int (*map)(struct fore200e*);
+ void (*reset)(struct fore200e*);
+ int (*prom_read)(struct fore200e*, struct prom_data*);
+ void (*unmap)(struct fore200e*);
+ void (*irq_enable)(struct fore200e*);
+ int (*irq_check)(struct fore200e*);
+ void (*irq_ack)(struct fore200e*);
+ int (*proc_read)(struct fore200e*, char*);
+} fore200e_bus_t;
+
+
+/* per-device data */
+
+typedef struct fore200e {
+ struct fore200e* next; /* next device */
+ const struct fore200e_bus* bus; /* bus-dependent code and data */
+ union fore200e_regs regs; /* bus-dependent registers */
+ struct atm_dev* atm_dev; /* ATM device */
+
+ enum fore200e_state state; /* device state */
+
+ char name[16]; /* device name */
+ void* bus_dev; /* bus-specific kernel data */
+ int irq; /* irq number */
+ unsigned long phys_base; /* physical base address */
+ void* virt_base; /* virtual base address */
+
+ unsigned char esi[ ESI_LEN ]; /* end system identifier */
+
+ struct cp_monitor* cp_monitor; /* i960 monitor address */
+ struct cp_queues* cp_queues; /* cp resident queues */
+ struct host_cmdq host_cmdq; /* host resident cmd queue */
+ struct host_txq host_txq; /* host resident tx queue */
+ struct host_rxq host_rxq; /* host resident rx queue */
+ /* host resident buffer supply queues */
+ struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ];
+
+ u32 available_cell_rate; /* remaining pseudo-CBR bw on link */
+
+ int loop_mode; /* S/UNI loopback mode */
+
+ struct stats* stats; /* last snapshot of the stats */
+
+ struct semaphore rate_sf; /* protects rate reservation ops */
+ spinlock_t tx_lock; /* protects tx ops */
+
+} fore200e_t;
+
+
+/* per-vcc data */
+
+typedef struct fore200e_vcc {
+ enum buffer_scheme scheme; /* rx buffer scheme */
+ struct tpd_rate rate; /* tx rate control data */
+ int rx_min_pdu; /* size of smallest PDU received */
+ int rx_max_pdu; /* size of largest PDU received */
+ int tx_min_pdu; /* size of smallest PDU transmitted */
+ int tx_max_pdu; /* size of largest PDU transmitted */
+} fore200e_vcc_t;
+
+
+
+/* 200E-series common memory layout */
+
+#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */
+#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */
+
+
+/* PCA-200E memory layout */
+
+#define PCA200E_IOSPACE_LENGTH 0x00200000
+
+#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */
+#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */
+#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */
+
+
+/* PCA-200E host control register */
+
+#define PCA200E_HCR_RESET (1<<0) /* read / write */
+#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */
+#define PCA200E_HCR_I960FAIL (1<<2) /* read */
+#define PCA200E_HCR_INTRB (1<<2) /* write */
+#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */
+#define PCA200E_HCR_INTRA (1<<3) /* write */
+#define PCA200E_HCR_OUTFULL (1<<4) /* read */
+#define PCA200E_HCR_CLRINTR (1<<4) /* write */
+#define PCA200E_HCR_ESPHOLD (1<<5) /* read */
+#define PCA200E_HCR_INFULL (1<<6) /* read */
+#define PCA200E_HCR_TESTMODE (1<<7) /* read */
+
+
+/* PCA-200E PCI bus interface regs (offsets in PCI config space) */
+
+#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */
+#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */
+#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */
+
+/* PBI master control register */
+
+#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */
+#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */
+#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */
+#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */
+#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */
+#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */
+#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */
+
+
+
+#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */
+
+
+/* size of SBA-200E registers */
+
+#define SBA200E_HCR_LENGTH 4
+#define SBA200E_BSR_LENGTH 4
+#define SBA200E_ISR_LENGTH 4
+#define SBA200E_RAM_LENGTH 0x40000
+
+
+/* SBA-200E SBUS burst transfer size register */
+
+#define SBA200E_BSR_BURST4 0x04
+#define SBA200E_BSR_BURST8 0x08
+#define SBA200E_BSR_BURST16 0x10
+
+
+/* SBA-200E host control register */
+
+#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */
+#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */
+#define SBA200E_HCR_I960FAIL (1<<2) /* read */
+#define SBA200E_HCR_I960SETINTR (1<<2) /* write */
+#define SBA200E_HCR_OUTFULL (1<<3) /* read */
+#define SBA200E_HCR_INTR_CLR (1<<3) /* write */
+#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */
+#define SBA200E_HCR_ESPHOLD (1<<5) /* read */
+#define SBA200E_HCR_INFULL (1<<6) /* read */
+#define SBA200E_HCR_TESTMODE (1<<7) /* read */
+#define SBA200E_HCR_INTR_REQ (1<<8) /* read */
+
+#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA)
+
+
+#endif /* __KERNEL__ */
+#endif /* _FORE200E_H */
diff --git a/drivers/atm/fore200e_firmware_copyright b/drivers/atm/fore200e_firmware_copyright
new file mode 100644
index 000000000..d58e64908
--- /dev/null
+++ b/drivers/atm/fore200e_firmware_copyright
@@ -0,0 +1,31 @@
+
+These microcode data are placed under the terms of the GNU General Public License.
+
+We would prefer you not to distribute modified versions of it and not to ask
+for assembly or other microcode source.
+
+Copyright (c) 1995-2000 FORE Systems, Inc., as an unpublished work. This
+notice does not imply unrestricted or public access to these materials which
+are a trade secret of FORE Systems, Inc. or its subsidiaries or affiliates
+(together referred to as "FORE"), and which may not be reproduced, used, sold
+or transferred to any third party without FORE's prior written consent. All
+rights reserved.
+
+U.S. Government Restricted Rights. If you are licensing the Software on
+behalf of the U.S. Government ("Government"), the following provisions apply
+to you. If the software is supplied to the Department of Defense ("DoD"), it
+is classified as "Commercial Computer Software" under paragraph 252.227-7014
+of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any
+successor regulations) and the Government is acquiring only the license
+rights granted herein (the license rights customarily provided to non-Government
+users). If the Software is supplied to any unit or agency of the Government
+other than the DoD, it is classified as "Restricted Computer Software" and
+the Government's rights in the Software are defined in paragraph 52.227-19 of
+the Federal Acquisition Regulations ("FAR") (or any successor regulations) or,
+in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR
+(or any successor regulations).
+
+FORE Systems is a registered trademark, and ForeRunner, ForeRunnerLE, and
+ForeThought are trademarks of FORE Systems, Inc. All other brands or product
+names are trademarks or registered trademarks of their respective holders.
+
diff --git a/drivers/atm/fore200e_mkfirm.c b/drivers/atm/fore200e_mkfirm.c
new file mode 100644
index 000000000..10e972840
--- /dev/null
+++ b/drivers/atm/fore200e_mkfirm.c
@@ -0,0 +1,155 @@
+/*
+ $Id: fore200e_mkfirm.c,v 1.1 2000/02/21 16:04:32 davem Exp $
+
+ mkfirm.c: generates a C readable file from a binary firmware image
+
+ Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999.
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */
+char* default_infname = "<stdin>";
+char* default_outfname = "<stdout>";
+
+char* progname;
+int verbose = 0;
+int inkernel = 0;
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n",
+ progname);
+ exit(-1);
+}
+
+
+int main(int argc, char** argv)
+{
+ time_t now;
+ char* infname = NULL;
+ char* outfname = NULL;
+ char* basename = NULL;
+ FILE* infile;
+ FILE* outfile;
+ unsigned firmsize;
+ int c;
+
+ progname = *(argv++);
+
+ while (argc > 1) {
+ if ((*argv)[0] == '-') {
+ switch ((*argv)[1]) {
+ case 'i':
+ if (argc-- < 3)
+ usage();
+ infname = *(++argv);
+ break;
+ case 'o':
+ if (argc-- < 3)
+ usage();
+ outfname = *(++argv);
+ break;
+ case 'b':
+ if (argc-- < 3)
+ usage();
+ basename = *(++argv);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'k':
+ inkernel = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ else {
+ usage();
+ }
+ argc--;
+ argv++;
+ }
+
+ if (infname != NULL) {
+ infile = fopen(infname, "r");
+ if (infile == NULL) {
+ fprintf(stderr, "%s: can't open %s for reading\n",
+ progname, infname);
+ exit(-2);
+ }
+ }
+ else {
+ infile = stdin;
+ infname = default_infname;
+ }
+
+ if (outfname) {
+ outfile = fopen(outfname, "w");
+ if (outfile == NULL) {
+ fprintf(stderr, "%s: can't open %s for writing\n",
+ progname, outfname);
+ exit(-3);
+ }
+ }
+ else {
+ outfile = stdout;
+ outfname = default_outfname;
+ }
+
+ if (basename == NULL)
+ basename = default_basename;
+
+ if (verbose) {
+ fprintf(stderr, "%s: input file = %s\n", progname, infname );
+ fprintf(stderr, "%s: output file = %s\n", progname, outfname );
+ fprintf(stderr, "%s: firmware basename = %s\n", progname, basename );
+ }
+
+ time(&now);
+ fprintf(outfile, "/*\n generated by %s from %s on %s"
+ " DO NOT EDIT!\n*/\n\n",
+ progname, infname, ctime(&now));
+
+ if (inkernel)
+ fprintf(outfile, "#include <linux/init.h>\n\n" );
+
+ /* XXX force 32 bit alignment? */
+ fprintf(outfile, "const unsigned char%s %s_data[] = {\n",
+ inkernel ? " __initdata" : "", basename );
+
+ c = getc(infile);
+ fprintf(outfile,"\t0x%02x", c);
+ firmsize = 1;
+
+ while ((c = getc(infile)) >= 0) {
+
+ if (firmsize++ % 8)
+ fprintf(outfile,", 0x%02x", c);
+ else
+ fprintf(outfile,",\n\t0x%02x", c);
+ }
+
+ fprintf(outfile, "\n};\n\n");
+
+ fprintf(outfile, "const unsigned int%s %s_size = %u;\n",
+ inkernel ? " __initdata" : "", basename, firmsize );
+
+ if (infile != stdin)
+ fclose(infile);
+ if (outfile != stdout)
+ fclose(outfile);
+
+ if(verbose)
+ fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize);
+
+ exit(0);
+}
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 5208fd62d..84bdda6d6 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2359,7 +2359,7 @@ __initfunc(static int ia_init(struct atm_dev *dev))
{
printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n",
dev->number,error);
- return error;
+ return -EIO;
}
/*
* Delay at least 1us before doing any mem accesses (how 'bout 10?)
@@ -2499,7 +2499,7 @@ __initfunc(static int ia_start(struct atm_dev *dev))
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+"
"master (0x%x)\n",dev->number, error);
free_irq(iadev->irq, dev);
- return error;
+ return -EIO;
}
udelay(10);
@@ -3074,7 +3074,7 @@ static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
if (!skb)
printk(KERN_CRIT "null skb in ia_send\n");
- dev_kfree_skb(skb);
+ else dev_kfree_skb(skb);
return -EINVAL;
}
spin_lock_irqsave(&iadev->tx_lock, flags);
diff --git a/drivers/atm/pca200e.data b/drivers/atm/pca200e.data
new file mode 100644
index 000000000..e78e83bec
--- /dev/null
+++ b/drivers/atm/pca200e.data
@@ -0,0 +1,850 @@
+:150000001F8B0808AB5A10380203706361323030652E62696E4D
+:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE
+:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3
+:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F
+:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826
+:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56
+:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7
+:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677
+:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8
+:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79
+:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB
+:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC
+:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE
+:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600
+:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4
+:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02
+:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11
+:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8
+:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8
+:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83
+:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA
+:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA
+:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6
+:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9
+:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C
+:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176
+:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D
+:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08
+:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE
+:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220
+:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C
+:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF
+:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479
+:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42
+:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A
+:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B
+:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24
+:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7
+:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5
+:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0
+:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2
+:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F
+:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF
+:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1
+:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307
+:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0
+:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847
+:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17
+:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E
+:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648
+:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE
+:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B
+:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB
+:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2
+:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F
+:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD
+:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2
+:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050
+:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE
+:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53
+:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199
+:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A
+:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3
+:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC
+:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22
+:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938
+:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E
+:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC
+:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487
+:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB
+:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861
+:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7
+:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58
+:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332
+:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F
+:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F
+:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40
+:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4
+:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506
+:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506
+:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587
+:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD
+:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7
+:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A
+:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110
+:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662
+:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD
+:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8
+:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9
+:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C
+:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0
+:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01
+:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7
+:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF
+:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32
+:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8
+:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929
+:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9
+:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39
+:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D
+:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5
+:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86
+:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5
+:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD
+:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7
+:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C
+:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040
+:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE
+:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592
+:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24
+:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D
+:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F
+:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E
+:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1
+:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70
+:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A
+:15098400A835607E52D421448C255D7548EE0F723FD656E84744
+:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197
+:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1
+:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32
+:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8
+:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8
+:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE
+:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310
+:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C
+:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0
+:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419
+:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E
+:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7
+:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2
+:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D
+:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2
+:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524
+:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6
+:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06
+:150B130045E420F33B90DB12700BE117C47D4058E0468A700568
+:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C
+:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9
+:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0
+:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3
+:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC
+:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1
+:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121
+:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB
+:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE
+:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768
+:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500
+:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448
+:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1
+:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3
+:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6
+:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182
+:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5
+:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F
+:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E
+:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB
+:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326
+:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732
+:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916
+:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2
+:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2
+:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82
+:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244
+:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D
+:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908
+:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F
+:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D
+:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51
+:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD
+:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5
+:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476
+:150E070037F149D60767196DF37D72BB73D787F76764B77176CD
+:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553
+:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19
+:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913
+:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F
+:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8
+:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E
+:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B
+:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C
+:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A
+:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C
+:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F
+:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF
+:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8
+:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194
+:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D
+:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC
+:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9
+:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60
+:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295
+:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057
+:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932
+:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609
+:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D
+:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29
+:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC
+:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8
+:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35
+:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83
+:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8
+:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23
+:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40
+:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C
+:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2
+:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69
+:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F
+:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C
+:15111000370CBF436C2882554932692E84518A67BFD838550E10
+:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2
+:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE
+:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0
+:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C
+:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226
+:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8
+:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5
+:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1
+:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086
+:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124
+:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223
+:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42
+:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55
+:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D
+:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E
+:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C
+:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39
+:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D
+:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76
+:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027
+:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1
+:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD
+:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB
+:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2
+:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1
+:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018
+:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC
+:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC
+:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11
+:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C
+:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7
+:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E
+:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F
+:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58
+:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3
+:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE
+:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730
+:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1
+:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7
+:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF
+:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25
+:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460
+:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479
+:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7
+:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB
+:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C
+:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53
+:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9
+:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6
+:15152A0046C2209588708447715A422648964C43182F78306934
+:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4
+:1515540020E10729D548462638B4B064E30938322B123C47248E
+:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65
+:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8
+:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D
+:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1
+:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9
+:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B
+:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0
+:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307
+:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152
+:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5
+:15163B008478348FE466095BA45B7DABB6FA16196876F3735093
+:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D
+:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D
+:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57
+:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF
+:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C
+:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70
+:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79
+:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4
+:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89
+:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3
+:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3
+:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13
+:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912
+:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014
+:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA
+:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86
+:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39
+:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD
+:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33
+:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F
+:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A
+:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC
+:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13
+:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464
+:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6
+:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4
+:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC
+:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF
+:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807
+:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE
+:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B
+:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52
+:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A
+:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A
+:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72
+:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3
+:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D
+:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09
+:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039
+:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83
+:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2
+:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2
+:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6
+:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9
+:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202
+:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F
+:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD
+:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41
+:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E
+:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809
+:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844
+:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11
+:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572
+:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619
+:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607
+:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293
+:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F
+:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585
+:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A
+:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C
+:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98
+:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710
+:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3
+:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491
+:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C
+:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E
+:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424
+:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2
+:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D
+:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28
+:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE
+:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD
+:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA
+:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432
+:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8
+:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB
+:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC
+:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5
+:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB
+:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C
+:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214
+:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B
+:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC
+:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B
+:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A
+:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398
+:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F
+:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4
+:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7
+:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214
+:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8
+:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0
+:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48
+:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF
+:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68
+:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7
+:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE
+:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0
+:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD
+:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1
+:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687
+:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C
+:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042
+:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5
+:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54
+:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91
+:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF
+:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792
+:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76
+:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B
+:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394
+:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2
+:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C
+:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40
+:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76
+:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6
+:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A
+:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39
+:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA
+:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364
+:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4
+:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85
+:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3
+:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D
+:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219
+:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D
+:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0
+:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0
+:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C
+:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6
+:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45
+:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8
+:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085
+:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701
+:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E
+:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756
+:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C
+:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE
+:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF
+:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14
+:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A
+:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE
+:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99
+:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D
+:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24
+:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F
+:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3
+:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC
+:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C
+:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34
+:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D
+:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E
+:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B
+:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669
+:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA
+:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF
+:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17
+:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3
+:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D
+:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A
+:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741
+:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F
+:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65
+:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74
+:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE
+:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D
+:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5
+:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983
+:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10
+:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220
+:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A
+:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B
+:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F
+:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E
+:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24
+:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845
+:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A
+:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46
+:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7
+:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8
+:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E
+:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9
+:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5
+:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04
+:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439
+:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498
+:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B
+:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24
+:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379
+:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497
+:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601
+:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254
+:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3
+:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9
+:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD
+:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43
+:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C
+:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB
+:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060
+:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E
+:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603
+:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B
+:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44
+:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519
+:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314
+:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A
+:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0
+:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C
+:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8
+:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A
+:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC
+:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A
+:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111
+:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4
+:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0
+:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667
+:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167
+:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98
+:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0
+:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E
+:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2
+:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43
+:15288600189561411343153E7661037E200CFD1465C2ADC02FED
+:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235
+:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0
+:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD
+:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323
+:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487
+:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6
+:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168
+:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64
+:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B
+:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE
+:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B
+:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8
+:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB
+:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9
+:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C
+:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D
+:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24
+:152A00008FFECD579F3664F575D21913464495EF78E9A197A820
+:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0
+:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812
+:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B
+:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E
+:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F
+:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07
+:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1
+:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B
+:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B
+:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E
+:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A
+:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918
+:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974
+:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325
+:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5
+:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987
+:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762
+:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586
+:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920
+:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E
+:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858
+:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0
+:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6
+:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751
+:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6
+:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80
+:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9
+:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED
+:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD
+:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806
+:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611
+:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6
+:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF
+:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673
+:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05
+:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7
+:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850
+:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE
+:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF
+:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371
+:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1
+:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB
+:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6
+:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0
+:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003
+:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604
+:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088
+:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975
+:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81
+:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040
+:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0
+:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367
+:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F
+:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182
+:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE
+:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730
+:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6
+:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9
+:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979
+:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA
+:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48
+:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E
+:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F
+:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC
+:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F
+:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D
+:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45
+:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808
+:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520
+:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE
+:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251
+:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494
+:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4
+:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6
+:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72
+:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372
+:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5
+:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C
+:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612
+:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146
+:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C
+:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1
+:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382
+:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D
+:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF
+:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2
+:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8
+:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B
+:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55
+:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694
+:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5
+:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC
+:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C
+:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13
+:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568
+:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C
+:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070
+:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709
+:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10
+:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD
+:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D
+:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53
+:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF
+:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B
+:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195
+:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D
+:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1
+:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C
+:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062
+:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E
+:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696
+:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C
+:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F
+:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51
+:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3
+:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8
+:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834
+:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2
+:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9
+:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94
+:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18
+:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2
+:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6
+:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896
+:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51
+:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045
+:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46
+:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA
+:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867
+:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412
+:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892
+:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B
+:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79
+:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92
+:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0
+:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188
+:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3
+:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC
+:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355
+:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6
+:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330
+:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800
+:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99
+:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1
+:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11
+:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460
+:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36
+:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9
+:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D
+:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494
+:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4
+:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5
+:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73
+:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4
+:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7
+:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F
+:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A
+:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7
+:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1
+:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926
+:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63
+:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA
+:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6
+:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C
+:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24
+:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8
+:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C
+:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C
+:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B
+:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7
+:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954
+:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0
+:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74
+:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC
+:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932
+:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC
+:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6
+:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA
+:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D
+:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023
+:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED
+:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6
+:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634
+:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC
+:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1
+:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5
+:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7
+:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D
+:1539810071CE7372162BACB8981D3F326414D96517C986FC2802
+:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D
+:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892
+:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA
+:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E
+:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3
+:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E
+:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E
+:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7
+:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947
+:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058
+:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC
+:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB
+:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9
+:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C
+:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5
+:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288
+:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E
+:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B
+:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539
+:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD
+:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504
+:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5
+:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E
+:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA
+:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13
+:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1
+:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9
+:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8
+:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11
+:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863
+:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5
+:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723
+:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030
+:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C
+:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F
+:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D
+:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910
+:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415
+:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648
+:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513
+:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC
+:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A
+:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B
+:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE
+:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C
+:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75
+:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6
+:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789
+:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6
+:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D
+:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB
+:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5
+:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64
+:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92
+:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F
+:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF
+:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70
+:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F
+:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A
+:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41
+:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7
+:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B
+:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A
+:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6
+:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708
+:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27
+:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37
+:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224
+:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C
+:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181
+:153F54006397F836A0B013F598673FF7560E53E3234B133497BD
+:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40
+:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533
+:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C
+:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F
+:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC
+:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5
+:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8
+:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71
+:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4
+:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52
+:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF
+:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8
+:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D
+:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB
+:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23
+:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828
+:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F
+:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1
+:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3
+:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B
+:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C
+:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93
+:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712
+:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4
+:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21
+:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9
+:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F
+:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E
+:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4
+:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C
+:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B
+:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C
+:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203
+:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49
+:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92
+:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75
+:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F
+:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A
+:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5
+:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06
+:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16
+:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF
+:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3
+:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838
+:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89
+:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86
+:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818
+:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C
+:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B
+:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3
+:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78
+:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1
+:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372
+:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95
+:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F
+:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98
+:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC
+:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D
+:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1
+:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1
+:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966
+:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69
+:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207
+:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A
+:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177
+:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3
+:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957
+:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43
+:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0
+:154512009A34256789969773A7061EF693BC61AF376C3CF4031B
+:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6
+:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72
+:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB
+:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5
+:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849
+:06459000C0E6B892000035
+:00000001FF
diff --git a/drivers/atm/pca200e_ecd.data b/drivers/atm/pca200e_ecd.data
new file mode 100644
index 000000000..eca84aa7e
--- /dev/null
+++ b/drivers/atm/pca200e_ecd.data
@@ -0,0 +1,906 @@
+:150000001F8B0808AC5A10380203706361323030655F65636428
+:150015002E62696E327D00DC3A0D7054459AFD261333136278A4
+:15002A00192663E02479728060A10E9063213F64F0700F3DE05E
+:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C
+:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D
+:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0
+:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8
+:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1
+:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321
+:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC
+:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D
+:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919
+:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B
+:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E
+:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965
+:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26
+:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D
+:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46
+:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62
+:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425
+:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC
+:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572
+:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5
+:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD
+:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA
+:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4
+:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2
+:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2
+:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9
+:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB
+:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E
+:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025
+:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC
+:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69
+:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0
+:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E
+:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B
+:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C
+:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1
+:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406
+:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D
+:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946
+:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF
+:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A
+:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777
+:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF
+:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105
+:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52
+:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D
+:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0
+:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0
+:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7
+:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0
+:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD
+:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24
+:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9
+:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68
+:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66
+:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9
+:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A
+:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650
+:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9
+:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D
+:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7
+:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1
+:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A
+:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8
+:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923
+:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678
+:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390
+:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56
+:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE
+:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121
+:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB
+:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369
+:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677
+:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31
+:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5
+:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA
+:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360
+:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076
+:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653
+:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761
+:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3
+:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0
+:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF
+:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F
+:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C
+:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8
+:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5
+:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12
+:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925
+:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870
+:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E
+:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41
+:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7
+:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A
+:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6
+:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4
+:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469
+:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90
+:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6
+:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE
+:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C
+:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318
+:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D
+:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70
+:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD
+:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220
+:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24
+:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8
+:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387
+:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5
+:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC
+:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F
+:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5
+:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC
+:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB
+:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB
+:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F
+:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3
+:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1
+:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7
+:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360
+:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5
+:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D
+:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B
+:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3
+:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6
+:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E
+:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49
+:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992
+:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33
+:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF
+:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F
+:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69
+:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74
+:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B
+:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798
+:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94
+:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C
+:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D
+:150BA60043484524B702756A8067E58101519721BC73FE108595
+:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84
+:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F
+:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9
+:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A
+:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C
+:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02
+:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207
+:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0
+:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360
+:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E
+:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6
+:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76
+:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC
+:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408
+:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36
+:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4
+:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4
+:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE
+:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D
+:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57
+:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B
+:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED
+:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631
+:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3
+:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641
+:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE
+:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557
+:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0
+:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB
+:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5
+:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C
+:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E
+:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92
+:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB
+:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D
+:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30
+:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29
+:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613
+:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF
+:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC
+:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC
+:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9
+:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6
+:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72
+:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943
+:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36
+:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6
+:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1
+:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59
+:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8
+:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB
+:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90
+:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E
+:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57
+:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB
+:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D
+:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD
+:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1
+:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3
+:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D
+:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67
+:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B
+:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079
+:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE
+:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E
+:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5
+:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2
+:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB
+:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78
+:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD
+:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D
+:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD
+:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31
+:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56
+:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7
+:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA
+:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611
+:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A
+:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB
+:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B
+:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616
+:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED
+:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA
+:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C
+:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B
+:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD
+:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02
+:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD
+:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A
+:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9
+:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38
+:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B
+:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05
+:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654
+:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490
+:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716
+:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F
+:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162
+:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35
+:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3
+:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E
+:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55
+:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146
+:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9
+:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656
+:15145800229960D0640871E2A297502C37025AEFB141264ADC60
+:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3
+:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497
+:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5
+:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7
+:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B
+:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C
+:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0
+:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4
+:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81
+:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC
+:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF
+:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF
+:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD
+:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527
+:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9
+:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6
+:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F
+:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9
+:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F
+:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C
+:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7
+:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142
+:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B
+:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22
+:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0
+:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A
+:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A
+:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33
+:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7
+:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C
+:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84
+:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D
+:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE
+:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841
+:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519
+:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8
+:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123
+:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9
+:15178B007C79756E475D795E5DA9A36E812AED48204577F72309
+:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C
+:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57
+:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3
+:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79
+:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3
+:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C
+:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4
+:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65
+:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D
+:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5
+:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0
+:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B
+:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824
+:1518B1003B1018CB295B01654381E3765929969541D98D8149CF
+:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4
+:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45
+:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB
+:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF
+:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C
+:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F
+:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C
+:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723
+:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B
+:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436
+:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6
+:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8
+:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A
+:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6
+:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5
+:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C
+:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13
+:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B
+:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9
+:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56
+:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9
+:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72
+:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA
+:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15
+:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216
+:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F
+:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E
+:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A
+:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F
+:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8
+:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C
+:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F
+:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842
+:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9
+:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273
+:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22
+:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C
+:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399
+:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F
+:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E
+:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D
+:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9
+:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB
+:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC
+:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD
+:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA
+:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341
+:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103
+:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4
+:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD
+:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5
+:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C
+:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC
+:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5
+:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8
+:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A
+:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379
+:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150
+:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF
+:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0
+:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729
+:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492
+:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279
+:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C
+:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC
+:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC
+:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC
+:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD
+:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540
+:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2
+:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C
+:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3
+:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA
+:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB
+:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1
+:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399
+:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C
+:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C
+:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03
+:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374
+:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6
+:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89
+:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56
+:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E
+:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2
+:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309
+:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90
+:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7
+:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C
+:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C
+:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4
+:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2
+:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F
+:152067008CB0F9D23625047E26F5697848F8946063455F46F90A
+:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28
+:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E
+:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386
+:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0
+:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4
+:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1
+:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D
+:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69
+:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C
+:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE
+:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B
+:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21
+:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D
+:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD
+:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E
+:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8
+:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC
+:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26
+:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D
+:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93
+:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4
+:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8
+:15224A0033E7914354D0D24055CE975679875080BA653E202FCF
+:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE
+:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477
+:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022
+:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB
+:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77
+:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243
+:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393
+:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E
+:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118
+:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C
+:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E
+:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607
+:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718
+:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134
+:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16
+:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9
+:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C
+:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D
+:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014
+:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB
+:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E
+:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F
+:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C
+:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6
+:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8
+:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8
+:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3
+:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA
+:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352
+:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9
+:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30
+:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679
+:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4
+:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6
+:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D
+:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909
+:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6
+:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A
+:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646
+:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700
+:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601
+:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C
+:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624
+:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10
+:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9
+:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334
+:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59
+:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785
+:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165
+:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21
+:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7
+:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2
+:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8
+:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E
+:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6
+:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721
+:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153
+:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB
+:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5
+:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F
+:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730
+:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6
+:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD
+:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997
+:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621
+:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E
+:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04
+:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97
+:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC
+:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5
+:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3
+:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3
+:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630
+:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9
+:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6
+:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720
+:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631
+:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C
+:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD
+:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3
+:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456
+:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3
+:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2
+:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92
+:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE
+:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC
+:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2
+:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499
+:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849
+:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5
+:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8
+:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7
+:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B
+:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44
+:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA
+:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4
+:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47
+:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5
+:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C
+:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372
+:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3
+:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676
+:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13
+:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00
+:152AE7005889058FF03015F65A266695480E6E209539909014D9
+:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293
+:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72
+:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D
+:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC
+:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784
+:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45
+:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64
+:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3
+:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B
+:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D
+:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7
+:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC
+:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC
+:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B
+:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26
+:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B
+:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91
+:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952
+:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674
+:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1
+:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89
+:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE
+:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12
+:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF
+:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28
+:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75
+:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495
+:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1
+:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A
+:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6
+:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425
+:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778
+:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B
+:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F
+:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C
+:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3
+:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7
+:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E
+:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408
+:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26
+:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB
+:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3
+:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6
+:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087
+:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB
+:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154
+:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7
+:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1
+:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05
+:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB
+:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E
+:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E
+:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694
+:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52
+:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1
+:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5
+:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE
+:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E
+:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612
+:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3
+:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D
+:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D
+:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029
+:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22
+:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088
+:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243
+:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD
+:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3
+:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7
+:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3
+:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5
+:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA
+:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9
+:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7
+:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8
+:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7
+:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4
+:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0
+:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3
+:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47
+:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610
+:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69
+:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317
+:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA
+:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31
+:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235
+:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8
+:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012
+:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD
+:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F
+:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182
+:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299
+:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45
+:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538
+:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0
+:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC
+:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175
+:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561
+:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F
+:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE
+:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E
+:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA
+:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E
+:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E
+:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD
+:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6
+:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373
+:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE
+:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E
+:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA
+:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB
+:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54
+:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1
+:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E
+:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49
+:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B
+:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54
+:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17
+:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E
+:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A
+:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F
+:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F
+:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A
+:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54
+:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2
+:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A
+:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6
+:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C
+:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA
+:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6
+:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28
+:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2
+:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53
+:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779
+:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D
+:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5
+:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654
+:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE
+:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E
+:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E
+:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4
+:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0
+:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD
+:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512
+:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D
+:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE
+:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B
+:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796
+:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C
+:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F
+:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08
+:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94
+:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9
+:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589
+:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A
+:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5
+:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847
+:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5
+:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4
+:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D
+:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA
+:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753
+:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016
+:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1
+:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0
+:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528
+:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A
+:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48
+:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87
+:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA
+:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC
+:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161
+:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209
+:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E
+:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC
+:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD
+:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24
+:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08
+:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA
+:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E
+:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2
+:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B
+:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0
+:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61
+:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B
+:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF
+:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4
+:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890
+:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB
+:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1
+:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94
+:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A
+:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC
+:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366
+:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1
+:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE
+:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF
+:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF
+:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26
+:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0
+:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD
+:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E
+:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99
+:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81
+:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5
+:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1
+:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61
+:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799
+:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6
+:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77
+:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC
+:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD
+:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29
+:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8
+:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB
+:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC
+:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6
+:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0
+:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8
+:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1
+:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A
+:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F
+:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90
+:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83
+:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57
+:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617
+:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA
+:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA
+:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772
+:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9
+:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863
+:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A
+:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C
+:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7
+:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2
+:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A
+:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144
+:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462
+:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB
+:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A
+:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD
+:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C
+:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0
+:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735
+:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC
+:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66
+:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7
+:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD
+:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2
+:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E
+:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46
+:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C
+:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0
+:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001
+:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127
+:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8
+:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960
+:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54
+:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81
+:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9
+:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9
+:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10
+:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097
+:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09
+:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C
+:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2
+:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E
+:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC
+:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51
+:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC
+:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A
+:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A
+:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13
+:1541610081F683EB92828072A7A6058347FA65909112F78EF437
+:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC
+:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96
+:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7
+:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC
+:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33
+:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2
+:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51
+:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F
+:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0
+:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9
+:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B
+:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865
+:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013
+:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB
+:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB
+:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D
+:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33
+:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965
+:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6
+:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3
+:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7
+:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F
+:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493
+:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B
+:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1
+:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA
+:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F
+:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B
+:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668
+:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F
+:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4
+:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3
+:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D
+:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF
+:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789
+:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4
+:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67
+:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9
+:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6
+:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765
+:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2
+:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92
+:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF
+:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F
+:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C
+:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E
+:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F
+:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1
+:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D
+:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B
+:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4
+:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B
+:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE
+:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933
+:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62
+:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755
+:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983
+:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E
+:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C
+:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47
+:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F
+:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2
+:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630
+:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE
+:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6
+:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92
+:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72
+:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75
+:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0
+:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC
+:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691
+:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64
+:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1
+:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF
+:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD
+:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1
+:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B
+:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208
+:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB
+:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4
+:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630
+:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7
+:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D
+:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F
+:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C
+:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE
+:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365
+:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218
+:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10
+:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37
+:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101
+:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A
+:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70
+:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95
+:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7
+:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732
+:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F
+:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C
+:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9
+:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68
+:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0
+:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35
+:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C
+:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F
+:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E
+:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504
+:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7
+:00000001FF
diff --git a/drivers/atm/sba200e_ecd.data b/drivers/atm/sba200e_ecd.data
new file mode 100644
index 000000000..d097e743b
--- /dev/null
+++ b/drivers/atm/sba200e_ecd.data
@@ -0,0 +1,928 @@
+:150000001F8B0808AC5A10380203736261323030655F65636426
+:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4
+:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3
+:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1
+:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC
+:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E
+:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742
+:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3
+:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC
+:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D
+:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2
+:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F
+:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D
+:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D
+:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68
+:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA
+:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5
+:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83
+:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B
+:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674
+:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67
+:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A
+:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057
+:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6
+:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32
+:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518
+:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2
+:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692
+:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F
+:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D
+:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1
+:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6
+:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E
+:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0
+:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546
+:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402
+:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715
+:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180
+:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447
+:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81
+:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10
+:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458
+:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C
+:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296
+:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923
+:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07
+:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B
+:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204
+:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572
+:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76
+:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6
+:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26
+:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966
+:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035
+:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744
+:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA
+:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD
+:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67
+:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3
+:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F
+:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9
+:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD
+:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9
+:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934
+:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294
+:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86
+:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D
+:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6
+:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5
+:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA
+:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A
+:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2
+:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D
+:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013
+:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48
+:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05
+:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877
+:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE
+:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28
+:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3
+:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394
+:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE
+:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6
+:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095
+:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB
+:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910
+:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A
+:1507230074D043D0D24325E80169074B68831F4E194FF38472E3
+:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4
+:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D
+:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45
+:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB
+:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191
+:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056
+:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A
+:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60
+:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E
+:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627
+:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53
+:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1
+:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380
+:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568
+:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37
+:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8
+:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82
+:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916
+:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC
+:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED
+:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF
+:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153
+:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68
+:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447
+:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70
+:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C
+:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875
+:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647
+:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA
+:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F
+:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F
+:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5
+:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827
+:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71
+:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A
+:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A
+:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190
+:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30
+:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A
+:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F
+:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E
+:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838
+:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B
+:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61
+:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783
+:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA
+:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6
+:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891
+:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C
+:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45
+:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF
+:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038
+:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7
+:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7
+:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF
+:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4
+:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9
+:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484
+:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E
+:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF
+:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C
+:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099
+:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F
+:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB
+:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315
+:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754
+:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3
+:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB
+:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0
+:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF
+:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD
+:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9
+:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363
+:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1
+:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969
+:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B
+:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3
+:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14
+:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D
+:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79
+:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF
+:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3
+:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70
+:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A
+:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B
+:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC
+:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB
+:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413
+:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F
+:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B
+:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779
+:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124
+:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353
+:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427
+:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514
+:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5
+:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D
+:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593
+:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E
+:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E
+:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D
+:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA
+:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E
+:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4
+:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6
+:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF
+:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6
+:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617
+:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6
+:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE
+:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C
+:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC
+:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E
+:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E
+:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197
+:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8
+:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E
+:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3
+:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232
+:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A
+:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C
+:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04
+:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A
+:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C
+:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A
+:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719
+:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5
+:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E
+:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D
+:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74
+:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0
+:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F
+:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC
+:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552
+:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4
+:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B
+:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA
+:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA
+:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08
+:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD
+:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D
+:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5
+:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9
+:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455
+:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E
+:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7
+:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15
+:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057
+:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5
+:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB
+:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64
+:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB
+:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755
+:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C
+:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6
+:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72
+:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27
+:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368
+:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC
+:151443001988C3038611280C0F1CD6E045326894648038C168C9
+:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA
+:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B
+:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E
+:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3
+:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC
+:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A
+:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39
+:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179
+:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E
+:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F
+:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21
+:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB
+:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE
+:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601
+:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309
+:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4
+:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0
+:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197
+:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE
+:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68
+:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20
+:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4
+:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C
+:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED
+:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA
+:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1
+:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50
+:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55
+:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2
+:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F
+:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D
+:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54
+:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD
+:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42
+:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31
+:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2
+:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9
+:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D
+:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4
+:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7
+:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187
+:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865
+:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB
+:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03
+:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC
+:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7
+:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464
+:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA
+:1518480098670742867C3B2105072B357D32E5763A3AD5367878
+:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA
+:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8
+:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9
+:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF
+:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F
+:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0
+:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2
+:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3
+:15190500B179E0A4896D045924842C12421609218B04CAA2F079
+:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD
+:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62
+:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3
+:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261
+:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E
+:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A
+:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A
+:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71
+:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D
+:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99
+:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352
+:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922
+:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4
+:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7
+:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440
+:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94
+:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328
+:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7
+:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29
+:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE
+:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70
+:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F
+:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0
+:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4
+:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732
+:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D
+:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3
+:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF
+:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB
+:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307
+:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F
+:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494
+:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5
+:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3
+:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4
+:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7
+:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984
+:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D
+:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498
+:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455
+:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B
+:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7
+:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD
+:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8
+:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A
+:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0
+:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99
+:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8
+:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C
+:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B
+:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D
+:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3
+:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899
+:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D
+:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690
+:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824
+:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05
+:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA
+:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8
+:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482
+:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F
+:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2
+:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F
+:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713
+:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B
+:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726
+:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D
+:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5
+:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB
+:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53
+:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E
+:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873
+:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C
+:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A
+:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A
+:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC
+:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B
+:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C
+:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1
+:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326
+:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943
+:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7
+:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7
+:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C
+:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B
+:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630
+:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4
+:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4
+:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704
+:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF
+:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5
+:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951
+:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4
+:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99
+:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC
+:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C
+:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368
+:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B
+:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D
+:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF
+:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E
+:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775
+:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81
+:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980
+:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371
+:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7
+:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26
+:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196
+:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD
+:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A
+:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73
+:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9
+:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2
+:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926
+:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987
+:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A
+:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334
+:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A
+:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379
+:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8
+:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876
+:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB
+:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1
+:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E
+:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC
+:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4
+:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3
+:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B
+:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77
+:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426
+:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70
+:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6
+:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002
+:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9
+:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C
+:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E
+:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC
+:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D
+:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0
+:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E
+:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D
+:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8
+:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F
+:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988
+:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4
+:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80
+:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5
+:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC
+:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108
+:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB
+:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616
+:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C
+:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF
+:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B
+:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB
+:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7
+:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24
+:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B
+:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76
+:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95
+:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D
+:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8
+:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B
+:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F
+:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6
+:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5
+:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78
+:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F
+:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99
+:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD
+:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5
+:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8
+:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E
+:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733
+:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC
+:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F
+:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A
+:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49
+:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848
+:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B
+:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A
+:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4
+:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0
+:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01
+:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9
+:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C
+:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0
+:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A
+:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44
+:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97
+:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812
+:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71
+:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D
+:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174
+:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D
+:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA
+:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719
+:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3
+:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F
+:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63
+:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B
+:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7
+:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E
+:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF
+:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D
+:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9
+:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021
+:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788
+:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA
+:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3
+:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53
+:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627
+:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015
+:152A93005AC3CC20B0905A443892A33833625024598481B05E2D
+:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7
+:152ABD00C42318890137B8E913589615337224AF7C0B398507C9
+:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3
+:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21
+:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0
+:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10
+:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F
+:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3
+:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514
+:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8
+:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB
+:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9
+:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A
+:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61
+:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8
+:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F
+:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7
+:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1
+:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15
+:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52
+:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6
+:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442
+:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419
+:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202
+:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1
+:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7
+:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B
+:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C
+:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF
+:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994
+:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7
+:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF
+:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770
+:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6
+:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9
+:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218
+:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC
+:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0
+:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019
+:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727
+:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF
+:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1
+:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E
+:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1
+:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113
+:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B
+:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC
+:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76
+:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080
+:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC
+:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999
+:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496
+:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC
+:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA
+:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6
+:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2
+:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB
+:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF
+:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0
+:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC
+:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4
+:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF
+:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3
+:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9
+:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF
+:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02
+:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5
+:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B
+:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB
+:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4
+:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4
+:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7
+:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A
+:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916
+:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946
+:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85
+:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217
+:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC
+:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6
+:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A
+:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5
+:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811
+:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2
+:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000
+:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A
+:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A
+:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46
+:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2
+:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90
+:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8
+:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F
+:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A
+:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE
+:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0
+:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E
+:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C
+:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A
+:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5
+:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC
+:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF
+:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649
+:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4
+:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F
+:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD
+:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF
+:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2
+:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8
+:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67
+:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8
+:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748
+:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A
+:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661
+:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC
+:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77
+:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9
+:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD
+:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606
+:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB
+:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC
+:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836
+:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7
+:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0
+:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA
+:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31
+:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1
+:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434
+:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A
+:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3
+:15352800D915524B23A17031953D54754F634546A631B3562FB7
+:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD
+:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706
+:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55
+:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B
+:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC
+:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8
+:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49
+:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F
+:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B
+:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98
+:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5
+:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD
+:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194
+:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D
+:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB
+:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97
+:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D
+:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6
+:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD
+:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6
+:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708
+:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A
+:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58
+:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD
+:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91
+:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395
+:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D
+:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D
+:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889
+:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777
+:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9
+:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1
+:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC
+:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00
+:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9
+:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E
+:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766
+:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A
+:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34
+:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86
+:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4
+:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33
+:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6
+:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB
+:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953
+:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99
+:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC
+:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D
+:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D
+:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8
+:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3
+:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D
+:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5
+:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958
+:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5
+:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4
+:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C
+:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6
+:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916
+:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD
+:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459
+:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73
+:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23
+:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766
+:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E
+:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599
+:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B
+:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98
+:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4
+:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7
+:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40
+:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3
+:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC
+:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA
+:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F
+:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA
+:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2
+:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54
+:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23
+:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A
+:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361
+:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F
+:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8
+:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365
+:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5
+:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D
+:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9
+:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5
+:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8
+:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C
+:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895
+:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D
+:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E
+:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD
+:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058
+:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F
+:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424
+:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C
+:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5
+:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018
+:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0
+:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5
+:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6
+:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49
+:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613
+:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD
+:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084
+:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD
+:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5
+:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92
+:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5
+:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF
+:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582
+:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8
+:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9
+:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9
+:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81
+:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A
+:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621
+:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929
+:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F
+:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA
+:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B
+:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1
+:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D
+:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96
+:153F9300F02905E78C00B33732B854245945A43C2729CF769297
+:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE
+:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419
+:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A
+:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84
+:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59
+:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19
+:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C
+:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53
+:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D
+:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4
+:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C
+:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D
+:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765
+:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC
+:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB
+:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0
+:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE
+:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485
+:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F
+:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F
+:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299
+:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9
+:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556
+:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6
+:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2
+:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44
+:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732
+:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409
+:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685
+:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B
+:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD
+:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7
+:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508
+:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB
+:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743
+:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26
+:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00
+:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9
+:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22
+:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44
+:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C
+:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3
+:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4
+:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887
+:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16
+:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2
+:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03
+:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D
+:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4
+:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C
+:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446
+:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF
+:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E
+:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3
+:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B
+:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9
+:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9
+:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2
+:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE
+:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E
+:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948
+:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6
+:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B
+:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24
+:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3
+:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2
+:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC
+:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583
+:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33
+:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45
+:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4
+:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD
+:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521
+:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3
+:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E
+:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA
+:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20
+:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932
+:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE
+:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F
+:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22
+:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008
+:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198
+:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541
+:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6
+:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5
+:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C
+:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69
+:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F
+:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF
+:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A
+:15471F00DF553D1057F9FE1264E459605865C15042301C22180D
+:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE
+:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E
+:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745
+:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825
+:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9
+:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01
+:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1
+:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026
+:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91
+:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851
+:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35
+:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4
+:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E
+:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844
+:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0
+:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A
+:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4
+:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374
+:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2
+:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924
+:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4
+:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E
+:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731
+:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473
+:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63
+:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB
+:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B
+:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469
+:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7
+:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF
+:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6
+:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA
+:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E
+:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC
+:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2
+:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25
+:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785
+:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA
+:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242
+:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418
+:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F
+:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40
+:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197
+:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED
+:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5
+:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E
+:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1
+:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A
+:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081
+:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2
+:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121
+:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75
+:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC
+:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2
+:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE
+:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6
+:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1
+:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037
+:014BF60000BE
+:00000001FF
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 11cd3e6ca..26c8c9d90 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -636,12 +636,12 @@ printk("dummy: 0x%08lx, 0x%08lx\n",dummy[0],dummy[1]);
event_dump();
}
if (!size) {
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
if (vcc) vcc->stats->rx_err++;
continue;
}
if (!atm_charge(vcc,skb->truesize)) {
- kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
continue;
}
skb->len = size;
@@ -854,7 +854,7 @@ printk("NONONONOO!!!!\n");
uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC);
if (!dsc) {
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_irq(skb);
return -EAGAIN;
}
/* @@@ should check alignment */
@@ -908,7 +908,7 @@ if (*ZATM_PRV_DSC(skb) != (uPD98401_TXPD_V | uPD98401_TXPD_DP |
*ZATM_PRV_DSC(skb) = 0; /* mark as invalid */
zatm_vcc->txing--;
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
+ else dev_kfree_skb_irq(skb);
while ((skb = skb_dequeue(&zatm_vcc->backlog)))
if (do_tx(skb) == RING_BUSY) {
skb_queue_head(&zatm_vcc->backlog,skb);
@@ -1395,7 +1395,7 @@ static int __init zatm_init(struct atm_dev *dev)
command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)"
"\n",dev->number,error);
- return error;
+ return -EIO;
}
eprom_get_esi(dev);
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,",
@@ -1741,7 +1741,6 @@ static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb)
if (!skb) {
printk(KERN_CRIT "!skb in zatm_send ?\n");
if (vcc->pop) vcc->pop(vcc,skb);
- else dev_kfree_skb(skb);
return -EINVAL;
}
ATM_SKB(skb)->vcc = vcc;
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 01fc28943..d4ba3f06b 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -44,6 +44,7 @@ else
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+ bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO
@@ -54,38 +55,43 @@ else
define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n
fi
fi
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+ bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP
+ fi
bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then
- bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then
+ bool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING
fi
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409
+ bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AMD7409" = "y" ]; then
+ bool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE
fi
fi
bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X
- if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_CMD64X" = "y" ]; then
+ bool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID
fi
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
fi
+ bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
- bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
+ bool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA
fi
bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366
- if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then
- bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' CONFIG_HPT366_FAST_IRQ_PREDICTION
- bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' CONFIG_HPT366_MODE3
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then
+ bool ' HPT366 Fast Interrupts (WIP)' CONFIG_HPT366_FIP
+ bool ' HPT366 mode Three (WIP)' CONFIG_HPT366_MODE3
fi
- if [ "$CONFIG_X86" = "y" ]; then
+ if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_PCI_AUTO" = "y" ]; then
- bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING
+ bool ' PIIXn Tuning support' CONFIG_PIIX_TUNING
fi
fi
fi
@@ -98,21 +104,18 @@ else
if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
- bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+ bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST
+ if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" ]; then
+ bool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER
fi
fi
if [ "$CONFIG_X86" = "y" ]; then
bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
fi
- bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530
fi
if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX
- fi
+ bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX
fi
fi
if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
@@ -232,6 +235,7 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
"$CONFIG_BLK_DEV_AMD7409" = "y" -o \
"$CONFIG_BLK_DEV_CMD640" = "y" -o \
"$CONFIG_BLK_DEV_CMD64X" = "y" -o \
+ "$CONFIG_BLK_DEV_CS5530" = "y" -o \
"$CONFIG_BLK_DEV_CY82C693" = "y" -o \
"$CONFIG_BLK_DEV_HPT34X" = "y" -o \
"$CONFIG_BLK_DEV_HPT366" = "y" -o \
@@ -240,7 +244,6 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
"$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
"$CONFIG_BLK_DEV_PIIX" = "y" -o \
"$CONFIG_BLK_DEV_SIS5513" = "y" -o \
- "$CONFIG_BLK_DEV_CS5530" = "y" -o \
"$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
define_bool CONFIG_BLK_DEV_IDE_MODES y
else
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9f313de8f..be158ca1a 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -130,6 +130,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD64X),y)
IDE_OBJS += cmd64x.o
endif
+ifeq ($(CONFIG_BLK_DEV_CS5530),y)
+IDE_OBJS += cs5530.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_CY82C693),y)
IDE_OBJS += cy82c693.o
endif
@@ -198,10 +202,6 @@ ifeq ($(CONFIG_BLK_DEV_PDC202XX),y)
IDE_OBJS += pdc202xx.o
endif
-ifeq ($(CONFIG_BLK_DEV_CS5530),y)
-IDE_OBJS += cs5530.o
-endif
-
ifeq ($(CONFIG_BLK_DEV_PDC4030),y)
IDE_OBJS += pdc4030.o
endif
diff --git a/drivers/block/README.lvm b/drivers/block/README.lvm
deleted file mode 100644
index 3d652457f..000000000
--- a/drivers/block/README.lvm
+++ /dev/null
@@ -1,8 +0,0 @@
-
-This is the Logical Volume Manager driver for Linux,
-
-Tools, library that manage logical volumes can be found
-at <http://linux.msede.com/lvm>.
-
-There you can obtain actual driver versions too.
-
diff --git a/drivers/block/README.md b/drivers/block/README.md
deleted file mode 100644
index 6ad19ac99..000000000
--- a/drivers/block/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr
-in public/Linux/md035.tar.gz.
-
- Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c
index f74103d9a..30be6a7cc 100644
--- a/drivers/block/aec6210.c
+++ b/drivers/block/aec6210.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/aec6210.c Version 0.04 Dec. 13, 1999
+ * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000
*
- * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02
@@ -56,7 +56,52 @@
#define ACARD_DEBUG_DRIVE_INFO 1
-#ifdef CONFIG_BLK_DEV_AEC6210_TUNING
+#define DISPLAY_AEC6210_TIMINGS
+
+#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int aec6210_get_info(char *, char **, off_t, int);
+extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ p += sprintf(p, "\n AEC6210 Chipset.\n");
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+ return p-buffer;/* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte aec6210_proc = 0;
+
+#ifdef CONFIG_AEC6210_TUNING
struct chipset_bus_clock_list_entry {
byte xfer_speed;
@@ -269,7 +314,7 @@ int aec6210_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
}
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
-#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */
+#endif /* CONFIG_AEC6210_TUNING */
unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
{
@@ -277,12 +322,19 @@ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name)
pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
}
+
+#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
+ aec6210_proc = 1;
+ bmide_dev = dev;
+ aec6210_display_info = &aec6210_get_info;
+#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */
+
return dev->irq;
}
void __init ide_init_aec6210 (ide_hwif_t *hwif)
{
-#ifdef CONFIG_BLK_DEV_AEC6210_TUNING
+#ifdef CONFIG_AEC6210_TUNING
hwif->tuneproc = &aec6210_tune_drive;
if (hwif->dma_base) {
@@ -291,7 +343,7 @@ void __init ide_init_aec6210 (ide_hwif_t *hwif)
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
-#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */
+#endif /* CONFIG_AEC6210_TUNING */
}
void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase)
diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c
index e86fe61db..e7fd203b4 100644
--- a/drivers/block/ali14xx.c
+++ b/drivers/block/ali14xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996
+ * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
@@ -55,12 +55,12 @@
/* port addresses for auto-detection */
#define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
+static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4};
/* register initialization data */
typedef struct { byte reg, data; } RegInitializer;
-static RegInitializer initData[] = {
+static RegInitializer __init initData[] = {
{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
@@ -150,7 +150,7 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
/*
* Auto-detect the IDE controller port.
*/
-static int findPort (void)
+static int __init findPort (void)
{
int i;
byte t;
@@ -183,7 +183,7 @@ static int findPort (void)
/*
* Initialize controller registers with default values.
*/
-static int initRegisters (void) {
+static int __init initRegisters (void) {
RegInitializer *p;
byte t;
unsigned long flags;
@@ -200,7 +200,7 @@ static int initRegisters (void) {
return t;
}
-void init_ali14xx (void)
+void __init init_ali14xx (void)
{
/* auto-detect IDE controller port */
if (!findPort()) {
diff --git a/drivers/block/alim15x3.c b/drivers/block/alim15x3.c
index 4b9b28e3b..bc3d2b9e3 100644
--- a/drivers/block/alim15x3.c
+++ b/drivers/block/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000
+ * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -493,7 +493,6 @@ static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
default:
break;
}
-
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
@@ -518,6 +517,13 @@ unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
if (inb(fixdma_base+2) & 0x80)
printk("%s: simplex device: DMA will fail!!\n", name);
}
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+ ali_proc = 1;
+ bmide_dev = dev;
+ ali_display_info = &ali_get_info;
+#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
return 0;
}
@@ -666,22 +672,11 @@ void __init ide_init_ali15x3 (ide_hwif_t *hwif)
*/
hwif->dmaproc = &ali15x3_dmaproc;
hwif->autodma = 1;
- hwif->drives[0].autotune = 0;
- hwif->drives[1].autotune = 0;
} else {
hwif->autodma = 0;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
- if (!ali_proc) {
- ali_proc = 1;
- bmide_dev = hwif->pci_dev;
- ali_display_info = &ali_get_info;
- }
-#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
return;
}
diff --git a/drivers/block/amd7409.c b/drivers/block/amd7409.c
index 46d5f36af..b12847843 100644
--- a/drivers/block/amd7409.c
+++ b/drivers/block/amd7409.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000
+ * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000
*
* Copyright (C) 2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -24,6 +24,51 @@
#include "ide_modes.h"
+#define DISPLAY_VIPER_TIMINGS
+
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int amd7409_get_info(char *, char **, off_t, int);
+extern int (*amd7409_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ p += sprintf(p, "\n AMD 7409 VIPER Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte amd7409_proc = 0;
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
/*
* Here is where all the hard work goes to program the chipset.
*
@@ -33,11 +78,13 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
int err = 0;
- int drive_number = ((HWIF(drive)->channel ? 2 : 0) +
- (drive->select.b.unit & 0x01));
+ byte unit = (drive->select.b.unit & 0x01);
+ int drive_number = ((HWIF(drive)->channel ? 2 : 0) + unit);
+ unsigned long dma_base = hwif->dma_base;
byte drive_pci = 0x00;
byte drive_pci2 = 0x00;
- byte drive_timing = 0x00;
+ byte ultra_timing = 0x00;
+ byte dma_pio_timing = 0x00;
byte pio_timing = 0x00;
switch (drive_number) {
@@ -49,54 +96,99 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
return ((int) ide_dma_off_quietly);
}
- pci_read_config_byte(dev, drive_pci, &drive_timing);
- pci_read_config_byte(dev, drive_pci2, &pio_timing);
+ pci_read_config_byte(dev, drive_pci, &ultra_timing);
+ pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
+ pci_read_config_byte(dev, 0x4c, &pio_timing);
- printk("%s: UDMA 0x%02x PIO 0x%02x ",
- drive->name, drive_timing, pio_timing);
+#ifdef DEBUG
+ printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+ drive->name, ultra_timing, dma_pio_timing, pio_timing);
+#endif
+
+ ultra_timing &= ~0xC7;
+ dma_pio_timing &= ~0xFF;
+ pio_timing &= ~(0x03 << drive_number);
+
+#ifdef DEBUG
+ printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
+ ultra_timing, dma_pio_timing, pio_timing);
+#endif
switch(speed) {
case XFER_UDMA_4:
- drive_timing &= ~0xC7;
- drive_timing |= 0x45;
- pci_write_config_byte(dev, drive_pci, drive_timing);
+ ultra_timing |= 0x45;
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
break;
case XFER_UDMA_3:
- drive_timing &= ~0xC7;
- drive_timing |= 0x44;
- pci_write_config_byte(dev, drive_pci, drive_timing);
+ ultra_timing |= 0x44;
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
break;
case XFER_UDMA_2:
- drive_timing &= ~0xC7;
- drive_timing |= 0x40;
- pci_write_config_byte(dev, drive_pci, drive_timing);
+ ultra_timing |= 0x40;
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
break;
case XFER_UDMA_1:
- drive_timing &= ~0xC7;
- drive_timing |= 0x41;
- pci_write_config_byte(dev, drive_pci, drive_timing);
+ ultra_timing |= 0x41;
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
break;
case XFER_UDMA_0:
- drive_timing &= ~0xC7;
- drive_timing |= 0x42;
- pci_write_config_byte(dev, drive_pci, drive_timing);
+ ultra_timing |= 0x42;
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_MW_DMA_2:
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_MW_DMA_1:
+ dma_pio_timing |= 0x21;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_MW_DMA_0:
+ dma_pio_timing |= 0x77;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_PIO_4:
+ dma_pio_timing |= 0x20;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_PIO_3:
+ dma_pio_timing |= 0x22;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_PIO_2:
+ dma_pio_timing |= 0x42;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_PIO_1:
+ dma_pio_timing |= 0x65;
+ pio_timing |= (0x03 << drive_number);
+ break;
+ case XFER_PIO_0:
+ default:
+ dma_pio_timing |= 0xA8;
+ pio_timing |= (0x03 << drive_number);
break;
- case XFER_MW_DMA_2:break;
- case XFER_MW_DMA_1:break;
- case XFER_MW_DMA_0:break;
- case XFER_SW_DMA_2:break;
- case XFER_SW_DMA_1:break;
- case XFER_SW_DMA_0:break;
- case XFER_PIO_4:break;
- case XFER_PIO_3:break;
- case XFER_PIO_2:break;
- case XFER_PIO_1:break;
- case XFER_PIO_0:break;
- default: break;
}
- printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing);
+ pci_write_config_byte(dev, drive_pci, ultra_timing);
+ pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
+ pci_write_config_byte(dev, 0x4c, pio_timing);
+
+#ifdef DEBUG
+ printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
+ ultra_timing, dma_pio_timing, pio_timing);
+#endif
+ if (speed > XFER_PIO_4) {
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+ } else {
+ outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
+ }
err = ide_config_drive_speed(drive, speed);
return (err);
}
@@ -109,12 +201,14 @@ static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
static int config_chipset_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
+ byte udma_66 = ((id->hw_config & 0x2000) &&
+ (HWIF(drive)->udma_four)) ? 1 : 0;
byte speed = 0x00;
int rval;
- if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) {
+ if ((id->dma_ultra & 0x0010) && (udma_66)) {
speed = XFER_UDMA_4;
- } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) {
+ } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
speed = XFER_UDMA_3;
} else if (id->dma_ultra & 0x0004) {
speed = XFER_UDMA_2;
@@ -128,12 +222,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
speed = XFER_MW_DMA_1;
} else if (id->dma_mword & 0x0001) {
speed = XFER_MW_DMA_0;
- } else if (id->dma_1word & 0x0004) {
- speed = XFER_SW_DMA_2;
- } else if (id->dma_1word & 0x0002) {
- speed = XFER_SW_DMA_1;
- } else if (id->dma_1word & 0x0001) {
- speed = XFER_SW_DMA_0;
} else {
return ((int) ide_dma_off_quietly);
}
@@ -143,7 +231,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
((id->dma_ultra >> 8) & 7) ? ide_dma_on :
((id->dma_mword >> 8) & 7) ? ide_dma_on :
- ((id->dma_1word >> 8) & 7) ? ide_dma_on :
ide_dma_off_quietly);
return rval;
@@ -222,8 +309,7 @@ static int config_drive_xfer_rate (ide_drive_t *drive)
}
} else if (id->field_valid & 2) {
try_dma_modes:
- if ((id->dma_mword & 0x0007) ||
- (id->dma_1word & 0x0007)) {
+ if (id->dma_mword & 0x0007) {
/* Force if Capable regular DMA modes */
dma_func = config_chipset_for_dma(drive);
if (dma_func != ide_dma_on)
@@ -265,16 +351,45 @@ int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return ide_dmaproc(func, drive); /* use standard DMA stuff */
}
+unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
+{
+ unsigned long fixdma_base = dev->resource[4].start;
+
+ if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) {
+ /*
+ *
+ */
+ } else {
+ /*
+ * enable DMA capable bit, and "not" simplex only
+ */
+ outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
+
+ if (inb(fixdma_base+2) & 0x80)
+ printk("%s: simplex device: DMA will fail!!\n", name);
+ }
+#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
+ amd7409_proc = 1;
+ bmide_dev = dev;
+ amd7409_display_info = &amd7409_get_info;
+#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
+
+ return 0;
+}
+
unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
{
-#if 0
+#ifdef CONFIG_AMD7409_OVERRIDE
+ byte ata66 = 1;
+#else
byte ata66 = 0;
+#endif /* CONFIG_AMD7409_OVERRIDE */
+#if 0
pci_read_config_byte(hwif->pci_dev, 0x48, &ata66);
return ((ata66 & 0x02) ? 0 : 1);
-#else
- return 0;
#endif
+ return ata66;
}
void __init ide_init_amd7409 (ide_hwif_t *hwif)
@@ -288,3 +403,8 @@ void __init ide_init_amd7409 (ide_hwif_t *hwif)
hwif->drives[1].autotune = 1;
}
}
+
+void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+ ide_setup_dma(hwif, dmabase, 8);
+}
diff --git a/drivers/block/buddha.c b/drivers/block/buddha.c
index e5862cd31..3e1cfcd33 100644
--- a/drivers/block/buddha.c
+++ b/drivers/block/buddha.c
@@ -42,7 +42,7 @@
#define BUDDHA_BASE2 0xa00
#define BUDDHA_BASE3 0xc00
-static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = {
+static const u_int __init buddha_bases[CATWEASEL_NUM_HWIFS] = {
BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
};
@@ -61,7 +61,7 @@ static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = {
#define BUDDHA_STATUS 0x1e /* see status-bits */
#define BUDDHA_CONTROL 0x11a
-static int buddha_offsets[IDE_NR_PORTS] = {
+static int __init buddha_offsets[IDE_NR_PORTS] = {
BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL
};
@@ -75,7 +75,7 @@ static int buddha_offsets[IDE_NR_PORTS] = {
#define BUDDHA_IRQ2 0xf40 /* interrupt */
#define BUDDHA_IRQ3 0xf80
-static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = {
+static const int __init buddha_irqports[CATWEASEL_NUM_HWIFS] = {
BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
};
@@ -109,7 +109,7 @@ static int buddha_ack_intr(ide_hwif_t *hwif)
* Any Buddha or Catweasel boards present?
*/
-static int find_buddha(void)
+static int __init find_buddha(void)
{
struct zorro_dev *z = NULL;
@@ -143,7 +143,7 @@ static int find_buddha(void)
* We support only _one_ of them, no multiple boards!
*/
-void buddha_init(void)
+void __init buddha_init(void)
{
hw_regs_t hw;
int i, index;
diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c
index 3e5f56cec..b2077df6d 100644
--- a/drivers/block/cmd640.c
+++ b/drivers/block/cmd640.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996
+ * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
*/
@@ -290,7 +290,7 @@ static byte get_cmd640_reg_vlb (unsigned short reg)
return b;
}
-static int match_pci_cmd640_device (void)
+static int __init match_pci_cmd640_device (void)
{
const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
unsigned int i;
@@ -310,7 +310,7 @@ static int match_pci_cmd640_device (void)
/*
* Probe for CMD640x -- pci method 1
*/
-static int probe_for_cmd640_pci1 (void)
+static int __init probe_for_cmd640_pci1 (void)
{
get_cmd640_reg = get_cmd640_reg_pci1;
put_cmd640_reg = put_cmd640_reg_pci1;
@@ -324,7 +324,7 @@ static int probe_for_cmd640_pci1 (void)
/*
* Probe for CMD640x -- pci method 2
*/
-static int probe_for_cmd640_pci2 (void)
+static int __init probe_for_cmd640_pci2 (void)
{
get_cmd640_reg = get_cmd640_reg_pci2;
put_cmd640_reg = put_cmd640_reg_pci2;
@@ -338,7 +338,7 @@ static int probe_for_cmd640_pci2 (void)
/*
* Probe for CMD640x -- vlb
*/
-static int probe_for_cmd640_vlb (void)
+static int __init probe_for_cmd640_vlb (void)
{
byte b;
@@ -359,7 +359,7 @@ static int probe_for_cmd640_vlb (void)
* Returns 1 if an IDE interface/drive exists at 0x170,
* Returns 0 otherwise.
*/
-static int secondary_port_responding (void)
+static int __init secondary_port_responding (void)
{
unsigned long flags;
@@ -403,7 +403,7 @@ void cmd640_dump_regs (void)
* Check whether prefetch is on for a drive,
* and initialize the unmask flags for safe operation.
*/
-static void check_prefetch (unsigned int index)
+static void __init check_prefetch (unsigned int index)
{
ide_drive_t *drive = cmd_drives[index];
byte b = get_cmd640_reg(prefetch_regs[index]);
@@ -424,7 +424,7 @@ static void check_prefetch (unsigned int index)
/*
* Figure out which devices we control
*/
-static void setup_device_ptrs (void)
+static void __init setup_device_ptrs (void)
{
unsigned int i;
@@ -507,7 +507,7 @@ inline static byte pack_nibbles (byte upper, byte lower)
/*
* This routine retrieves the initial drive timings from the chipset.
*/
-static void retrieve_drive_counts (unsigned int index)
+static void __init retrieve_drive_counts (unsigned int index)
{
byte b;
@@ -694,7 +694,7 @@ static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
/*
* Probe for a cmd640 chipset, and initialize it if found. Called from ide.c
*/
-int ide_probe_for_cmd640x (void)
+int __init ide_probe_for_cmd640x (void)
{
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
int second_port_toggled = 0;
diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c
index 8f5f04aea..4e98893ec 100644
--- a/drivers/block/cmd64x.c
+++ b/drivers/block/cmd64x.c
@@ -1,4 +1,4 @@
-/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
*
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Note, this driver is not used at all on other systems because
@@ -8,7 +8,7 @@
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright (C) 1999 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com)
*/
#include <linux/types.h>
@@ -18,8 +18,10 @@
#include <linux/ide.h>
#include <asm/io.h>
+#include "ide_modes.h"
#define CMD_DEBUG 0
+#undef NO_WRITE
#if CMD_DEBUG
#define cmdprintk(x...) printk(##x)
@@ -27,6 +29,235 @@
#define cmdprintk(x...)
#endif
+/*
+ * CMD64x specific registers definition.
+ */
+
+#define CNTRL 0x51
+#define CNTRL_DIS_RA0 0x40
+#define CNTRL_DIS_RA1 0x80
+#define CNTRL_ENA_2ND 0x08
+
+#define CMDTIM 0x52
+#define ARTTIM0 0x53
+#define DRWTIM0 0x54
+#define ARTTIM1 0x55
+#define DRWTIM1 0x56
+#define ARTTIM23 0x57
+#define ARTTIM23_DIS_RA2 0x04
+#define ARTTIM23_DIS_RA3 0x08
+#define DRWTIM23 0x58
+#define DRWTIM2 0x58
+#define BRST 0x59
+#define DRWTIM3 0x5b
+
+#define MRDMODE 0x71
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int cmd64x_get_info(char *, char **, off_t, int);
+extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ switch(bmide_dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ p += sprintf(p, "\n CMD648 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_CMD_646:
+ p += sprintf(p, "\n CMD646 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_CMD_643:
+ p += sprintf(p, "\n CMD643 Chipset.\n");
+ break;
+ default:
+ p += sprintf(p, "\n CMD64? Chipse.\n");
+ break;
+ }
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte cmd64x_proc = 0;
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+ unsigned long flags;
+ ide_drive_t *drives = HWIF(drive)->drives;
+ byte temp_b;
+ static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+ static const byte recovery_counts[] =
+ {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+ static const byte arttim_regs[2][2] = {
+ { ARTTIM0, ARTTIM1 },
+ { ARTTIM23, ARTTIM23 }
+ };
+ static const byte drwtim_regs[2][2] = {
+ { DRWTIM0, DRWTIM1 },
+ { DRWTIM2, DRWTIM3 }
+ };
+ int channel = (int) HWIF(drive)->channel;
+ int slave = (drives != drive); /* Is this really the best way to determine this?? */
+
+ cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
+ active_count, recovery_count, drive->present);
+ /*
+ * Set up address setup count registers.
+ * Primary interface has individual count/timing registers for
+ * each drive. Secondary interface has one common set of registers,
+ * for address setup so we merge these timings, using the slowest
+ * value.
+ */
+ if (channel) {
+ drive->drive_data = setup_count;
+ setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
+ cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
+ }
+
+ /*
+ * Convert values to internal chipset representation
+ */
+ setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+ active_count &= 0xf; /* Remember, max value is 16 */
+ recovery_count = (int) recovery_counts[recovery_count];
+
+ cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count);
+
+ /*
+ * Now that everything is ready, program the new timings
+ */
+ __save_flags (flags);
+ __cli();
+ /*
+ * Program the address_setup clocks into ARTTIM reg,
+ * and then the active/recovery counts into the DRWTIM reg
+ */
+ (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
+#ifndef NO_WRITE
+ (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
+ ((byte) setup_count) | (temp_b & 0x3f));
+ (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
+ (byte) ((active_count << 4) | recovery_count));
+#endif
+ cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
+ cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
+ __restore_flags(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is
+ * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
+ byte recovery_count2, cycle_count;
+ int setup_count, active_count, recovery_count;
+ int bus_speed = ide_system_bus_speed();
+ /*byte b;*/
+ ide_pio_data_t d;
+
+ switch (mode_wanted) {
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ mode_wanted &= 1;
+ /*set_prefetch_mode(index, mode_wanted);*/
+ cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+ return;
+ }
+
+ (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+ pio_mode = d.pio_mode;
+ cycle_time = d.cycle_time;
+
+ /*
+ * I copied all this complicated stuff from cmd640.c and made a few minor changes.
+ * For now I am just going to pray that it is correct.
+ */
+ if (pio_mode > 5)
+ pio_mode = 5;
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+
+ active_count = (active_time + clock_time - 1) / clock_time;
+
+ recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count2 = cycle_count - (setup_count + active_count);
+ if (recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if (recovery_count > 16) {
+ active_count += recovery_count - 16;
+ recovery_count = 16;
+ }
+ if (active_count > 16)
+ active_count = 16; /* maximum allowed by cmd646 */
+
+ /*
+ * In a perfect world, we might set the drive pio mode here
+ * (using WIN_SETFEATURE) before continuing.
+ *
+ * But we do not, because:
+ * 1) this is the wrong place to do it (proper is do_special() in ide.c)
+ * 2) in practice this is rarely, if ever, necessary
+ */
+ program_drive_counts (drive, setup_count, active_count, recovery_count);
+
+ printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n",
+ drive->name, pio_mode, cycle_time,
+ d.overridden ? " (overriding vendor mode)" : "",
+ setup_count, active_count, recovery_count);
+}
+
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
@@ -123,7 +354,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev)
{
- /* FIXME!! figure out some PIOing junk.... */
+ cmd64x_tuneproc(drive, 5);
}
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
@@ -198,7 +429,7 @@ fast_ata_pio:
no_dma_set:
config_chipset_for_pio(drive, class_rev);
}
- return hwif->dmaproc(dma_func, drive);
+ return HWIF(drive)->dmaproc(dma_func, drive);
}
static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
@@ -277,9 +508,9 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
#endif
/* Setup interrupts. */
- (void) pci_read_config_byte(dev, 0x71, &mrdmode);
+ (void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
mrdmode &= ~(0x30);
- (void) pci_write_config_byte(dev, 0x71, mrdmode);
+ (void) pci_write_config_byte(dev, MRDMODE, mrdmode);
/* Use MEMORY READ LINE for reads.
* NOTE: Although not mentioned in the PCI0646U specs,
@@ -287,16 +518,26 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
* back as set or not. The PCI0646U2 specs clarify
* this point.
*/
- (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02);
-
+ (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+#if 0
/* Set reasonable active/recovery/address-setup values. */
- (void) pci_write_config_byte(dev, 0x53, 0x40);
- (void) pci_write_config_byte(dev, 0x54, 0x3f);
- (void) pci_write_config_byte(dev, 0x55, 0x40);
- (void) pci_write_config_byte(dev, 0x56, 0x3f);
- (void) pci_write_config_byte(dev, 0x57, 0x5c);
- (void) pci_write_config_byte(dev, 0x58, 0x3f);
- (void) pci_write_config_byte(dev, 0x5b, 0x3f);
+ (void) pci_write_config_byte(dev, ARTTIM0, 0x40);
+ (void) pci_write_config_byte(dev, DRWTIM0, 0x3f);
+ (void) pci_write_config_byte(dev, ARTTIM1, 0x40);
+ (void) pci_write_config_byte(dev, DRWTIM1, 0x3f);
+ (void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+ (void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+ (void) pci_write_config_byte(dev, DRWTIM3, 0x3f);
+#else
+ (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#endif
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+ cmd64x_proc = 1;
+ bmide_dev = dev;
+ cmd64x_display_info = &cmd64x_get_info;
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
return 0;
}
@@ -317,8 +558,13 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
- if (!hwif->dma_base)
+ hwif->tuneproc = &cmd64x_tuneproc;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
return;
+ }
switch(dev->device) {
case PCI_DEVICE_ID_CMD_643:
diff --git a/drivers/block/cs5530.c b/drivers/block/cs5530.c
index 3e26b8006..0f2f04990 100644
--- a/drivers/block/cs5530.c
+++ b/drivers/block/cs5530.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
+ * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
*
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
* May be copied or modified under the terms of the GNU General Public License
@@ -24,130 +24,63 @@
#include <asm/irq.h>
#include "ide_modes.h"
-/*
- * Return the mode name for a drive transfer mode value:
- */
-static const char *strmode (byte mode)
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int cs5530_get_info(char *, char **, off_t, int);
+extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
{
- switch (mode) {
- case XFER_UDMA_4: return("UDMA4");
- case XFER_UDMA_3: return("UDMA3");
- case XFER_UDMA_2: return("UDMA2");
- case XFER_UDMA_1: return("UDMA1");
- case XFER_UDMA_0: return("UDMA0");
- case XFER_MW_DMA_2: return("MDMA2");
- case XFER_MW_DMA_1: return("MDMA1");
- case XFER_MW_DMA_0: return("MDMA0");
- case XFER_SW_DMA_2: return("SDMA2");
- case XFER_SW_DMA_1: return("SDMA1");
- case XFER_SW_DMA_0: return("SDMA0");
- case XFER_PIO_4: return("PIO4");
- case XFER_PIO_3: return("PIO3");
- case XFER_PIO_2: return("PIO2");
- case XFER_PIO_1: return("PIO1");
- case XFER_PIO_0: return("PIO0");
- default: return("???");
- }
+ char *p = buffer;
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ p += sprintf(p, "\n Cyrix 5530 Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer;
}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+byte cs5530_proc = 0;
+
+extern char *ide_xfer_verbose (byte xfer_rate);
/*
* Set a new transfer mode at the drive
*/
int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
{
- int i, error = 1;
- byte stat;
- ide_hwif_t *hwif = HWIF(drive);
-
- printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode));
- /*
- * If this is a DMA mode setting, then turn off all DMA bits.
- * We will set one of them back on afterwards, if all goes well.
- *
- * Not sure why this is needed (it looks very silly),
- * but other IDE chipset drivers also do this fiddling. ???? -ml
- */
- switch (mode) {
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1:
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- }
+ int error = 0;
- /*
- * Select the drive, and issue the SETFEATURES command
- */
- disable_irq(hwif->irq);
- udelay(1);
- SELECT_DRIVE(HWIF(drive), drive);
- udelay(1);
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
- OUT_BYTE(mode, IDE_NSECTOR_REG);
- OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
- OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
- udelay(1); /* spec allows drive 400ns to assert "BUSY" */
+ printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+ error = ide_config_drive_speed(drive, mode);
- /*
- * Wait for drive to become non-BUSY
- */
- if ((stat = GET_STAT()) & BUSY_STAT) {
- unsigned long flags, timeout;
- __save_flags(flags); /* local CPU only */
- ide__sti(); /* local CPU only -- for jiffies */
- timeout = jiffies + WAIT_CMD;
- while ((stat = GET_STAT()) & BUSY_STAT) {
- if (0 < (signed long)(jiffies - timeout))
- break;
- }
- __restore_flags(flags); /* local CPU only */
- }
-
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
- error = 0;
- break;
- }
- }
- enable_irq(hwif->irq);
-
- /*
- * Turn dma bit on if all is okay
- */
- if (error) {
- (void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat);
- } else {
- switch (mode) {
- case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break;
- case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break;
- case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break;
- case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break;
- case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break;
- case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
- case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
- case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
- case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
- case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
- case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
- }
- }
return error;
}
@@ -302,8 +235,10 @@ int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_check:
return cs5530_config_dma(drive);
default:
- return ide_dmaproc(func, drive);
+ break;
}
+ /* Other cases are done by generic IDE-DMA code. */
+ return ide_dmaproc(func, drive);
}
/*
@@ -384,6 +319,13 @@ unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
pci_write_config_byte(master_0, 0x43, 0xc1);
restore_flags(flags);
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+ cs5530_proc = 1;
+ bmide_dev = dev;
+ cs5530_display_info = &cs5530_get_info;
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
return 0;
}
diff --git a/drivers/block/cy82c693.c b/drivers/block/cy82c693.c
index 412f403c3..cfff0381c 100644
--- a/drivers/block/cy82c693.c
+++ b/drivers/block/cy82c693.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999
+ * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999
*
* Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-99 Andre Hedrick, Integrater
@@ -54,7 +54,7 @@
#include "ide_modes.h"
/* the current version */
-#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)"
+#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
/*
* The following are used to debug the driver.
@@ -439,4 +439,3 @@ void __init ide_init_cy82c693(ide_hwif_t *hwif)
hwif->drives[1].autotune = 1;
}
}
-
diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c
index d805dec75..d8838e111 100644
--- a/drivers/block/dtc2278.c
+++ b/drivers/block/dtc2278.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996
+ * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
@@ -95,7 +95,7 @@ static void tune_dtc2278 (ide_drive_t *drive, byte pio)
HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
}
-void init_dtc2278 (void)
+void __init init_dtc2278 (void)
{
unsigned long flags;
diff --git a/drivers/block/falconide.c b/drivers/block/falconide.c
index 321569eb1..7bce07517 100644
--- a/drivers/block/falconide.c
+++ b/drivers/block/falconide.c
@@ -40,7 +40,7 @@
#define ATA_HD_STATUS 0x1d /* see status-bits */
#define ATA_HD_CONTROL 0x39
-static int falconide_offsets[IDE_NR_PORTS] = {
+static int __init falconide_offsets[IDE_NR_PORTS] = {
ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
};
@@ -50,7 +50,7 @@ static int falconide_offsets[IDE_NR_PORTS] = {
* Probe for a Falcon IDE interface
*/
-void falconide_init(void)
+void __init falconide_init(void)
{
if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
hw_regs_t hw;
diff --git a/drivers/block/gayle.c b/drivers/block/gayle.c
index 920f2ee0a..29cceb20e 100644
--- a/drivers/block/gayle.c
+++ b/drivers/block/gayle.c
@@ -41,7 +41,7 @@
#define GAYLE_STATUS 0x1e /* see status-bits */
#define GAYLE_CONTROL 0x101a
-static int gayle_offsets[IDE_NR_PORTS] = {
+static int __init gayle_offsets[IDE_NR_PORTS] = {
GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
};
@@ -105,7 +105,7 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
* Probe for a Gayle IDE interface (and optionally for an IDE doubler)
*/
-void gayle_init(void)
+void __init gayle_init(void)
{
int a4000, i;
diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c
index 10fe3ebc1..7a077368e 100644
--- a/drivers/block/hpt34x.c
+++ b/drivers/block/hpt34x.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/hpt34x.c Version 0.28 Dec. 13, 1999
+ * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000
*
- * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
*
@@ -16,6 +16,12 @@
* hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070)
* hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0)
*
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
*/
#include <linux/config.h>
@@ -27,7 +33,6 @@
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
-
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -35,16 +40,56 @@
#include <asm/io.h>
#include <asm/irq.h>
-
#include "ide_modes.h"
#ifndef SPLIT_BYTE
#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
#endif
-#define HPT343_DEBUG_DRIVE_INFO 0
-#define HPT343_DISABLE_ALL_DMAING 0
-#define HPT343_DMA_DISK_ONLY 0
+#define HPT343_DEBUG_DRIVE_INFO 1
+
+#define DISPLAY_HPT34X_TIMINGS
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ p += sprintf(p, "\n HPT34X Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte hpt34x_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
@@ -109,12 +154,8 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
struct hd_driveid *id = drive->id;
byte speed = 0x00;
-#if HPT343_DISABLE_ALL_DMAING
- return ((int) ide_dma_off);
-#elif HPT343_DMA_DISK_ONLY
if (drive->media != ide_disk)
return ((int) ide_dma_off_quietly);
-#endif /* HPT343_DISABLE_ALL_DMAING */
hpt34x_clear_chipset(drive);
@@ -249,14 +290,13 @@ try_dma_modes:
fast_ata_pio:
dma_func = ide_dma_off_quietly;
no_dma_set:
-
config_chipset_for_pio(drive);
}
-#if 0
+#ifndef CONFIG_HPT34X_AUTODMA
if (dma_func == ide_dma_on)
dma_func = ide_dma_off;
-#endif
+#endif /* CONFIG_HPT34X_AUTODMA */
return HWIF(drive)->dmaproc(dma_func, drive);
}
@@ -273,18 +313,10 @@ int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long dma_base = hwif->dma_base;
- byte unit = (drive->select.b.unit & 0x01);
unsigned int count, reading = 0;
byte dma_stat;
switch (func) {
- case ide_dma_off:
- case ide_dma_off_quietly:
- outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
- break;
- case ide_dma_on:
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- break;
case ide_dma_check:
return config_drive_xfer_rate(drive);
case ide_dma_read:
@@ -357,11 +389,16 @@ unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-
pci_write_config_word(dev, PCI_COMMAND, cmd);
__restore_flags(flags); /* local CPU only */
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+ hpt34x_proc = 1;
+ bmide_dev = dev;
+ hpt34x_display_info = &hpt34x_get_info;
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
return dev->irq;
}
@@ -372,11 +409,7 @@ void __init ide_init_hpt34x (ide_hwif_t *hwif)
unsigned short pcicmd = 0;
pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-#ifdef CONFIG_BLK_DEV_HPT34X_DMA
-#if 0
hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-#endif
-#endif /* CONFIG_BLK_DEV_HPT34X_DMA */
hwif->dmaproc = &hpt34x_dmaproc;
} else {
hwif->drives[0].autotune = 1;
diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c
index 7328ea7b8..02c9c16dd 100644
--- a/drivers/block/hpt366.c
+++ b/drivers/block/hpt366.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999
+ * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000
*
- * Copyright (C) 1999 Andre Hedrick <andre@suse.com>
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
* May be copied or modified under the terms of the GNU General Public License
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -30,6 +30,13 @@
#include "ide_modes.h"
+#define DISPLAY_HPT366_TIMINGS
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
const char *bad_ata66_4[] = {
"WDC AC310200R",
NULL
@@ -120,6 +127,48 @@ struct chipset_bus_clock_list_entry twenty_five_base [] = {
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+static int hpt366_get_info(char *, char **, off_t, int);
+extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+static struct pci_dev *bmide2_dev;
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ u32 bibma = bmide_dev->resource[4].start;
+ u32 bibma2 = bmide2_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ if (bmide2_dev)
+ c1 = inb_p((unsigned short)bibma2 + 0x02);
+
+ p += sprintf(p, "\n HPT366 Chipset.\n");
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer;/* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte hpt366_proc = 0;
+
extern char *ide_xfer_verbose (byte xfer_rate);
byte hpt363_shared_irq = 0;
byte hpt363_shared_pin = 0;
@@ -263,20 +312,20 @@ static int config_chipset_for_dma (ide_drive_t *drive)
pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, &reg51h);
-#ifdef CONFIG_HPT366_FAST_IRQ_PREDICTION
+#ifdef CONFIG_HPT366_FIP
/*
* Some drives prefer/allow for the method of handling interrupts.
*/
if (!(reg51h & 0x80))
pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80);
-#else /* ! CONFIG_HPT366_FAST_IRQ_PREDICTION */
+#else /* ! CONFIG_HPT366_FIP */
/*
* Disable the "fast interrupt" prediction.
* Instead, always wait for the real interrupt from the drive!
*/
if (reg51h & 0x80)
pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
-#endif /* CONFIG_HPT366_FAST_IRQ_PREDICTION */
+#endif /* CONFIG_HPT366_FIP */
/*
* Preserve existing PIO settings:
@@ -420,7 +469,6 @@ no_dma_set:
* This is specific to the HPT366 UDMA bios chipset
* by HighPoint|Triones Technologies, Inc.
*/
-
int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
byte reg50h = 0;
@@ -434,7 +482,6 @@ int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
/* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */
case ide_dma_timeout:
- break;
default:
break;
}
@@ -464,6 +511,17 @@ unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
if (test != 0x08)
pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!hpt366_proc) {
+ hpt366_proc = 1;
+ bmide_dev = dev;
+ hpt366_display_info = &hpt366_get_info;
+ }
+ if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) {
+ bmide2_dev = dev;
+ }
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+
return dev->irq;
}
@@ -482,18 +540,6 @@ unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
void __init ide_init_hpt366 (ide_hwif_t *hwif)
{
-#if 0
- if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) {
- hwif->mate = &ide_hwifs[hwif->index-1];
- hwif->mate->mate = hwif;
- hwif->serialized = hwif->mate->serialized = 1;
- }
-
- if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) {
-
- }
-#endif
-
hwif->tuneproc = &hpt366_tune_drive;
if (hwif->dma_base) {
hwif->dmaproc = &hpt366_dmaproc;
diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c
index d9fb885c2..6b7d5af72 100644
--- a/drivers/block/ht6560b.c
+++ b/drivers/block/ht6560b.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ht6580.c Version 0.04 Mar 19, 1996
+ * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000
*
- * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
+ * Copyright (C) 1995-2000 Linus Torvalds & author (see below)
*/
/*
@@ -12,42 +12,31 @@
*
* Version 0.03 Some cleanups
*
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use IDE_SELECT_REG to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
+ * Version 0.05 PIO mode cycle timings auto-tune using bus-speed
*
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives. [see cmd640.c for an extreme example of this. -ml]
+ * Version 0.06 Prefetch mode now defaults no OFF. To set
+ * prefetch mode OFF/ON use "hdparm -p8/-p9".
+ * Unmask irq is disabled when prefetch mode
+ * is enabled.
*
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time (rt) and the lower nibble
- * of the value is the Active Time (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Port 0x3e6 bit 0x20 sets these timings on/off. If 0x20 bit is set
- * these timings are disabled.
+ * Version 0.07 Trying to fix CD-ROM detection problem.
+ * "Prefetch" mode bit OFF for ide disks and
+ * ON for anything else.
*
- * Mikko Ala-Fossi
*
- * More notes:
+ * HT-6560B EIDE-controller support
+ * To activate controller support use kernel parameter "ide0=ht6560b".
+ * Use hdparm utility to enable PIO mode support.
*
- * There's something still missing from the initialization code, though.
- * If I have booted to dos sometime after power on, I can get smaller
- * timing values working. Perhaps I could soft-ice the initialization.
+ * Author: Mikko Ala-Fossi <maf@iki.fi>
+ * Jan Evert van Grootheest <janevert@iae.nl>
*
- * -=- malafoss@snakemail.hut.fi -=- searching the marvels of universe -=-
+ * Try: http://www.maf.iki.fi/~maf/ht6560b/
*/
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/types.h>
#include <linux/kernel.h>
@@ -63,175 +52,291 @@
#include "ide_modes.h"
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- *
- * This stuff is courtesy of malafoss@snakemail.hut.fi
- * (or maf@nemesis.tky.hut.fi)
- *
- * At least one user has reported that this code can confuse the floppy
- * controller and/or driver -- perhaps this should be changed to use
- * a read-modify-write sequence, so as not to disturb other bits in the reg?
- */
+/* #define DEBUG */ /* remove comments for DEBUG messages */
/*
- * The special i/o-port that HT-6560B uses to select interfaces:
+ * The special i/o-port that HT-6560B uses to configuration:
+ * bit0 (0x01): "1" selects secondary interface
+ * bit2 (0x04): "1" enables FIFO function
+ * bit5 (0x20): "1" enables prefetched data read function (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ * bit0 (0x01): "1" selects secondary interface
+ * bit1 (0x02): "1" enables prefetched data read function
+ * bit2 (0x04): "0" enables multi-master system (?)
+ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?)
*/
-#define HT_SELECT_PORT 0x3e6
-
+#define HT_CONFIG_PORT 0x3e6
+#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
/*
- * We don't know what all of the bits are for, but we *do* know about these:
- * bit5 (0x20): "1" selects slower speed by disabling use of timing values
- * bit0 (0x01): "1" selects second interface
+ * FIFO + PREFETCH (both a/b-model)
*/
-static byte ht6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}};
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF 0x01
+#define HT_PREFETCH_MODE 0x20
/*
- * VLB ht6560b Timing values:
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use IDE_SELECT_REG to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives. [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time (rt) and the lower nibble
+ * of the value is the Active Time (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
*
* Timing byte consists of
- * High nibble: Recovery Time (rt)
- * The valid values range from 2 to 15. The default is 15.
+ * High nibble: Recovery Cycle Time (rt)
+ * The valid values range from 2 to 15. The default is 15.
*
- * Low nibble: Active Time (at)
- * The valid values range from 2 to 15. The default is 15.
+ * Low nibble: Active Cycle Time (at)
+ * The valid values range from 2 to 15. The default is 15.
*
* You can obtain optimized timing values by running Holtek IDESETUP.COM
* for DOS. DOS drivers get their timing values from command line, where
* the first value is the Recovery Time and the second value is the
* Active Time for each drive. Smaller value gives higher speed.
* In case of failures you should probably fall back to a higher value.
- *
- * Here's an example to make it clearer:
- *
- * DOS: DEVICE=C:\bin\HTIDE\HTIDE.SYS /D0=2,4 /D1=4,5 /D2=10,10 /D3=15,15
- * Linux: byte ht6560b_timings [][] = {{0x24, 0x45}, {0xaa, 0xff}};
- *
- * Note: There are no ioctls to change these values directly,
- * but settings can be approximated as PIO modes, using "hdparm":
- *
- * rc.local: hdparm -p3 /dev/hda -p2 /dev/hdb -p1 /dev/hdc -p0 /dev/hdd
*/
+#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
-static byte ht6560b_timings [2][MAX_DRIVES] = {{0xff,0xff}, {0xff,0xff}};
-
-static byte pio_to_timings[6] = {0xff, 0xaa, 0x45, 0x24, 0x13, 0x12};
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
/*
* This routine is invoked from ide.c to prepare for access to a given drive.
*/
static void ht6560b_selectproc (ide_drive_t *drive)
{
- byte t;
unsigned long flags;
static byte current_select = 0;
static byte current_timing = 0;
- byte select = ht6560b_selects[HWIF(drive)->index][drive->select.b.unit];
- byte timing = ht6560b_timings[HWIF(drive)->index][drive->select.b.unit];
-
+ byte select, timing;
+
+ __save_flags (flags); /* local CPU only */
+ __cli(); /* local CPU only */
+
+ select = HT_CONFIG(drive);
+ timing = HT_TIMING(drive);
+
if (select != current_select || timing != current_timing) {
current_select = select;
current_timing = timing;
- __save_flags (flags); /* local CPU only */
- __cli(); /* local CPU only */
- (void) inb(HT_SELECT_PORT);
- (void) inb(HT_SELECT_PORT);
- (void) inb(HT_SELECT_PORT);
+ if (drive->media != ide_disk || !drive->present)
+ select |= HT_PREFETCH_MODE;
+ (void) inb(HT_CONFIG_PORT);
+ (void) inb(HT_CONFIG_PORT);
+ (void) inb(HT_CONFIG_PORT);
+ (void) inb(HT_CONFIG_PORT);
+ outb(select, HT_CONFIG_PORT);
/*
- * Note: input bits are reversed to output bits!!
+ * Set timing for this drive:
*/
- t = inb(HT_SELECT_PORT) ^ 0x3f;
- t &= (~0x21);
- t |= (current_select & 0x21);
- outb(t, HT_SELECT_PORT);
- /*
- * Set timing for this drive:
- */
- outb (timing, IDE_SELECT_REG);
- (void) inb (IDE_STATUS_REG);
- __restore_flags (flags); /* local CPU only */
+ outb(timing, IDE_SELECT_REG);
+ (void) inb(IDE_STATUS_REG);
#ifdef DEBUG
- printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing);
+ printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
#endif
}
+ __restore_flags (flags); /* local CPU only */
}
/*
* Autodetection and initialization of ht6560b
*/
-int try_to_init_ht6560b(void)
+static int __init try_to_init_ht6560b(void)
{
byte orig_value;
int i;
-
+
/* Autodetect ht6560b */
- if ((orig_value=inb(HT_SELECT_PORT)) == 0xff)
+ if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
return 0;
-
+
for (i=3;i>0;i--) {
- outb(0x00, HT_SELECT_PORT);
- if (!( (~inb(HT_SELECT_PORT)) & 0x3f )) {
- outb(orig_value, HT_SELECT_PORT);
- return 0;
+ outb(0x00, HT_CONFIG_PORT);
+ if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+ outb(orig_value, HT_CONFIG_PORT);
+ return 0;
}
}
- outb(0x00, HT_SELECT_PORT);
- if ((~inb(HT_SELECT_PORT))& 0x3f) {
- outb(orig_value, HT_SELECT_PORT);
+ outb(0x00, HT_CONFIG_PORT);
+ if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+ outb(orig_value, HT_CONFIG_PORT);
return 0;
}
/*
- * Ht6560b autodetected:
- * reverse input bits to output bits
- * initialize bit1 to 0
+ * Ht6560b autodetected
*/
- outb((orig_value ^ 0x3f) & 0xfd, HT_SELECT_PORT);
-
- printk("\nht6560b: detected and initialized");
+ outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+ outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */
+ (void) inb(0x1f7); /* IDE_STATUS_REG */
+
+ printk("\nht6560b " HT6560B_VERSION
+ ": chipset detected and initialized"
+#ifdef DEBUG
+ " with debug enabled"
+#endif
+ );
return 1;
}
-static void tune_ht6560b (ide_drive_t *drive, byte pio)
+static byte ht_pio2timings(ide_drive_t *drive, byte pio)
{
- unsigned int hwif, unit;
+ int bus_speed, active_time, recovery_time;
+ int active_cycles, recovery_cycles;
+ ide_pio_data_t d;
+
+ if (pio) {
+ pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+
+ /*
+ * Just like opti621.c we try to calculate the
+ * actual cycle time for recovery and activity
+ * according system bus speed.
+ */
+ bus_speed = ide_system_bus_speed();
+ active_time = ide_pio_timings[pio].active_time;
+ recovery_time = d.cycle_time
+ - active_time
+ - ide_pio_timings[pio].setup_time;
+ /*
+ * Cycle times should be Vesa bus cycles
+ */
+ active_cycles = (active_time * bus_speed + 999) / 1000;
+ recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+ /*
+ * Upper and lower limits
+ */
+ if (active_cycles < 2) active_cycles = 2;
+ if (recovery_cycles < 2) recovery_cycles = 2;
+ if (active_cycles > 15) active_cycles = 15;
+ if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+
+ return (byte)((recovery_cycles << 4) | active_cycles);
+ } else {
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+
+ return HT_TIMING_DEFAULT; /* default setting */
+ }
+}
+
+/*
+ * Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, byte state)
+{
+ unsigned long flags;
+ int t = HT_PREFETCH_MODE << 8;
+
+ save_flags (flags); /* all CPUs */
+ cli(); /* all CPUs */
+
+ /*
+ * Prefetch mode and unmask irq seems to conflict
+ */
+ if (state) {
+ drive->drive_data |= t; /* enable prefetch mode */
+ drive->no_unmask = 1;
+ drive->unmask = 0;
+ } else {
+ drive->drive_data &= ~t; /* disable prefetch mode */
+ drive->no_unmask = 0;
+ }
+
+ restore_flags (flags); /* all CPUs */
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
- if (pio == 255) { /* auto-tune */
- if (drive->media != ide_disk)
- pio = 0; /* some CDROMs don't like fast modes (?) */
- else
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+static void tune_ht6560b (ide_drive_t *drive, byte pio)
+{
+ unsigned long flags;
+ byte timing;
+
+ switch (pio) {
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ ht_set_prefetch(drive, pio & 1);
+ return;
}
- unit = drive->select.b.unit;
- hwif = HWIF(drive)->index;
- ht6560b_timings[hwif][unit] = pio_to_timings[pio];
- if (pio == 0)
- ht6560b_selects[hwif][unit] |= 0x20;
- else
- ht6560b_selects[hwif][unit] &= ~0x20;
+
+ timing = ht_pio2timings(drive, pio);
+
+ save_flags (flags); /* all CPUs */
+ cli(); /* all CPUs */
+
+ drive->drive_data &= 0xff00;
+ drive->drive_data |= timing;
+
+ restore_flags (flags); /* all CPUs */
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
}
-void init_ht6560b (void)
+void __init init_ht6560b (void)
{
- if (check_region(HT_SELECT_PORT,1)) {
- printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n");
+ int t;
+
+ if (check_region(HT_CONFIG_PORT,1)) {
+ printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
} else {
if (try_to_init_ht6560b()) {
- request_region(HT_SELECT_PORT, 1, ide_hwifs[0].name);
+ request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
ide_hwifs[0].chipset = ide_ht6560b;
ide_hwifs[1].chipset = ide_ht6560b;
ide_hwifs[0].selectproc = &ht6560b_selectproc;
ide_hwifs[1].selectproc = &ht6560b_selectproc;
ide_hwifs[0].tuneproc = &tune_ht6560b;
ide_hwifs[1].tuneproc = &tune_ht6560b;
- ide_hwifs[0].serialized = 1;
- ide_hwifs[1].serialized = 1;
+ ide_hwifs[0].serialized = 1; /* is this needed? */
+ ide_hwifs[1].serialized = 1; /* is this needed? */
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
ide_hwifs[1].channel = 1;
+
+ /*
+ * Setting default configurations for drives
+ */
+ t = (HT_CONFIG_DEFAULT << 8);
+ t |= HT_TIMING_DEFAULT;
+ ide_hwifs[0].drives[0].drive_data = t;
+ ide_hwifs[0].drives[1].drive_data = t;
+ t |= (HT_SECONDARY_IF << 8);
+ ide_hwifs[1].drives[0].drive_data = t;
+ ide_hwifs[1].drives[1].drive_data = t;
} else
- printk("\nht6560b: not found\n");
+ printk(KERN_ERR "ht6560b: not found\n");
}
}
diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h
index 8891205ed..1eb48ef6c 100644
--- a/drivers/block/ide-cd.h
+++ b/drivers/block/ide-cd.h
@@ -1,11 +1,11 @@
-#ifndef _IDE_CD_H
-#define _IDE_CD_H
/*
* linux/drivers/block/ide_cd.h
*
- * Copyright (C) 1996, 1997, 1998 Erik Andersen
- * Copyright (C) 1998, 1999 Jens Axboe
+ * Copyright (C) 1996-98 Erik Andersen
+ * Copyright (C) 1998-2000 Jens Axboe
*/
+#ifndef _IDE_CD_H
+#define _IDE_CD_H
#include <linux/cdrom.h>
#include <asm/byteorder.h>
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index e62295241..f766605bc 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999
+ * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index 3b6f5e56a..751424831 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999
+ * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999
*
* Copyright (c) 1999 Andre Hedrick
* May be copied or modified under the terms of the GNU General Public License
@@ -91,6 +91,8 @@
#include <asm/io.h>
#include <asm/irq.h>
+extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+
#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
struct drive_list_entry {
@@ -401,6 +403,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long dma_base = hwif->dma_base;
+ byte unit = (drive->select.b.unit & 0x01);
unsigned int count, reading = 0;
byte dma_stat;
@@ -408,8 +411,11 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_off:
printk("%s: DMA disabled\n", drive->name);
case ide_dma_off_quietly:
+ outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
case ide_dma_on:
drive->using_dma = (func == ide_dma_on);
+ if (drive->using_dma)
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
@@ -424,7 +430,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
drive->waiting_for_dma = 1;
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
case ide_dma_begin:
/* Note that this is done *after* the cmd has
@@ -449,12 +455,10 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
return check_drive_lists(drive, (func == ide_dma_good_drive));
case ide_dma_lostirq:
case ide_dma_timeout:
- /*
- * printk("ide_dmaproc: chipset supported func only: %d\n", func);
- */
+ printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func);
return 1;
default:
- printk("ide_dmaproc: unsupported func: %d\n", func);
+ printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
return 1;
}
}
@@ -541,14 +545,15 @@ unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const
}
}
if (dma_base) {
- if (extra) /* PDC20246, PDC20262, & HPT343 */
+ if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
request_region(dma_base+16, extra, name);
dma_base += hwif->channel ? 8 : 0;
hwif->dma_extra = extra;
switch(dev->device) {
- case PCI_DEVICE_ID_CMD_643:
case PCI_DEVICE_ID_AL_M5219:
+ case PCI_DEVICE_ID_AMD_VIPER_7409:
+ case PCI_DEVICE_ID_CMD_643:
outb(inb(dma_base+2) & 0x60, dma_base+2);
if (inb(dma_base+2) & 0x80) {
printk("%s: simplex device: DMA forced\n", name);
diff --git a/drivers/block/ide-features.c b/drivers/block/ide-features.c
index 87b7cacb4..3f29ed591 100644
--- a/drivers/block/ide-features.c
+++ b/drivers/block/ide-features.c
@@ -1,16 +1,15 @@
/*
- * linux/drivers/block/ide-features.c
+ * linux/drivers/block/ide-features.c Version 0.03 Feb. 10, 2000
*
- * Copyright (C) 1999 Linus Torvalds & authors (see below)
+ * Copyright (C) 1999-2000 Linus Torvalds & authors (see below)
*
- * Andre Hedrick <andre@suse.com>
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@suse.com>
*
* Extracts if ide.c to address the evolving transfer rate code for
- * the SETFEATURES_XFER callouts. Below are original authors of some or
- * various parts of any given function below.
+ * the SETFEATURES_XFER callouts. Various parts of any given function
+ * are credited to previous ATA-IDE maintainers.
*
- * Mark Lord <mlord@pobox.com>
- * Gadi Oxman <gadio@netvision.net.il>
+ * May be copied or modified under the terms of the GNU General Public License
*/
#define __NO_VERSION__
@@ -36,12 +35,15 @@
#include <asm/io.h>
#include <asm/bitops.h>
+#define SETFEATURES_CONTROL_REG (0) /* some arch's may need */
+
/*
- *
+ * A Verbose noise maker for debugging on the attempted transfer rates.
*/
char *ide_xfer_verbose (byte xfer_rate)
{
switch(xfer_rate) {
+ case XFER_UDMA_7: return("UDMA 7");
case XFER_UDMA_6: return("UDMA 6");
case XFER_UDMA_5: return("UDMA 5");
case XFER_UDMA_4: return("UDMA 4");
@@ -71,14 +73,42 @@ char *ide_xfer_verbose (byte xfer_rate)
char *ide_media_verbose (ide_drive_t *drive)
{
switch (drive->media) {
- case ide_disk: return("disk ");
- case ide_cdrom: return("cdrom ");
- case ide_tape: return("tape ");
- case ide_floppy: return("floppy");
- default: return("??????");
+ case ide_scsi: return("scsi ");
+ case ide_disk: return("disk ");
+ case ide_optical: return("optical");
+ case ide_cdrom: return("cdrom ");
+ case ide_tape: return("tape ");
+ case ide_floppy: return("floppy ");
+ default: return("???????");
}
}
+/*
+ * A Verbose noise maker for debugging on the attempted dmaing calls.
+ */
+char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
+{
+ switch (dmafunc) {
+ case ide_dma_read: return("ide_dma_read");
+ case ide_dma_write: return("ide_dma_write");
+ case ide_dma_begin: return("ide_dma_begin");
+ case ide_dma_end: return("ide_dma_end:");
+ case ide_dma_check: return("ide_dma_check");
+ case ide_dma_on: return("ide_dma_on");
+ case ide_dma_off: return("ide_dma_off");
+ case ide_dma_off_quietly: return("ide_dma_off_quietly");
+ case ide_dma_test_irq: return("ide_dma_test_irq");
+ case ide_dma_bad_drive: return("ide_dma_bad_drive");
+ case ide_dma_good_drive: return("ide_dma_good_drive");
+ case ide_dma_lostirq: return("ide_dma_lostirq");
+ case ide_dma_timeout: return("ide_dma_timeout");
+ default: return("unknown");
+ }
+}
+
+/*
+ * Update the
+ */
int ide_driveid_update (ide_drive_t *drive)
{
/*
@@ -129,50 +159,6 @@ int ide_driveid_update (ide_drive_t *drive)
}
/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere. Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again. :) -ml
- */
-int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
-{
- byte stat;
- int i;
- unsigned long flags;
-
- udelay(1); /* spec allows drive 400ns to assert "BUSY" */
- if ((stat = GET_STAT()) & BUSY_STAT) {
- __save_flags(flags); /* local CPU only */
- ide__sti(); /* local CPU only */
- timeout += jiffies;
- while ((stat = GET_STAT()) & BUSY_STAT) {
- if (0 < (signed long)(jiffies - timeout)) {
- __restore_flags(flags); /* local CPU only */
- (void)ide_dump_status(drive, "ide_wait_noerr", stat);
- return 1;
- }
- }
- __restore_flags(flags); /* local CPU only */
- }
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- if (OK_STAT((stat = GET_STAT()), good, bad))
- return 0;
- }
- (void)ide_dump_status(drive, "ide_wait_noerr", stat);
- return 1;
-}
-
-
-/*
* Verify that we are doing an approved SETFEATURES_XFER with respect
* to the hardware being able to support request. Since some hardware
* can improperly report capabilties, we check to see if the host adapter
@@ -213,70 +199,96 @@ int set_transfer (ide_drive_t *drive, int cmd, int nsect, int feature)
return 0;
}
-#if 0
-ide_startstop_t set_drive_speed_intr (ide_drive_t *drive)
-{
- byte stat;
-
- if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
/*
- * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT))
- * if (stat != DRIVE_READY)
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere. Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again. :) -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
*/
- (void) ide_dump_status(drive, "set_drive_speed_status", stat);
-
- return ide_stopped;
-}
-#endif
-
int ide_config_drive_speed (ide_drive_t *drive, byte speed)
{
- unsigned long flags;
- int err;
+ ide_hwif_t *hwif = HWIF(drive);
+ int i, error = 1;
+ byte unit = (drive->select.b.unit & 0x01);
byte stat;
- __save_flags(flags); /* local CPU only */
- __cli(); /* local CPU only */
-
/*
* Don't use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate,
* but for some reason these don't work at
* this point (lost interrupt).
*/
+ /*
+ * Select the drive, and issue the SETFEATURES command
+ */
+ disable_irq(hwif->irq); /* disable_irq_nosync ?? */
+ udelay(1);
SELECT_DRIVE(HWIF(drive), drive);
+ udelay(1);
if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
OUT_BYTE(speed, IDE_NSECTOR_REG);
OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-
- err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
-
-#if 0
- if (IDE_CONTROL_REG)
+ if ((IDE_CONTROL_REG) && (SETFEATURES_CONTROL_REG))
OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-#endif
+ udelay(1);
+ /*
+ * Wait for drive to become non-BUSY
+ */
+ if ((stat = GET_STAT()) & BUSY_STAT) {
+ unsigned long flags, timeout;
+ __save_flags(flags); /* local CPU only */
+ ide__sti(); /* local CPU only -- for jiffies */
+ timeout = jiffies + WAIT_CMD;
+ while ((stat = GET_STAT()) & BUSY_STAT) {
+ if (0 < (signed long)(jiffies - timeout))
+ break;
+ }
+ __restore_flags(flags); /* local CPU only */
+ }
- __restore_flags(flags); /* local CPU only */
+ /*
+ * Allow status to settle, then read it again.
+ * A few rare drives vastly violate the 400ns spec here,
+ * so we'll wait up to 10usec for a "good" status
+ * rather than expensively fail things immediately.
+ * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+ */
+ for (i = 0; i < 10; i++) {
+ udelay(1);
+ if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+ error = 0;
+ break;
+ }
+ }
-#if 0
- ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL);
-#endif
+ enable_irq(hwif->irq);
- stat = GET_STAT();
- if (stat != DRIVE_READY)
+ if (error) {
(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+ return error;
+ }
drive->id->dma_ultra &= ~0xFF00;
drive->id->dma_mword &= ~0x0F00;
drive->id->dma_1word &= ~0x0F00;
+ if (speed > XFER_PIO_4) {
+ outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
+ } else {
+ outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
+ }
+
switch(speed) {
-#if 0
- case XFER_UDMA_6: drive->id->dma_ultra |= 0x1010; break;
- case XFER_UDMA_5: drive->id->dma_ultra |= 0x1010; break;
-#endif
+ case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break;
+ case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break;
+ case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break;
case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break;
case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break;
case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break;
@@ -290,11 +302,10 @@ int ide_config_drive_speed (ide_drive_t *drive, byte speed)
case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
default: break;
}
- return(err);
+ return error;
}
EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_wait_noerr);
EXPORT_SYMBOL(ide_ata66_check);
EXPORT_SYMBOL(set_transfer);
EXPORT_SYMBOL(ide_config_drive_speed);
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index e2977c754..bee6a4c6c 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999
+ * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999
*
* Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -1264,8 +1264,11 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
blocks = descriptor->blocks = ntohl (descriptor->blocks);
length = descriptor->length = ntohs (descriptor->length);
if (!i && descriptor->dc == CAPACITY_CURRENT) {
- if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
- printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
+ if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) {
+ printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size, %s \n",
+ drive->name, blocks * length / 1024, blocks, length,
+ drive->using_dma ? ", DMA":"");
+ }
floppy->capacity = *descriptor;
if (!length || length % 512)
printk (KERN_ERR "%s: %d bytes block size not supported\n", drive->name, length);
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
index a5593dffb..2ddbbc8bd 100644
--- a/drivers/block/ide-pci.c
+++ b/drivers/block/ide-pci.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999
+ * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999
*
* Copyright (c) 1998-1999 Andre Hedrick
*
@@ -31,6 +31,7 @@
#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB})
#define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1})
#define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1})
+#define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1})
#define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561})
#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
@@ -95,13 +96,19 @@ extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
#endif
#ifdef CONFIG_BLK_DEV_AMD7409
+extern unsigned int pci_init_amd7409(struct pci_dev *, const char *);
extern unsigned int ata66_amd7409(ide_hwif_t *);
extern void ide_init_amd7409(ide_hwif_t *);
+extern void ide_dmacapable_amd7409(ide_hwif_t *, unsigned long);
+#define PCI_AMD7409 &pci_init_amd7409
#define ATA66_AMD7409 &ata66_amd7409
#define INIT_AMD7409 &ide_init_amd7409
+#define DMA_AMD7409 &ide_dmacapable_amd7409
#else
+#define PCI_AMD7409 NULL
#define ATA66_AMD7409 NULL
#define INIT_AMD7409 NULL
+#define DMA_AMD7409 NULL
#endif
#ifdef CONFIG_BLK_DEV_CMD64X
@@ -135,11 +142,11 @@ extern void ide_init_cy82c693(ide_hwif_t *);
#ifdef CONFIG_BLK_DEV_CS5530
extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
extern void ide_init_cs5530(ide_hwif_t *);
-#define INIT_CS5530 &ide_init_cs5530
#define PCI_CS5530 &pci_init_cs5530
+#define INIT_CS5530 &ide_init_cs5530
#else
-#define INIT_CS5530 NULL
#define PCI_CS5530 NULL
+#define INIT_CS5530 NULL
#endif
#ifdef CONFIG_BLK_DEV_HPT34X
@@ -149,7 +156,7 @@ extern void ide_init_hpt34x(ide_hwif_t *);
#define INIT_HPT34X &ide_init_hpt34x
#else
#define PCI_HPT34X NULL
-#define INIT_HPT34X NULL
+#define INIT_HPT34X IDE_IGNORE
#endif
#ifdef CONFIG_BLK_DEV_HPT366
@@ -289,6 +296,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
+ {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 },
{DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 },
@@ -318,7 +326,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
{DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
- {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
+ {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 },
{IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }};
/*
@@ -329,27 +337,6 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
{
switch(dev->device) {
- case PCI_DEVICE_ID_TTI_HPT343:
- {
- int i;
- unsigned long hpt34xIoBase = dev->resource[4].start;
- unsigned short pcicmd = 0;
-
- pci_write_config_byte(dev, 0x80, 0x00);
- pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
- if (!(pcicmd & PCI_COMMAND_MEMORY)) {
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
- } else {
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
- }
-
- dev->resource[0].start = (hpt34xIoBase + 0x20);
- dev->resource[1].start = (hpt34xIoBase + 0x34);
- dev->resource[2].start = (hpt34xIoBase + 0x28);
- dev->resource[3].start = (hpt34xIoBase + 0x3c);
- for(i=0; i<4; i++)
- dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
- }
case PCI_DEVICE_ID_TTI_HPT366:
case PCI_DEVICE_ID_PROMISE_20246:
case PCI_DEVICE_ID_PROMISE_20262:
@@ -535,17 +522,8 @@ check_if_enabled:
#endif
}
if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
- /*
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values
- * reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
- if (pcicmd & PCI_COMMAND_MEMORY) {
- printk("%s: is IDE Express HPT363.\n", d->name);
- d->bootable = OFF_BOARD;
- }
+ /* see comments in hpt34x.c on why..... */
+ d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
}
/*
* Set up the IDE ports
@@ -618,9 +596,7 @@ check_if_enabled:
if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-#ifdef CONFIG_BLK_DEV_HPT34X
IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-#endif /* CONFIG_BLK_DEV_HPT34X */
IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index b57fa28da..24eef80b7 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999
+ * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -57,7 +57,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
ide__sti(); /* local CPU only */
ide_fix_driveid(id);
if (!drive->forced_lun)
- drive->last_lun = id->word126 & 0x7;
+ drive->last_lun = id->last_lun & 0x7;
#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
/*
* EATA SCSI controllers do a hardware ATA emulation:
@@ -395,6 +395,56 @@ static inline byte probe_for_drive (ide_drive_t *drive)
}
/*
+ * Calculate the region that this interface occupies,
+ * handling interfaces where the registers may not be
+ * ordered sanely. We deal with the CONTROL register
+ * separately.
+ */
+static int hwif_check_regions (ide_hwif_t *hwif)
+{
+ int region_errors = 0;
+
+ region_errors = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+ region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+ if (hwif->io_ports[IDE_IRQ_OFFSET])
+ region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+
+ return(region_errors);
+}
+
+static void hwif_register (ide_hwif_t *hwif)
+{
+ if (hwif->io_ports[IDE_DATA_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_ERROR_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_SECTOR_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_LCYL_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_HCYL_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_SELECT_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_STATUS_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+ if (hwif->io_ports[IDE_IRQ_OFFSET])
+ ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+}
+
+/*
* This routine only knows how to look for drive units 0 and 1
* on an interface, so any setting of MAX_DRIVES > 2 won't work here.
*/
@@ -403,12 +453,6 @@ static void probe_hwif (ide_hwif_t *hwif)
unsigned int unit;
unsigned long flags;
- ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET];
- ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET];
- ide_ioreg_t region_high = region_low;
- unsigned int region_request = 8;
- int i;
-
if (hwif->noprobe)
return;
if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
@@ -417,30 +461,11 @@ static void probe_hwif (ide_hwif_t *hwif)
probe_cmos_for_drives (hwif);
}
- /*
- * Calculate the region that this interface occupies,
- * handling interfaces where the registers may not be
- * ordered sanely. We deal with the CONTROL register
- * separately.
- */
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- if (hwif->io_ports[i]) {
- if (hwif->io_ports[i] < region_low)
- region_low = hwif->io_ports[i];
- if (hwif->io_ports[i] > region_high)
- region_high = hwif->io_ports[i];
- }
- }
- region_request = (region_high - region_low);
- if (region_request == 0x0007)
- region_request++;
if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
#if CONFIG_BLK_DEV_PDC4030
(hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
#endif /* CONFIG_BLK_DEV_PDC4030 */
- (ide_check_region(region_low, region_request) ||
- (ide_control_reg && ide_check_region(ide_control_reg,1))))
- {
+ (hwif_check_regions(hwif))) {
int msgout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
@@ -467,20 +492,18 @@ static void probe_hwif (ide_hwif_t *hwif)
if (drive->present && !hwif->present) {
hwif->present = 1;
if (hwif->chipset != ide_4drives || !hwif->mate->present) {
- ide_request_region(region_low, region_request, hwif->name);
- if (ide_control_reg)
- ide_request_region(ide_control_reg, 1, hwif->name);
+ hwif_register(hwif);
}
}
}
- if (ide_control_reg && hwif->reset) {
+ if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
unsigned long timeout = jiffies + WAIT_WORSTCASE;
byte stat;
printk("%s: reset\n", hwif->name);
- OUT_BYTE(12, ide_control_reg);
+ OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
udelay(10);
- OUT_BYTE(8, ide_control_reg);
+ OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
do {
ide_delay_50ms();
stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
@@ -594,7 +617,11 @@ static int init_irq (ide_hwif_t *hwif)
* Allocate the irq, if not already obtained for another hwif
*/
if (!match || match->irq != hwif->irq) {
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+ int sa = (hwif->chipset == ide_pci) ? SA_SHIRQ : SA_INTERRUPT;
+#else /* !CONFIG_IDEPCI_SHARE_IRQ */
int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
if (!match)
kfree(hwgroup);
@@ -784,20 +811,18 @@ static int hwif_init (ide_hwif_t *hwif)
return (hwif->present = 0);
}
- if (init_irq (hwif)) {
+ if (init_irq(hwif)) {
int i = hwif->irq;
/*
* It failed to initialise. Find the default IRQ for
* this port and try that.
*/
- if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
- {
+ if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
(void) unregister_blkdev (hwif->major, hwif->name);
return (hwif->present = 0);
}
- if(init_irq (hwif))
- {
+ if (init_irq(hwif)) {
printk("%s: probed IRQ %d and default IRQ %d failed.\n",
hwif->name, i, hwif->irq);
(void) unregister_blkdev (hwif->major, hwif->name);
@@ -863,7 +888,8 @@ int ideprobe_init (void)
for (index = 0; index < MAX_HWIFS; ++index)
if (probe[index])
hwif_init(&ide_hwifs[index]);
- ide_register_module(&ideprobe_module);
+ if (!ide_probe)
+ ide_probe = &ideprobe_module;
MOD_DEC_USE_COUNT;
return 0;
}
@@ -882,6 +908,6 @@ int init_module (void)
void cleanup_module (void)
{
- ide_unregister_module(&ideprobe_module);
+ ide_probe = NULL;
}
#endif /* MODULE */
diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c
index 66e45001c..90977c959 100644
--- a/drivers/block/ide-proc.c
+++ b/drivers/block/ide-proc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998
+ * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998
*
* Copyright (C) 1997-1998 Mark Lord
*/
@@ -73,21 +73,46 @@
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
+#ifdef CONFIG_BLK_DEV_AEC6210
+extern byte aec6210_proc;
+int (*aec6210_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_AEC6210 */
#ifdef CONFIG_BLK_DEV_ALI15X3
extern byte ali_proc;
int (*ali_display_info)(char *, char **, off_t, int) = NULL;
#endif /* CONFIG_BLK_DEV_ALI15X3 */
-
+#ifdef CONFIG_BLK_DEV_AMD7409
+extern byte amd7409_proc;
+int (*amd7409_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_AMD7409 */
+#ifdef CONFIG_BLK_DEV_CMD64X
+extern byte cmd64x_proc;
+int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+extern byte cs5530_proc;
+int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+extern byte hpt34x_proc;
+int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+extern byte hpt366_proc;
+int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+extern byte pdc202xx_proc;
+int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
+#endif /* CONFIG_BLK_DEV_PDC202XX */
#ifdef CONFIG_BLK_DEV_PIIX
extern byte piix_proc;
int (*piix_display_info)(char *, char **, off_t, int) = NULL;
#endif /* CONFIG_BLK_DEV_PIIX */
-
#ifdef CONFIG_BLK_DEV_SIS5513
extern byte sis_proc;
int (*sis_display_info)(char *, char **, off_t, int) = NULL;
#endif /* CONFIG_BLK_DEV_SIS5513 */
-
#ifdef CONFIG_BLK_DEV_VIA82CXXX
extern byte via_proc;
int (*via_display_info)(char *, char **, off_t, int) = NULL;
@@ -229,7 +254,7 @@ static int proc_ide_write_config
#endif /* CONFIG_BLK_DEV_IDEPCI */
if (for_real) {
#if 0
- printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
+ printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
#endif
if (is_pci) {
#ifdef CONFIG_BLK_DEV_IDEPCI
@@ -349,7 +374,7 @@ static int proc_ide_read_drivers
while (p) {
driver = (ide_driver_t *) p->info;
- if (p->type == IDE_DRIVER_MODULE && driver)
+ if (driver)
out += sprintf(out, "%s version %s\n", driver->name, driver->version);
p = p->next;
}
@@ -775,10 +800,38 @@ void proc_ide_create(void)
create_proc_read_entry("drivers",0,proc_ide_root,
proc_ide_read_drivers, NULL);
+#ifdef CONFIG_BLK_DEV_AEC6210
+ if ((aec6210_display_info) && (aec6210_proc))
+ create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info);
+#endif /* CONFIG_BLK_DEV_AEC6210 */
#ifdef CONFIG_BLK_DEV_ALI15X3
if ((ali_display_info) && (ali_proc))
create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD7409
+ if ((amd7409_display_info) && (amd7409_proc))
+ create_proc_info_entry("amd7409", 0, proc_ide_root, amd7409_display_info);
+#endif /* CONFIG_BLK_DEV_AMD7409 */
+#ifdef CONFIG_BLK_DEV_CMD64X
+ if ((cmd64x_display_info) && (cmd64x_proc))
+ create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+ if ((cs5530_display_info) && (cs5530_proc))
+ create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+ if ((hpt34x_display_info) && (hpt34x_proc))
+ create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info);
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+ if ((hpt366_display_info) && (hpt366_proc))
+ create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info);
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+ if ((pdc202xx_display_info) && (pdc202xx_proc))
+ create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
+#endif /* CONFIG_BLK_DEV_PDC202XX */
#ifdef CONFIG_BLK_DEV_PIIX
if ((piix_display_info) && (piix_proc))
create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
@@ -799,10 +852,38 @@ void proc_ide_destroy(void)
* Mmmm.. does this free up all resources,
* or do we need to do a more proper cleanup here ??
*/
+#ifdef CONFIG_BLK_DEV_AEC6210
+ if ((aec6210_display_info) && (aec6210_proc))
+ remove_proc_entry("ide/aec6210",0);
+#endif /* CONFIG_BLK_DEV_AEC6210 */
#ifdef CONFIG_BLK_DEV_ALI15X3
if ((ali_display_info) && (ali_proc))
remove_proc_entry("ide/ali",0);
#endif /* CONFIG_BLK_DEV_ALI15X3 */
+#ifdef CONFIG_BLK_DEV_AMD7409
+ if ((amd7409_display_info) && (amd7409_proc))
+ remove_proc_entry("ide/amd7409",0);
+#endif /* CONFIG_BLK_DEV_AMD7409 */
+#ifdef CONFIG_BLK_DEV_CMD64X
+ if ((cmd64x_display_info) && (cmd64x_proc))
+ remove_proc_entry("ide/cmd64x",0);
+#endif /* CONFIG_BLK_DEV_CMD64X */
+#ifdef CONFIG_BLK_DEV_CS5530
+ if ((cs5530_display_info) && (cs5530_proc))
+ remove_proc_entry("ide/cs5530",0);
+#endif /* CONFIG_BLK_DEV_CS5530 */
+#ifdef CONFIG_BLK_DEV_HPT34X
+ if ((hpt34x_display_info) && (hpt34x_proc))
+ remove_proc_entry("ide/hpt34x",0);
+#endif /* CONFIG_BLK_DEV_HPT34X */
+#ifdef CONFIG_BLK_DEV_HPT366
+ if ((hpt366_display_info) && (hpt366_proc))
+ remove_proc_entry("ide/hpt366",0);
+#endif /* CONFIG_BLK_DEV_HPT366 */
+#ifdef CONFIG_BLK_DEV_PDC202XX
+ if ((pdc202xx_display_info) && (pdc202xx_proc))
+ remove_proc_entry("ide/pdc202xx",0);
+#endif /* CONFIG_BLK_DEV_PDC202XX */
#ifdef CONFIG_BLK_DEV_PIIX
if ((piix_display_info) && (piix_proc))
remove_proc_entry("ide/piix",0);
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index 1e1b6e44e..95e780abf 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999
+ * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999
*
* Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
*
@@ -411,12 +411,12 @@
#include <asm/bitops.h>
-#define NO_LONGER_REQUIRE (1)
+#define NO_LONGER_REQUIRED (1)
/*
* OnStream support
*/
-#define ONSTREAM_DEBUG (1)
+#define ONSTREAM_DEBUG (0)
#define OS_CONFIG_PARTITION (0xff)
#define OS_DATA_PARTITION (0)
#define OS_PARTITION_VERSION (1)
@@ -543,6 +543,7 @@ typedef struct os_header_s {
/*
* The following are used to debug the driver:
*
+ * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities.
* Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
* Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
* some places.
@@ -557,7 +558,9 @@ typedef struct os_header_s {
* is verified to be stable enough. This will make it much more
* esthetic.
*/
+#define IDETAPE_DEBUG_INFO 0
#define IDETAPE_DEBUG_LOG 1
+#define IDETAPE_DEBUG_LOG_VERBOSE 0
#define IDETAPE_DEBUG_BUGS 1
/*
@@ -700,9 +703,10 @@ typedef struct idetape_packet_command_s {
*/
typedef struct {
unsigned page_code :6; /* Page code - Should be 0x2a */
- unsigned reserved1_67 :2;
- u8 page_length; /* Page Length - Should be 0x12 */
- u8 reserved2, reserved3;
+ __u8 reserved0_6 :1;
+ __u8 ps :1; /* parameters saveable */
+ __u8 page_length; /* Page Length - Should be 0x12 */
+ __u8 reserved2, reserved3;
unsigned ro :1; /* Read Only Mode */
unsigned reserved4_1234 :4;
unsigned sprev :1; /* Supports SPACE in the reverse direction */
@@ -716,7 +720,8 @@ typedef struct {
unsigned locked :1; /* The volume is locked */
unsigned prevent :1; /* The device defaults in the prevent state after power up */
unsigned eject :1; /* The device can eject the volume */
- unsigned reserved6_45 :2; /* Reserved */
+ __u8 disconnect :1; /* The device can break request > ctl */
+ __u8 reserved6_5 :1;
unsigned ecc :1; /* Supports error correction */
unsigned cmprs :1; /* Supports data compression */
unsigned reserved7_0 :1;
@@ -726,12 +731,12 @@ typedef struct {
unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
/* transfers for slow buffer memory ??? */
/* Also 32768 block size in some cases */
- u16 max_speed; /* Maximum speed supported in KBps */
- u8 reserved10, reserved11;
- u16 ctl; /* Continuous Transfer Limit in blocks */
- u16 speed; /* Current Speed, in KBps */
- u16 buffer_size; /* Buffer Size, in 512 bytes */
- u8 reserved18, reserved19;
+ __u16 max_speed; /* Maximum speed supported in KBps */
+ __u8 reserved10, reserved11;
+ __u16 ctl; /* Continuous Transfer Limit in blocks */
+ __u16 speed; /* Current Speed, in KBps */
+ __u16 buffer_size; /* Buffer Size, in 512 bytes */
+ __u8 reserved18, reserved19;
} idetape_capabilities_page_t;
/*
@@ -741,8 +746,8 @@ typedef struct {
unsigned page_code :6; /* Page code - Should be 0x30 */
unsigned reserved1_6 :1;
unsigned ps :1;
- u8 page_length; /* Page Length - Should be 2 */
- u8 reserved2;
+ __u8 page_length; /* Page Length - Should be 2 */
+ __u8 reserved2;
unsigned play32 :1;
unsigned play32_5 :1;
unsigned reserved2_23 :2;
@@ -768,23 +773,23 @@ typedef struct idetape_stage_s {
typedef struct {
unsigned error_code :7; /* Current of deferred errors */
unsigned valid :1; /* The information field conforms to QIC-157C */
- u8 reserved1 :8; /* Segment Number - Reserved */
+ __u8 reserved1 :8; /* Segment Number - Reserved */
unsigned sense_key :4; /* Sense Key */
unsigned reserved2_4 :1; /* Reserved */
unsigned ili :1; /* Incorrect Length Indicator */
unsigned eom :1; /* End Of Medium */
unsigned filemark :1; /* Filemark */
- u32 information __attribute__ ((packed));
- u8 asl; /* Additional sense length (n-7) */
- u32 command_specific; /* Additional command specific information */
- u8 asc; /* Additional Sense Code */
- u8 ascq; /* Additional Sense Code Qualifier */
- u8 replaceable_unit_code; /* Field Replaceable Unit Code */
+ __u32 information __attribute__ ((packed));
+ __u8 asl; /* Additional sense length (n-7) */
+ __u32 command_specific; /* Additional command specific information */
+ __u8 asc; /* Additional Sense Code */
+ __u8 ascq; /* Additional Sense Code Qualifier */
+ __u8 replaceable_unit_code; /* Field Replaceable Unit Code */
unsigned sk_specific1 :7; /* Sense Key Specific */
unsigned sksv :1; /* Sense Key Specific information is valid */
- u8 sk_specific2; /* Sense Key Specific */
- u8 sk_specific3; /* Sense Key Specific */
- u8 pad[2]; /* Padding to 20 bytes */
+ __u8 sk_specific2; /* Sense Key Specific */
+ __u8 sk_specific3; /* Sense Key Specific */
+ __u8 pad[2]; /* Padding to 20 bytes */
} idetape_request_sense_result_t;
@@ -1247,13 +1252,13 @@ typedef struct {
unsigned reserved3_45 :2; /* Reserved */
unsigned reserved3_6 :1; /* TrmIOP - Reserved */
unsigned reserved3_7 :1; /* AENC - Reserved */
- u8 additional_length; /* Additional Length (total_length-4) */
- u8 rsv5, rsv6, rsv7; /* Reserved */
- u8 vendor_id[8]; /* Vendor Identification */
- u8 product_id[16]; /* Product Identification */
- u8 revision_level[4]; /* Revision Level */
- u8 vendor_specific[20]; /* Vendor Specific - Optional */
- u8 reserved56t95[40]; /* Reserved - Optional */
+ __u8 additional_length; /* Additional Length (total_length-4) */
+ __u8 rsv5, rsv6, rsv7; /* Reserved */
+ __u8 vendor_id[8]; /* Vendor Identification */
+ __u8 product_id[16]; /* Product Identification */
+ __u8 revision_level[4]; /* Revision Level */
+ __u8 vendor_specific[20]; /* Vendor Specific - Optional */
+ __u8 reserved56t95[40]; /* Reserved - Optional */
/* Additional information may be returned */
} idetape_inquiry_result_t;
@@ -1287,10 +1292,25 @@ typedef struct {
* Mode Parameter Header for the MODE SENSE packet command
*/
typedef struct {
- u8 mode_data_length; /* Length of the following data transfer */
- u8 medium_type; /* Medium Type */
- u8 dsp; /* Device Specific Parameter */
- u8 bdl; /* Block Descriptor Length */
+ __u8 mode_data_length; /* Length of the following data transfer */
+ __u8 medium_type; /* Medium Type */
+ __u8 dsp; /* Device Specific Parameter */
+ __u8 bdl; /* Block Descriptor Length */
+#if 0
+ /* data transfer page */
+ __u8 page_code :6;
+ __u8 reserved0_6 :1;
+ __u8 ps :1; /* parameters saveable */
+ __u8 page_length; /* page Length == 0x02 */
+ __u8 reserved2;
+ __u8 read32k :1; /* 32k blk size (data only) */
+ __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */
+ __u8 reserved3_23 :2;
+ __u8 write32k :1; /* 32k blk size (data only) */
+ __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */
+ __u8 reserved3_6 :1;
+ __u8 streaming :1; /* streaming mode enable */
+#endif
} idetape_mode_parameter_header_t;
/*
@@ -1299,10 +1319,10 @@ typedef struct {
* Support for block descriptors is optional.
*/
typedef struct {
- u8 density_code; /* Medium density code */
- u8 blocks[3]; /* Number of blocks */
- u8 reserved4; /* Reserved */
- u8 length[3]; /* Block Length */
+ __u8 density_code; /* Medium density code */
+ __u8 blocks[3]; /* Number of blocks */
+ __u8 reserved4; /* Reserved */
+ __u8 length[3]; /* Block Length */
} idetape_parameter_block_descriptor_t;
/*
@@ -1312,16 +1332,16 @@ typedef struct {
unsigned page_code :6; /* Page Code - Should be 0xf */
unsigned reserved0 :1; /* Reserved */
unsigned ps :1;
- u8 page_length; /* Page Length - Should be 14 */
+ __u8 page_length; /* Page Length - Should be 14 */
unsigned reserved2 :6; /* Reserved */
unsigned dcc :1; /* Data Compression Capable */
unsigned dce :1; /* Data Compression Enable */
unsigned reserved3 :5; /* Reserved */
unsigned red :2; /* Report Exception on Decompression */
unsigned dde :1; /* Data Decompression Enable */
- u32 ca; /* Compression Algorithm */
- u32 da; /* Decompression Algorithm */
- u8 reserved[4]; /* Reserved */
+ __u32 ca; /* Compression Algorithm */
+ __u32 da; /* Decompression Algorithm */
+ __u8 reserved[4]; /* Reserved */
} idetape_data_compression_page_t;
/*
@@ -1331,16 +1351,16 @@ typedef struct {
unsigned page_code :6; /* Page Code - Should be 0x11 */
unsigned reserved1_6 :1; /* Reserved */
unsigned ps :1;
- u8 page_length; /* Page Length - Should be 6 */
- u8 map; /* Maximum Additional Partitions - Should be 0 */
- u8 apd; /* Additional Partitions Defined - Should be 0 */
+ __u8 page_length; /* Page Length - Should be 6 */
+ __u8 map; /* Maximum Additional Partitions - Should be 0 */
+ __u8 apd; /* Additional Partitions Defined - Should be 0 */
unsigned reserved4_012 :3; /* Reserved */
unsigned psum :2; /* Should be 0 */
unsigned idp :1; /* Should be 0 */
unsigned sdp :1; /* Should be 0 */
unsigned fdp :1; /* Fixed Data Partitions */
- u8 mfr; /* Medium Format Recognition */
- u8 reserved[2]; /* Reserved */
+ __u8 mfr; /* Medium Format Recognition */
+ __u8 reserved[2]; /* Reserved */
} idetape_medium_partition_page_t;
/*
@@ -1359,6 +1379,53 @@ typedef struct {
static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES];
static int idetape_chrdev_present = 0;
+#if IDETAPE_DEBUG_LOG_VERBOSE
+
+/*
+ * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
+ */
+
+char *idetape_sense_key_verbose (byte idetape_sense_key)
+{
+ switch (idetape_sense_key) {
+ default: {
+ char buf[22];
+ sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
+ return(buf);
+ }
+
+ }
+}
+
+char *idetape_command_key_verbose (byte idetape_command_key)
+{
+ switch (idetape_command_key) {
+ case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD");
+ case IDETAPE_REWIND_CMD: return("REWIND_CMD");
+ case IDETAPE_REQUEST_SENSE_CMD: return("REQUEST_SENSE_CMD");
+ case IDETAPE_READ_CMD: return("READ_CMD");
+ case IDETAPE_WRITE_CMD: return("WRITE_CMD");
+ case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD");
+ case IDETAPE_SPACE_CMD: return("SPACE_CMD");
+ case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD");
+ case IDETAPE_ERASE_CMD: return("ERASE_CMD")
+ case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD");
+ case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD");
+ case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD");
+ case IDETAPE_PREVENT_CMD: return("PREVENT_CMD");
+ case IDETAPE_LOCATE_CMD: return("LOCATE_CMD");
+ case IDETAPE_READ_POSITION_CMD: return("READ_POSITION_CMD");
+ case IDETAPE_READ_BUFFER_CMD: return("READ_BUFFER_CMD");
+ case IDETAPE_SET_SPEED_CMD: return("SET_SPEED_CMD");
+ default: {
+ char buf[20];
+ sprintf(buf, "CMD (0x%02x)", idetape_command_key);
+ return(buf);
+ }
+ }
+}
+#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
+
/*
* Too bad. The drive wants to send us data which we are not ready to accept.
* Just throw it away.
@@ -1523,6 +1590,14 @@ static void idetape_analyze_error (ide_drive_t *drive,idetape_request_sense_resu
*/
if (tape->debug_level >= 1)
printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq);
+#if IDETAPE_DEBUG_LOG_VERBOSE
+ if (tape->debug_level >= 1)
+ printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
+ idetape_command_key_verbose((byte) pc->c[0]),
+ result->sense_key,
+ result->asc,
+ result->ascq);
+#endif /* IDETAPE_DEBUG_LOG_VERBOSE */
#endif /* IDETAPE_DEBUG_LOG */
if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
@@ -3833,7 +3908,7 @@ static int idetape_get_logical_blk (ide_drive_t *drive, int logical_blk_num, int
if (tape->onstream) {
#if ONSTREAM_DEBUG
if (tape->debug_level >= 1)
- printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
+ printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ld\n", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags));
#endif
clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
position = idetape_read_position(drive);
@@ -5280,16 +5355,16 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
{
struct idetape_id_gcw gcw;
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_INFO
unsigned short mask,i;
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_INFO */
if (!id)
return 0;
*((unsigned short *) &gcw) = id->config;
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_INFO
printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
printk (KERN_INFO "ide-tape: Protocol Type: ");
switch (gcw.protocol) {
@@ -5377,7 +5452,7 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
} else
printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_INFO */
/* Check that we can support this device */
@@ -5462,12 +5537,12 @@ static void idetape_onstream_configure_block_size (ide_drive_t *drive)
header = (idetape_mode_parameter_header_t *) pc.buffer;
bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_INFO
printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No");
printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No");
printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No");
printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No");
-#endif
+#endif /* IDETAPE_DEBUG_INFO */
/*
* Configure default auto columns mode, 32.5KB block size
@@ -5587,7 +5662,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
else if (tape->onstream && capabilities->blk32768)
tape->tape_block_size = 32768;
-#if IDETAPE_DEBUG_LOG
+#if IDETAPE_DEBUG_INFO
printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
@@ -5615,7 +5690,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive)
printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);
printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
-#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_INFO */
}
static void idetape_add_settings (ide_drive_t *drive)
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 93da9bea2..b82092452 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -186,6 +186,7 @@ static int ide_lock = 0;
* ide_modules keeps track of the available IDE chipset/probe/driver modules.
*/
ide_module_t *ide_modules = NULL;
+ide_module_t *ide_probe = NULL;
/*
* This is declared extern in ide.h, for access by other IDE modules:
@@ -281,7 +282,7 @@ static void init_hwif_data (unsigned int index)
* for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
*/
#define MAGIC_COOKIE 0x12345678
-static void init_ide_data (void)
+static void __init init_ide_data (void)
{
unsigned int index;
static unsigned long magic_cookie = MAGIC_COOKIE;
@@ -1093,13 +1094,18 @@ static ide_startstop_t start_request (ide_drive_t *drive)
#endif
block = rq->sector;
blockend = block + rq->nr_sectors;
- if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
- printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
- (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
- goto kill_rq;
+#if 0
+ if ((rq->cmd == READ || rq->cmd == WRITE) &&
+ (drive->media == ide_disk || drive->media == ide_floppy))
+#endif
+ {
+ if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
+ printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+ (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
+ goto kill_rq;
+ }
+ block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
}
- block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-
/* Yecch - this will shift the entire interval,
possibly killing some innocent following sector */
if (block == 0 && drive->remap_0_to_1 == 1)
@@ -1409,9 +1415,9 @@ void ide_timer_expiry (unsigned long data)
}
} else {
ide_drive_t *drive = hwgroup->drive;
- hwgroup->handler = NULL;
if (!drive) {
printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+ hwgroup->handler = NULL;
} else {
ide_hwif_t *hwif;
ide_startstop_t startstop;
@@ -1429,6 +1435,7 @@ void ide_timer_expiry (unsigned long data)
return;
}
}
+ hwgroup->handler = NULL;
/*
* We need to simulate a real interrupt when invoking
* the handler() function, which means we need to globally
@@ -1436,7 +1443,7 @@ void ide_timer_expiry (unsigned long data)
*/
spin_unlock(&io_request_lock);
hwif = HWIF(drive);
- disable_irq(hwif->irq);
+ disable_irq(hwif->irq); /* disable_irq_nosync ?? */
__cli(); /* local CPU only, as if we were handling an interrupt */
if (hwgroup->poll_timeout != 0) {
startstop = handler(drive);
@@ -1802,23 +1809,33 @@ static void revalidate_drives (void)
}
}
-static void ide_init_module (int type)
+static void ide_probe_module (void)
+{
+ if (!ide_probe) {
+#ifdef CONFIG_KMOD
+ (void) request_module("ide-probe-mod");
+#endif /* CONFIG_KMOD */
+ } else {
+ (void) ide_probe->init();
+ }
+ revalidate_drives();
+}
+
+static void ide_driver_module (void)
{
- int found = 0;
+ int index;
ide_module_t *module = ide_modules;
-
+
+ for (index = 0; index < MAX_HWIFS; ++index)
+ if (ide_hwifs[index].present)
+ goto search;
+ ide_probe_module();
+search:
while (module) {
- if (module->type == type) {
- found = 1;
- (void) module->init();
- }
+ (void) module->init();
module = module->next;
}
revalidate_drives();
-#ifdef CONFIG_KMOD
- if (!found && type == IDE_PROBE_MODULE)
- (void) request_module("ide-probe-mod");
-#endif /* CONFIG_KMOD */
}
static int ide_open (struct inode * inode, struct file * filp)
@@ -1830,7 +1847,7 @@ static int ide_open (struct inode * inode, struct file * filp)
return -ENXIO;
MOD_INC_USE_COUNT;
if (drive->driver == NULL)
- ide_init_module(IDE_DRIVER_MODULE);
+ ide_driver_module();
#ifdef CONFIG_KMOD
if (drive->driver == NULL) {
if (drive->media == ide_disk)
@@ -1881,9 +1898,9 @@ int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
goto abort;
strncpy(drive->driver_req, driver, 9);
- ide_init_module(IDE_DRIVER_MODULE);
+ ide_driver_module();
drive->driver_req[0] = 0;
- ide_init_module(IDE_DRIVER_MODULE);
+ ide_driver_module();
if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
return 0;
abort:
@@ -1897,6 +1914,35 @@ ide_proc_entry_t generic_subdriver_entries[] = {
};
#endif
+/*
+ * Note that we only release the standard ports,
+ * and do not even try to handle any extra ports
+ * allocated for weird IDE interface chipsets.
+ */
+void hwif_unregister (ide_hwif_t *hwif)
+{
+ if (hwif->io_ports[IDE_DATA_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+ if (hwif->io_ports[IDE_ERROR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+ if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+ if (hwif->io_ports[IDE_SECTOR_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+ if (hwif->io_ports[IDE_LCYL_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+ if (hwif->io_ports[IDE_HCYL_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+ if (hwif->io_ports[IDE_SELECT_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+ if (hwif->io_ports[IDE_STATUS_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+ if (hwif->io_ports[IDE_IRQ_OFFSET])
+ ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+}
+
void ide_unregister (unsigned int index)
{
struct gendisk *gd, **gdp;
@@ -1967,9 +2013,7 @@ void ide_unregister (unsigned int index)
* and do not even try to handle any extra ports
* allocated for weird IDE interface chipsets.
*/
- ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
- if (hwif->io_ports[IDE_CONTROL_OFFSET])
- ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+ hwif_unregister(hwif);
/*
* Remove us from the hwgroup, and free
@@ -2036,23 +2080,28 @@ void ide_unregister (unsigned int index)
kfree (gd->flags);
kfree(gd);
}
- old_hwif = *hwif;
+ old_hwif = *hwif;
init_hwif_data (index); /* restore hwif data to pristine status */
- hwif->hwgroup = old_hwif.hwgroup;
- hwif->tuneproc = old_hwif.tuneproc;
- hwif->resetproc = old_hwif.resetproc;
- hwif->dmaproc = old_hwif.dmaproc;
- hwif->dma_base = old_hwif.dma_base;
- hwif->dma_extra = old_hwif.dma_extra;
- hwif->config_data = old_hwif.config_data;
- hwif->select_data = old_hwif.select_data;
- hwif->irq = old_hwif.irq;
- hwif->major = old_hwif.major;
- hwif->proc = old_hwif.proc;
- hwif->udma_four = old_hwif.udma_four;
- hwif->chipset = old_hwif.chipset;
- hwif->pci_dev = old_hwif.pci_dev;
- hwif->pci_devid = old_hwif.pci_devid;
+ hwif->hwgroup = old_hwif.hwgroup;
+ hwif->tuneproc = old_hwif.tuneproc;
+ hwif->selectproc = old_hwif.selectproc;
+ hwif->resetproc = old_hwif.resetproc;
+ hwif->dmaproc = old_hwif.dmaproc;
+ hwif->dma_base = old_hwif.dma_base;
+ hwif->dma_extra = old_hwif.dma_extra;
+ hwif->config_data = old_hwif.config_data;
+ hwif->select_data = old_hwif.select_data;
+ hwif->proc = old_hwif.proc;
+ hwif->irq = old_hwif.irq;
+ hwif->major = old_hwif.major;
+ hwif->chipset = old_hwif.chipset;
+ hwif->autodma = old_hwif.autodma;
+ hwif->udma_four = old_hwif.udma_four;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ hwif->pci_dev = old_hwif.pci_dev;
+ hwif->pci_devid = old_hwif.pci_devid;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
abort:
restore_flags(flags); /* all CPUs */
}
@@ -2087,6 +2136,7 @@ void ide_setup_ports ( hw_regs_t *hw,
}
}
hw->irq = irq;
+ hw->dma = NO_DMA;
hw->ack_intr = ack_intr;
}
@@ -2126,11 +2176,11 @@ found:
hwif->noprobe = 0;
if (!initializing) {
- ide_init_module(IDE_PROBE_MODULE);
+ ide_probe_module();
#ifdef CONFIG_PROC_FS
create_proc_ide_interfaces();
#endif
- ide_init_module(IDE_DRIVER_MODULE);
+ ide_driver_module();
}
if (hwifp)
@@ -2750,7 +2800,7 @@ int __init ide_setup (char *s)
if (!strcmp(s, "ide=doubler")) {
extern int ide_doubler;
- printk("ide: Enabled support for IDE doublers\n");
+ printk(" : Enabled support for IDE doublers\n");
ide_doubler = 1;
return 0;
}
@@ -2759,12 +2809,14 @@ int __init ide_setup (char *s)
#ifdef CONFIG_BLK_DEV_IDEPCI
if (!strcmp(s, "ide=reverse")) {
ide_scan_direction = 1;
- printk("ide: Enabled support for IDE inverse scan order.\n");
+ printk(" : Enabled support for IDE inverse scan order.\n");
return 0;
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
+#ifndef CONFIG_BLK_DEV_IDEPCI
init_ide_data ();
+#endif /* CONFIG_BLK_DEV_IDEPCI */
/*
* Look for drive options: "hdx="
@@ -3176,7 +3228,7 @@ void __init ide_init_builtin_drivers (void)
#if defined(__mc68000__) || defined(CONFIG_APUS)
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */
- disable_irq(ide_hwifs[0].irq);
+ disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */
}
#endif /* __mc68000__ || CONFIG_APUS */
@@ -3293,10 +3345,6 @@ ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *drive
{
unsigned int unit, index, i;
- for (index = 0; index < MAX_HWIFS; ++index)
- if (ide_hwifs[index].present) goto search;
- ide_init_module(IDE_PROBE_MODULE);
-search:
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
ide_hwif_t *hwif = &ide_hwifs[index];
if (!hwif->present)
@@ -3327,8 +3375,16 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
setup_driver_defaults(drive);
restore_flags(flags); /* all CPUs */
if (drive->autotune != 2) {
- if (driver->supports_dma && HWIF(drive)->dmaproc != NULL)
+ if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
+ /*
+ * Force DMAing for the beginning of the check.
+ * Some chipsets appear to do interesting things,
+ * if not checked and cleared.
+ * PARANOIA!!!
+ */
+ (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+ }
drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
drive->nice1 = 1;
}
@@ -3400,6 +3456,7 @@ EXPORT_SYMBOL(ide_spin_wait_hwgroup);
/*
* Probe module
*/
+EXPORT_SYMBOL(ide_probe);
EXPORT_SYMBOL(drive_is_flashcard);
EXPORT_SYMBOL(ide_timer_expiry);
EXPORT_SYMBOL(ide_intr);
@@ -3474,7 +3531,7 @@ EXPORT_SYMBOL(ide_register_hw);
EXPORT_SYMBOL(ide_register);
EXPORT_SYMBOL(ide_unregister);
EXPORT_SYMBOL(ide_setup_ports);
-
+EXPORT_SYMBOL(hwif_unregister);
EXPORT_SYMBOL(get_info_ptr);
EXPORT_SYMBOL(current_capacity);
@@ -3539,13 +3596,9 @@ void cleanup_module (void)
{
int index;
- for (index = 0; index < MAX_HWIFS; ++index) {
+ for (index = 0; index < MAX_HWIFS; ++index)
ide_unregister(index);
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (ide_hwifs[index].dma_base)
- (void) ide_release_dma(&ide_hwifs[index]);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- }
+
#ifdef CONFIG_PROC_FS
proc_ide_destroy();
#endif
diff --git a/drivers/block/ide_modes.h b/drivers/block/ide_modes.h
index d8c8a7144..b6c28e6ab 100644
--- a/drivers/block/ide_modes.h
+++ b/drivers/block/ide_modes.h
@@ -1,11 +1,12 @@
-#ifndef _IDE_MODES_H
-#define _IDE_MODES_H
/*
* linux/drivers/block/ide_modes.h
*
* Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord
*/
+#ifndef _IDE_MODES_H
+#define _IDE_MODES_H
+
#include <linux/config.h>
/*
diff --git a/drivers/block/linear.c b/drivers/block/linear.c
index 1c3305bae..978d75b80 100644
--- a/drivers/block/linear.c
+++ b/drivers/block/linear.c
@@ -121,14 +121,15 @@ static int linear_stop (mddev_t *mddev)
return 0;
}
-static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh)
+static int linear_make_request (request_queue_t *q, mddev_t *mddev,
+ int rw, struct buffer_head * bh)
{
linear_conf_t *conf = mddev_to_conf(mddev);
struct linear_hash *hash;
dev_info_t *tmp_dev;
long block;
- block = bh->b_blocknr * (bh->b_size >> 10);
+ block = bh->b_rsector >> 1;
hash = conf->hash_table + (block / conf->smallest->size);
if (block >= (hash->dev0->size + hash->dev0->offset)) {
@@ -149,8 +150,7 @@ static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh)
bh->b_rdev = tmp_dev->dev;
bh->b_rsector = (block - tmp_dev->offset) << 1;
- generic_make_request(rw, bh);
- return 0;
+ return 1;
}
static int linear_status (char *page, mddev_t *mddev)
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 808878b3e..a0ac26a49 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -952,96 +952,122 @@ end_io:
bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
}
-void generic_make_request(int rw, struct buffer_head * bh)
+static inline void buffer_IO_error(struct buffer_head * bh)
+{
+ mark_buffer_clean(bh);
+ /*
+ * b_end_io has to clear the BH_Uptodate bitflag in the error case!
+ */
+ bh->b_end_io(bh, 0);
+}
+
+int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
{
- request_queue_t * q;
unsigned long flags;
+ int ret;
- q = blk_get_queue(bh->b_rdev);
+ /*
+ * Resolve the mapping until finished. (drivers are
+ * still free to implement/resolve their own stacking
+ * by explicitly returning 0)
+ */
+ while (q->make_request_fn) {
+ ret = q->make_request_fn(q, rw, bh);
+ if (ret > 0) {
+ q = blk_get_queue(bh->b_rdev);
+ continue;
+ }
+ return ret;
+ }
+ /*
+ * Does the block device want us to queue
+ * the IO request? (normal case)
+ */
__make_request(q, rw, bh);
-
spin_lock_irqsave(&io_request_lock,flags);
if (q && !q->plugged)
(q->request_fn)(q);
spin_unlock_irqrestore(&io_request_lock,flags);
-}
+ return 0;
+}
/* This function can be used to request a number of buffers from a block
device. Currently the only restriction is that all buffers must belong to
the same device */
-static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock)
+static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[],
+ int haslock)
{
+ struct buffer_head *bh;
+ request_queue_t *q;
unsigned int major;
int correct_size;
- request_queue_t *q;
int i;
- major = MAJOR(bh[0]->b_dev);
- q = blk_get_queue(bh[0]->b_dev);
+ major = MAJOR(bhs[0]->b_dev);
+ q = blk_get_queue(bhs[0]->b_dev);
if (!q) {
printk(KERN_ERR
"ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
- kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
+ kdevname(bhs[0]->b_dev), bhs[0]->b_blocknr);
goto sorry;
}
/* Determine correct block size for this device. */
correct_size = BLOCK_SIZE;
if (blksize_size[major]) {
- i = blksize_size[major][MINOR(bh[0]->b_dev)];
+ i = blksize_size[major][MINOR(bhs[0]->b_dev)];
if (i)
correct_size = i;
}
/* Verify requested block sizes. */
for (i = 0; i < nr; i++) {
- if (bh[i]->b_size != correct_size) {
+ bh = bhs[i];
+ if (bh->b_size != correct_size) {
printk(KERN_NOTICE "ll_rw_block: device %s: "
"only %d-char blocks implemented (%u)\n",
- kdevname(bh[0]->b_dev),
- correct_size, bh[i]->b_size);
+ kdevname(bhs[0]->b_dev),
+ correct_size, bh->b_size);
goto sorry;
}
}
- if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) {
+ if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) {
printk(KERN_NOTICE "Can't write to read-only device %s\n",
- kdevname(bh[0]->b_dev));
+ kdevname(bhs[0]->b_dev));
goto sorry;
}
for (i = 0; i < nr; i++) {
+ bh = bhs[i];
+
/* Only one thread can actually submit the I/O. */
if (haslock) {
- if (!buffer_locked(bh[i]))
+ if (!buffer_locked(bh))
BUG();
} else {
- if (test_and_set_bit(BH_Lock, &bh[i]->b_state))
+ if (test_and_set_bit(BH_Lock, &bh->b_state))
continue;
}
- set_bit(BH_Req, &bh[i]->b_state);
+ set_bit(BH_Req, &bh->b_state);
- if (q->make_request_fn)
- q->make_request_fn(rw, bh[i]);
- else {
- bh[i]->b_rdev = bh[i]->b_dev;
- bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9);
+ /*
+ * First step, 'identity mapping' - RAID or LVM might
+ * further remap this.
+ */
+ bh->b_rdev = bh->b_dev;
+ bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);
- generic_make_request(rw, bh[i]);
- }
+ generic_make_request(q, rw, bh);
}
-
return;
sorry:
- for (i = 0; i < nr; i++) {
- mark_buffer_clean(bh[i]); /* remeber to refile it */
- clear_bit(BH_Uptodate, &bh[i]->b_state);
- bh[i]->b_end_io(bh[i], 0);
- }
+ for (i = 0; i < nr; i++)
+ buffer_IO_error(bhs[i]);
return;
}
@@ -1176,10 +1202,7 @@ int __init blk_dev_init(void)
#ifdef CONFIG_BLK_DEV_FD
floppy_init();
#else
-#if !defined(CONFIG_SGI_IP22) && !defined(CONFIG_SGI_IP27) && \
- !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__) && \
- !defined(CONFIG_APUS) && !defined(CONFIG_DECSTATION) && \
- !defined(CONFIG_BAGET_MIPS) && !defined(__sh__) && !defined(__ia64__)
+#if defined(__i386__) /* Do we even need this? */
outb_p(0xc, 0x3f2);
#endif
#endif
diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c
index 6d2f2743e..9f58a48d5 100644
--- a/drivers/block/lvm.c
+++ b/drivers/block/lvm.c
@@ -192,7 +192,7 @@ extern int lvm_init(void);
static void lvm_dummy_device_request(request_queue_t *);
#define DEVICE_REQUEST lvm_dummy_device_request
-static void lvm_make_request_fn(int, struct buffer_head*);
+static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*);
static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong);
static int lvm_blk_open(struct inode *, struct file *);
@@ -1292,14 +1292,14 @@ static int lvm_proc_get_info(char *page, char **start, off_t pos, int count)
*/
static int lvm_map(struct buffer_head *bh, int rw)
{
- int minor = MINOR(bh->b_dev);
+ int minor = MINOR(bh->b_rdev);
int ret = 0;
ulong index;
ulong pe_start;
ulong size = bh->b_size >> 9;
- ulong rsector_tmp = bh->b_blocknr * size;
+ ulong rsector_tmp = bh->b_rsector;
ulong rsector_sav;
- kdev_t rdev_tmp = bh->b_dev;
+ kdev_t rdev_tmp = bh->b_rdev;
kdev_t rdev_sav;
lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)];
@@ -1513,11 +1513,10 @@ static void lvm_dummy_device_request(request_queue_t * t)
/*
* make request function
*/
-static void lvm_make_request_fn(int rw, struct buffer_head *bh)
+static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh)
{
lvm_map(bh, rw);
- if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh);
- return;
+ return 1;
}
diff --git a/drivers/block/macide.c b/drivers/block/macide.c
index 4f6febd28..46a14ba19 100644
--- a/drivers/block/macide.c
+++ b/drivers/block/macide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/macide.c -- Macintosh IDE Driver
+ * linux/drivers/ide/macide.c -- Macintosh IDE Driver
*
* Copyright (C) 1998 by Michael Schmitz
*
@@ -43,7 +43,7 @@
#define MAC_HD_STATUS 0x1c /* see status-bits */
#define MAC_HD_CONTROL 0x38 /* control/altstatus */
-static int macide_offsets[IDE_NR_PORTS] = {
+static int __init macide_offsets[IDE_NR_PORTS] = {
MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL,
MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL
};
@@ -84,7 +84,7 @@ static int mac_ack_intr(ide_hwif_t* hwif)
* Probe for a Macintosh IDE interface
*/
-void macide_init(void)
+void __init macide_init(void)
{
hw_regs_t hw;
int index = -1;
diff --git a/drivers/block/md.c b/drivers/block/md.c
index b258fc6c5..171b3b659 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -75,16 +75,16 @@ static devfs_handle_t devfs_handle = NULL;
static struct gendisk md_gendisk=
{
- MD_MAJOR,
- "md",
- 0,
- 1,
- md_hd_struct,
- md_size,
- MAX_MD_DEVS,
- NULL,
- NULL,
- &md_fops,
+ major: MD_MAJOR,
+ major_name: "md",
+ minor_shift: 0,
+ max_p: 1,
+ part: md_hd_struct,
+ sizes: md_size,
+ nr_real: MAX_MD_DEVS,
+ real_devices: NULL,
+ next: NULL,
+ fops: &md_fops,
};
void md_plug_device (request_queue_t *mdqueue, kdev_t dev)
@@ -178,17 +178,16 @@ static void do_md_request (request_queue_t * q)
return;
}
-void md_make_request (int rw, struct buffer_head * bh)
+static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
{
- mddev_t *mddev = kdev_to_mddev(bh->b_dev);
+ mddev_t *mddev = kdev_to_mddev(bh->b_rdev);
- if (!mddev || !mddev->pers)
- bh->b_end_io(bh, 0);
+ if (mddev && mddev->pers)
+ return mddev->pers->make_request(q, mddev, rw, bh);
else {
- if ((rw == READ || rw == READA) && buffer_uptodate(bh))
- bh->b_end_io(bh, 1);
- else
- mddev->pers->make_request(mddev, rw, bh);
+ mark_buffer_clean(bh);
+ bh->b_end_io(bh, 0);
+ return -1;
}
}
@@ -234,28 +233,6 @@ static mddev_t * alloc_mddev (kdev_t dev)
return mddev;
}
-static void free_mddev (mddev_t *mddev)
-{
- if (!mddev) {
- MD_BUG();
- return;
- }
-
- /*
- * Make sure nobody else is using this mddev
- * (careful, we rely on the global kernel lock here)
- */
- while (md_atomic_read(&mddev->resync_sem.count) != 1)
- schedule();
- while (md_atomic_read(&mddev->recovery_sem.count) != 1)
- schedule();
-
- del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev)));
- md_list_del(&mddev->all_mddevs);
- MD_INIT_LIST_HEAD(&mddev->all_mddevs);
- kfree(mddev);
-}
-
struct gendisk * find_gendisk (kdev_t dev)
{
struct gendisk *tmp = gendisk_head;
@@ -757,6 +734,32 @@ static void export_array (mddev_t *mddev)
MD_BUG();
}
+static void free_mddev (mddev_t *mddev)
+{
+ if (!mddev) {
+ MD_BUG();
+ return;
+ }
+
+ export_array(mddev);
+ md_size[mdidx(mddev)] = 0;
+ md_hd_struct[mdidx(mddev)].nr_sects = 0;
+
+ /*
+ * Make sure nobody else is using this mddev
+ * (careful, we rely on the global kernel lock here)
+ */
+ while (md_atomic_read(&mddev->resync_sem.count) != 1)
+ schedule();
+ while (md_atomic_read(&mddev->recovery_sem.count) != 1)
+ schedule();
+
+ del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev)));
+ md_list_del(&mddev->all_mddevs);
+ MD_INIT_LIST_HEAD(&mddev->all_mddevs);
+ kfree(mddev);
+}
+
#undef BAD_CSUM
#undef BAD_MAGIC
#undef OUT_OF_MEM
@@ -1723,13 +1726,7 @@ static int do_md_stop (mddev_t * mddev, int ro)
printk (STILL_MOUNTED, mdidx(mddev));
OUT(-EBUSY);
}
-
- /*
- * complain if it's already stopped
- */
- if (!mddev->nb_dev)
- OUT(-ENXIO);
-
+
if (mddev->pers) {
/*
* It is safe to call stop here, it only frees private
@@ -1796,9 +1793,6 @@ static int do_md_stop (mddev_t * mddev, int ro)
* Free resources if final stop
*/
if (!ro) {
- export_array(mddev);
- md_size[mdidx(mddev)] = 0;
- md_hd_struct[mdidx(mddev)].nr_sects = 0;
free_mddev(mddev);
printk (KERN_INFO "md%d stopped.\n", mdidx(mddev));
@@ -3279,15 +3273,15 @@ static void md_geninit (void)
{
int i;
- blksize_size[MD_MAJOR] = md_blocksizes;
- max_readahead[MD_MAJOR] = md_maxreadahead;
-
for(i = 0; i < MAX_MD_DEVS; i++) {
md_blocksizes[i] = 1024;
+ md_size[i] = 0;
md_maxreadahead[i] = MD_READAHEAD;
register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0);
-
}
+ blksize_size[MD_MAJOR] = md_blocksizes;
+ blk_size[MAJOR_NR] = md_size;
+ max_readahead[MD_MAJOR] = md_maxreadahead;
printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c
index 8b8bb3f60..0e5675fde 100644
--- a/drivers/block/ns87415.c
+++ b/drivers/block/ns87415.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
+ * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
*
* Copyright (C) 1997-1998 Mark Lord
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c
index 0885ed49e..cc2aa567c 100644
--- a/drivers/block/opti621.c
+++ b/drivers/block/opti621.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999
+ * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999
*
* Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c
index c5a0c4924..bce80650c 100644
--- a/drivers/block/pdc202xx.c
+++ b/drivers/block/pdc202xx.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/pdc202xx.c Version 0.28 Dec. 13, 1999
+ * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000
*
- * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
@@ -14,7 +14,7 @@
* 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
* The 8/4 ratio is a BIOS code limit by promise.
*
- * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT"
+ * UNLESS you enable "CONFIG_PDC202XX_BURST"
*
* There is only one BIOS in the three contollers.
*
@@ -100,6 +100,61 @@
#define PDC202XX_DEBUG_DRIVE_INFO 0
#define PDC202XX_DECODE_REGISTER_INFO 0
+#define DISPLAY_PDC202XX_TIMINGS
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static struct pci_dev *bmide_dev;
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+
+ u32 bibma = bmide_dev->resource[4].start;
+ u8 c0 = 0, c1 = 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ switch(bmide_dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20262:
+ p += sprintf(p, "\n PDC20262 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_PROMISE_20246:
+ p += sprintf(p, "\n PDC20246 Chipset.\n");
+ break;
+ default:
+ p += sprintf(p, "\n PDC202XX Chipset.\n");
+ break;
+ }
+
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
+ p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+byte pdc202xx_proc = 0;
+
extern char *ide_xfer_verbose (byte xfer_rate);
/* A Register */
@@ -620,15 +675,15 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
(primary_mode & 1) ? "MASTER" : "PCI",
(secondary_mode & 1) ? "MASTER" : "PCI" );
-#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT
+#ifdef CONFIG_PDC202XX_BURST
if (!(udma_speed_flag & 1)) {
printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
outb(udma_speed_flag|1, high_16 + 0x001f);
printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA");
}
-#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */
+#endif /* CONFIG_PDC202XX_BURST */
-#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE
+#ifdef CONFIG_PDC202XX_MASTER
if (!(primary_mode & 1)) {
printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
name, primary_mode, (primary_mode|1));
@@ -642,7 +697,14 @@ unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
outb(secondary_mode|1, high_16 + 0x001b);
printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
}
-#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */
+#endif /* CONFIG_PDC202XX_MASTER */
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+ pdc202xx_proc = 1;
+ bmide_dev = dev;
+ pdc202xx_display_info = &pdc202xx_get_info;
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
return dev->irq;
}
diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c
index 0b682645c..f42c4946f 100644
--- a/drivers/block/pdc4030.c
+++ b/drivers/block/pdc4030.c
@@ -1,5 +1,5 @@
/* -*- linux-c -*-
- * linux/drivers/block/pdc4030.c Version 0.90 May 27, 1999
+ * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999
*
* Copyright (C) 1995-1999 Linus Torvalds & authors (see below)
*/
diff --git a/drivers/block/pdc4030.h b/drivers/block/pdc4030.h
index 9f08da5aa..551785c36 100644
--- a/drivers/block/pdc4030.h
+++ b/drivers/block/pdc4030.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/pdc4030.h
+ * linux/drivers/ide/pdc4030.h
*
* Copyright (C) 1995-1998 Linus Torvalds & authors
*/
diff --git a/drivers/block/piix.c b/drivers/block/piix.c
index 64cf45853..4c2d94c99 100644
--- a/drivers/block/piix.c
+++ b/drivers/block/piix.c
@@ -1,8 +1,8 @@
/*
- * linux/drivers/block/piix.c Version 0.28 Dec. 13, 1999
+ * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* PIO mode setting function for Intel chipsets.
@@ -49,13 +49,33 @@
* pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
* pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ * 00:1f.1 IDE interface: Intel Corporation:
+ * Unknown device 2411 (rev 01) (prog-if 80 [Master])
+ * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop-
+ * ParErr- Stepping- SERR- FastB2B-
+ * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
+ * <TAbort- <MAbort- >SERR- <PERR-
+ * Latency: 0 set
+ * Region 4: I/O ports at ffa0
+ * 00: 86 80 11 24 05 00 80 02 01 80 01 01 00 00 00 00
+ * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 20: a1 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 40: 07 a3 03 a3 00 00 00 00 05 00 02 02 00 00 00 00
+ * 50: 00 00 00 00 11 04 00 00 00 00 00 00 00 00 00 00
+ * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ * f0: 00 00 00 00 00 00 00 00 3a 0f 00 00 00 00 00 00
*
- * #if 0
- * int err;
- * err = ide_config_drive_speed(drive, speed);
- * (void) ide_config_drive_speed(drive, speed);
- * #else
- * #endif
*/
#include <linux/config.h>
@@ -86,16 +106,88 @@ static struct pci_dev *bmide_dev;
static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
{
- /* int rc; */
- int piix_who = ((bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
- (bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) ||
- (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB)) ? 4 : 3;
char *p = buffer;
- p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who);
- p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n");
+ u32 bibma = bmide_dev->resource[4].start;
+ u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+ u8 c0 = 0, c1 = 0;
+ u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0;
+
+ pci_read_config_word(bmide_dev, 0x40, &reg40);
+ pci_read_config_word(bmide_dev, 0x42, &reg42);
+ pci_read_config_byte(bmide_dev, 0x44, &reg44);
+ pci_read_config_byte(bmide_dev, 0x48, &reg48);
+ pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+ pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+ pci_read_config_byte(bmide_dev, 0x54, &reg54);
+
+ psitre = (reg40 & 0x4000) ? 1 : 0;
+ ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte registers
+ * to investigate:
+ */
+ c0 = inb_p((unsigned short)bibma + 0x02);
+ c1 = inb_p((unsigned short)bibma + 0x0a);
+
+ switch(bmide_dev->device) {
+ case PCI_DEVICE_ID_INTEL_82372FB_1:
+ case PCI_DEVICE_ID_INTEL_82801AA_1:
+ p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_INTEL_82801AB_1:
+ case PCI_DEVICE_ID_INTEL_82371AB:
+ p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_INTEL_82371SB_1:
+ p += sprintf(p, "\n Intel PIIX3 Chipset.\n");
+ break;
+ case PCI_DEVICE_ID_INTEL_82371FB_1:
+ case PCI_DEVICE_ID_INTEL_82371FB_0:
+ default:
+ p += sprintf(p, "\n Intel PIIX Chipset.\n");
+ break;
+ }
+ p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+ p += sprintf(p, " %sabled %sabled\n",
+ (c0&0x80) ? "dis" : " en",
+ (c1&0x80) ? "dis" : " en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
- p += sprintf(p, "\n");
- p += sprintf(p, "\n");
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (c0&0x20) ? "yes" : "no ",
+ (c0&0x40) ? "yes" : "no ",
+ (c1&0x20) ? "yes" : "no ",
+ (c1&0x40) ? "yes" : "no " );
+ p += sprintf(p, "UDMA enabled: %s %s %s %s\n",
+ (reg48&0x01) ? "yes" : "no ",
+ (reg48&0x02) ? "yes" : "no ",
+ (reg48&0x04) ? "yes" : "no ",
+ (reg48&0x08) ? "yes" : "no " );
+ p += sprintf(p, "UDMA enabled: %s %s %s %s\n",
+ ((reg54&0x11) && (reg4a&0x02)) ? "4" :
+ ((reg54&0x11) && (reg4a&0x01)) ? "3" :
+ (reg4a&0x02) ? "2" :
+ (reg4a&0x01) ? "1" :
+ (reg4a&0x00) ? "0" : "X",
+ ((reg54&0x22) && (reg4a&0x20)) ? "4" :
+ ((reg54&0x22) && (reg4a&0x10)) ? "3" :
+ (reg4a&0x20) ? "2" :
+ (reg4a&0x10) ? "1" :
+ (reg4a&0x00) ? "0" : "X",
+ ((reg54&0x44) && (reg4b&0x02)) ? "4" :
+ ((reg54&0x44) && (reg4b&0x01)) ? "3" :
+ (reg4b&0x02) ? "2" :
+ (reg4b&0x01) ? "1" :
+ (reg4b&0x00) ? "0" : "X",
+ ((reg54&0x88) && (reg4b&0x20)) ? "4" :
+ ((reg54&0x88) && (reg4b&0x10)) ? "3" :
+ (reg4b&0x20) ? "2" :
+ (reg4b&0x10) ? "1" :
+ (reg4b&0x00) ? "0" : "X");
+
+ p += sprintf(p, "UDMA\n");
+ p += sprintf(p, "DMA\n");
+ p += sprintf(p, "PIO\n");
/*
* FIXME.... Add configuration junk data....blah blah......
@@ -113,7 +205,6 @@ byte piix_proc = 0;
extern char *ide_xfer_verbose (byte xfer_rate);
-#ifdef CONFIG_BLK_DEV_PIIX_TUNING
/*
*
*/
@@ -143,7 +234,6 @@ static byte piix_dma_2_pio (byte xfer_rate) {
return 0;
}
}
-#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
/*
* Based on settings done by AMI BIOS
@@ -191,8 +281,6 @@ static void piix_tune_drive (ide_drive_t *drive, byte pio)
restore_flags(flags);
}
-#ifdef CONFIG_BLK_DEV_PIIX_TUNING
-
static int piix_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -205,12 +293,15 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
byte maslave = hwif->channel ? 0x42 : 0x40;
byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
- int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
+ int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
+ (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
+ int ultra = ((ultra66) ||
+ (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
(dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
- int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ? 1 : 0;
int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
int a_speed = 2 << (drive_number * 4);
int u_flag = 1 << drive_number;
+ int v_flag = 0x10 << drive_number;
int u_speed = 0;
pci_read_config_word(dev, maslave, &reg4042);
@@ -245,10 +336,6 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
}
- /*
- * This is !@#$% ugly and stupid.............
- * But ugly harware generates ugly code.........
- */
if (speed >= XFER_UDMA_0) {
if (!(reg48 & u_flag))
pci_write_config_word(dev, 0x48, reg48|u_flag);
@@ -256,10 +343,12 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
pci_write_config_word(dev, 0x4a, reg4a|u_speed);
}
- if ((speed > XFER_UDMA_2) && (!(reg54 & u_flag))) {
- pci_write_config_word(dev, 0x54, reg54|u_flag);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag)) {
+ pci_write_config_word(dev, 0x54, reg54|v_flag);
+ }
} else {
- pci_write_config_word(dev, 0x54, reg54 & ~u_flag);
+ pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
}
}
@@ -268,8 +357,8 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- if (reg54 & u_flag)
- pci_write_config_word(dev, 0x54, reg54 & ~u_flag);
+ if (reg54 & v_flag)
+ pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
}
piix_tune_drive(drive, piix_dma_2_pio(speed));
@@ -277,8 +366,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
(void) ide_config_drive_speed(drive, speed);
#if PIIX_DEBUG_DRIVE_INFO
- printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number);
- printk("\n");
+ printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number);
#endif /* PIIX_DEBUG_DRIVE_INFO */
return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
@@ -299,16 +387,13 @@ static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
/* Other cases are done by generic IDE-DMA code. */
return ide_dmaproc(func, drive);
}
-#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
{
#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
- if (!piix_proc) {
- piix_proc = 1;
- bmide_dev = dev;
- piix_display_info = &piix_get_info;
- }
+ piix_proc = 1;
+ bmide_dev = dev;
+ piix_display_info = &piix_get_info;
#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
return 0;
}
@@ -325,7 +410,7 @@ unsigned int __init ata66_piix (ide_hwif_t *hwif)
pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
- ata66 = (reg54h & mask) ? 0 : 1;
+ ata66 = (reg54h & mask) ? 1 : 0;
return ata66;
}
@@ -335,9 +420,9 @@ void __init ide_init_piix (ide_hwif_t *hwif)
hwif->tuneproc = &piix_tune_drive;
if (hwif->dma_base) {
-#ifdef CONFIG_BLK_DEV_PIIX_TUNING
+#ifdef CONFIG_PIIX_TUNING
hwif->dmaproc = &piix_dmaproc;
-#endif /* CONFIG_BLK_DEV_PIIX_TUNING */
+#endif /* CONFIG_PIIX_TUNING */
hwif->drives[0].autotune = 0;
hwif->drives[1].autotune = 0;
} else {
diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c
index d7b2784d1..31781a9f0 100644
--- a/drivers/block/qd6580.c
+++ b/drivers/block/qd6580.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996
+ * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996
*
* Copyright (C) 1996 Linus Torvalds & author (see below)
*/
@@ -60,7 +60,7 @@ static void tune_qd6580 (ide_drive_t *drive, byte pio)
restore_flags(flags); /* all CPUs */
}
-void init_qd6580 (void)
+void __init init_qd6580 (void)
{
ide_hwifs[0].chipset = ide_qd6580;
ide_hwifs[1].chipset = ide_qd6580;
diff --git a/drivers/block/raid0.c b/drivers/block/raid0.c
index 661855a18..0e075277a 100644
--- a/drivers/block/raid0.c
+++ b/drivers/block/raid0.c
@@ -223,23 +223,23 @@ static int raid0_stop (mddev_t *mddev)
* Of course, those facts may not be valid anymore (and surely won't...)
* Hey guys, there's some work out there ;-)
*/
-static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh)
+static int raid0_make_request (request_queue_t *q, mddev_t *mddev,
+ int rw, struct buffer_head * bh)
{
- unsigned long size = bh->b_size >> 10;
+ int blk_in_chunk, chunksize_bits, chunk, chunk_size;
raid0_conf_t *conf = mddev_to_conf(mddev);
struct raid0_hash *hash;
struct strip_zone *zone;
mdk_rdev_t *tmp_dev;
- int blk_in_chunk, chunksize_bits, chunk, chunk_size;
long block, rblock;
chunk_size = mddev->param.chunk_size >> 10;
chunksize_bits = ffz(~chunk_size);
- block = bh->b_blocknr * size;
+ block = bh->b_rsector >> 1;
hash = conf->hash_table + block / conf->smallest->size;
/* Sanity check */
- if (chunk_size < (block % chunk_size) + size)
+ if (chunk_size < (block % chunk_size) + (bh->b_size >> 10))
goto bad_map;
if (!hash)
@@ -261,20 +261,19 @@ static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh)
rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset;
/*
- * Important, at this point we are not guaranteed to be the only
- * CPU modifying b_rdev and b_rsector! Only __make_request() later
- * on serializes the IO. So in 2.4 we must never write temporary
- * values to bh->b_rdev, like 2.2 and 2.0 did.
+ * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+ * is the only IO operation happening on this bh.
*/
bh->b_rdev = tmp_dev->dev;
bh->b_rsector = rblock << 1;
- generic_make_request(rw, bh);
-
- return 0;
+ /*
+ * Let the main block layer submit the IO and resolve recursion:
+ */
+ return 1;
bad_map:
- printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, bh->b_rsector, size);
+ printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10);
return -1;
bad_hash:
printk("raid0_make_request bug: hash==NULL for block %ld\n", block);
diff --git a/drivers/block/rapide.c b/drivers/block/rapide.c
index 468f2e3b1..5905aca41 100644
--- a/drivers/block/rapide.c
+++ b/drivers/block/rapide.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/drivers/block/ide-rapide.c
+ * linux/drivers/block/rapide.c
*
* Copyright (c) 1996-1998 Russell King.
*
@@ -16,7 +16,7 @@
#include <asm/ecard.h>
-static const card_ids rapide_cids[] = {
+static const card_ids __init rapide_cids[] = {
{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
{ 0xffff, 0xffff }
};
@@ -43,7 +43,7 @@ static inline int rapide_register(struct expansion_card *ec)
return ide_register_hw(&hw, NULL);
}
-int rapide_init(void)
+int __init rapide_init(void)
{
int i;
diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c
index 811e1665f..455641c1d 100644
--- a/drivers/block/rz1000.c
+++ b/drivers/block/rz1000.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
+ * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
*
* Copyright (C) 1995-1998 Linus Torvalds & author (see below)
*/
diff --git a/drivers/block/sis5513.c b/drivers/block/sis5513.c
index d255bbdf8..942187900 100644
--- a/drivers/block/sis5513.c
+++ b/drivers/block/sis5513.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/sis5513.c Version 0.08 Dec. 13, 1999
+ * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000
*
- * Copyright (C) 1999 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* Thanks to SIS Taiwan for direct support and hardware.
@@ -50,6 +50,7 @@ static const struct {
{ "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, },
{ "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
{ "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+ { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, },
{ "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, },
{ "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, },
{ "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, },
@@ -233,8 +234,10 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
byte drive_pci, test1, test2, mask;
int err;
+ unsigned long dma_base = hwif->dma_base;
+ byte unit = (drive->select.b.unit & 0x01);
byte speed = 0x00, unmask = 0xE0, four_two = 0x00;
- int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01));
+ int drive_number = ((hwif->channel ? 2 : 0) + unit);
byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
if (host_dev) {
@@ -314,6 +317,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
return ((int) ide_dma_off_quietly);
}
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
err = ide_config_drive_speed(drive, speed);
#if SIS5513_DEBUG_DRIVE_INFO
@@ -532,6 +536,7 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
case PCI_DEVICE_ID_SI_630:
case PCI_DEVICE_ID_SI_5600:
case PCI_DEVICE_ID_SI_5597:
+ case PCI_DEVICE_ID_SI_5591:
hwif->autodma = 1;
hwif->dmaproc = &sis5513_dmaproc;
break;
diff --git a/drivers/block/sl82c105.c b/drivers/block/sl82c105.c
index 9ab90f0df..29f006682 100644
--- a/drivers/block/sl82c105.c
+++ b/drivers/block/sl82c105.c
@@ -1,5 +1,5 @@
/*
- * drivers/block/sl82c105.c
+ * linux/drivers/block/sl82c105.c
*
* SL82C105/Winbond 553 IDE driver
*
diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c
index 4ec1d09c6..fb5e8d1af 100644
--- a/drivers/block/trm290.c
+++ b/drivers/block/trm290.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
+ * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
*
* Copyright (c) 1997-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c
index 13f5f39a7..02b581a28 100644
--- a/drivers/block/umc8672.c
+++ b/drivers/block/umc8672.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996
+ * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996
*
* Copyright (C) 1995-1996 Linus Torvalds & author (see below)
*/
@@ -76,7 +76,7 @@ static void out_umc (char port,char wert)
outb_p (wert,0x109);
}
-static byte in_umc (char port)
+static inline byte in_umc (char port)
{
outb_p (port,0x108);
return inb_p (0x109);
@@ -125,7 +125,7 @@ static void tune_umc (ide_drive_t *drive, byte pio)
restore_flags(flags); /* all CPUs */
}
-void init_umc8672 (void) /* called from ide.c */
+void __init init_umc8672 (void) /* called from ide.c */
{
unsigned long flags;
diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c
index 09c4a86a7..54681f38c 100644
--- a/drivers/block/via82cxxx.c
+++ b/drivers/block/via82cxxx.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999
+ * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000
*
- * Copyright (C) 1998-99 Michel Aubry, Maintainer
- * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com)
- * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com)
+ * Copyright (C) 1998-99 Michel Aubry, Maintainer
+ * Copyright (C) 1999 Jeff Garzik, MVP4 Support
+ * (jgarzik@mandrakesoft.com)
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com)
* May be copied or modified under the terms of the GNU General Public License
*
* The VIA MVP-4 is reported OK with UDMA.
@@ -473,12 +474,6 @@ static int via_set_fifoconfig(ide_hwif_t *hwif)
!(newfifo & 0x03) ? "1" :
(!(newfifo & 0x02) ? "3/4" :
(newfifo & 0x01) ? "1/4" : "1/2"));
-
-#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
- via_proc = 1;
- bmide_dev = hwif->pci_dev;
- via_display_info = &via_get_info;
-#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/
return 0;
}
@@ -530,6 +525,12 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
printk("\n");
}
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+ via_proc = 1;
+ bmide_dev = dev;
+ via_display_info = &via_get_info;
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/
+
return 0;
}
@@ -555,7 +556,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
}
/*
- * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long)
+ * ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long)
* checks if channel "channel" of if hwif is dma
* capable or not, according to kernel command line,
* and the new fifo settings.
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index c34978479..97e1f1f58 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -122,7 +122,8 @@ endmenu
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
-if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
+bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
+if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 4667e1fa3..7f3c6133b 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -158,13 +158,17 @@ obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o
obj-$(CONFIG_PC110_PAD) += pc110pad.o
obj-$(CONFIG_WDT) += wdt.o
obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
obj-$(CONFIG_NVRAM) += nvram.o
endif
-obj-$(CONFIG_I810_RNG) += i810_rng.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o
+obj-$(CONFIG_21825_WATCHDOG) += wdt285.o
+obj-$(CONFIG_977_WATCHDOG) += wdt977.o
+obj-$(CONFIG_DS1620) += ds1620.o
+
#
# for external dependencies in arm/config.in and video/config.in
#
@@ -205,7 +209,7 @@ ifeq ($(CONFIG_I2C_PARPORT),y)
L_I2C = y
else
ifeq ($(CONFIG_I2C_PARPORT),m)
- M_I2C = y
+ L_I2C = m
endif
endif
@@ -277,6 +281,13 @@ ifeq ($(CONFIG_DZ),y)
L_OBJS += dz.o
endif
+obj-$(CONFIG_NWBUTTON) += nwbutton.o
+obj-$(CONFIG_NWFLASH) += nwflash.o
+
+ifeq ($(CONFIG_DZ),y)
+ L_OBJS += dz.o
+endif
+
ifeq ($(CONFIG_DRM),y)
SUB_DIRS += drm
ALL_SUB_DIRS += drm
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index a21556a2b..c478395f8 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -1397,8 +1397,6 @@ static int __init sis_generic_setup (struct pci_dev *pdev)
agp_bridge.free_by_type = agp_generic_free_by_type;
return 0;
-
- (void) pdev; /* unused */
}
#endif /* CONFIG_AGP_SIS */
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
new file mode 100644
index 000000000..e3a37611d
--- /dev/null
+++ b/drivers/char/ds1620.c
@@ -0,0 +1,436 @@
+/*
+ * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620
+ * thermometer driver (as used in the Rebel.com NetWinder)
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/capability.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/therm.h>
+
+#ifdef CONFIG_PROC_FS
+/* define for /proc interface */
+#define THERM_USE_PROC
+#endif
+
+/* Definitions for DS1620 chip */
+#define THERM_START_CONVERT 0xee
+#define THERM_RESET 0xaf
+#define THERM_READ_CONFIG 0xac
+#define THERM_READ_TEMP 0xaa
+#define THERM_READ_TL 0xa2
+#define THERM_READ_TH 0xa1
+#define THERM_WRITE_CONFIG 0x0c
+#define THERM_WRITE_TL 0x02
+#define THERM_WRITE_TH 0x01
+
+#define CFG_CPU 2
+#define CFG_1SHOT 1
+
+static const char *fan_state[] = { "off", "on", "on (hardwired)" };
+
+/*
+ * Start of NetWinder specifics
+ * Note! We have to hold the gpio lock with IRQs disabled over the
+ * whole of our transaction to the Dallas chip, since there is a
+ * chance that the WaveArtist driver could touch these bits to
+ * enable or disable the speaker.
+ */
+extern spinlock_t gpio_lock;
+extern unsigned int system_rev;
+
+static inline void netwinder_ds1620_set_clk(int clk)
+{
+ gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0);
+}
+
+static inline void netwinder_ds1620_set_data(int dat)
+{
+ gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0);
+}
+
+static inline int netwinder_ds1620_get_data(void)
+{
+ return gpio_read() & GPIO_DATA;
+}
+
+static inline void netwinder_ds1620_set_data_dir(int dir)
+{
+ gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0);
+}
+
+static inline void netwinder_ds1620_reset(void)
+{
+ cpld_modify(CPLD_DS_ENABLE, 0);
+ cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE);
+}
+
+static inline void netwinder_lock(unsigned long *flags)
+{
+ spin_lock_irqsave(&gpio_lock, *flags);
+}
+
+static inline void netwinder_unlock(unsigned long *flags)
+{
+ spin_unlock_irqrestore(&gpio_lock, *flags);
+}
+
+static inline void netwinder_set_fan(int i)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static inline int netwinder_get_fan(void)
+{
+ if ((system_rev & 0xf000) == 0x4000)
+ return FAN_ALWAYS_ON;
+
+ return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF;
+}
+
+/*
+ * End of NetWinder specifics
+ */
+
+static void ds1620_send_bits(int nr, int value)
+{
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ netwinder_ds1620_set_data(value & 1);
+ netwinder_ds1620_set_clk(0);
+ udelay(1);
+ netwinder_ds1620_set_clk(1);
+ udelay(1);
+
+ value >>= 1;
+ }
+}
+
+static unsigned int ds1620_recv_bits(int nr)
+{
+ unsigned int value = 0, mask = 1;
+ int i;
+
+ netwinder_ds1620_set_data(0);
+
+ for (i = 0; i < nr; i++) {
+ netwinder_ds1620_set_clk(0);
+ udelay(1);
+
+ if (netwinder_ds1620_get_data())
+ value |= mask;
+
+ mask <<= 1;
+
+ netwinder_ds1620_set_clk(1);
+ udelay(1);
+ }
+
+ return value;
+}
+
+static void ds1620_out(int cmd, int bits, int value)
+{
+ unsigned long flags;
+
+ netwinder_lock(&flags);
+ netwinder_ds1620_set_clk(1);
+ netwinder_ds1620_set_data_dir(0);
+ netwinder_ds1620_reset();
+
+ udelay(1);
+
+ ds1620_send_bits(8, cmd);
+ if (bits)
+ ds1620_send_bits(bits, value);
+
+ udelay(1);
+
+ netwinder_ds1620_reset();
+ netwinder_unlock(&flags);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2);
+}
+
+static unsigned int ds1620_in(int cmd, int bits)
+{
+ unsigned long flags;
+ unsigned int value;
+
+ netwinder_lock(&flags);
+ netwinder_ds1620_set_clk(1);
+ netwinder_ds1620_set_data_dir(0);
+ netwinder_ds1620_reset();
+
+ udelay(1);
+
+ ds1620_send_bits(8, cmd);
+
+ netwinder_ds1620_set_data_dir(1);
+ value = ds1620_recv_bits(bits);
+
+ netwinder_ds1620_reset();
+ netwinder_unlock(&flags);
+
+ return value;
+}
+
+static int cvt_9_to_int(unsigned int val)
+{
+ if (val & 0x100)
+ val |= 0xfffffe00;
+
+ return val;
+}
+
+static void ds1620_write_state(struct therm *therm)
+{
+ ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
+ ds1620_out(THERM_WRITE_TL, 9, therm->lo);
+ ds1620_out(THERM_WRITE_TH, 9, therm->hi);
+ ds1620_out(THERM_START_CONVERT, 0, 0);
+}
+
+static void ds1620_read_state(struct therm *therm)
+{
+ therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9));
+ therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9));
+}
+
+static ssize_t
+ds1620_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+ signed int cur_temp;
+ signed char cur_temp_degF;
+
+ /* Can't seek (pread) on this device */
+ if (ptr != &file->f_pos)
+ return -ESPIPE;
+
+ cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1;
+
+ /* convert to Fahrenheit, as per wdt.c */
+ cur_temp_degF = (cur_temp * 9) / 5 + 32;
+
+ if (copy_to_user(buf, &cur_temp_degF, 1))
+ return -EFAULT;
+
+ return 1;
+}
+
+static int
+ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct therm therm;
+ int i;
+
+ switch(cmd) {
+ case CMD_SET_THERMOSTATE:
+ case CMD_SET_THERMOSTATE2:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (cmd == CMD_SET_THERMOSTATE) {
+ if (get_user(therm.hi, (int *)arg))
+ return -EFAULT;
+ therm.lo = therm.hi - 3;
+ } else {
+ if (copy_from_user(&therm, (void *)arg, sizeof(therm)))
+ return -EFAULT;
+ }
+
+ therm.lo <<= 1;
+ therm.hi <<= 1;
+
+ ds1620_write_state(&therm);
+ break;
+
+ case CMD_GET_THERMOSTATE:
+ case CMD_GET_THERMOSTATE2:
+ ds1620_read_state(&therm);
+
+ therm.lo >>= 1;
+ therm.hi >>= 1;
+
+ if (cmd == CMD_GET_THERMOSTATE) {
+ if (put_user(therm.hi, (int *)arg))
+ return -EFAULT;
+ } else {
+ if (copy_to_user((void *)arg, &therm, sizeof(therm)))
+ return -EFAULT;
+ }
+ break;
+
+ case CMD_GET_TEMPERATURE:
+ case CMD_GET_TEMPERATURE2:
+ i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
+
+ if (cmd == CMD_GET_TEMPERATURE)
+ i >>= 1;
+
+ return put_user(i, (int *)arg) ? -EFAULT : 0;
+
+ case CMD_GET_STATUS:
+ i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3;
+
+ return put_user(i, (int *)arg) ? -EFAULT : 0;
+
+ case CMD_GET_FAN:
+ i = netwinder_get_fan();
+
+ return put_user(i, (int *)arg) ? -EFAULT : 0;
+
+ case CMD_SET_FAN:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (get_user(i, (int *)arg))
+ return -EFAULT;
+
+ netwinder_set_fan(i);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int
+ds1620_open(struct inode *inode, struct file *file)
+{
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int
+ds1620_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+#ifdef THERM_USE_PROC
+static int
+proc_therm_ds1620_read(char *buf, char **start, off_t offset,
+ int len, int *eof, void *unused)
+{
+ struct therm th;
+ int temp;
+
+ ds1620_read_state(&th);
+ temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
+
+ len = sprintf(buf, "Thermostat: HI %i.%i, LOW %i.%i; "
+ "temperature: %i.%i C, fan %s\n",
+ th.hi >> 1, th.hi & 1 ? 5 : 0,
+ th.lo >> 1, th.lo & 1 ? 5 : 0,
+ temp >> 1, temp & 1 ? 5 : 0,
+ fan_state[netwinder_get_fan()]);
+
+ return len;
+}
+
+static struct proc_dir_entry *proc_therm_ds1620;
+#endif
+
+static struct file_operations ds1620_fops = {
+ NULL, /* lseek */
+ ds1620_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ ds1620_ioctl, /* ioctl */
+ NULL, /* mmap */
+ ds1620_open, /* open */
+ NULL, /* flush */
+ ds1620_release, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+};
+
+static struct miscdevice ds1620_miscdev = {
+ TEMP_MINOR,
+ "temp",
+ &ds1620_fops
+};
+
+int __init ds1620_init(void)
+{
+ int ret;
+ struct therm th, th_start;
+
+ if (!machine_is_netwinder())
+ return -ENODEV;
+
+ ds1620_out(THERM_RESET, 0, 0);
+ ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
+ ds1620_out(THERM_START_CONVERT, 0, 0);
+
+ /*
+ * Trigger the fan to start by setting
+ * temperature high point low. This kicks
+ * the fan into action.
+ */
+ ds1620_read_state(&th);
+ th_start.lo = 0;
+ th_start.hi = 1;
+ ds1620_write_state(&th_start);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2*HZ);
+
+ ds1620_write_state(&th);
+
+ ret = misc_register(&ds1620_miscdev);
+ if (ret < 0)
+ return ret;
+
+#ifdef THERM_USE_PROC
+ proc_therm_ds1620 = create_proc_entry("therm", 0, 0);
+ if (proc_therm_ds1620)
+ proc_therm_ds1620->read_proc = proc_therm_ds1620_read;
+ else
+ printk(KERN_ERR "therm: unable to register /proc/therm\n");
+#endif
+
+ ds1620_read_state(&th);
+ ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
+
+ printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, "
+ "current %i.%i C, fan %s.\n",
+ th.hi >> 1, th.hi & 1 ? 5 : 0,
+ th.lo >> 1, th.lo & 1 ? 5 : 0,
+ ret >> 1, ret & 1 ? 5 : 0,
+ fan_state[netwinder_get_fan()]);
+
+ return 0;
+}
+
+void __exit ds1620_exit(void)
+{
+#ifdef THERM_USE_PROC
+ remove_proc_entry("therm", NULL);
+#endif
+ misc_deregister(&ds1620_miscdev);
+}
+
+module_init(ds1620_init);
+module_exit(ds1620_exit);
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 391cfcfc0..0f26dedd9 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -334,6 +334,7 @@ efi_rtc_read_proc(char *page, char **start, off_t off,
if (len<0) len = 0;
return len;
}
+
static int __init
efi_rtc_init(void)
{
@@ -345,6 +346,7 @@ efi_rtc_init(void)
return 0;
}
+
static int __exit
efi_rtc_exit(void)
{
diff --git a/drivers/char/h8.c b/drivers/char/h8.c
index 0583923d9..acc898cb8 100644
--- a/drivers/char/h8.c
+++ b/drivers/char/h8.c
@@ -6,6 +6,8 @@
*
* Fixes:
* June 1999, AV added releasing /proc/driver/h8
+ * Feb 2000, Borislav Deianov
+ * changed queues to use list.h instead of lists.h
*/
#include <linux/config.h>
@@ -23,7 +25,7 @@
#include <linux/stat.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
-#include <linux/lists.h>
+#include <linux/list.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/init.h>
@@ -52,18 +54,13 @@
/*
* Forward declarations.
*/
-int h8_init(void);
+static int h8_init(void);
int h8_display_blank(void);
int h8_display_unblank(void);
static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
-#ifdef CONFIG_PROC_FS
static int h8_get_info(char *, char **, off_t, int);
-#else
-static int h8_get_info(char *, char **, off_t, int) {}
-#error "Somebody needs to learn C. Badly."
-#endif
/*
* Support Routines.
@@ -141,7 +138,9 @@ unsigned int h8_state = H8_IDLE;
unsigned int h8_index = -1;
unsigned int h8_enabled = 0;
-queue_head_t h8_actq, h8_cmdq, h8_freeq;
+LIST_HEAD(h8_actq);
+LIST_HEAD(h8_cmdq);
+LIST_HEAD(h8_freeq);
/*
* Globals used in thermal control of Alphabook1.
@@ -170,7 +169,7 @@ int speed_tab[6] = {230, 153, 115, 57, 28, 14};
static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
{
u_char stat_reg, data_reg;
- h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+ h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
stat_reg = H8_GET_STATUS;
data_reg = H8_READ_DATA;
@@ -260,7 +259,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
return;
} else if (data_reg == H8_SYNC_BYTE) {
h8_state = H8_IDLE;
- if (!QUEUE_IS_EMPTY(&h8_actq, link))
+ if (!list_empty(&h8_actq))
h8_send_next_cmd_byte();
} else {
Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
@@ -276,10 +275,10 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
/* If command reception finished. */
if (qp->cnt == qp->nrsp) {
h8_state = H8_IDLE;
- QUEUE_REMOVE(&h8_actq, qp, link);
+ list_del(&qp->link);
h8_cmd_done (qp);
/* More commands to send over? */
- if (!QUEUE_IS_EMPTY(&h8_cmdq, link))
+ if (!list_empty(&h8_cmdq))
h8_start_new_cmd();
}
return;
@@ -317,9 +316,6 @@ static int __init h8_init(void)
misc_register(&h8_device);
request_region(h8_base, 8, "h8");
- QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
- QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
- QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
h8_alloc_queues();
h8_hw_init();
@@ -364,9 +360,9 @@ static void __init h8_hw_init(void)
return;
}
-#ifdef CONFIG_PROC_FS
static int h8_get_info(char *buf, char **start, off_t fpos, int length)
{
+#ifdef CONFIG_PROC_FS
char *p;
if (!h8_enabled)
@@ -387,8 +383,10 @@ static int h8_get_info(char *buf, char **start, off_t fpos, int length)
);
return p - buf;
-}
+#else
+ return 0;
#endif
+}
/* Called from console driver -- must make sure h8_enabled. */
int h8_display_blank(void)
@@ -440,7 +438,7 @@ h8_alloc_queues(void)
save_flags(flags); cli();
for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
/* place each at front of freeq */
- QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *);
+ list_add(&qp[i].link, &h8_freeq);
}
restore_flags(flags);
return (1);
@@ -458,15 +456,15 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
/* get cmd buf */
save_flags(flags); cli();
- while (QUEUE_IS_EMPTY(&h8_freeq, link)) {
+ while (list_empty(&h8_freeq)) {
Dprintk("H8: need to allocate more cmd buffers\n");
restore_flags(flags);
h8_alloc_queues();
save_flags(flags); cli();
}
/* get first element from queue */
- qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link);
- QUEUE_REMOVE(&h8_freeq, qp, link);
+ qp = list_entry(h8_freeq.next, h8_cmd_q_t, link);
+ list_del(&qp->link);
restore_flags(flags);
@@ -479,7 +477,8 @@ h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
/* queue it at the end of the cmd queue */
save_flags(flags); cli();
- QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *);
+ /* XXX this actually puts it at the start of cmd queue, bug? */
+ list_add(&qp->link, &h8_cmdq);
restore_flags(flags);
@@ -500,13 +499,13 @@ h8_start_new_cmd(void)
return;
}
- if (!QUEUE_IS_EMPTY(&h8_actq, link)) {
+ if (!list_empty(&h8_actq)) {
Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
restore_flags(flags);
return;
}
- if (QUEUE_IS_EMPTY(&h8_cmdq, link)) {
+ if (list_empty(&h8_cmdq)) {
Dprintk("h8_start_new_cmd: no command to dequeue\n");
restore_flags(flags);
return;
@@ -515,9 +514,10 @@ h8_start_new_cmd(void)
* Take first command off of the command queue and put
* it on the active queue.
*/
- qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link);
- QUEUE_REMOVE(&h8_cmdq, qp, link);
- QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *);
+ qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link);
+ list_del(&qp->link);
+ /* XXX should this go to the end of the active queue? */
+ list_add(&qp->link, &h8_actq);
h8_state = H8_XMIT;
if (h8_debug & 0x1)
Dprintk("h8_start_new_cmd: Starting a command\n");
@@ -532,7 +532,7 @@ h8_start_new_cmd(void)
void
h8_send_next_cmd_byte(void)
{
- h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+ h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link);
int cnt;
cnt = qp->cnt;
@@ -689,7 +689,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
if (h8_debug & 0x40000)
printk("H8: Sync command done - byte returned was 0x%x\n",
qp->rcvbuf[0]);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_SN:
@@ -697,7 +697,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n",
qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_HW_VER:
@@ -705,13 +705,13 @@ h8_cmd_done(h8_cmd_q_t *qp)
case H8_RD_MAX_TEMP:
printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
qp->rcvbuf[0], qp->rcvbuf[1]);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_MIN_TEMP:
printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
qp->rcvbuf[0], qp->rcvbuf[1]);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_CURR_TEMP:
@@ -719,7 +719,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
xx.byte[0] = qp->rcvbuf[0];
xx.byte[1] = qp->rcvbuf[1];
wake_up(&h8_sync_wait);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_SYS_VARIENT:
@@ -740,7 +740,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
xx.byte[0] = qp->rcvbuf[1];
h8_sync_channel |= H8_GET_EXT_STATUS;
wake_up(&h8_sync_wait);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_USER_CFG:
@@ -755,7 +755,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
case H8_RD_INT_BATT_STATUS:
printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_RD_EXT_BATT_STATUS:
@@ -767,7 +767,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
printk("H8: Device control cmd done - byte returned was 0x%x\n",
qp->rcvbuf[0]);
}
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_CTL_TFT_BRT_DC:
@@ -788,7 +788,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
qp->rcvbuf[0]);
}
- QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ list_add(&qp->link, &h8_freeq);
break;
case H8_CTL_LOWER_TEMP:
diff --git a/drivers/char/h8.h b/drivers/char/h8.h
index b59aadea8..986eef591 100644
--- a/drivers/char/h8.h
+++ b/drivers/char/h8.h
@@ -229,7 +229,7 @@ struct h8_data {
* H8 command buffers
*/
typedef struct h8_cmd_q {
- DLNODE(struct h8_cmd_q) link; /* double linked list */
+ struct list_head link; /* double linked list */
int ncmd; /* number of bytes in command */
int nrsp; /* number of bytes in response */
int cnt; /* number of bytes sent/received */
@@ -238,10 +238,6 @@ typedef struct h8_cmd_q {
u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */
} h8_cmd_q_t;
-typedef struct __queue_head {
- DLNODE(struct h8_cmd_q) link;
-} queue_head_t;
-
union intr_buf {
u_char byte[2];
u_int word;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index bb00a32fa..fcf0644ff 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -783,13 +783,13 @@ int __init lp_init (void)
return -EIO;
}
+ devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL);
+
if (parport_register_driver (&lp_driver)) {
printk ("lp: unable to register with parport\n");
return -EIO;
}
- devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL);
-
if (!lp_count) {
printk (KERN_INFO "lp: driver loaded but no devices found\n");
#ifndef CONFIG_PARPORT_1284
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e70860ea9..824ef94e4 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -5,6 +5,7 @@
*
* Added devfs support.
* Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
+ * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
*/
#include <linux/config.h>
@@ -285,8 +286,7 @@ static ssize_t write_kmem(struct file * file, const char * buf,
return do_write_mem(file, (void*)p, p, buf, count, ppos);
}
-#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
- defined(CONFIG_HAVE_IO_PORTS)
+#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS)
static ssize_t read_port(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
@@ -435,7 +435,7 @@ out:
static int mmap_zero(struct file * file, struct vm_area_struct * vma)
{
if (vma->vm_flags & VM_SHARED)
- return -EINVAL;
+ return map_zero_setup(vma);
if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
@@ -515,8 +515,7 @@ static struct file_operations null_fops = {
write: write_null,
};
-#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
- defined(CONFIG_HAVE_IO_PORTS)
+#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS)
static struct file_operations port_fops = {
llseek: memory_lseek,
read: read_port,
@@ -550,8 +549,7 @@ static int memory_open(struct inode * inode, struct file * filp)
case 3:
filp->f_op = &null_fops;
break;
-#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
- defined(CONFIG_HAVE_IO_PORTS)
+#if (!defined(__mc68000__) && !defined(__mips__)) || defined(CONFIG_HAVE_IO_PORTS)
case 4:
filp->f_op = &port_fops;
break;
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
new file mode 100644
index 000000000..7c9bafc3b
--- /dev/null
+++ b/drivers/char/nwbutton.c
@@ -0,0 +1,276 @@
+/*
+ * NetWinder Button Driver-
+ * Copyright (C) Alex Holden <alex@linuxhacker.org> 1998, 1999.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#define __NWBUTTON_C /* Tell the header file who we are */
+#include "nwbutton.h"
+
+static int button_press_count = 0; /* The count of button presses */
+static struct timer_list button_timer; /* Times for the end of a sequence */
+static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */
+static char button_output_buffer[32]; /* Stores data to write out of device */
+static int bcount = 0; /* The number of bytes in the buffer */
+static int bdelay = BUTTON_DELAY; /* The delay, in jiffies */
+static struct button_callback button_callback_list[32]; /* The callback list */
+static int callback_count = 0; /* The number of callbacks registered */
+static int reboot_count = NUM_PRESSES_REBOOT; /* Number of presses to reboot */
+
+/*
+ * This function is called by other drivers to register a callback function
+ * to be called when a particular number of button presses occurs.
+ * The callback list is a static array of 32 entries (I somehow doubt many
+ * people are ever going to want to register more than 32 different actions
+ * to be performed by the kernel on different numbers of button presses ;).
+ * However, if an attempt to register a 33rd entry (perhaps a stuck loop
+ * somewhere registering the same entry over and over?) it will fail to
+ * do so and return -ENOMEM. If an attempt is made to register a null pointer,
+ * it will fail to do so and return -EINVAL.
+ * Because callbacks can be unregistered at random the list can become
+ * fragmented, so we need to search through the list until we find the first
+ * free entry.
+ */
+
+int button_add_callback (void (*callback) (void), int count)
+{
+ int lp = 0;
+ if (callback_count == 32) {
+ return -ENOMEM;
+ }
+ if (!callback) {
+ return -EINVAL;
+ }
+ callback_count++;
+ for (; (button_callback_list [lp].callback); lp++);
+ button_callback_list [lp].callback = callback;
+ button_callback_list [lp].count = count;
+ return 0;
+}
+
+/*
+ * This function is called by other drivers to deregister a callback function.
+ * If you attempt to unregister a callback which does not exist, it will fail
+ * with -EINVAL. If there is more than one entry with the same address,
+ * because it searches the list from end to beginning, it will unregister the
+ * last one to be registered first (FILO- First In Last Out).
+ * Note that this is not neccessarily true if the entries are not submitted
+ * at the same time, because another driver could have unregistered a callback
+ * between the submissions creating a gap earlier in the list, which would
+ * be filled first at submission time.
+ */
+
+int button_del_callback (void (*callback) (void))
+{
+ int lp = 31;
+ if (!callback) {
+ return -EINVAL;
+ }
+ while (lp >= 0) {
+ if ((button_callback_list [lp].callback) == callback) {
+ button_callback_list [lp].callback = NULL;
+ button_callback_list [lp].count = 0;
+ callback_count--;
+ return 0;
+ };
+ lp--;
+ };
+ return -EINVAL;
+}
+
+/*
+ * This function is called by button_sequence_finished to search through the
+ * list of callback functions, and call any of them whose count argument
+ * matches the current count of button presses. It starts at the beginning
+ * of the list and works up to the end. It will refuse to follow a null
+ * pointer (which should never happen anyway).
+ */
+
+static void button_consume_callbacks (int bpcount)
+{
+ int lp = 0;
+ for (; lp <= 31; lp++) {
+ if ((button_callback_list [lp].count) == bpcount) {
+ if (button_callback_list [lp].callback) {
+ button_callback_list[lp].callback();
+ }
+ }
+ }
+}
+
+/*
+ * This function is called when the button_timer times out.
+ * ie. When you don't press the button for bdelay jiffies, this is taken to
+ * mean you have ended the sequence of key presses, and this function is
+ * called to wind things up (write the press_count out to /dev/button, call
+ * any matching registered function callbacks, initiate reboot, etc.).
+ */
+
+static void button_sequence_finished (unsigned long parameters)
+{
+#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */
+ if (button_press_count == reboot_count) {
+ kill_proc (1, SIGINT, 1); /* Ask init to reboot us */
+ }
+#endif /* CONFIG_NWBUTTON_REBOOT */
+ button_consume_callbacks (button_press_count);
+ bcount = sprintf (button_output_buffer, "%d\n", button_press_count);
+ button_press_count = 0; /* Reset the button press counter */
+ wake_up_interruptible (&button_wait_queue);
+}
+
+/*
+ * This handler is called when the orange button is pressed (GPIO 10 of the
+ * SuperIO chip, which maps to logical IRQ 26). If the press_count is 0,
+ * this is the first press, so it starts a timer and increments the counter.
+ * If it is higher than 0, it deletes the old timer, starts a new one, and
+ * increments the counter.
+ */
+
+static void button_handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (button_press_count) {
+ del_timer (&button_timer);
+ }
+ button_press_count++;
+ init_timer (&button_timer);
+ button_timer.function = button_sequence_finished;
+ button_timer.expires = (jiffies + bdelay);
+ add_timer (&button_timer);
+}
+
+/*
+ * This function is called when a user space program attempts to read
+ * /dev/nwbutton. It puts the device to sleep on the wait queue until
+ * button_sequence_finished writes some data to the buffer and flushes
+ * the queue, at which point it writes the data out to the device and
+ * returns the number of characters it has written. This function is
+ * reentrant, so that many processes can be attempting to read from the
+ * device at any one time.
+ */
+
+static int button_read (struct file *filp, char *buffer,
+ size_t count, loff_t *ppos)
+{
+ interruptible_sleep_on (&button_wait_queue);
+ return (copy_to_user (buffer, &button_output_buffer, bcount))
+ ? -EFAULT : bcount;
+}
+
+/*
+ * This function is called when a user space process attempts to open the
+ * device. If the driver is compiled into the kernel it does nothing but
+ * succeed, but if it is compiled in as a module it also increments the
+ * module usage count to prevent the module from being removed whilst a
+ * process has the device open.
+ */
+
+static int button_open (struct inode *inode, struct file *filp)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * This function is called when a user space process attempts to close the
+ * device. If the driver is compiled into the kernel it does nothing at all,
+ * but if it is compiled in as a module it also decrements the module usage
+ * count so that it will be possible to unload the module again once all the
+ * user processes have closed the device.
+ */
+
+static int button_release (struct inode *inode, struct file *filp)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * This structure is the file operations structure, which specifies what
+ * callbacks functions the kernel should call when a user mode process
+ * attempts to perform these operations on the device.
+ */
+
+static struct file_operations button_fops = {
+ NULL, /* lseek */
+ button_read,
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ button_open,
+ NULL, /* flush */
+ button_release,
+};
+
+/*
+ * This structure is the misc device structure, which specifies the minor
+ * device number (158 in this case), the name of the device (for /proc/misc),
+ * and the address of the above file operations structure.
+ */
+
+static struct miscdevice button_misc_device = {
+ BUTTON_MINOR,
+ "nwbutton",
+ &button_fops,
+};
+
+/*
+ * This function is called to initialise the driver, either from misc.c at
+ * bootup if the driver is compiled into the kernel, or from init_module
+ * below at module insert time. It attempts to register the device node
+ * and the IRQ and fails with a warning message if either fails, though
+ * neither ever should because the device number and IRQ are unique to
+ * this driver.
+ */
+
+static int __init nwbutton_init(void)
+{
+ if (!machine_is_netwinder())
+ return -ENODEV;
+
+ printk (KERN_INFO "NetWinder Button Driver Version %s (C) Alex Holden "
+ "<alex@linuxhacker.org> 1998.\n", VERSION);
+
+ if (misc_register (&button_misc_device)) {
+ printk (KERN_WARNING "nwbutton: Couldn't register device 10, "
+ "%d.\n", BUTTON_MINOR);
+ return -EBUSY;
+ }
+
+ if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT,
+ "nwbutton", NULL)) {
+ printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n",
+ IRQ_NETWINDER_BUTTON);
+ misc_deregister (&button_misc_device);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void __exit nwbutton_exit (void)
+{
+ free_irq (IRQ_NETWINDER_BUTTON, NULL);
+ misc_deregister (&button_misc_device);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(nwbutton_init);
+module_exit(nwbutton_exit);
diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h
new file mode 100644
index 000000000..ba5067443
--- /dev/null
+++ b/drivers/char/nwbutton.h
@@ -0,0 +1,48 @@
+#ifndef __NWBUTTON_H
+#define __NWBUTTON_H
+
+/*
+ * NetWinder Button Driver-
+ * Copyright (C) Alex Holden <alex@linuxhacker.org> 1998, 1999.
+ */
+
+#ifdef __NWBUTTON_C /* Actually compiling the driver itself */
+
+/* Various defines: */
+
+#define NUM_PRESSES_REBOOT 2 /* How many presses to activate shutdown */
+#define BUTTON_DELAY 30 /* How many jiffies for sequence to end */
+#define VERSION "0.3" /* Driver version number */
+#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/nwbutton */
+
+/* Structure definitions: */
+
+struct button_callback {
+ void (*callback) (void);
+ int count;
+};
+
+/* Function prototypes: */
+
+static void button_sequence_finished (unsigned long parameters);
+static void button_handler (int irq, void *dev_id, struct pt_regs *regs);
+static int button_read (struct file *filp, char *buffer,
+ size_t count, loff_t *ppos);
+static int button_open (struct inode *inode, struct file *filp);
+static int button_release (struct inode *inode, struct file *filp);
+int button_init (void);
+int button_add_callback (void (*callback) (void), int count);
+int button_del_callback (void (*callback) (void));
+static void button_consume_callbacks (int bpcount);
+#ifdef MODULE
+int init_module (void);
+void cleanup_module (void);
+#endif /* MODULE */
+
+#else /* Not compiling the driver itself */
+
+extern int button_add_callback (void (*callback) (void), int count);
+extern int button_del_callback (void (*callback) (void));
+
+#endif /* __NWBUTTON_C */
+#endif /* __NWBUTTON_H */
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
new file mode 100644
index 000000000..a905be058
--- /dev/null
+++ b/drivers/char/nwflash.c
@@ -0,0 +1,708 @@
+/*
+ * Flash memory interface rev.5 driver for the Intel
+ * Flash chips used on the NetWinder.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/dec21285.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*****************************************************************************/
+#include <asm/nwflash.h>
+
+//#define MINIKERNEL 1 //export flash write, erase routines for MiniKernel
+
+#ifndef MINIKERNEL
+#define MSTATIC static
+#else
+#define MSTATIC
+#endif
+
+#define NWFLASH_VERSION "6.2"
+
+MSTATIC void kick_open(void);
+MSTATIC int get_flash_id(void);
+MSTATIC int erase_block(int nBlock);
+MSTATIC int write_block(unsigned long p, const char *buf, int count);
+static int open_flash(struct inode *inodep, struct file *filep);
+static int release_flash(struct inode *inodep, struct file *filep);
+static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg);
+static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos);
+static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
+static long long flash_llseek(struct file *file, long long offset, int orig);
+
+#define KFLASH_SIZE 1024*1024 //1 Meg
+#define KFLASH_SIZE4 4*1024*1024 //4 Meg
+#define KFLASH_ID 0x89A6 //Intel flash
+#define KFLASH_ID4 0xB0D4 //Intel flash 4Meg
+
+static int flashdebug = 0; //if set - we will display progress msgs
+
+static int gbWriteEnable = 0;
+static int gbWriteBase64Enable = 0;
+MSTATIC int gbFlashSize = KFLASH_SIZE;
+
+extern spinlock_t gpio_lock;
+
+static struct file_operations flash_fops =
+{
+ flash_llseek, /* llseek */
+ flash_read, /* read */
+ flash_write, /* write */
+ NULL, /* no special readdir */
+ NULL, /* no special select */
+ flash_ioctl,
+ NULL, /* no special mmap */
+ open_flash,
+ NULL, /* no special flush */
+ release_flash,
+ NULL, /* no special fsync */
+ NULL, /* no special fasync */
+ NULL, /* no special check_media_change */
+ NULL /* no special revaldate */
+};
+
+static struct miscdevice flash_miscdev =
+{
+ FLASH_MINOR,
+ "nwflash",
+ &flash_fops
+};
+
+/*
+ * the delay routine - it is often required to let the flash "breeze"...
+ */
+void flash_wait(int timeout)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(timeout);
+}
+
+MSTATIC int get_flash_id(void)
+{
+ volatile unsigned int c1, c2;
+
+ /*
+ * try to get flash chip ID
+ */
+ kick_open();
+ c2 = inb(0x80);
+ *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90;
+ udelay(15);
+ c1 = *(unsigned char *) FLASH_BASE;
+ c2 = inb(0x80);
+
+ /*
+ * on 4 Meg flash the second byte is actually at offset 2...
+ */
+ if (c1 == 0xB0)
+ c2 = *(unsigned char *) (FLASH_BASE + 2);
+ else
+ c2 = *(unsigned char *) (FLASH_BASE + 1);
+
+ c2 += (c1 << 8);
+
+ /*
+ * set it back to read mode
+ */
+ *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF;
+
+ if (c2 == KFLASH_ID4)
+ gbFlashSize = KFLASH_SIZE4;
+
+ return c2;
+}
+
+static int open_flash(struct inode *inodep, struct file *filep)
+{
+ int id;
+
+ id = get_flash_id();
+ if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
+ printk("Flash: incorrect ID 0x%04X.\n", id);
+ return -ENXIO;
+ }
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+
+static int release_flash(struct inode *inodep, struct file *filep)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+
+static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
+{
+// printk("Flash_ioctl: cmd = 0x%X.\n",cmd);
+
+ switch (cmd) {
+ case CMD_WRITE_DISABLE:
+ gbWriteBase64Enable = 0;
+ gbWriteEnable = 0;
+ break;
+
+ case CMD_WRITE_ENABLE:
+ gbWriteEnable = 1;
+ break;
+
+ case CMD_WRITE_BASE64K_ENABLE:
+ gbWriteBase64Enable = 1;
+ break;
+
+ default:
+ gbWriteBase64Enable = 0;
+ gbWriteEnable = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+
+static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+ unsigned long p = file->f_pos;
+ int read;
+
+ if (flashdebug)
+ printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n",
+ (unsigned int) p, (unsigned int) buf, count);
+
+
+ if (count < 0)
+ return -EINVAL;
+
+ if (count > gbFlashSize - p)
+ count = gbFlashSize - p;
+
+ /*
+ * flash virtual address
+ */
+ p += FLASH_BASE;
+
+ read = 0;
+
+ if (copy_to_user(buf, (void *) p, count))
+ return -EFAULT;
+ read += count;
+ file->f_pos += read;
+ return read;
+}
+
+static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+ unsigned long p = file->f_pos;
+ int written;
+ int nBlock, temp, rc;
+ int i, j;
+
+
+ if (flashdebug)
+ printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n",
+ (unsigned int) p, (unsigned int) buf, count);
+
+ if (!gbWriteEnable)
+ return -EINVAL;
+
+ if (p < 64 * 1024 && (!gbWriteBase64Enable))
+ return -EINVAL;
+
+ if (count < 0)
+ return -EINVAL;
+
+ /*
+ * if write size to big - error!
+ */
+ if (count > gbFlashSize - p)
+ return -EINVAL;
+
+
+ if (verify_area(VERIFY_READ, buf, count))
+ return -EFAULT;
+
+
+ written = 0;
+
+ leds_event(led_claim);
+ leds_event(led_green_on);
+
+ nBlock = (int) p >> 16; //block # of 64K bytes
+
+ /*
+ * # of 64K blocks to erase and write
+ */
+ temp = ((int) (p + count) >> 16) - nBlock + 1;
+
+ /*
+ * write ends at exactly 64k boundry?
+ */
+ if (((int) (p + count) & 0xFFFF) == 0)
+ temp -= 1;
+
+ if (flashdebug)
+ printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock);
+
+ for (; temp; temp--, nBlock++) {
+ if (flashdebug)
+ printk("FlashWrite: erasing block %d.\n", nBlock);
+
+ /*
+ * first we have to erase the block(s), where we will write...
+ */
+ i = 0;
+ j = 0;
+ RetryBlock:
+ do {
+ rc = erase_block(nBlock);
+ i++;
+ } while (rc && i < 10);
+
+ if (rc) {
+ if (flashdebug)
+ printk("FlashWrite: erase error %X. Aborting...\n", rc);
+
+ break;
+ }
+ if (flashdebug)
+ printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n",
+ (unsigned int) p, (unsigned int) buf, count - written);
+
+ /*
+ * write_block will limit write to space left in this block
+ */
+ rc = write_block(p, buf, count - written);
+ j++;
+
+ /*
+ * if somehow write verify failed? Can't happen??
+ */
+ if (!rc) {
+ /*
+ * retry up to 10 times
+ */
+ if (j < 10)
+ goto RetryBlock;
+ else
+ /*
+ * else quit with error...
+ */
+ rc = -1;
+
+ }
+ if (rc < 0) {
+ if (flashdebug)
+ printk("FlashWrite: write error %X. Aborting...\n", rc);
+ break;
+ }
+ p += rc;
+ buf += rc;
+ written += rc;
+ file->f_pos += rc;
+
+ if (flashdebug)
+ printk("FlashWrite: written 0x%X bytes OK.\n", written);
+ }
+
+ /*
+ * restore reg on exit
+ */
+ leds_event(led_release);
+
+ return written;
+}
+
+
+/*
+ * The memory devices use the full 32/64 bits of the offset, and so we cannot
+ * check against negative addresses: they are ok. The return value is weird,
+ * though, in that case (0).
+ *
+ * also note that seeking relative to the "end of file" isn't supported:
+ * it has no meaning, so it returns -EINVAL.
+ */
+static long long flash_llseek(struct file *file, long long offset, int orig)
+{
+ if (flashdebug)
+ printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n",
+ (unsigned int) offset, (unsigned int) orig);
+
+ switch (orig) {
+ case 0:
+ if (offset < 0)
+ return -EINVAL;
+
+ if ((unsigned int) offset > gbFlashSize)
+ return -EINVAL;
+
+ file->f_pos = (unsigned int) offset;
+ return file->f_pos;
+ case 1:
+ if ((file->f_pos + offset) > gbFlashSize)
+ return -EINVAL;
+ if ((file->f_pos + offset) < 0)
+ return -EINVAL;
+ file->f_pos += offset;
+ return file->f_pos;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/*
+ * assume that main Write routine did the parameter checking...
+ * so just go ahead and erase, what requested!
+ */
+
+MSTATIC int erase_block(int nBlock)
+{
+ volatile unsigned int c1;
+ volatile unsigned char *pWritePtr;
+ int temp, temp1;
+
+ /*
+ * orange LED == erase
+ */
+ leds_event(led_amber_on);
+
+ /*
+ * reset footbridge to the correct offset 0 (...0..3)
+ */
+ *CSR_ROMWRITEREG = 0;
+
+ /*
+ * dummy ROM read
+ */
+ c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000);
+
+ kick_open();
+ /*
+ * reset status if old errors
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
+
+ /*
+ * erase a block...
+ * aim at the middle of a current block...
+ */
+ pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + 0x8000 + (nBlock << 16)));
+ /*
+ * dummy read
+ */
+ c1 = *pWritePtr;
+
+ kick_open();
+ /*
+ * erase
+ */
+ *(volatile unsigned char *) pWritePtr = 0x20;
+
+ /*
+ * confirm
+ */
+ *(volatile unsigned char *) pWritePtr = 0xD0;
+
+ /*
+ * wait 10 ms
+ */
+ flash_wait(HZ / 100);
+
+ /*
+ * wait while erasing in process (up to 10 sec)
+ */
+ temp = jiffies + 10 * HZ;
+ c1 = 0;
+ while (!(c1 & 0x80) && time_before(jiffies, temp)) {
+ flash_wait(HZ / 100);
+ /*
+ * read any address
+ */
+ c1 = *(volatile unsigned char *) (pWritePtr);
+ // printk("Flash_erase: status=%X.\n",c1);
+ }
+
+ /*
+ * set flash for normal read access
+ */
+ kick_open();
+// *(volatile unsigned char*)(FLASH_BASE+0x8000) = 0xFF;
+ *(volatile unsigned char *) pWritePtr = 0xFF; //back to normal operation
+
+ /*
+ * check if erase errors were reported
+ */
+ if (c1 & 0x20) {
+ if (flashdebug)
+ printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr);
+ /*
+ * reset error
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
+
+ return -2;
+ }
+
+ /*
+ * just to make sure - verify if erased OK...
+ */
+ flash_wait(HZ / 100);
+
+ pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16)));
+
+ for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) {
+ if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) {
+ if (flashdebug)
+ printk("Flash_erase: verify err at %X = %X.\n",
+ (unsigned int) pWritePtr, temp1);
+ return -1;
+ }
+ }
+
+ return 0;
+
+}
+
+/*
+ * write_block will limit number of bytes written to the space in this block
+ */
+MSTATIC int write_block(unsigned long p, const char *buf, int count)
+{
+ volatile unsigned int c1;
+ volatile unsigned int c2;
+ unsigned char *pWritePtr;
+ unsigned int uAddress;
+ unsigned int offset;
+ unsigned int timeout;
+ unsigned int timeout1;
+
+ /*
+ * red LED == write
+ */
+ leds_event(led_amber_off);
+ leds_event(led_red_on);
+
+ pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
+
+ /*
+ * check if write will end in this block....
+ */
+ offset = p & 0xFFFF;
+
+ if (offset + count > 0x10000)
+ count = 0x10000 - offset;
+
+ /*
+ * wait up to 30 sec for this block
+ */
+ timeout = jiffies + 30 * HZ;
+
+ for (offset = 0; offset < count; offset++, pWritePtr++) {
+ uAddress = (unsigned int) pWritePtr;
+ uAddress &= 0xFFFFFFFC;
+ if (__get_user(c2, buf + offset))
+ return -EFAULT;
+
+ WriteRetry:
+ /*
+ * dummy read
+ */
+ c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000);
+
+ /*
+ * kick open the write gate
+ */
+ kick_open();
+
+ /*
+ * program footbridge to the correct offset...0..3
+ */
+ *CSR_ROMWRITEREG = (unsigned int) pWritePtr & 3;
+
+ /*
+ * write cmd
+ */
+ *(volatile unsigned char *) (uAddress) = 0x40;
+
+ /*
+ * data to write
+ */
+ *(volatile unsigned char *) (uAddress) = c2;
+
+ /*
+ * get status
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x10000) = 0x70;
+
+ c1 = 0;
+
+ /*
+ * wait up to 1 sec for this byte
+ */
+ timeout1 = jiffies + 1 * HZ;
+
+ /*
+ * while not ready...
+ */
+ while (!(c1 & 0x80) && time_before(jiffies, timeout1))
+ c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000);
+
+ /*
+ * if timeout getting status
+ */
+ if (time_after_eq(jiffies, timeout1)) {
+ kick_open();
+ /*
+ * reset err
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
+
+ goto WriteRetry;
+ }
+ /*
+ * switch on read access, as a default flash operation mode
+ */
+ kick_open();
+ /*
+ * read access
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF;
+
+ /*
+ * if hardware reports an error writing, and not timeout -
+ * reset the chip and retry
+ */
+ if (c1 & 0x10) {
+ kick_open();
+ /*
+ * reset err
+ */
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
+
+ /*
+ * before timeout?
+ */
+ if (time_before(jiffies, timeout)) {
+ if (flashdebug)
+ printk("FlashWrite: Retrying write (addr=0x%X)...\n",
+ (unsigned int) pWritePtr - FLASH_BASE);
+
+ /*
+ * no LED == waiting
+ */
+ leds_event(led_amber_off);
+ /*
+ * wait couple ms
+ */
+ flash_wait(HZ / 100);
+ /*
+ * red LED == write
+ */
+ leds_event(led_red_on);
+
+ goto WriteRetry;
+ } else {
+ printk("Timeout in flash write! (addr=0x%X) Aborting...\n",
+ (unsigned int) pWritePtr - FLASH_BASE);
+ /*
+ * return error -2
+ */
+ return -2;
+
+ }
+ }
+ }
+
+ /*
+ * green LED == read/verify
+ */
+ leds_event(led_amber_off);
+ leds_event(led_green_on);
+
+ flash_wait(HZ / 100);
+
+ pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
+
+ for (offset = 0; offset < count; offset++) {
+ char c, c1;
+ if (__get_user(c, buf))
+ return -EFAULT;
+ buf++;
+ if ((c1 = *pWritePtr++) != c) {
+ if (flashdebug)
+ printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n",
+ (unsigned int) pWritePtr, c1, c);
+ return 0;
+ }
+ }
+
+ return count;
+}
+
+
+MSTATIC void kick_open(void)
+{
+ unsigned long flags;
+
+ /*
+ * we want to write a bit pattern XXX1 to Xilinx to enable
+ * the write gate, which will be open for about the next 2ms.
+ */
+ spin_lock_irqsave(&gpio_lock, flags);
+ cpld_modify(1, 1);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ /*
+ * let the ISA bus to catch on...
+ */
+ udelay(25);
+}
+
+MSTATIC int __init nwflash_init(void)
+{
+ int ret = -ENODEV;
+
+ if (machine_is_netwinder()) {
+ int id;
+
+ id = get_flash_id();
+ printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n",
+ NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024));
+
+ misc_register(&flash_miscdev);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+MSTATIC void __exit nwflash_exit(void)
+{
+ misc_deregister(&flash_miscdev);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(flashdebug, "i");
+
+module_init(nwflash_init);
+module_exit(nwflash_exit);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 6ffbb517c..61dfd6e42 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -197,7 +197,12 @@ int raw_ctl_ioctl(struct inode *inode,
raw_device_bindings[minor] =
bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
} else {
- kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev);
+ kdev_t dev;
+ if (!raw_device_bindings[minor]) {
+ err = -ENODEV;
+ break;
+ }
+ dev = to_kdev_t(raw_device_bindings[minor]->bd_dev);
rq.block_major = MAJOR(dev);
rq.block_minor = MINOR(dev);
err = copy_to_user((void *) arg, &rq, sizeof(rq));
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 6296e789b..f68c65afe 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -36,9 +36,11 @@
* 1.09b Jeff Garzik: Modularize, init cleanup
* 1.09c Jeff Garzik: SMP cleanup
* 1.10 Paul Barton-Davis: add support for async I/O
+ * 1.10a Andrea Arcangeli: Alpha updates
+ * 1.10b Andrew Morton: SMP lock fix
*/
-#define RTC_VERSION "1.10"
+#define RTC_VERSION "1.10b"
#define RTC_IRQ 8 /* Can't see this changing soon. */
#define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */
@@ -378,7 +380,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
if (yrs > 169) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return -EINVAL;
}
if (yrs >= 100)
@@ -706,7 +708,9 @@ static void __exit rtc_exit (void)
free_irq (rtc_irq, &rtc_port);
#else
release_region (RTC_PORT (0), RTC_IO_EXTENT);
+#ifndef __alpha__
free_irq (RTC_IRQ, NULL);
+#endif
#endif /* __sparc__ */
}
diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c
new file mode 100644
index 000000000..b5dc94e2f
--- /dev/null
+++ b/drivers/char/wdt285.c
@@ -0,0 +1,204 @@
+/*
+ * Intel 21285 watchdog driver
+ * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
+ *
+ * based on
+ *
+ * SoftDog 0.05: A Software Watchdog Device
+ *
+ * (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
+ * http://www.cymru.net
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/dec21285.h>
+
+/*
+ * Define this to stop the watchdog actually rebooting the machine.
+ */
+#undef ONLY_TESTING
+
+#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */
+
+#define FCLK (50*1000*1000) /* 50MHz */
+
+static int soft_margin = TIMER_MARGIN; /* in seconds */
+static int timer_alive = 0;
+
+#ifdef ONLY_TESTING
+/*
+ * If the timer expires..
+ */
+
+static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs)
+{
+ printk(KERN_CRIT "Watchdog: Would Reboot.\n");
+ *CSR_TIMER4_CNTL = 0;
+ *CSR_TIMER4_CLR = 0;
+}
+#endif
+
+static void watchdog_ping(void)
+{
+ /*
+ * Refresh the timer.
+ */
+ *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256);
+}
+
+/*
+ * Allow only one person to hold it open
+ */
+
+static int watchdog_open(struct inode *inode, struct file *file)
+{
+ if(timer_alive)
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+ /*
+ * Ahead watchdog factor ten, Mr Sulu
+ */
+ *CSR_TIMER4_CLR = 0;
+ watchdog_ping();
+ *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
+ | TIMER_CNTL_DIV256;
+#ifdef ONLY_TESTING
+ request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
+#else
+ *CSR_SA110_CNTL |= 1 << 13;
+#endif
+ timer_alive = 1;
+ return 0;
+}
+
+static int watchdog_release(struct inode *inode, struct file *file)
+{
+#ifdef ONLY_TESTING
+ free_irq(IRQ_TIMER4, NULL);
+ timer_alive = 0;
+ MOD_DEC_USE_COUNT;
+#else
+ /*
+ * It's irreversible!
+ */
+#endif
+ return 0;
+}
+
+static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /*
+ * Refresh the timer.
+ */
+ if(len)
+ {
+ watchdog_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static int watchdog_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int i;
+ static struct watchdog_info ident=
+ {
+ 0,
+ 0,
+ "Footbridge Watchdog"
+ };
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info));
+ if (i)
+ return i;
+ else
+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0,(int *)arg);
+ case WDIOC_KEEPALIVE:
+ watchdog_ping();
+ return 0;
+ }
+}
+
+static struct file_operations watchdog_fops=
+{
+ NULL, /* Seek */
+ NULL, /* Read */
+ watchdog_write, /* Write */
+ NULL, /* Readdir */
+ NULL, /* Select */
+ watchdog_ioctl, /* Ioctl */
+ NULL, /* MMap */
+ watchdog_open,
+ NULL, /* flush */
+ watchdog_release,
+ NULL,
+ NULL /* Fasync */
+};
+
+static struct miscdevice watchdog_miscdev=
+{
+ WATCHDOG_MINOR,
+ "watchdog",
+ &watchdog_fops
+};
+
+static int __init footbridge_watchdog_init(void)
+{
+ if (machine_is_netwinder())
+ return -ENODEV;
+
+ misc_register(&watchdog_miscdev);
+ printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
+ soft_margin);
+ if (machine_is_cats())
+ printk("Warning: Watchdog reset may not work on this machine.\n");
+ return 0;
+}
+
+static void __exit footbridge_watchdog_exit(void)
+{
+ misc_deregister(&watchdog_miscdev);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");
+MODULE_DESCRIPTION("21285 watchdog driver");
+
+MODULE_PARM(soft_margin,"i");
+MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds");
+
+module_init(footbridge_watchdog_init);
+module_exit(footbridge_watchdog_exit);
diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c
new file mode 100644
index 000000000..c45e63d60
--- /dev/null
+++ b/drivers/char/wdt977.c
@@ -0,0 +1,204 @@
+/*
+ * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip
+ *
+ * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
+ *
+ * -----------------------
+ *
+ * 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.
+ *
+ * -----------------------
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define WATCHDOG_MINOR 130
+
+static int timeout = 3;
+static int timer_alive = 0;
+static int testmode = 0;
+
+/*
+ * Allow only one person to hold it open
+ */
+
+static int wdt977_open(struct inode *inode, struct file *file)
+{
+ if(timer_alive)
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+ timer_alive++;
+
+ //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
+ if (timeout>255)
+ timeout = 255;
+
+ printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout);
+
+ // unlock the SuperIO chip
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
+ //F2 has the timeout in minutes
+ //F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
+ // at timeout, and to reset timer on kbd/mouse activity (not now)
+ //F4 is used to just clear the TIMEOUT'ed state (bit 0)
+
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF2,0x370);
+ outb(timeout,0x371);
+ outb(0xF3,0x370);
+ outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED
+ outb(0xF4,0x370);
+ outb(0x00,0x371);
+
+ //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+ if (!testmode)
+ {
+ outb(0x07,0x370);
+ outb(0x07,0x371);
+ outb(0xE6,0x370);
+ outb(0x08,0x371);
+ }
+
+ // lock the SuperIO chip
+ outb(0xAA,0x370);
+
+ return 0;
+}
+
+static int wdt977_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ * Lock it in if it's a module and we defined ...NOWAYOUT
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+
+ // unlock the SuperIO chip
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+ //F3 is reset to its default state
+ //F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+ //We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF2,0x370);
+ outb(0xFF,0x371);
+ outb(0xF3,0x370);
+ outb(0x00,0x371);
+ outb(0xF4,0x370);
+ outb(0x00,0x371);
+ outb(0xF2,0x370);
+ outb(0x00,0x371);
+
+ //at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+ outb(0x07,0x370);
+ outb(0x07,0x371);
+ outb(0xE6,0x370);
+ outb(0x08,0x371);
+
+ // lock the SuperIO chip
+ outb(0xAA,0x370);
+
+ MOD_DEC_USE_COUNT;
+ timer_alive=0;
+
+ printk(KERN_INFO "Watchdog: shutdown.\n");
+#endif
+ return 0;
+}
+
+static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+
+ //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
+ if (timeout>255)
+ timeout = 255;
+
+ /*
+ * Refresh the timer.
+ */
+
+ //we have a hw bug somewhere, so each 977 minute is actually only 30sec
+ //as such limit the max timeout to half of max of 255 minutes...
+// if (timeout>126)
+// timeout = 126;
+
+ // unlock the SuperIO chip
+ outb(0x87,0x370);
+ outb(0x87,0x370);
+
+ //select device Aux2 (device=8) and kicks watchdog reg F2
+ //F2 has the timeout in minutes
+
+ outb(0x07,0x370);
+ outb(0x08,0x371);
+ outb(0xF2,0x370);
+ outb(timeout,0x371);
+
+ // lock the SuperIO chip
+ outb(0xAA,0x370);
+
+ return 1;
+}
+
+static struct file_operations wdt977_fops=
+{
+ NULL, /* Seek */
+ NULL, /* Read */
+ wdt977_write, /* Write */
+ NULL, /* Readdir */
+ NULL, /* Select */
+ NULL, /* Ioctl */
+ NULL, /* MMap */
+ wdt977_open,
+ NULL, /* flush */
+ wdt977_release,
+ NULL,
+ NULL /* Fasync */
+};
+
+static struct miscdevice wdt977_miscdev=
+{
+ WATCHDOG_MINOR,
+ "watchdog",
+ &wdt977_fops
+};
+
+static int __init nwwatchdog_init(void)
+{
+ if (!machine_is_netwinder())
+ return -ENODEV;
+
+ misc_register(&wdt977_miscdev);
+ printk(KERN_INFO "NetWinder Watchdog sleeping.\n");
+ return 0;
+}
+
+static void __exit nwwatchdog_exit(void)
+{
+ misc_deregister(&wdt977_miscdev);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(nwwatchdog_init);
+module_exit(nwwatchdog_exit);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index c98cb7c6f..493befb7d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -101,10 +101,6 @@ static struct file_operations i2cproc_operations = {
read: i2cproc_bus_read,
};
-static struct inode_operations i2cproc_inode_operations = {
- &i2cproc_operations
-};
-
static int i2cproc_initialized = 0;
#else /* undef CONFIG_PROC_FS */
@@ -163,7 +159,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)
name);
return -ENOENT;
}
- proc_entry->ops = &i2cproc_inode_operations;
+ proc_entry->proc_fops = &i2cproc_operations;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
proc_entry->owner = THIS_MODULE;
#else
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index 8bf595282..d61b88375 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -1,11 +1,14 @@
/*
- * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $
+ * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil 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.3 2000/02/26 01:00:53 keil
+ * changes from 2.3.47
+ *
* Revision 1.2 2000/01/25 14:44:47 calle
* typo in b1pciv4_detect().
*
@@ -31,7 +34,7 @@
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.2 $";
+static char *revision = "$Revision: 1.3 $";
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 62f246407..fb8a32460 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,14 @@
/*
- * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $
+ * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.23 2000/02/26 01:00:53 keil
+ * changes from 2.3.47
+ *
* Revision 1.22 1999/11/13 21:27:16 keil
* remove KERNELVERSION
*
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 110b5a172..de56823c0 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -315,8 +315,6 @@ static struct file_operations isdn_fops =
NULL /* fsync */
};
-struct inode_operations divert_file_inode_operations;
-
/****************************/
/* isdn subdir in /proc/net */
/****************************/
@@ -342,9 +340,7 @@ divert_dev_init(void)
remove_proc_entry("isdn", proc_net);
return (-1);
}
- memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations));
- divert_file_inode_operations.default_file_ops = &isdn_fops;
- isdn_divert_entry->ops = &divert_file_inode_operations;
+ isdn_divert_entry->proc_fops = &isdn_fops;
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c
index e53469070..eb3590069 100644
--- a/drivers/isdn/eicon/eicon_idi.c
+++ b/drivers/isdn/eicon/eicon_idi.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
* IDI interface
@@ -26,6 +26,13 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_idi.c,v $
+ * Revision 1.31 2000/02/22 16:26:40 armin
+ * Fixed membase error message.
+ * Fixed missing log buffer struct.
+ *
+ * Revision 1.30 2000/02/16 16:08:46 armin
+ * Fixed virtual channel handling of IDI.
+ *
* Revision 1.29 2000/01/23 21:21:23 armin
* Added new trace capability and some updates.
* DIVA Server BRI now supports data for ISDNLOG.
@@ -149,7 +156,7 @@
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.29 $";
+char *eicon_idi_revision = "$Revision: 1.31 $";
eicon_manifbuf *manbuf;
@@ -255,10 +262,10 @@ idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
}
int
-idi_put_req(eicon_REQ *reqbuf, int rq, int signet)
+idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch)
{
reqbuf->Req = rq;
- reqbuf->ReqCh = 0;
+ reqbuf->ReqCh = Ch;
reqbuf->ReqId = 1;
reqbuf->XBuffer.length = 1;
reqbuf->XBuffer.P[0] = 0;
@@ -368,34 +375,34 @@ idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
break;
case REMOVE:
case REMOVE|0x700:
- idi_put_req(reqbuf, REMOVE, layer);
+ idi_put_req(reqbuf, REMOVE, layer, 0);
break;
case INDICATE_REQ:
- idi_put_req(reqbuf, INDICATE_REQ, 0);
+ idi_put_req(reqbuf, INDICATE_REQ, 0, 0);
break;
case HANGUP:
- idi_put_req(reqbuf, HANGUP, 0);
+ idi_put_req(reqbuf, HANGUP, 0, 0);
break;
case REJECT:
- idi_put_req(reqbuf, REJECT, 0);
+ idi_put_req(reqbuf, REJECT, 0 ,0);
break;
case CALL_ALERT:
- idi_put_req(reqbuf, CALL_ALERT, 0);
+ idi_put_req(reqbuf, CALL_ALERT, 0, 0);
break;
case CALL_RES:
idi_call_res_req(reqbuf, chan);
break;
case IDI_N_CONNECT|0x700:
- idi_put_req(reqbuf, IDI_N_CONNECT, 1);
+ idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0);
break;
case IDI_N_CONNECT_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1);
+ idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0);
break;
case IDI_N_DISC|0x700:
- idi_put_req(reqbuf, IDI_N_DISC, 1);
+ idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh);
break;
case IDI_N_DISC_ACK|0x700:
- idi_put_req(reqbuf, IDI_N_DISC_ACK, 1);
+ idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh);
break;
default:
eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
@@ -813,6 +820,11 @@ idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsi
message->osa[i] = buffer[pos++];
eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
break;
+ case CAD:
+ pos += wlen;
+ eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n",
+ chan->No, wlen);
+ break;
case BC:
if (wlen > sizeof(message->bc)) {
pos += wlen;
@@ -1206,7 +1218,7 @@ idi_send_edata(eicon_card *card, eicon_chan *chan)
reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
reqbuf->Req = IDI_N_EDATA;
- reqbuf->ReqCh = 0;
+ reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
@@ -2205,7 +2217,7 @@ idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int
reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
reqbuf->Req = IDI_N_UDATA;
- reqbuf->ReqCh = 0;
+ reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
reqbuf->XBuffer.length = len + 1;
@@ -2322,7 +2334,7 @@ eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len)
unsigned char data[1];
} *q;
- if (!(p = kmalloc(buflen, GFP_KERNEL))) {
+ if (!(p = kmalloc(buflen, GFP_ATOMIC))) {
eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n");
return;
}
@@ -2380,7 +2392,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
return;
}
- if (ind->Ind != 8)
+ if ((ind->Ind != 8) && (ind->Ind != 0xc))
dlev = 144;
else
dlev = 128;
@@ -2634,6 +2646,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
break;
case IDI_N_CONNECT:
eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
+ chan->e.IndCh = ind->IndCh;
if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
if (chan->l2prot == ISDN_PROTO_L2_FAX) {
break;
@@ -2664,6 +2677,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
idi_fax_hangup(ccard, chan);
}
#endif
+ chan->e.IndCh = 0;
save_flags(flags);
cli();
chan->queued = 0;
@@ -2693,7 +2707,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
#endif
break;
case IDI_N_DATA_ACK:
- eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+ eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
break;
case IDI_N_DATA:
skb_pull(skb, sizeof(eicon_IND) - 1);
@@ -2774,6 +2788,11 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
} else {
/* Network layer */
switch(chan->e.Req & 0x0f) {
+ case IDI_N_CONNECT:
+ chan->e.IndCh = ack->RcCh;
+ eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
+ ack->RcId, ack->RcCh, ack->Reference);
+ break;
case IDI_N_MDATA:
case IDI_N_DATA:
if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
@@ -2999,7 +3018,7 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb,
reqbuf->Req = IDI_N_DATA;
if (ack) reqbuf->Req |= N_D_BIT;
}
- reqbuf->ReqCh = 0;
+ reqbuf->ReqCh = chan->e.IndCh;
reqbuf->ReqId = 1;
memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen);
reqbuf->XBuffer.length = plen;
diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c
index 86e6c0ef7..265e07e08 100644
--- a/drivers/isdn/eicon/eicon_isa.c
+++ b/drivers/isdn/eicon/eicon_isa.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $
*
* ISDN low-level module for Eicon active ISDN-Cards.
* Hardware-specific code for old ISA cards.
@@ -22,6 +22,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_isa.c,v $
+ * Revision 1.14 2000/02/22 16:26:40 armin
+ * Fixed membase error message.
+ * Fixed missing log buffer struct.
+ *
* Revision 1.13 2000/01/23 21:21:23 armin
* Added new trace capability and some updates.
* DIVA Server BRI now supports data for ISDNLOG.
@@ -83,7 +87,7 @@
#define release_shmem release_region
#define request_shmem request_region
-char *eicon_isa_revision = "$Revision: 1.13 $";
+char *eicon_isa_revision = "$Revision: 1.14 $";
#undef EICON_MCA_DEBUG
@@ -146,6 +150,9 @@ eicon_isa_find_card(int Mem, int Irq, char * Id)
if (!strlen(Id))
return -1;
+ if (Mem == -1)
+ return -1;
+
/* Check for valid membase address */
if ((Mem < 0x0c0000) ||
(Mem > 0x0fc000) ||
diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
index 688d74de3..9bc91d6f4 100644
--- a/drivers/isdn/eicon/eicon_mod.c
+++ b/drivers/isdn/eicon/eicon_mod.c
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $
*
* ISDN lowlevel-module for Eicon active cards.
*
@@ -31,6 +31,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: eicon_mod.c,v $
+ * Revision 1.25 2000/02/22 16:26:40 armin
+ * Fixed membase error message.
+ * Fixed missing log buffer struct.
+ *
* Revision 1.24 2000/01/23 21:21:23 armin
* Added new trace capability and some updates.
* DIVA Server BRI now supports data for ISDNLOG.
@@ -140,7 +144,7 @@
static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
start of card-list */
-static char *eicon_revision = "$Revision: 1.24 $";
+static char *eicon_revision = "$Revision: 1.25 $";
extern char *eicon_pci_revision;
extern char *eicon_isa_revision;
@@ -886,8 +890,10 @@ eicon_putstatus(eicon_card * card, char * buf)
u_char *p;
struct sk_buff *skb;
- if (!card)
- return;
+ if (!card) {
+ if (!(card = cards))
+ return;
+ }
save_flags(flags);
cli();
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 319e0b264..d87c43f37 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -1,4 +1,4 @@
-/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $
+/* $Id: avm_pci.c,v 1.15 2000/02/26 00:35:12 keil Exp $
* avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
* Thanks to AVM, Berlin for informations
@@ -7,6 +7,9 @@
*
*
* $Log: avm_pci.c,v $
+ * Revision 1.15 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.14 1999/12/19 13:09:41 keil
* changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
* signal proof delays
@@ -63,7 +66,7 @@
#include <linux/interrupt.h>
extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.14 $";
+static const char *avm_pci_rev = "$Revision: 1.15 $";
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
@@ -499,7 +502,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) {
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hdlc.count = 0;
bcs->tx_skb = NULL;
}
@@ -626,7 +629,7 @@ close_hdlcstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 8d389c623..377819551 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,10 +1,13 @@
-/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $
+/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log: config.c,v $
+ * Revision 2.44 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 2.43 2000/01/20 19:49:36 keil
* Support teles 13.3c vendor version 2.1
*
@@ -549,9 +552,9 @@ HiSaxVersion(void))
printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
#ifdef MODULE
- printk(KERN_INFO "HiSax: Version 3.3d (module)\n");
+ printk(KERN_INFO "HiSax: Version 3.3e (module)\n");
#else
- printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n");
+ printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n");
#endif
strcpy(tmp, l1_revision);
printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 5dc868942..30c6331a5 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $
+/* $Id: diva.c,v 1.19 2000/02/26 00:35:12 keil Exp $
* diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards
*
@@ -12,6 +12,9 @@
*
*
* $Log: diva.c,v $
+ * Revision 1.19 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.18 1999/12/19 13:09:41 keil
* changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
* signal proof delays
@@ -84,7 +87,7 @@
extern const char *CardType[];
-const char *Diva_revision = "$Revision: 1.18 $";
+const char *Diva_revision = "$Revision: 1.19 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -585,7 +588,7 @@ Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 529a74815..8bff1db1c 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -298,7 +298,7 @@ modem_fill(struct BCState *bcs) {
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st,
bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
}
@@ -442,13 +442,13 @@ close_elsastate(struct BCState *bcs)
bcs->hw.hscx.rcvbuf = NULL;
}
while ((skb = skb_dequeue(&bcs->rqueue))) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
while ((skb = skb_dequeue(&bcs->squeue))) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 2b22cdfea..bc4665863 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.12 2000/02/26 00:35:12 keil Exp $
*
* specific routines for CCD's HFC 2BDS0
*
@@ -6,6 +6,9 @@
*
*
* $Log: hfc_2bds0.c,v $
+ * Revision 1.12 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.11 1999/12/23 15:09:32 keil
* change email
*
@@ -293,7 +296,7 @@ static struct sk_buff
sti();
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
skb = NULL;
} else {
cli();
@@ -309,7 +312,7 @@ static struct sk_buff
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
bcs->err_crc++;
@@ -401,7 +404,7 @@ hfc_fill_fifo(struct BCState *bcs)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
WaitForBusy(cs);
@@ -603,7 +606,7 @@ close_2bs0(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -751,7 +754,7 @@ int receive_dmsg(struct IsdnCardState *cs)
sti();
debugl1(cs, "RFIFO D BUSY error");
printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
cs->err_rx++;
@@ -770,7 +773,7 @@ int receive_dmsg(struct IsdnCardState *cs)
chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
cs->err_crc++;
@@ -870,7 +873,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
cli();
WaitNoBusy(cs);
ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND);
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
sti();
WaitForBusy(cs);
@@ -1004,7 +1007,7 @@ hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val)
}
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index f3edefa3e..8a1d29762 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $
+/* $Id: hfc_2bs0.c,v 1.13 2000/02/26 00:35:12 keil Exp $
* specific routines for CCD's HFC 2BS0
*
@@ -6,6 +6,9 @@
*
*
* $Log: hfc_2bs0.c,v $
+ * Revision 1.13 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.12 1999/12/19 14:17:12 keil
* fix compiler warning
*
@@ -249,7 +252,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
if (idx != count) {
debugl1(cs, "RFIFO BUSY error");
printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
if (bcs->mode != L1_MODE_TRANS) {
WaitNoBusy(cs);
stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC |
@@ -270,7 +273,7 @@ hfc_empty_fifo(struct BCState *bcs, int count)
bcs->channel, chksum, stat);
if (stat) {
debugl1(cs, "FIFO CRC error");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
skb = NULL;
#ifdef ERROR_STATISTIC
bcs->err_crc++;
@@ -359,7 +362,7 @@ hfc_fill_fifo(struct BCState *bcs)
bcs->tx_cnt -= count;
if (PACKET_NOACK == bcs->tx_skb->pkt_type)
count = -1;
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
if (bcs->mode != L1_MODE_TRANS) {
WaitForBusy(cs);
@@ -573,7 +576,7 @@ close_hfcstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 76f353861..f2e7abf10 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $
+/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $
* hfc_pci.c low level driver for CCD´s hfc-pci based cards
*
@@ -23,6 +23,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hfc_pci.c,v $
+ * Revision 1.27 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.26 2000/02/09 20:22:55 werner
*
* Updated PCI-ID table
@@ -126,7 +129,7 @@
extern const char *CardType[];
-static const char *hfcpci_revision = "$Revision: 1.26 $";
+static const char *hfcpci_revision = "$Revision: 1.27 $";
/* table entry in the PCI devices list */
typedef struct {
@@ -636,7 +639,7 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
df->f1 = new_f1; /* next frame */
restore_flags(flags);
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
return;
}
@@ -710,7 +713,7 @@ hfcpci_fill_fifo(struct BCState *bcs)
debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
bcs->channel, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
cli();
bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
sti();
@@ -778,7 +781,7 @@ hfcpci_fill_fifo(struct BCState *bcs)
bz->f1 = new_f1; /* next frame */
restore_flags(flags);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
return;
@@ -1130,7 +1133,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
@@ -1522,7 +1525,7 @@ close_hfcpci(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 462de9d91..85040aabf 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1,4 +1,4 @@
-/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $
+/* $Id: hfc_sx.c,v 1.4 2000/02/26 00:35:12 keil Exp $
* hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards
*
@@ -22,6 +22,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: hfc_sx.c,v $
+ * Revision 1.4 2000/02/26 00:35:12 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.3 2000/01/20 19:49:36 keil
* Support teles 13.3c vendor version 2.1
*
@@ -38,6 +41,7 @@
*
*/
+#include <linux/config.h>
#define __NO_VERSION__
#include "hisax.h"
#include "hfc_sx.h"
@@ -46,7 +50,7 @@
extern const char *CardType[];
-static const char *hfcsx_revision = "$Revision: 1.3 $";
+static const char *hfcsx_revision = "$Revision: 1.4 $";
/***************************************/
/* IRQ-table for CCDs demo board */
@@ -327,7 +331,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */
Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */
if (Read_hfc(cs, HFCSX_FIF_DRD)) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
if (cs->debug & L1_DEB_ISAC_FIFO)
debugl1(cs, "hfcsx_read_fifo %d crc error", fifo);
skb = NULL;
@@ -600,7 +604,7 @@ hfcsx_fill_dfifo(struct IsdnCardState *cs)
return;
if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
return;
@@ -633,7 +637,7 @@ hfcsx_fill_fifo(struct BCState *bcs)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
@@ -777,7 +781,7 @@ receive_emsg(struct IsdnCardState *cs)
} else
HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
}
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
} while (--count && skb);
@@ -931,7 +935,7 @@ hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
@@ -1305,7 +1309,7 @@ close_hfcsx(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 6f5b5615c..da55eb2df 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,8 +1,11 @@
-/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $
+/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $
* Basic declarations, defines and prototypes
*
* $Log: hisax.h,v $
+ * Revision 2.41 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 2.40 2000/01/20 19:51:46 keil
* Fix AddTimer message
* Change CONFIG defines
@@ -157,8 +160,9 @@
#include <linux/isdnif.h>
#include <linux/tty.h>
#include <linux/serial_reg.h>
+#include <linux/netdevice.h>
-#undef ERROR_STATISTIC
+#define ERROR_STATISTIC
#define REQUEST 0
#define CONFIRM 1
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
index 1c57cd3f1..092b23243 100644
--- a/drivers/isdn/hisax/hscx.c
+++ b/drivers/isdn/hisax/hscx.c
@@ -1,4 +1,4 @@
-/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $
+/* $Id: hscx.c,v 1.18 2000/02/26 00:35:13 keil Exp $
* hscx.c HSCX specific routines
*
@@ -6,6 +6,9 @@
*
*
* $Log: hscx.c,v $
+ * Revision 1.18 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.17 1999/07/01 08:11:41 keil
* Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
*
@@ -219,7 +222,7 @@ close_hscxstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c
index 655508f70..821f5bc8b 100644
--- a/drivers/isdn/hisax/hscx_irq.c
+++ b/drivers/isdn/hisax/hscx_irq.c
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $
+/* $Id: hscx_irq.c,v 1.14 2000/02/26 00:35:13 keil Exp $
* hscx_irq.c low level b-channel stuff for Siemens HSCX
*
@@ -7,6 +7,9 @@
* This is an include file for fast inline IRQ stuff
*
* $Log: hscx_irq.c,v $
+ * Revision 1.14 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.13 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -250,7 +253,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index a992f76c4..07c76cf2f 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -1,4 +1,4 @@
-/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $
+/* $Id: isac.c,v 1.25 2000/02/26 00:35:13 keil Exp $
* isac.c ISAC specific routines
*
@@ -9,6 +9,9 @@
* ../../../Documentation/isdn/HiSax.cert
*
* $Log: isac.c,v $
+ * Revision 1.25 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.24 1999/10/14 20:25:28 keil
* add a statistic for error monitoring
*
@@ -338,7 +341,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
isac_fill_fifo(cs);
goto afterXPR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
@@ -627,7 +630,7 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
discard_queue(&cs->rq);
discard_queue(&cs->sq);
if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
@@ -683,7 +686,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index bfff86707..d53dc729a 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -1,4 +1,4 @@
-/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $
+/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $
* isar.c ISAR (Siemens PSB 7110) specific routines
*
@@ -6,6 +6,9 @@
*
*
* $Log: isar.c,v $
+ * Revision 1.10 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.9 2000/01/20 19:47:45 keil
* Add Fax Class 1 support
*
@@ -774,7 +777,7 @@ send_frames(struct BCState *bcs)
}
}
}
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->hw.isar.txcnt = 0;
bcs->tx_skb = NULL;
}
@@ -1631,7 +1634,7 @@ close_isarstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
if (bcs->cs->debug & L1_DEB_HSCX)
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index 4f07eed87..c1bf72ca8 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -1,10 +1,13 @@
-/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $
+/* $Id: jade.c,v 1.3 2000/02/26 00:35:13 keil Exp $
*
* jade.c JADE stuff (derived from original hscx.c)
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: jade.c,v $
+ * Revision 1.3 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.2 1999/07/01 08:07:57 keil
* Initial version
*
@@ -214,7 +217,7 @@ close_jadestate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
index e54c80c1a..02fef2627 100644
--- a/drivers/isdn/hisax/jade_irq.c
+++ b/drivers/isdn/hisax/jade_irq.c
@@ -1,10 +1,13 @@
-/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $
+/* $Id: jade_irq.c,v 1.3 2000/02/26 00:35:13 keil Exp $
*
* jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c)
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log: jade_irq.c,v $
+ * Revision 1.3 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.2 1999/07/01 08:07:59 keil
* Initial version
*
@@ -192,7 +195,7 @@ jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 9fa10e326..2b0451a0a 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -1,4 +1,4 @@
-/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $
+/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $
* EURO/DSS1 D-channel protocol
*
@@ -13,6 +13,9 @@
* Fritz Elfert
*
* $Log: l3dss1.c,v $
+ * Revision 2.23 2000/02/26 01:38:14 keil
+ * Fixes for V.110 encoding LLC from Jens Jakobsen
+ *
* Revision 2.22 2000/01/20 19:44:20 keil
* Fixed uninitialiesed location
* Fixed redirecting number IE in Setup
@@ -104,7 +107,7 @@
#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.22 $";
+const char *dss1_revision = "$Revision: 2.23 $";
#define EXT_BEARER_CAPS 1
@@ -1045,7 +1048,8 @@ u_char *
EncodeASyncParams(u_char * p, u_char si2)
{ // 7c 06 88 90 21 42 00 bb
- p[0] = p[1] = 0;
+ p[0] = 0;
+ p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
p[2] = 0x80;
if (si2 & 32) // 7 data bits
@@ -1059,7 +1063,7 @@ EncodeASyncParams(u_char * p, u_char si2)
p[2] += 96;
else // 1 stop bit
- p[2] = 32;
+ p[2] += 32;
if (si2 & 8) // even parity
diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc
index 985bd4cb4..afb83e1c8 100644
--- a/drivers/isdn/hisax/md5sums.asc
+++ b/drivers/isdn/hisax/md5sums.asc
@@ -6,26 +6,26 @@
# Eicon Technology Diva 2.01 PCI cards in the moment.
# Read ../../../Documentation/isdn/HiSax.cert for more informations.
#
-3c2b1c96274cba97a8261d1cecc662b8 isac.c
-a9a15d069dbacb383cc24c238cb5ebbe isdnl1.c
+3fb9c99465857a4c136ae2881f4e30ba isac.c
+dd3955847bbf680b41233478fe521d88 isdnl1.c
bb51bd223040b511c18f091da5ab6456 isdnl2.c
b7aa7f97b2374967a4aca7c52991142c isdnl3.c
a23fbf8879c1432b04640b8b04bdf419 tei.c
-d7072dbbeeb7c4c45f3810ed13cf5545 callc.c
+ce248e56c2e1326012d0b25f92bbf99b callc.c
bf9605b36429898f7be6630034e83230 cert.c
-0e500813968adacaea2ef22c9cdd89eb l3dss1.c
-2d748ced0eea375b21fe7ea91ca7917c l3_1tr6.c
-d45fde1c90dda636ab134f2a51db435e elsa.c
-0b5fb429f5bfe188fd42a5be01abbb14 diva.c
+6ce0a184127be1a44747e2017ed24ad9 l3dss1.c
+a3a570781f828b6d59e6b231653133de l3_1tr6.c
+4aeba32c4c3480d2a6b9af34600b974f elsa.c
+a296edc459b508bf0346c3132815a4db diva.c
# end of md5sums
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3i
Charset: noconv
-iQCVAwUBOCYF6jpxHvX/mS9tAQFnxQP/dpHyNjbo5BhFEZ8qIgpPJzoCgV+b2pB+
-h9Z/Q1jg8l23L/lP9dW00ogrKnKziVUUJqg+wWVEAA7BnNVr3aeyQKFTVuOnK5MC
-Oy0Z98p530vgOBiZ47elNfpefjhfD3duSSYNA4R9fEHVZB/atKFYvB5GDGmrwjIZ
-2f3g3kBP5Os=
-=zNnO
+iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR
+HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd
+BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS
+ZMQ1pb9W6jE=
+=CA5N
-----END PGP SIGNATURE-----
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 3855625bd..b1b0fd8d4 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $
+/* $Id: netjet.c,v 1.18 2000/02/26 00:35:13 keil Exp $
* netjet.c low level stuff for Traverse Technologie NETJet ISDN cards
*
@@ -7,6 +7,9 @@
* Thanks to Traverse Technologie Australia for documents and informations
*
* $Log: netjet.c,v $
+ * Revision 1.18 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.17 1999/12/19 13:09:42 keil
* changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
* signal proof delays
@@ -85,7 +88,7 @@
extern const char *CardType[];
-const char *NETjet_revision = "$Revision: 1.17 $";
+const char *NETjet_revision = "$Revision: 1.18 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -730,7 +733,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
}
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
@@ -873,7 +876,7 @@ close_tigerstate(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 724ce52c9..c6fe2acdd 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1,4 +1,4 @@
-/* $Id: w6692.c,v 1.1 1999/09/04 06:28:58 keil Exp $
+/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $
* w6692.c Winbond W6692 specific routines
*
@@ -8,6 +8,9 @@
* This file is (c) under GNU PUBLIC LICENSE
*
* $Log: w6692.c,v $
+ * Revision 1.2 2000/02/26 00:35:13 keil
+ * Fix skb freeing in interrupt context
+ *
* Revision 1.1 1999/09/04 06:28:58 keil
* first revision
*
@@ -47,7 +50,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.1 $";
+const char *w6692_revision = "$Revision: 1.2 $";
#define DBUSY_TIMER_VALUE 80
@@ -378,7 +381,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count);
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_irq(bcs->tx_skb);
bcs->hw.w6692.count = 0;
bcs->tx_skb = NULL;
}
@@ -478,7 +481,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
W6692_fill_fifo(cs);
goto afterXFR;
} else {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_irq(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
}
@@ -655,7 +658,7 @@ W6692_l1hw(struct PStack *st, int pr, void *arg)
discard_queue(&cs->rq);
discard_queue(&cs->sq);
if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
}
if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
@@ -704,7 +707,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
/* discard frame; reset transceiver */
test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
if (cs->tx_skb) {
- dev_kfree_skb(cs->tx_skb);
+ dev_kfree_skb_any(cs->tx_skb);
cs->tx_cnt = 0;
cs->tx_skb = NULL;
} else {
@@ -819,7 +822,7 @@ close_w6692state(struct BCState *bcs)
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
- dev_kfree_skb(bcs->tx_skb);
+ dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 81e1b84f0..4cb480588 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -416,8 +416,6 @@ static struct file_operations conf_fops =
NULL /* fsync */
};
-static struct inode_operations conf_inode_operations;
-
/*****************************/
/* hysdn subdir in /proc/net */
/*****************************/
@@ -446,10 +444,8 @@ hysdn_procconf_init(void)
if ((card->procconf = (void *) create_proc_entry(conf_name,
S_IFREG | S_IRUGO | S_IWUSR,
hysdn_proc_entry)) != NULL) {
- memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
- conf_inode_operations.default_file_ops = &conf_fops;
- ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
+ ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c
index d70d350e9..b43e2ade7 100644
--- a/drivers/isdn/hysdn/hysdn_procfs.c
+++ b/drivers/isdn/hysdn/hysdn_procfs.c
@@ -351,27 +351,6 @@ static struct file_operations log_fops =
NULL /* fsync */
};
-struct inode_operations log_inode_operations =
-{
- &log_fops, /* log proc file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
-};
-
/*****************************************/
/* Output info data to the cardinfo file */
/*****************************************/
@@ -464,7 +443,7 @@ hysdn_procfs_init(void)
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
- pd->log->ops = &log_inode_operations; /* set new operations table */
+ pd->log->proc_fops = &log_fops; /* set new operations table */
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index aea6a96ad..67a91cf0f 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -433,8 +433,6 @@ static struct file_operations log_fops =
NULL /* fsync */
};
-struct inode_operations log_inode_operations;
-
/***********************************************************************************/
/* hysdn_proclog_init is called when the module is loaded after creating the cards */
/* conf files. */
@@ -448,12 +446,10 @@ hysdn_proclog_init(hysdn_card * card)
if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
memset(pd, 0, sizeof(struct procdata));
- memset(&log_inode_operations, 0, sizeof(struct inode_operations));
- log_inode_operations.default_file_ops = &log_fops;
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL)
- pd->log->ops = &log_inode_operations; /* set new operations table */
+ pd->log->proc_fops = &log_fops; /* set new operations table */
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index f1df11f55..b259cdc4b 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $
+/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -21,6 +21,12 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.99 2000/02/26 01:00:52 keil
+ * changes from 2.3.47
+ *
+ * Revision 1.98 2000/02/16 14:56:27 paul
+ * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers
+ *
* Revision 1.97 2000/01/23 18:45:37 keil
* Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
*
@@ -443,7 +449,7 @@
isdn_dev *dev = (isdn_dev *) 0;
-static char *isdn_revision = "$Revision: 1.97 $";
+static char *isdn_revision = "$Revision: 1.99 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -1795,15 +1801,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int i;
if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+ (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
* ISDN_MAX_CHANNELS)))
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if (copy_to_user(p, dev->mdm.info[i].emu.profile,
- ISDN_MODEM_ANZREG))
+ ISDN_MODEM_NUMREG))
return -EFAULT;
- p += ISDN_MODEM_ANZREG;
+ p += ISDN_MODEM_NUMREG;
if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
return -EFAULT;
p += ISDN_MSNLEN;
@@ -1811,7 +1817,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
return -EFAULT;
p += ISDN_LMSNLEN;
}
- return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+ return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
} else
return -EINVAL;
break;
@@ -1822,15 +1828,15 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
int i;
if ((ret = verify_area(VERIFY_READ, (void *) arg,
- (ISDN_MODEM_ANZREG + ISDN_MSNLEN)
+ (ISDN_MODEM_NUMREG + ISDN_MSNLEN)
* ISDN_MAX_CHANNELS)))
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
if (copy_from_user(dev->mdm.info[i].emu.profile, p,
- ISDN_MODEM_ANZREG))
+ ISDN_MODEM_NUMREG))
return -EFAULT;
- p += ISDN_MODEM_ANZREG;
+ p += ISDN_MODEM_NUMREG;
if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
return -EFAULT;
p += ISDN_MSNLEN;
@@ -2632,7 +2638,7 @@ static void isdn_cleanup_devfs(void)
devfs_unregister (devfs_handle);
}
-#else /* CONFIG_DEVFS_FS */
+#else /* CONFIG_DEVFS_FS */
static void isdn_register_devfs(int dummy)
{
return;
@@ -2653,7 +2659,7 @@ static void isdn_cleanup_devfs(void)
return;
}
-#endif /* CONFIG_DEVFS_FS */
+#endif /* CONFIG_DEVFS_FS */
/*
* Allocate and initialize all data, register modem-devices
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 592d20ed9..ee3af91fa 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $
+/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -21,6 +21,16 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_net.c,v $
+ * Revision 1.110 2000/02/26 01:00:53 keil
+ * changes from 2.3.47
+ *
+ * Revision 1.109 2000/02/25 11:29:17 paul
+ * changed chargetime to ulong from int (after about 20 days the "chargetime of
+ * ipppX is now 1234" message displays a negative number on alpha).
+ *
+ * Revision 1.108 2000/02/15 12:54:01 kai
+ * set TX timeout back to 2 secs for 2.2.x, just to be safe
+ *
* Revision 1.107 2000/02/13 09:52:05 kai
* increased TX_TIMEOUT to 20sec
*
@@ -521,6 +531,14 @@ static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
netif_wake_queue(&lp->netdev->dev);
}
+/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
+ * to be safe.
+ * For 2.3.x we push it up to 20 secs, because call establishment
+ * (in particular callback) may take such a long time, and we
+ * don't want confusing messages in the log. However, there is a slight
+ * possibility that this large timeout will break other things like MPPP,
+ * which might rely on the tx timeout. If so, we'll find out this way...
+ */
#define ISDN_NET_TX_TIMEOUT (20*HZ)
@@ -530,7 +548,7 @@ int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *);
-char *isdn_net_revision = "$Revision: 1.107 $";
+char *isdn_net_revision = "$Revision: 1.110 $";
/*
* Code for raw-networking over ISDN
@@ -727,7 +745,7 @@ isdn_net_autohup()
isdn_net_hangup(&p->dev);
} else if (jiffies - l->chargetime > l->chargeint) {
printk(KERN_DEBUG
- "isdn_net: %s: chtime = %d, chint = %d\n",
+ "isdn_net: %s: chtime = %lu, chint = %d\n",
l->name, l->chargetime, l->chargeint);
isdn_net_hangup(&p->dev);
}
@@ -868,7 +886,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
* we correct the timestamp here.
*/
lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n",
+ printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n",
lp->name, lp->chargetime);
/* reset dial-timeout */
@@ -915,7 +933,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
if (lp->hupflags & ISDN_WAITCHARGE)
lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
- printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n",
+ printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
lp->name, lp->chargetime);
return 1;
}
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index 0503c67a2..1e314128c 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $
+/* $Id: isdn_tty.c,v 1.84 2000/02/16 15:10:14 paul Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,15 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.84 2000/02/16 15:10:14 paul
+ * If a ttyI has no open FDs, don't connect incoming calls to it.
+ * (Hangup on close of last FD is still to be done.)
+ *
+ * Revision 1.83 2000/02/16 14:59:33 paul
+ * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers;
+ * used defines for result codes;
+ * fixed RING ... RUNG problem (no empty lines in between).
+ *
* Revision 1.82 2000/01/23 18:45:37 keil
* Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
*
@@ -379,7 +388,7 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.82 $";
+char *isdn_tty_revision = "$Revision: 1.84 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -901,7 +910,7 @@ static void
isdn_tty_modem_do_ncarrier(unsigned long data)
{
modem_info *info = (modem_info *) data;
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
}
/* Next routine is called, whenever the DTR-signal is raised.
@@ -986,7 +995,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
- isdn_tty_modem_result(6, info);
+ isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
@@ -1056,8 +1065,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
if (info->online) {
info->last_lhup = local;
info->online = 0;
- /* NO CARRIER message */
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
}
#ifdef CONFIG_ISDN_AUDIO
info->vonline = 0;
@@ -1086,7 +1094,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
#endif
if ((info->msr & UART_MSR_RI) &&
(info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
- isdn_tty_modem_result(12, info);
+ isdn_tty_modem_result(RESULT_RUNG, info);
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
info->lsr |= UART_LSR_TEMT;
if (info->isdn_driver >= 0) {
@@ -1197,7 +1205,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
- isdn_tty_modem_result(6, info);
+ isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
@@ -1265,7 +1273,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
l = strlen(msg);
if (!l) {
- isdn_tty_modem_result(4, info);
+ isdn_tty_modem_result(RESULT_ERROR, info);
return;
}
for (j = 7; j >= 0; j--)
@@ -1291,7 +1299,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
if (i < 0) {
restore_flags(flags);
- isdn_tty_modem_result(6, info);
+ isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
info->isdn_driver = dev->drvmap[i];
info->isdn_channel = dev->chanmap[i];
@@ -1589,7 +1597,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
#endif
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
isdn_tty_modem_hup(info, 1);
} else
c = isdn_tty_edit_at(buf, c, info, from_user);
@@ -2321,7 +2329,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force)
{
atemu *m = &info->emu;
if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
- memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
+ memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
@@ -2338,7 +2346,7 @@ isdn_tty_modem_reset_regs(modem_info * info, int force)
static void
modem_write_profile(atemu * m)
{
- memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
+ memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
if (dev->profd)
@@ -2447,6 +2455,13 @@ isdn_tty_modem_init(void)
return 0;
}
+
+/*
+ * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
+ * match the MSN against the MSNs (glob patterns) defined for tty_emulator,
+ * and return 0 for match, 1 for no match, 2 if MSN could match if longer.
+ */
+
static int
isdn_tty_match_icall(char *cid, atemu *emu, int di)
{
@@ -2512,15 +2527,14 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
int idx;
int si1;
int si2;
- char nr[32];
+ char *nr;
ulong flags;
if (!setup.phone[0]) {
- nr[0] = '0';
- nr[1] = '\0';
+ nr = "0";
printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
} else
- strcpy(nr, setup.phone);
+ nr = setup.phone;
si1 = (int) setup.si1;
si2 = (int) setup.si2;
if (!setup.eazmsn[0]) {
@@ -2537,6 +2551,8 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
+ if (info->count == 0)
+ continue;
if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
(info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
idx = isdn_dc2minor(di, ch);
@@ -2574,7 +2590,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup)
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
info->line);
info->msr |= UART_MSR_RI;
- isdn_tty_modem_result(2, info);
+ isdn_tty_modem_result(RESULT_RING, info);
isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
return 1;
}
@@ -2660,9 +2676,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#endif
if (TTY_IS_ACTIVE(info)) {
if (info->dialing == 1)
- isdn_tty_modem_result(7, info);
+ isdn_tty_modem_result(RESULT_BUSY, info);
if (info->dialing > 1)
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
info->dialing = 0;
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
@@ -2691,12 +2707,12 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
if (USG_MODEM(dev->usage[i])) {
if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
strcpy(info->emu.connmsg, c->parm.num);
- isdn_tty_modem_result(1, info);
+ isdn_tty_modem_result(RESULT_CONNECT, info);
} else
- isdn_tty_modem_result(5, info);
+ isdn_tty_modem_result(RESULT_CONNECT64000, info);
}
if (USG_VOICE(dev->usage[i]))
- isdn_tty_modem_result(11, info);
+ isdn_tty_modem_result(RESULT_VCON, info);
return 1;
}
break;
@@ -2722,7 +2738,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
info->last_l2 = -1;
info->last_si = 0;
sprintf(info->last_cause, "0000");
- isdn_tty_modem_result(6, info);
+ isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
}
isdn_tty_modem_hup(info, 0);
return 1;
@@ -2937,6 +2953,7 @@ isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
* For CONNECT-messages also switch to online-mode.
* For RING-message handle auto-ATA if register 0 != 0
*/
+
static void
isdn_tty_modem_result(int code, modem_info * info)
{
@@ -2949,14 +2966,13 @@ isdn_tty_modem_result(int code, modem_info * info)
char s[ISDN_MSNLEN+10];
switch (code) {
- case 2:
- m->mdmreg[REG_RINGCNT]++; /* RING */
+ case RESULT_RING:
+ m->mdmreg[REG_RINGCNT]++;
if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
/* Automatically accept incoming call */
isdn_tty_cmd_ATA(info);
break;
- case 3:
- /* NO CARRIER */
+ case RESULT_NO_CARRIER:
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
(info->flags & ISDN_ASYNC_CLOSING),
@@ -2991,13 +3007,13 @@ isdn_tty_modem_result(int code, modem_info * info)
}
#endif
break;
- case 1:
- case 5:
+ case RESULT_CONNECT:
+ case RESULT_CONNECT64000:
sprintf(info->last_cause, "0000");
if (!info->online)
info->online = 2;
break;
- case 11:
+ case RESULT_VCON:
#ifdef ISDN_DEBUG_MODEM_VOICE
printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
info->line);
@@ -3006,27 +3022,30 @@ isdn_tty_modem_result(int code, modem_info * info)
if (!info->online)
info->online = 1;
break;
- }
+ } /* switch(code) */
+
if (m->mdmreg[REG_RESP] & BIT_RESP) {
/* Show results */
- isdn_tty_at_cout("\r\n", info);
if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
- /* Show numeric results */
- sprintf(s, "%d", code);
+ /* Show numeric results only */
+ sprintf(s, "\r\n%d\r\n", code);
isdn_tty_at_cout(s, info);
} else {
- if ((code == 2) &&
- (m->mdmreg[REG_RUNG] & BIT_RUNG) &&
- (m->mdmreg[REG_RINGCNT] > 1))
- return;
- if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) {
- isdn_tty_at_cout("CALLER NUMBER: ", info);
- isdn_tty_at_cout(dev->num[info->drv_index], info);
- isdn_tty_at_cout("\r\n", info);
+ if (code == RESULT_RING) {
+ /* return if "show RUNG" and ringcounter>1 */
+ if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
+ (m->mdmreg[REG_RINGCNT] > 1))
+ return;
+ /* print CID, _before_ _every_ ring */
+ if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
+ isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
+ isdn_tty_at_cout(dev->num[info->drv_index], info);
+ }
}
+ isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout(msg[code], info);
switch (code) {
- case 1:
+ case RESULT_CONNECT:
switch (m->mdmreg[REG_L2PROT]) {
case ISDN_PROTO_L2_MODEM:
isdn_tty_at_cout(" ", info);
@@ -3034,13 +3053,13 @@ isdn_tty_modem_result(int code, modem_info * info)
break;
}
break;
- case 2:
+ case RESULT_RING:
/* Append CPN, if enabled */
if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
sprintf(s, "/%s", m->cpn);
isdn_tty_at_cout(s, info);
}
- /* Print CID only once, _after_ 1.st RING */
+ /* Print CID only once, _after_ 1st RING */
if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
(m->mdmreg[REG_RINGCNT] == 1)) {
isdn_tty_at_cout("\r\n", info);
@@ -3048,10 +3067,10 @@ isdn_tty_modem_result(int code, modem_info * info)
isdn_tty_at_cout(dev->num[info->drv_index], info);
}
break;
- case 3:
- case 6:
- case 7:
- case 8:
+ case RESULT_NO_CARRIER:
+ case RESULT_NO_DIALTONE:
+ case RESULT_BUSY:
+ case RESULT_NO_ANSWER:
m->mdmreg[REG_RINGCNT] = 0;
/* Append Cause-Message if enabled */
if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
@@ -3059,7 +3078,7 @@ isdn_tty_modem_result(int code, modem_info * info)
isdn_tty_at_cout(s, info);
}
break;
- case 5:
+ case RESULT_CONNECT64000:
/* Append Protocol to CONNECT message */
switch (m->mdmreg[REG_L2PROT]) {
case ISDN_PROTO_L2_X75I:
@@ -3087,10 +3106,10 @@ isdn_tty_modem_result(int code, modem_info * info)
}
break;
}
+ isdn_tty_at_cout("\r\n", info);
}
- isdn_tty_at_cout("\r\n", info);
}
- if (code == 3) {
+ if (code == RESULT_NO_CARRIER) {
save_flags(flags);
cli();
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
@@ -3108,6 +3127,7 @@ isdn_tty_modem_result(int code, modem_info * info)
}
}
+
/*
* Display a modem-register-value.
*/
@@ -3160,8 +3180,8 @@ isdn_tty_getdial(char *p, char *q,int cnt)
*q = 0;
}
-#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; }
-#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; }
+#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
+#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
static void
isdn_tty_report(modem_info * info)
@@ -3329,8 +3349,8 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
/* &L -Set Numbers to listen on */
p[0]++;
i = 0;
- while ((strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN) && *p[0])
+ while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
+ (i < ISDN_LMSNLEN))
m->lmsn[i++] = *p[0]++;
m->lmsn[i] = '\0';
break;
@@ -3381,7 +3401,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
/* &V - Show registers */
p[0]++;
isdn_tty_at_cout("\r\n", info);
- for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
+ for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
sprintf(rb, "S%02d=%03d%s", i,
m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
isdn_tty_at_cout(rb, info);
@@ -3486,7 +3506,7 @@ isdn_tty_cmd_ATS(char **p, modem_info * info)
int bval;
mreg = isdn_getnum(p);
- if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG)
+ if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
PARSE_ERROR1;
switch (*p[0]) {
case '=':
@@ -3589,7 +3609,7 @@ isdn_tty_cmd_ATA(modem_info * info)
isdn_command(&cmd);
isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
} else
- isdn_tty_modem_result(8, info);
+ isdn_tty_modem_result(RESULT_NO_ANSWER, info);
}
#ifdef CONFIG_ISDN_AUDIO
@@ -3779,7 +3799,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
if (!m->vpar[0])
PARSE_ERROR1;
if (info->online != 1) {
- isdn_tty_modem_result(8, info);
+ isdn_tty_modem_result(RESULT_NO_ANSWER, info);
return 1;
}
info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
@@ -3803,7 +3823,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
printk(KERN_DEBUG "AT: +VRX\n");
#endif
info->vonline |= 1;
- isdn_tty_modem_result(1, info);
+ isdn_tty_modem_result(RESULT_CONNECT, info);
return 0;
break;
case 4:
@@ -3893,7 +3913,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
if (!m->vpar[0])
PARSE_ERROR1;
if (info->online != 1) {
- isdn_tty_modem_result(8, info);
+ isdn_tty_modem_result(RESULT_NO_ANSWER, info);
return 1;
}
info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
@@ -3913,7 +3933,7 @@ isdn_tty_cmd_PLUSV(char **p, modem_info * info)
#endif
m->lastDLE = 0;
info->vonline |= 2;
- isdn_tty_modem_result(1, info);
+ isdn_tty_modem_result(RESULT_CONNECT, info);
return 0;
break;
case 7:
@@ -3998,13 +4018,13 @@ isdn_tty_parse_at(modem_info * info)
if (info->msr & UART_MSR_DCD)
PARSE_ERROR;
if (info->msr & UART_MSR_RI) {
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
return;
}
isdn_tty_getdial(++p, ds, sizeof ds);
p += strlen(p);
if (!strlen(m->msn))
- isdn_tty_modem_result(10, info);
+ isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
else if (strlen(ds))
isdn_tty_dial(ds, info, m);
else
@@ -4076,9 +4096,9 @@ isdn_tty_parse_at(modem_info * info)
p++;
if (info->msr & UART_MSR_DCD)
/* if B-Channel is up */
- isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info);
+ isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info);
else
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
return;
case 'Q':
/* Q - Turn Emulator messages on/off */
@@ -4171,7 +4191,7 @@ isdn_tty_parse_at(modem_info * info)
#ifdef CONFIG_ISDN_AUDIO
if (!info->vonline)
#endif
- isdn_tty_modem_result(0, info);
+ isdn_tty_modem_result(RESULT_OK, info);
}
/* Need own toupper() because standard-toupper is not available
@@ -4282,7 +4302,7 @@ isdn_tty_modem_escape(void)
((jiffies - info->emu.lastplus) > PLUSWAIT2)) {
info->emu.pluscount = 0;
info->online = 0;
- isdn_tty_modem_result(0, info);
+ isdn_tty_modem_result(RESULT_OK, info);
}
}
}
@@ -4304,7 +4324,7 @@ isdn_tty_modem_ring(void)
modem_info *info = &dev->mdm.info[i];
if (info->msr & UART_MSR_RI) {
ton = 1;
- isdn_tty_modem_result(2, info);
+ isdn_tty_modem_result(RESULT_RING, info);
}
}
isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
@@ -4346,7 +4366,7 @@ isdn_tty_carrier_timeout(void)
if (info->dialing) {
if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
info->dialing = 0;
- isdn_tty_modem_result(3, info);
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
isdn_tty_modem_hup(info, 1);
}
else
diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h
index ff7e479f0..ed9190cfe 100644
--- a/drivers/isdn/isdn_tty.h
+++ b/drivers/isdn/isdn_tty.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $
+/* $Id: isdn_tty.h,v 1.19 2000/02/16 14:59:33 paul Exp $
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
@@ -20,6 +20,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.h,v $
+ * Revision 1.19 2000/02/16 14:59:33 paul
+ * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers;
+ * used defines for result codes;
+ * fixed RING ... RUNG problem (no empty lines in between).
+ *
* Revision 1.18 2000/01/20 19:55:33 keil
* Add FAX Class 1 support
*
@@ -110,7 +115,7 @@
* Definition of some special Registers of AT-Emulator
*/
#define REG_RINGATA 0
-#define REG_RINGCNT 1
+#define REG_RINGCNT 1 /* ring counter register */
#define REG_ESC 2
#define REG_CR 3
#define REG_LF 4
@@ -118,10 +123,10 @@
#define REG_WAITC 7
-#define REG_RESP 12
-#define BIT_RESP 1
-#define REG_RESPNUM 12
-#define BIT_RESPNUM 2
+#define REG_RESP 12 /* show response messages register */
+#define BIT_RESP 1 /* show response messages bit */
+#define REG_RESPNUM 12 /* show numeric responses register */
+#define BIT_RESPNUM 2 /* show numeric responses bit */
#define REG_ECHO 12
#define BIT_ECHO 4
#define REG_DCD 12
@@ -144,8 +149,8 @@
#define BIT_RESPXT 8
#define REG_CIDONCE 13
#define BIT_CIDONCE 16
-#define REG_RUNG 13
-#define BIT_RUNG 64
+#define REG_RUNG 13 /* show RUNG message register */
+#define BIT_RUNG 64 /* show RUNG message bit */
#define REG_DISPLAY 13
#define BIT_DISPLAY 128
@@ -163,6 +168,21 @@
#define BIT_CPN 1
#define BIT_CPNFCON 2
+/* defines for result codes */
+#define RESULT_OK 0
+#define RESULT_CONNECT 1
+#define RESULT_RING 2
+#define RESULT_NO_CARRIER 3
+#define RESULT_ERROR 4
+#define RESULT_CONNECT64000 5
+#define RESULT_NO_DIALTONE 6
+#define RESULT_BUSY 7
+#define RESULT_NO_ANSWER 8
+#define RESULT_RINGING 9
+#define RESULT_NO_MSN_EAZ 10
+#define RESULT_VCON 11
+#define RESULT_RUNG 12
+
#define TTY_IS_FCLASS1(info) \
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h
index f813b5c99..ba100543d 100644
--- a/drivers/isdn/sc/debug.h
+++ b/drivers/isdn/sc/debug.h
@@ -1,5 +1,5 @@
/*
- * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $
+ * $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $
* Copyright (C) 1996 SpellCaster Telecommunications Inc.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index d66393649..5a5d5fcf0 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -361,8 +361,7 @@ static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char b
static inline void prime_rx(struct net_device *dev)
{
elp_device *adapter = dev->priv;
- while (adapter->rx_active < ELP_RX_PCBS &&
- netif_running(dev->state)) {
+ while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
if (!start_receive(dev, &adapter->itx_pcb))
break;
}
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index c2eceb8db..6169eb742 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -87,7 +87,7 @@ an MMIO register read.
#include <asm/io.h>
-#define RTL8139_VERSION "0.9.3"
+#define RTL8139_VERSION "0.9.4"
#define RTL8139_MODULE_NAME "8139too"
#define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION
#define PFX RTL8139_MODULE_NAME ": "
@@ -101,8 +101,8 @@ an MMIO register read.
#define DPRINTK(fmt, args...)
#endif
-#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
-#if RTL8139_NDEBUG
+#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */
+#ifdef RTL8139_NDEBUG
#define assert(expr)
#else
#define assert(expr) \
@@ -144,6 +144,7 @@ static int multicast_filter_limit = 32;
#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */
#define TX_DMA_BURST 4 /* Calculate as 16<<val. */
+
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (6*HZ)
@@ -154,12 +155,13 @@ enum {
HAS_LNK_CHNG = 0x040000,
};
-#define RTL_IO_SIZE 0x80
+#define RTL_MIN_IO_SIZE 0x80
+#define RTL8139B_IO_SIZE 0xFF
-#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
+#define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG
typedef enum {
- RTL8139,
+ RTL8139 = 0,
RTL8139_CB,
SMC1211TX,
/*MPX5030,*/
@@ -168,17 +170,16 @@ typedef enum {
} chip_t;
+/* indexed by chip_t, above */
static struct {
- chip_t chip;
const char *name;
} chip_info[] __devinitdata = {
- { RTL8139, "RealTek RTL8139 Fast Ethernet"},
- { RTL8139_CB, "RealTek RTL8139B PCI/CardBus"},
- { SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"},
-/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)"},*/
- { DELTA8139, "Delta Electronics 8139 10/100BaseTX"},
- { ADDTRON8139, "Addtron Technolgy 8139 10/100BaseTX"},
- {0,},
+ { "RealTek RTL8139 Fast Ethernet" },
+ { "RealTek RTL8139B PCI/CardBus" },
+ { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
+/* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/
+ { "Delta Electronics 8139 10/100BaseTX" },
+ { "Addtron Technolgy 8139 10/100BaseTX" },
};
@@ -298,6 +299,14 @@ enum Config1Bits {
Cfg1_LED1 = 0x80,
};
+enum RxConfigBits {
+ RxCfgRcv8K = 0,
+ RxCfgRcv16K = (1 << 11),
+ RxCfgRcv32K = (1 << 12),
+ RxCfgRcv64K = (1 << 11) | (1 << 12),
+};
+
+
/* Twister tuning parameters from RealTek.
Completely undocumented, but required to tune bad links. */
enum CSCRBits {
@@ -307,6 +316,14 @@ enum CSCRBits {
CSCR_LinkDownOffCmd = 0x003c0,
CSCR_LinkDownCmd = 0x0f3c0,
};
+
+
+enum Cfg9346Bits {
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
+};
+
+
#define PARA78_default 0x78fa8388
#define PARA7c_default 0xcb38de43 /* param[0][3] */
#define PARA7c_xxx 0xcb38de43
@@ -327,7 +344,6 @@ struct ring_info {
struct rtl8139_private {
chip_t chip;
void *mmio_addr;
- spinlock_t lock;
int drv_flags;
struct pci_dev *pci_dev;
struct net_device_stats stats;
@@ -349,6 +365,8 @@ struct rtl8139_private {
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
unsigned int mediasense:1; /* Media sensing in progress. */
+ int extended_regs; /* bool: supports regs > 0x80 ? */
+ spinlock_t lock;
};
MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
@@ -374,6 +392,8 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
static inline u32 ether_crc (int length, unsigned char *data);
static void rtl8139_set_rx_mode (struct net_device *dev);
+static void rtl8139_hw_start (struct net_device *dev);
+
/* write MMIO register, with flush */
/* Flush avoids rtl8139 bug w/ posted MMIO writes */
@@ -409,30 +429,17 @@ static const u16 rtl8139_intr_mask =
TxErr | TxOK | RxErr | RxOK;
static const unsigned int rtl8139_rx_config =
- (RX_FIFO_THRESH << 13) |
- (RX_BUF_LEN_IDX << 11) |
+ (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) |
(RX_DMA_BURST << 8);
-static const char * __devinit rtl8139_name_from_chip (chip_t chip)
-{
- int i;
-
- for (i = 0; i < arraysize (chip_info); i++)
- if (chip == chip_info[i].chip)
- return chip_info[i].name;
-
- return "unknown";
-}
-
-
static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
{
void *ioaddr = NULL;
u8 tmp8;
int rc;
- u32 pio_start, pio_end, pio_flags;
- u32 mmio_start, mmio_end, mmio_flags;
+ u32 pio_start, pio_end, pio_flags, pio_len;
+ u32 mmio_start, mmio_end, mmio_flags, mmio_len;
DPRINTK ("ENTER\n");
@@ -444,48 +451,67 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
pio_start = pci_resource_start (pdev, 0);
pio_end = pci_resource_end (pdev, 0);
pio_flags = pci_resource_flags (pdev, 0);
+ pio_len = pci_resource_len (pdev, 0);
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
+ mmio_len = pci_resource_len (pdev, 1);
/* make sure PCI base addr 0 is PIO */
- if (pio_start == 0 || pio_end <= pio_start ||
- (!(pio_flags & IORESOURCE_IO))) {
- printk (KERN_ERR PFX "no PIO resource, aborting\n");
- return -ENODEV;
+ if (!(pio_flags & IORESOURCE_IO)) {
+ printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
+ rc = -ENODEV;
+ goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
- if (mmio_start == 0 || mmio_end <= mmio_start ||
- (!(mmio_flags & IORESOURCE_MEM))) {
- printk (KERN_ERR PFX "no MMIO resource, aborting\n");
- return -ENODEV;
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ /* check for weird/broken PCI region reporting */
+ if ((pio_len != mmio_len) ||
+ (pio_len < RTL_MIN_IO_SIZE) ||
+ (mmio_len < RTL_MIN_IO_SIZE)) {
+ printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+ rc = -ENODEV;
+ goto err_out;
}
/* make sure our PIO region in PCI space is available */
- if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
+ if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) {
printk (KERN_ERR PFX "no I/O resource available, aborting\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto err_out;
}
/* make sure our MMIO region in PCI space is available */
- if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) {
- release_region (pio_start, RTL_IO_SIZE);
+ if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) {
printk (KERN_ERR PFX "no mem resource available, aborting\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto err_out_free_pio;
}
/* enable device (incl. PCI PM wakeup), and bus-mastering */
- pci_enable_device (pdev);
+ rc = pci_enable_device (pdev);
+ if (rc) {
+ printk (KERN_ERR PFX "cannot enable PCI device (bus %d, "
+ "devfn %d), aborting\n",
+ pdev->bus->number, pdev->devfn);
+ goto err_out_free_mmio;
+ }
+
pci_set_master (pdev);
/* ioremap MMIO region */
- ioaddr = ioremap (mmio_start, RTL_IO_SIZE);
+ ioaddr = ioremap (mmio_start, mmio_len);
if (ioaddr == NULL) {
printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
rc = -EIO;
- goto err_out;
+ goto err_out_free_mmio;
}
/* Bring the chip out of low-power mode. */
@@ -496,12 +522,12 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
if ((tmp8 & Cfg1_PIO) == 0) {
printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8);
rc = -EIO;
- goto err_out;
+ goto err_out_iounmap;
}
if ((tmp8 & Cfg1_MMIO) == 0) {
printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8);
rc = -EIO;
- goto err_out;
+ goto err_out_iounmap;
}
/* sanity checks -- ensure PIO and MMIO registers agree */
@@ -514,28 +540,43 @@ static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out)
*ioaddr_out = ioaddr;
return 0;
+err_out_iounmap:
+ assert (ioaddr > 0);
+ iounmap (ioaddr);
+err_out_free_mmio:
+ release_mem_region (mmio_start, mmio_len);
+err_out_free_pio:
+ release_region (pio_start, pio_len);
err_out:
- if (ioaddr)
- iounmap (ioaddr);
- release_region (pio_start, RTL_IO_SIZE);
- release_mem_region (mmio_start, RTL_IO_SIZE);
DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
-static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit rtl8139_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct net_device *dev;
struct rtl8139_private *tp;
int i, addr_len, option = -1;
void *ioaddr = NULL;
+#ifndef RTL8139_NDEBUG
+ static int printed_version = 0;
+#endif /* RTL8139_NDEBUG */
+
DPRINTK ("ENTER\n");
assert (pdev != NULL);
assert (ent != NULL);
-
+
+#ifndef RTL8139_NDEBUG
+ if (!printed_version) {
+ printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n");
+ printed_version = 1;
+ }
+#endif /* RTL8139_NDEBUG */
+
i = rtl8139_init_pci (pdev, &ioaddr);
if (i < 0) {
DPRINTK ("EXIT, returning %d\n", i);
@@ -571,31 +612,34 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_de
dev->irq = pdev->irq;
dev->base_addr = pci_resource_start (pdev, 1);
+ /* dev->priv/tp zeroed in init_etherdev */
dev->priv = tp = (void *)
(((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN);
- printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- dev->name, rtl8139_name_from_chip(ent->driver_data),
- dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
-
- /* tp zeroed in init_etherdev */
tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | RTL8139_CAPS;
tp->pci_dev = pdev;
tp->chip = ent->driver_data;
tp->mmio_addr = ioaddr;
+ tp->extended_regs =
+ (pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0;
tp->lock = SPIN_LOCK_UNLOCKED;
PCI_SET_DRIVER_DATA (pdev, dev);
tp->phys[0] = 32;
+ printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ dev->name, chip_info[ent->driver_data].name,
+ dev->base_addr, dev->irq,
+ tp->extended_regs ? " 8139B regs," : "",
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+
/* Put the chip into low-power mode. */
- RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */
RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
@@ -635,8 +679,10 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
unregister_netdev (dev);
iounmap (np->mmio_addr);
- release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE);
- release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE);
+ release_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+ release_mem_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
#ifndef RTL8139_NDEBUG
/* poison memory before freeing */
@@ -644,7 +690,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
sizeof (struct net_device) +
sizeof (struct rtl8139_private) +
PRIV_ALIGN);
-#endif
+#endif /* RTL8139_NDEBUG */
kfree (dev);
@@ -851,16 +897,14 @@ static void mdio_write (struct net_device *dev, int phy_id, int location,
static int rtl8139_open (struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+#ifdef RTL8139_DEBUG
void *ioaddr = tp->mmio_addr;
- int i;
+#endif
DPRINTK ("ENTER\n");
MOD_INC_USE_COUNT;
- /* Soft reset the chip. */
- RTL_W8 (ChipCmd, CmdReset);
-
if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) {
DPRINTK ("EXIT, returning -EBUSY\n");
MOD_DEC_USE_COUNT;
@@ -891,44 +935,7 @@ static int rtl8139_open (struct net_device *dev)
tp->full_duplex = tp->duplex_lock;
tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
- break;
-
- RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
-
- /* Must enable Tx/Rx before setting transfer thresholds! */
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
- RTL_W32 (RxConfig, rtl8139_rx_config);
- RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000);
-
- /* Reset N-Way to chipset defaults */
- RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9));
- for (i = 1000; i > 0; i--)
- if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0)
- break;
-
- /* Set N-Way to sane defaults */
- RTL_W16 (FIFOTMS, 0x0000);
- RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1);
- RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
-
- RTL_W8 (Cfg9346, 0xC0);
- RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, 0x00);
-
- RTL_W32 (RxBuf, tp->rx_ring_dma);
-
- /* Start the chip's Tx and Rx process. */
- RTL_W32 (RxMissed, 0);
- rtl8139_set_rx_mode (dev);
-
- RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
-
- /* Enable all known interrupts by setting the interrupt mask. */
- RTL_W16 (IntrMask, rtl8139_intr_mask);
+ rtl8139_hw_start (dev);
DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d"
" GP Pins %2.2x %s-duplex.\n",
@@ -944,23 +951,26 @@ static int rtl8139_open (struct net_device *dev)
tp->timer.function = &rtl8139_timer;
add_timer (&tp->timer);
- netif_start_queue (dev);
-
DPRINTK ("EXIT, returning 0\n");
return 0;
}
+
/* Start the hardware at open or resume. */
static void rtl8139_hw_start (struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
int i;
+ unsigned long flags;
DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&tp->lock, flags);
/* Soft reset the chip. */
RTL_W8 (ChipCmd, CmdReset);
+
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--)
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
@@ -970,8 +980,9 @@ static void rtl8139_hw_start (struct net_device *dev)
RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
- /* Hmmm, do these belong here? */
- RTL_W8 (Cfg9346, 0x00);
+ /* unlock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
+
tp->cur_rx = 0;
/* Must enable Tx/Rx before setting transfer thresholds! */
@@ -993,19 +1004,30 @@ static void rtl8139_hw_start (struct net_device *dev)
RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8));
/* check_duplex() here. */
- RTL_W8 (Cfg9346, 0xC0);
RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, 0x00);
+
+ /* lock Config[01234] and BMCR register writes */
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
RTL_W32 (RxBuf, tp->rx_ring_dma);
+
/* Start the chip's Tx and Rx process. */
RTL_W32 (RxMissed, 0);
+
+ /* release lock cuz set_rx_mode wants it */
+ spin_unlock_irqrestore (&tp->lock, flags);
rtl8139_set_rx_mode (dev);
+ spin_lock_irqsave (&tp->lock, flags);
+
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
+
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16 (IntrMask, rtl8139_intr_mask);
- netif_start_queue (dev);
+ if (netif_queue_stopped (dev))
+ netif_start_queue (dev);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
DPRINTK ("EXIT\n");
}
@@ -1111,9 +1133,14 @@ static void rtl8139_timer (unsigned long data)
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
int next_tick = 60 * HZ;
- int mii_reg5 = mdio_read (dev, tp->phys[0], 5);
+ int mii_reg5;
+ unsigned long flags;
DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ mii_reg5 = mdio_read (dev, tp->phys[0], 5);
if (!tp->duplex_lock && mii_reg5 != 0xffff) {
int duplex = (mii_reg5 & 0x0100)
@@ -1125,9 +1152,9 @@ static void rtl8139_timer (unsigned long data)
" partner ability of %4.4x.\n", dev->name,
tp->full_duplex ? "full" : "half",
tp->phys[0], mii_reg5);
- RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, 0x00);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
}
}
@@ -1144,6 +1171,8 @@ static void rtl8139_timer (unsigned long data)
dev->name, RTL_R8 (Config0),
RTL_R8 (Config1));
+ spin_unlock_irqrestore (&tp->lock, flags);
+
tp->timer.expires = jiffies + next_tick;
add_timer (&tp->timer);
@@ -1156,10 +1185,11 @@ static void rtl8139_tx_timeout (struct net_device *dev)
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
int mii_reg, i;
+ unsigned long flags;
DPRINTK ("ENTER\n");
- netif_stop_queue (dev);
+ spin_lock_irqsave (&tp->lock, flags);
DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
"media %2.2x.\n", dev->name,
@@ -1201,6 +1231,8 @@ static void rtl8139_tx_timeout (struct net_device *dev)
}
}
+ spin_unlock_irqrestore (&tp->lock, flags);
+
rtl8139_hw_start (dev);
DPRINTK ("EXIT\n");
@@ -1227,6 +1259,7 @@ static void rtl8139_init_ring (struct net_device *dev)
DPRINTK ("EXIT\n");
}
+
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
@@ -1236,13 +1269,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
DPRINTK ("ENTER\n");
- netif_stop_queue (dev);
+ spin_lock_irqsave (&tp->lock, flags);
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;
- spin_lock_irqsave (&tp->lock, flags);
-
tp->tx_info[entry].skb = skb;
if ((long) skb->data & 3) { /* Must use alignment buffer. */
tp->tx_info[entry].mapping = 0;
@@ -1263,12 +1294,12 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
dev->trans_start = jiffies;
- if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */
- netif_start_queue (dev);
+ if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC)
+ netif_stop_queue (dev);
spin_unlock_irqrestore (&tp->lock, flags);
-
- DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n",
+
+ DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
dev->name, skb->data, skb->len, entry);
DPRINTK ("EXIT\n");
@@ -1277,16 +1308,16 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
static inline void rtl8139_tx_interrupt (struct net_device *dev,
- struct rtl8139_private *tp)
+ struct rtl8139_private *tp,
+ void *ioaddr)
{
- void *ioaddr;
unsigned int dirty_tx;
assert (dev != NULL);
assert (tp != NULL);
-
+ assert (ioaddr != NULL);
+
dirty_tx = tp->dirty_tx;
- ioaddr = tp->mmio_addr;
while (tp->cur_tx - dirty_tx > 0) {
int entry = dirty_tx % NUM_TX_DESC;
@@ -1338,8 +1369,6 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
dirty_tx++;
if (tp->cur_tx - dirty_tx < NUM_TX_DESC)
netif_wake_queue (dev);
- else
- netif_stop_queue (dev);
}
#ifndef RTL8139_NDEBUG
@@ -1349,7 +1378,7 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
dev->name, dirty_tx, tp->cur_tx);
dirty_tx += NUM_TX_DESC;
}
-#endif
+#endif /* RTL8139_NDEBUG */
tp->dirty_tx = dirty_tx;
}
@@ -1358,11 +1387,18 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev,
/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
field alignments and semantics. */
static inline void rtl8139_rx_interrupt (struct net_device *dev,
- struct rtl8139_private *tp)
+ struct rtl8139_private *tp,
+ void *ioaddr)
{
- void *ioaddr = tp->mmio_addr;
- unsigned char *rx_ring = tp->rx_ring;
- u16 cur_rx = tp->cur_rx;
+ unsigned char *rx_ring;
+ u16 cur_rx;
+
+ assert (dev != NULL);
+ assert (tp != NULL);
+ assert (ioaddr != NULL);
+
+ rx_ring = tp->rx_ring;
+ cur_rx = tp->cur_rx;
DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
" free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx,
@@ -1376,15 +1412,17 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
int rx_size = rx_status >> 16;
-#ifdef RTL8139_DEBUG
- int i;
DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x,"
" cur %4.4x.\n", dev->name, rx_status,
rx_size, cur_rx);
+#if RTL8139_DEBUG > 2
+ {
+ int i;
DPRINTK ("%s: Frame contents ", dev->name);
for (i = 0; i < 70; i++)
printk (" %2.2x", rx_ring[ring_offset + i]);
printk (".\n");
+ }
#endif
/* E. Gill */
@@ -1490,23 +1528,16 @@ static inline void rtl8139_rx_interrupt (struct net_device *dev,
static inline int rtl8139_weird_interrupt (struct net_device *dev,
struct rtl8139_private *tp,
+ void *ioaddr,
int status, int link_changed)
{
- void *ioaddr;
-
DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
dev->name, status);
assert (dev != NULL);
assert (tp != NULL);
-
- ioaddr = tp->mmio_addr;
-
- if (status == 0xffffffff) {
- printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n");
- return -1;
- }
-
+ assert (ioaddr != NULL);
+
/* Update the error count. */
tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
RTL_W32 (RxMissed, 0);
@@ -1519,9 +1550,9 @@ static inline int rtl8139_weird_interrupt (struct net_device *dev,
|| tp->duplex_lock;
if (tp->full_duplex != duplex) {
tp->full_duplex = duplex;
- RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
- RTL_W8 (Cfg9346, 0x00);
+ RTL_W8 (Cfg9346, Cfg9346_Lock);
}
status &= ~RxUnderrun;
}
@@ -1559,15 +1590,20 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
int boguscnt = max_interrupt_work;
void *ioaddr = tp->mmio_addr;
- int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */
-
- spin_lock_irq (&tp->lock);
+ int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
+ spin_lock (&tp->lock);
+
/* disable interrupt generation while handling this interrupt */
RTL_W16 (IntrMask, 0x0000);
do {
- int status = RTL_R16 (IntrStatus);
+ status = RTL_R16 (IntrStatus);
+
+ /* h/w no longer present (hotplug?) or major error, bail */
+ if (status == 0xFFFFFFFF)
+ break;
+
/* Acknowledge all of the current interrupt sources ASAP, but
an first get an additional status bit from CSCR. */
if (status & RxUnderrun)
@@ -1606,42 +1642,45 @@ static void rtl8139_interrupt (int irq, void *dev_instance,
/* Check uncommon events with one test. */
if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
RxFIFOOver | TxErr | RxErr))
- if (rtl8139_weird_interrupt (dev, tp, status,
- link_changed) == -1)
- break;
+ rtl8139_weird_interrupt (dev, tp, ioaddr,
+ status, link_changed);
if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */
- rtl8139_rx_interrupt (dev, tp);
+ rtl8139_rx_interrupt (dev, tp, ioaddr);
if (status & (TxOK | TxErr))
- rtl8139_tx_interrupt (dev, tp);
-
- if (--boguscnt < 0) {
- printk (KERN_WARNING
- "%s: Too much work at interrupt, "
- "IntrStatus=0x%4.4x.\n", dev->name,
- status);
- /* Clear all interrupt sources. */
- RTL_W16 (IntrStatus, 0xffff);
- break;
- }
- } while (1);
+ rtl8139_tx_interrupt (dev, tp, ioaddr);
+
+ boguscnt--;
+ } while (boguscnt > 0);
+
+ if (boguscnt <= 0) {
+ printk (KERN_WARNING
+ "%s: Too much work at interrupt, "
+ "IntrStatus=0x%4.4x.\n", dev->name,
+ status);
+
+ /* Clear all interrupt sources. */
+ RTL_W16 (IntrStatus, 0xffff);
+ }
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16 (IntrMask, rtl8139_intr_mask);
- spin_unlock_irq (&tp->lock);
-
+ spin_unlock (&tp->lock);
+
DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
- dev->name, RTL_R16 (IntrStatus));
+ dev->name, RTL_R16 (IntrStatus));
}
+
static int rtl8139_close (struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
int i;
+ unsigned long flags;
DPRINTK ("ENTER\n");
@@ -1650,6 +1689,8 @@ static int rtl8139_close (struct net_device *dev)
DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
dev->name, RTL_R16 (IntrStatus));
+ spin_lock_irqsave (&tp->lock, flags);
+
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16 (IntrMask, 0x0000);
@@ -1660,7 +1701,13 @@ static int rtl8139_close (struct net_device *dev)
tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
RTL_W32 (RxMissed, 0);
+ spin_unlock_irqrestore (&tp->lock, flags);
+
del_timer (&tp->timer);
+
+ /* snooze for a small bit */
+ if (current->need_resched)
+ schedule ();
free_irq (dev->irq, dev);
@@ -1685,7 +1732,7 @@ static int rtl8139_close (struct net_device *dev)
tp->tx_bufs = NULL;
/* Green! Put the chip in low-power mode. */
- RTL_W8 (Cfg9346, 0xC0);
+ RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, 0x03);
RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */
@@ -1695,10 +1742,13 @@ static int rtl8139_close (struct net_device *dev)
return 0;
}
+
static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
u16 *data = (u16 *) & rq->ifr_data;
+ unsigned long flags;
+ int rc = 0;
DPRINTK ("ENTER\n");
@@ -1706,24 +1756,34 @@ static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
data[0] = tp->phys[0] & 0x3f;
/* Fall Through */
+
case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */
+ spin_lock_irqsave (&tp->lock, flags);
data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
- DPRINTK ("EXIT\n");
- return 0;
+ spin_unlock_irqrestore (&tp->lock, flags);
+ break;
+
case SIOCDEVPRIVATE + 2: /* Write the specified MII register */
- if (!capable (CAP_NET_ADMIN))
- return -EPERM;
+ if (!capable (CAP_NET_ADMIN)) {
+ rc = -EPERM;
+ break;
+ }
+
+ spin_lock_irqsave (&tp->lock, flags);
mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
- DPRINTK ("EXIT\n");
- return 0;
+ spin_unlock_irqrestore (&tp->lock, flags);
+ break;
+
default:
- DPRINTK ("EXIT\n");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ break;
}
- DPRINTK ("EXIT\n");
+ DPRINTK ("EXIT, returning %d\n", rc);
+ return rc;
}
+
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
@@ -1734,8 +1794,14 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
assert (tp != NULL);
if (netif_running(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave (&tp->lock, flags);
+
tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
}
DPRINTK ("EXIT\n");
@@ -1765,12 +1831,14 @@ static inline u32 ether_crc (int length, unsigned char *data)
return crc;
}
+
static void rtl8139_set_rx_mode (struct net_device *dev)
{
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
+ unsigned long flags;
DPRINTK ("ENTER\n");
@@ -1803,11 +1871,19 @@ static void rtl8139_set_rx_mode (struct net_device *dev)
dmi_addr) >> 26,
mc_filter);
}
+
+ /* if called from irq handler, lock already acquired */
+ if (!in_irq ())
+ spin_lock_irqsave (&tp->lock, flags);
+
/* We can safely update without stopping the chip. */
RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode);
RTL_W32_F (MAR0 + 0, mc_filter[0]);
RTL_W32_F (MAR0 + 4, mc_filter[1]);
+ if (!in_irq ())
+ spin_unlock_irqrestore (&tp->lock, flags);
+
DPRINTK ("EXIT\n");
}
@@ -1817,9 +1893,12 @@ static void rtl8139_suspend (struct pci_dev *pdev)
struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
void *ioaddr = tp->mmio_addr;
+ unsigned long flags;
- netif_stop_queue (dev);
+ netif_device_detach (dev);
+ spin_lock_irqsave (&tp->lock, flags);
+
/* Disable interrupts, stop Tx and Rx. */
RTL_W16 (IntrMask, 0x0000);
RTL_W8 (ChipCmd, 0x00);
@@ -1827,6 +1906,8 @@ static void rtl8139_suspend (struct pci_dev *pdev)
/* Update the error counts. */
tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
RTL_W32 (RxMissed, 0);
+
+ spin_unlock_irqrestore (&tp->lock, flags);
}
@@ -1834,7 +1915,8 @@ static void rtl8139_resume (struct pci_dev *pdev)
{
struct net_device *dev = PCI_GET_DRIVER_DATA (pdev);
- rtl8139_hw_start(dev);
+ netif_device_attach (dev);
+ rtl8139_hw_start (dev);
}
@@ -1850,22 +1932,7 @@ static struct pci_driver rtl8139_pci_driver = {
static int __init rtl8139_init_module (void)
{
- int rc;
-
- DPRINTK ("ENTER\n");
-
- rc = pci_register_driver (&rtl8139_pci_driver);
-
- if (rc > 0) {
- printk (KERN_INFO RTL8139_DRIVER_NAME
- " loaded (%d device%s registered)\n",
- rc, rc > 1 ? "s" : "");
- } else {
- pci_unregister_driver (&rtl8139_pci_driver);
- }
-
- DPRINTK ("EXIT\n");
- return rc > 0 ? 0 : -ENODEV;
+ return pci_module_init (&rtl8139_pci_driver);
}
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index f3cc0af3a..abf7958ef 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -254,9 +254,7 @@ comment 'Wireless LAN (non-hamradio)'
bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" = "y" ]; then
dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
- if [ "$CONFIG_OBSOLETE" = "y" ]; then
- tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
- fi
+ tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3c2ede8f5..550a97ae2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -18,7 +18,7 @@ SUB_DIRS :=
MOD_SUB_DIRS :=
MOD_IN_SUB_DIRS :=
ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \
- arcnet skfp
+ arcnet skfp tulip
O_TARGET := net.o
MOD_LIST_NAME := NET_MODULES
@@ -38,6 +38,15 @@ else
endif
endif
+ifeq ($(CONFIG_TULIP),y)
+ SUB_DIRS += tulip
+ obj-y += tulip/tulip.o
+else
+ ifeq ($(CONFIG_TULIP),m)
+ MOD_SUB_DIRS += tulip
+ endif
+endif
+
ifeq ($(CONFIG_IRDA),y)
SUB_DIRS += irda
MOD_IN_SUB_DIRS += irda
@@ -122,7 +131,6 @@ obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
obj-$(CONFIG_PCNET32) += pcnet32.o
obj-$(CONFIG_EEPRO100) += eepro100.o
obj-$(CONFIG_TLAN) += tlan.o
-obj-$(CONFIG_TULIP) += tulip.o
obj-$(CONFIG_EPIC100) += epic100.o
obj-$(CONFIG_SIS900) += sis900.o
obj-$(CONFIG_DM9102) += dmfe.o
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 8410c0cf8..404d4a996 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -536,6 +536,9 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
static int did_version = 0; /* Already printed version info. */
+ if (speedo_debug > 0 && did_version++ == 0)
+ printk(version);
+
#ifdef USE_IO
ioaddr = pci_resource_start (pdev, 0);
#else
@@ -569,9 +572,6 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
}
#endif
- if (speedo_debug > 0 && did_version++ == 0)
- printk(version);
-
tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ sizeof(struct speedo_stats), &tx_ring_dma);
if (!tx_ring) {
@@ -604,7 +604,11 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
}
- pci_enable_device (pdev);
+ if (pci_enable_device (pdev)) {
+ printk(KERN_ERR PFX "Could not enable PCI device\n");
+ goto err_out_free_netdev;
+ }
+
pci_set_master (pdev);
/* Read the station address EEPROM before doing the reset.
@@ -732,11 +736,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
/* Return the chip to its original power state. */
pci_set_power_state (pdev, acpi_idle_state);
+ pdev->driver_data = dev;
+
dev->base_addr = ioaddr;
dev->irq = irq;
sp = dev->priv;
- memset(sp, 0, sizeof(*sp));
sp->pdev = pdev;
sp->acpi_pwr = acpi_idle_state;
@@ -872,6 +877,8 @@ speedo_open(struct net_device *dev)
if (speedo_debug > 1)
printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
+ MOD_INC_USE_COUNT;
+
pci_set_power_state(sp->pdev, 0);
/* Set up the Tx queue early.. */
@@ -882,12 +889,13 @@ speedo_open(struct net_device *dev)
spin_lock_init(&sp->lock);
/* .. we can safely take handler calls during init. */
- if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
return -EBUSY;
-
- MOD_INC_USE_COUNT;
+ }
dev->if_port = sp->default_port;
+
#if 0
/* With some transceivers we must retrigger negotiation to reset
power-up errors. */
@@ -1174,8 +1182,6 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
long ioaddr = dev->base_addr;
int entry;
- netif_stop_queue (dev);
-
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
@@ -1216,16 +1222,15 @@ speedo_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) {
sp->tx_full = 1;
+ netif_stop_queue (dev);
}
spin_unlock_irqrestore(&sp->lock, flags);
}
+
wait_for_cmd_done(ioaddr + SCBCmd);
outw(CUResume, ioaddr + SCBCmd);
dev->trans_start = jiffies;
- if (! sp->tx_full)
- netif_start_queue (dev);
-
return 0;
}
@@ -1328,22 +1333,18 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
&& sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) {
/* The ring is no longer full, clear tbusy. */
sp->tx_full = 0;
- }
-
- if (sp->tx_full)
- netif_stop_queue (dev);
- else
netif_wake_queue (dev);
+ }
}
- if (--boguscnt < 0) {
- printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
- dev->name, status);
- /* Clear all interrupt sources. */
- outl(0xfc00, ioaddr + SCBStatus);
- break;
- }
- } while (1);
+ } while (--boguscnt > 0);
+
+ if (boguscnt <= 0) {
+ printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
+ dev->name, status);
+ /* Clear all interrupt sources. */
+ outl(0xfc00, ioaddr + SCBStatus);
+ }
if (speedo_debug > 3)
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
@@ -1502,8 +1503,8 @@ speedo_close(struct net_device *dev)
/* Clear the Tx descriptors. */
if (skb) {
pci_unmap_single(sp->pdev,
- le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
- skb->len, PCI_DMA_TODEVICE);
+ le32_to_cpu(sp->tx_ring[i].tx_buf_addr0),
+ skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
}
}
@@ -1811,8 +1812,6 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev)
iounmap ((char *) dev->base_addr);
#endif
- pci_set_power_state (pdev, sp->acpi_pwr);
-
pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ sizeof(struct speedo_stats),
sp->tx_ring, sp->tx_ring_dma);
@@ -1841,23 +1840,10 @@ static struct pci_driver eepro100_driver = {
static int __init eepro100_init_module(void)
{
- int cards_found;
-
if (debug >= 0)
speedo_debug = debug;
- /* Always emit the version message. */
- if (speedo_debug)
- printk(KERN_INFO "%s", version);
-
- cards_found = pci_register_driver (&eepro100_driver);
- if (cards_found <= 0) {
- printk(KERN_INFO PFX "No cards found, driver not installed.\n");
- pci_unregister_driver (&eepro100_driver);
- return -ENODEV;
- }
-
- return 0;
+ return pci_module_init (&eepro100_driver);
}
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index b1871485a..8aa3ef765 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -752,8 +752,8 @@ static void __exit sixpack_cleanup_driver(void)
* VSV = if dev->start==0, then device
* unregistered while close proc.
*/
- if (netif_running(sixpack_ctrls[i]->dev))
- unregister_netdev(&(sixpack_ctrls[i]->dev));
+ if (netif_running(&sixpack_ctrls[i]->dev))
+ unregister_netdev(&sixpack_ctrls[i]->dev);
kfree(sixpack_ctrls[i]);
sixpack_ctrls[i] = NULL;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 1886ec73a..7a6cc5091 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -6,7 +6,7 @@
* Status: Stable.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Nov 7 21:43:15 1998
- * Modified at: Fri Jan 28 12:10:10 2000
+ * Modified at: Fri Feb 18 01:48:51 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -42,6 +42,7 @@
********************************************************************/
#include <linux/module.h>
+
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
@@ -1431,8 +1432,10 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
/* We must empty the status FIFO no matter what */
len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
- if (st_fifo->tail >= MAX_RX_WINDOW)
+ if (st_fifo->tail >= MAX_RX_WINDOW) {
+ IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n");
continue;
+ }
st_fifo->entries[st_fifo->tail].status = status;
st_fifo->entries[st_fifo->tail].len = len;
@@ -1492,7 +1495,18 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
st_fifo->pending_bytes += len;
st_fifo->entries[st_fifo->head].status = status;
st_fifo->entries[st_fifo->head].len = len;
-
+ /*
+ * DMA not finished yet, so try again
+ * later, set timer value, resolution
+ * 125 us
+ */
+ switch_bank(iobase, BANK4);
+ outb(0x02, iobase+TMRL); /* x 125 us */
+ outb(0x00, iobase+TMRH);
+
+ /* Start timer */
+ outb(IRCR1_TMR_EN, iobase+IRCR1);
+
/* Restore bank register */
outb(bank, iobase+BSR);
@@ -1597,7 +1611,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
else {
self->stats.tx_packets++;
- netif_wakeup_queue(self->netdev);
+ netif_wake_queue(self->netdev);
self->ier = IER_TXEMP_IE;
}
@@ -1648,21 +1662,12 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
/* Status FIFO event*/
if (eir & EIR_SFIF_EV) {
+ /* Check if DMA has finished */
if (nsc_ircc_dma_receive_complete(self, iobase)) {
/* Wait for next status FIFO interrupt */
self->ier = IER_SFIF_IE;
} else {
- /*
- * DMA not finished yet, so try again later, set
- * timer value, resolution 125 us
- */
- switch_bank(iobase, BANK4);
- outb(0x02, iobase+TMRL); /* 2 * 125 us */
- outb(0x00, iobase+TMRH);
-
- /* Start timer */
- outb(IRCR1_TMR_EN, iobase+IRCR1);
- self->ier = IER_TMR_IE | IER_SFIF_IE;
+ self->ier = IER_SFIF_IE | IER_TMR_IE;
}
} else if (eir & EIR_TMR_EV) { /* Timer finished */
/* Disable timer */
@@ -1677,15 +1682,17 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
if (self->io.direction == IO_XMIT) {
nsc_ircc_dma_xmit(self, iobase);
- /* Interrupt on DMA */
+ /* Interrupt on DMA */
self->ier = IER_DMA_IE;
} else {
- /* Check if DMA has now finished */
- nsc_ircc_dma_receive_complete(self, iobase);
-
- self->ier = IER_SFIF_IE;
+ /* Check (again) if DMA has finished */
+ if (nsc_ircc_dma_receive_complete(self, iobase)) {
+ self->ier = IER_SFIF_IE;
+ } else {
+ self->ier = IER_SFIF_IE | IER_TMR_IE;
+ }
}
- } else if (eir & EIR_DMA_EV) {
+ } else if (eir & EIR_DMA_EV) {
/* Finished with all transmissions? */
if (nsc_ircc_dma_xmit_complete(self)) {
/* Check if there are more frames to be transmitted */
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
index a93720cc9..06ebc072c 100644
--- a/drivers/net/irda/smc-ircc.c
+++ b/drivers/net/irda/smc-ircc.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Thomas Davis (tadavis@jps.net)
* Created at:
- * Modified at: Fri Jan 21 09:41:08 2000
+ * Modified at: Tue Feb 22 10:05:06 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999-2000 Dag Brattli
@@ -567,7 +567,6 @@ static void ircc_change_speed(void *priv, __u32 speed)
"(), using irport to change speed to %d\n", speed);
irport_change_speed(self->irport, speed);
}
- dev->tbusy = 0;
register_bank(iobase, 1);
outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode),
@@ -617,9 +616,7 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev)
if ((speed = irda_get_speed(skb)) != self->io.speed)
self->new_speed = speed;
- /* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
+ netif_stop_queue(dev);
memcpy(self->tx_buff.head, skb->data, skb->len);
@@ -741,11 +738,7 @@ static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase)
self->new_speed = 0;
}
- /* Unlock tx_buff and request another frame */
- self->netdev->tbusy = 0; /* Unlock */
-
- /* Tell the network layer, that we can accept more frames */
- mark_bh(NET_BH);
+ netif_wake_queue(self->netdev);
}
/*
@@ -875,7 +868,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
iobase = self->io.fir_base;
spin_lock(&self->lock);
- dev->interrupt = 1;
register_bank(iobase, 0);
iir = inb(iobase+IRCC_IIR);
@@ -898,7 +890,6 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
register_bank(iobase, 0);
outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
- dev->interrupt = 0;
spin_unlock(&self->lock);
}
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 33b1dbc60..010c7cfd0 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -788,8 +788,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while ((status = inw(ioaddr + EL3_STATUS)) &
(IntLatch | RxComplete | StatsFull)) {
- if (!netif_device_present(dev)) ||
- ((status & 0xe000) != 0x2000)) {
+ if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) {
DEBUG(1, "%s: interrupt from dead card\n", dev->name);
break;
}
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index d3722cf2d..fad404a4d 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -1172,7 +1172,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode)
* YY/MM/DD uid Description
-*/
-static int SK_timeout(struct net_device *dev)
+static void SK_timeout(struct net_device *dev)
{
printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name);
SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 5f80fc5eb..d4b2e0380 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -26,10 +26,9 @@
* resource. Driver also reports the card name returned by
* the pci resource.
* 1/11/00 - Added spinlocks for smp
- *
- * To Do:
+ * 2/23/00 - Updated to dev_kfree_irq
*
- * IPv6 Multicast
+ * To Do:
*
* If Problems do Occur
* Most problems can be rectified by either closing and opening the interface
@@ -88,7 +87,7 @@
*/
static char *version =
-"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ;
+"Olympic.c v0.3.2 2/23/00 - Peter De Schrijver & Mike Phillips" ;
static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion",
"Address Verification", "Neighbor Notification (Ring Poll)",
@@ -777,7 +776,7 @@ static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
olympic_priv->free_tx_ring_entries++;
olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len;
olympic_priv->olympic_stats.tx_packets++ ;
- dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
+ dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
netif_wake_queue(dev);
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
deleted file mode 100644
index 5619b961d..000000000
--- a/drivers/net/tulip.c
+++ /dev/null
@@ -1,3159 +0,0 @@
-/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
-/*
- Copyright 2000 The Linux Kernel Team
- Written/copyright 1994-1999 by Donald Becker.
-
- This software may be used and distributed according to the terms
- of the GNU Public License, incorporated herein by reference.
-
- This driver is for the Digital "Tulip" Ethernet adapter interface.
- It should work with most DEC 21*4*-based chips/ethercards, as well as
- with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
-
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
- Center of Excellence in Space Data and Information Sciences
- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
- Additional information available at
- http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
-
- For this specific driver variant please use linux-kernel for
- bug reports.
-
-
- Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the DECchip "Tulip", Digital's
-single-chip ethernet controllers for PCI. Supported members of the family
-are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike
-chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
-supported.
-
-These chips are used on at least 140 unique PCI board designs. The great
-number of chips and board designs supported is the reason for the
-driver size and complexity. Almost of the increasing complexity is in the
-board configuration and media selection code. There is very little
-increasing in the operational critical path length.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board. The system BIOS preferably should assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-Some boards have EEPROMs tables with default media entry. The factory default
-is usually "autoselect". This should only be overridden when using
-transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
-for forcing full-duplex when used with old link partners that do not do
-autonegotiation.
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
-This driver uses statically allocated rings of Rx and Tx descriptors, set at
-compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs
-for the Rx ring buffers at open() time and passes the skb->data field to the
-Tulip as receive data buffers. When an incoming frame is less than
-RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
-copied to the new skbuff. When the incoming frame is larger, the skbuff is
-passed directly up the protocol stack and replaced by a newly allocated
-skbuff.
-
-The RX_COPYBREAK value is chosen to trade-off the memory wasted by
-using a full-sized skbuff for small frames vs. the copying costs of larger
-frames. For small frames the copying cost is negligible (esp. considering
-that we are pre-loading the cache with immediately useful header
-information). For large frames the copying cost is non-trivial, and the
-larger copy might flush the cache of useful data. A subtle aspect of this
-choice is that the Tulip only receives into longword aligned buffers, thus
-the IP header at offset 14 isn't longword aligned for further processing.
-Copied frames are put into the new skbuff at an offset of "+2", thus copying
-has the beneficial effect of aligning the IP header and preloading the
-cache.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control. One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag. The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'tp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.) After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
-IV. Notes
-
-Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
-Greg LaPolla at Linksys provided PNIC and other Linksys boards.
-Znyx provided a four-port card for testing.
-
-IVb. References
-
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM")
-http://www.national.com/pf/DP/DP83840A.html
-http://www.asix.com.tw/pmac.htm
-http://www.admtek.com.tw/
-
-IVc. Errata
-
-The old DEC databooks were light on details.
-The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
-register of the set CSR12-15 written. Hmmm, now how is that possible?
-
-The DEC SROM format is very badly designed not precisely defined, leading to
-part of the media selection junkheap below. Some boards do not have EEPROM
-media tables and need to be patched up. Worse, other boards use the DEC
-design kit media table when it isn't correct for their board.
-
-We cannot use MII interrupts because there is no defined GPIO pin to attach
-them. The MII transceiver status is polled using an kernel timer.
-
-*/
-
-static const char version[] = "Linux Tulip driver version 0.9.2 (Feb 15, 2000)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/unaligned.h>
-#include <asm/delay.h>
-
-
-/* A few user-configurable values. */
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 25;
-
-#define MAX_UNITS 8
-/* Used to pass the full-duplex flag, etc. */
-static int full_duplex[MAX_UNITS] = {0, };
-static int options[MAX_UNITS] = {0, };
-static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
-
-/* The possible media types that can be set in options[] are: */
-static const char * const medianame[] = {
- "10baseT", "10base2", "AUI", "100baseTx",
- "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
- "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
- "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
-};
-
-/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
-#ifdef REVERSE_PROBE_ORDER
-static int reverse_probe = 1;
-#else
-static int reverse_probe = 0;
-#endif
-
-/* Keep the ring sizes a power of two for efficiency.
- Making the Tx ring too large decreases the effectiveness of channel
- bonding and packet priority.
- There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#ifdef __alpha__
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-
-/*
- Set the bus performance register.
- Typical: Set 16 longword cache alignment, no burst limit.
- Cache alignment bits 15:14 Burst length 13:8
- 0000 No alignment 0x00000000 unlimited 0800 8 longwords
- 4000 8 longwords 0100 1 longword 1000 16 longwords
- 8000 16 longwords 0200 2 longwords 2000 32 longwords
- C000 32 longwords 0400 4 longwords
- Warning: many older 486 systems are broken and require setting 0x00A04800
- 8 longword cache alignment, 8 longword burst.
- ToDo: Non-Intel setting could be better.
-*/
-
-#if defined(__alpha__)
-static int csr0 = 0x01A00000 | 0xE000;
-#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
-static int csr0 = 0x01A00000 | 0x8000;
-#else
-#warning Processor architecture undefined!
-static int csr0 = 0x00A00000 | 0x4800;
-#endif
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (4*HZ)
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
- to support a pre-NWay full-duplex signaling mechanism using short frames.
- No one knows what it should be, but if left at its default value some
- 10base2(!) packets trigger a full-duplex-request interrupt. */
-#define FULL_DUPLEX_MAGIC 0x6969
-
-
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(reverse_probe, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(csr0, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-
-#define TULIP_MODULE_NAME "tulip"
-#define PFX TULIP_MODULE_NAME ": "
-
-#define RUN_AT(x) (jiffies + (x))
-
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
-#define tulip_debug debug
-#ifdef TULIP_DEBUG
-static int tulip_debug = TULIP_DEBUG;
-#else
-static int tulip_debug = 1;
-#endif
-
-
-
-/* This table use during operation for capabilities and media timer. */
-
-static void tulip_timer(unsigned long data);
-static void t21142_timer(unsigned long data);
-static void mxic_timer(unsigned long data);
-static void pnic_timer(unsigned long data);
-static void comet_timer(unsigned long data);
-
-enum tbl_flag {
- HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
- HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
- HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */
- HAS_8023X=0x100,
-};
-static struct tulip_chip_table {
- char *chip_name;
- int io_size;
- int valid_intrs; /* CSR7 interrupt enable settings */
- int flags;
- void (*media_timer)(unsigned long data);
-} tulip_tbl[] = {
- { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
- { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
- { "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
- { "Digital DS21143 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
- t21142_timer },
- { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
- HAS_MII | HAS_PNICNWAY, pnic_timer },
- { "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
- { "Macronix 98715 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
- { "Macronix 98725 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
- { "ASIX AX88140", 128, 0x0001fbff,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
- { "Lite-On PNIC-II", 256, 0x0801fbff,
- HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
- { "ADMtek Comet", 256, 0x0001abef,
- MC_HASH_ONLY, comet_timer },
- { "Compex 9881 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
- { "Intel DS21145 Tulip", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
- t21142_timer },
- { "Xircom tulip work-alike", 128, 0x0801fbff,
- HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
- t21142_timer },
- {0},
-};
-/* This matches the table above. Note 21142 == 21143. */
-enum chips {
- DC21040=0,
- DC21041=1,
- DC21140=2,
- DC21142=3, DC21143=3,
- LC82C168,
- MX98713,
- MX98715,
- MX98725,
- AX88140,
- PNIC2,
- COMET,
- COMPEX9881,
- I21145,
- X3201_3,
-};
-
-
-static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
- { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
- { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
- { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
- { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },
- { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
- { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
- { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
- { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
- { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
- { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
- { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
- { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
- { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
- { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
- {0},
-};
-MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
-
-
-/* A full-duplex map for media types. */
-enum MediaIs {
- MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
- MediaIs100=16};
-static const char media_cap[] =
-{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
-static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
-/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
-static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
-
-static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
-static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
-static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
-
-/* Offsets to the Command and Status Registers, "CSRs". All accesses
- must be longword instructions and quadword aligned. */
-enum tulip_offsets {
- CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
- CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
- CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
-
-/* The bits in the CSR5 status registers, mostly interrupt sources. */
-enum status_bits {
- TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10,
- NormalIntr=0x10000, AbnormalIntr=0x8000,
- RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
- TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
-};
-
-/* The Tulip Rx and Tx buffer descriptors. */
-struct tulip_rx_desc {
- s32 status;
- s32 length;
- u32 buffer1, buffer2;
-};
-
-struct tulip_tx_desc {
- s32 status;
- s32 length;
- u32 buffer1, buffer2; /* We use only buffer 1. */
-};
-
-enum desc_status_bits {
- DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
-};
-
-/* Ring-wrap flag in length field, use for last ring entry.
- 0x01000000 means chain on buffer2 address,
- 0x02000000 means use the ring start address in CSR2/3.
- Note: Some work-alike chips do not function correctly in chained mode.
- The ASIX chip works only in chained mode.
- Thus we indicates ring mode, but always write the 'next' field for
- chained mode as well.
-*/
-#define DESC_RING_WRAP 0x02000000
-
-#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
-
-struct medialeaf {
- u8 type;
- u8 media;
- unsigned char *leafdata;
-};
-
-struct mediatable {
- u16 defaultmedia;
- u8 leafcount, csr12dir; /* General purpose pin directions. */
- unsigned has_mii:1, has_nonmii:1, has_reset:6;
- u32 csr15dir, csr15val; /* 21143 NWay setting. */
- struct medialeaf mleaf[0];
-};
-
-struct mediainfo {
- struct mediainfo *next;
- int info_type;
- int index;
- unsigned char *info;
-};
-
-struct tulip_private {
- char devname[8]; /* Used only for kernel debugging. */
- const char *product_name;
- struct net_device *next_module;
- struct tulip_rx_desc rx_ring[RX_RING_SIZE];
- struct tulip_tx_desc tx_ring[TX_RING_SIZE];
- /* The saved address of a sent-in-place packet/buffer, for skfree(). */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- /* The addresses of receive-in-place skbuffs. */
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- char *rx_buffs; /* Address of temporary Rx buffers. */
- u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */
- int chip_id;
- int revision;
- int flags;
- struct net_device_stats stats;
- struct timer_list timer; /* Media selection timer. */
- spinlock_t tx_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. */
- unsigned int default_port:4; /* Last dev->if_port value. */
- unsigned int media2:4; /* Secondary monitored media port. */
- unsigned int medialock:1; /* Don't sense media type. */
- unsigned int mediasense:1; /* Media sensing in progress. */
- unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
- unsigned int csr0; /* CSR0 setting. */
- unsigned int csr6; /* Current CSR6 control settings. */
- unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
- void (*link_change)(struct net_device *dev, int csr5);
- u16 to_advertise; /* NWay capabilities advertised. */
- u16 lpar; /* 21143 Link partner ability. */
- u16 advertising[4];
- signed char phys[4], mii_cnt; /* MII device addresses. */
- struct mediatable *mtable;
- int cur_index; /* Current media index. */
- int saved_if_port;
- struct pci_dev *pdev;
- int ttimer;
- int susp_rx;
- unsigned long nir;
- unsigned long base_addr;
- int pad0, pad1; /* Used for 8-byte alignment */
-};
-
-static void parse_eeprom(struct net_device *dev);
-static int read_eeprom(long ioaddr, int location, int addr_len);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
-static void select_media(struct net_device *dev, int startup);
-/* Chip-specific media selection (timer functions prototyped above). */
-static void t21142_lnk_change(struct net_device *dev, int csr5);
-static void t21142_start_nway(struct net_device *dev);
-static void pnic_lnk_change(struct net_device *dev, int csr5);
-static void pnic_do_nway(struct net_device *dev);
-
-static void tulip_tx_timeout(struct net_device *dev);
-static void tulip_init_ring(struct net_device *dev);
-static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int tulip_refill_rx(struct net_device *dev);
-static int tulip_rx(struct net_device *dev);
-static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int tulip_open(struct net_device *dev);
-static int tulip_close(struct net_device *dev);
-static void tulip_up(struct net_device *dev);
-static void tulip_down(struct net_device *dev);
-static struct net_device_stats *tulip_get_stats(struct net_device *dev);
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void set_rx_mode(struct net_device *dev);
-
-
-/* Serial EEPROM section. */
-/* The main routine to parse the very complicated SROM structure.
- Search www.digital.com for "21X4 SROM" to get details.
- This code is very complex, and will require changes to support
- additional cards, so I'll be verbose about what is going on.
- */
-
-/* Known cards that have old-style EEPROMs. */
-static struct fixups {
- char *name;
- unsigned char addr0, addr1, addr2;
- u16 newtable[32]; /* Max length below. */
-} eeprom_fixups[] = {
- {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
- 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
- {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0903, 0x006D, /* 100baseTx */
- 0x0905, 0x006D, /* 100baseTx-FD */ }},
- {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
- 0x0107, 0x8021, /* 100baseFx */
- 0x0108, 0x8021, /* 100baseFx-FD */
- 0x0100, 0x009E, /* 10baseT */
- 0x0104, 0x009E, /* 10baseT-FD */
- 0x0103, 0x006D, /* 100baseTx */
- 0x0105, 0x006D, /* 100baseTx-FD */ }},
- {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
- 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
- 0x0000, 0x009E, /* 10baseT */
- 0x0004, 0x009E, /* 10baseT-FD */
- 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
- 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
- {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
- 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
- 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
- 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
- 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
- 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
- }},
- {0, 0, 0, 0, {}}};
-
-static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
- "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
-
-#if defined(__i386__) /* AKA get_unaligned() */
-#define get_u16(ptr) (*(u16 *)(ptr))
-#else
-#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
-#endif
-
-static void parse_eeprom(struct net_device *dev)
-{
- /* The last media info list parsed, for multiport boards. */
- static struct mediatable *last_mediatable = NULL;
- static unsigned char *last_ee_data = NULL;
- static int controller_index = 0;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- unsigned char *ee_data = tp->eeprom;
- int i;
-
- tp->mtable = 0;
- /* Detect an old-style (SA only) EEPROM layout:
- memcmp(eedata, eedata+16, 8). */
- for (i = 0; i < 8; i ++)
- if (ee_data[i] != ee_data[16+i])
- break;
- if (i >= 8) {
- if (ee_data[0] == 0xff) {
- if (last_mediatable) {
- controller_index++;
- printk(KERN_INFO "%s: Controller %d of multiport board.\n",
- dev->name, controller_index);
- tp->mtable = last_mediatable;
- ee_data = last_ee_data;
- goto subsequent_board;
- } else
- printk(KERN_INFO "%s: Missing EEPROM, this interface may "
- "not work correctly!\n",
- dev->name);
- return;
- }
- /* Do a fix-up based on the vendor half of the station address prefix. */
- for (i = 0; eeprom_fixups[i].name; i++) {
- if (dev->dev_addr[0] == eeprom_fixups[i].addr0
- && dev->dev_addr[1] == eeprom_fixups[i].addr1
- && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
- if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
- i++; /* An Accton EN1207, not an outlaw Maxtech. */
- memcpy(ee_data + 26, eeprom_fixups[i].newtable,
- sizeof(eeprom_fixups[i].newtable));
- printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
- " substitute media control info.\n",
- dev->name, eeprom_fixups[i].name);
- break;
- }
- }
- if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
- printk(KERN_INFO "%s: Old style EEPROM with no media selection "
- "information.\n",
- dev->name);
- return;
- }
- }
-
- controller_index = 0;
- if (ee_data[19] > 1) { /* Multiport board. */
- last_ee_data = ee_data;
- }
-subsequent_board:
-
- if (ee_data[27] == 0) { /* No valid media table. */
- } else if (tp->chip_id == DC21041) {
- unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
- int media = get_u16(p);
- int count = p[2];
- p += 3;
-
- printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
- dev->name, media,
- media & 0x0800 ? "Autosense" : medianame[media & 15]);
- for (i = 0; i < count; i++) {
- unsigned char media_code = *p++;
- if (media_code & 0x40)
- p += 6;
- printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
- dev->name, media_code & 15, medianame[media_code & 15]);
- }
- } else {
- unsigned char *p = (void *)ee_data + ee_data[27];
- unsigned char csr12dir = 0;
- int count, new_advertise = 0;
- struct mediatable *mtable;
- u16 media = get_u16(p);
-
- p += 2;
- if (tp->flags & CSR12_IN_SROM)
- csr12dir = *p++;
- count = *p++;
- mtable = (struct mediatable *)
- kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
- GFP_KERNEL);
- if (mtable == NULL)
- return; /* Horrible, impossible failure. */
- last_mediatable = tp->mtable = mtable;
- mtable->defaultmedia = media;
- mtable->leafcount = count;
- mtable->csr12dir = csr12dir;
- mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
- mtable->csr15dir = mtable->csr15val = 0;
-
- printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
- media & 0x0800 ? "Autosense" : medianame[media & 15]);
- for (i = 0; i < count; i++) {
- struct medialeaf *leaf = &mtable->mleaf[i];
-
- if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
- leaf->type = 0;
- leaf->media = p[0] & 0x3f;
- leaf->leafdata = p;
- if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */
- mtable->has_mii = 1;
- p += 4;
- } else {
- leaf->type = p[1];
- if (p[1] == 0x05) {
- mtable->has_reset = i;
- leaf->media = p[2] & 0x0f;
- } else if (p[1] & 1) {
- mtable->has_mii = 1;
- leaf->media = 11;
- } else {
- mtable->has_nonmii = 1;
- leaf->media = p[2] & 0x0f;
- switch (leaf->media) {
- case 0: new_advertise |= 0x0020; break;
- case 4: new_advertise |= 0x0040; break;
- case 3: new_advertise |= 0x0080; break;
- case 5: new_advertise |= 0x0100; break;
- case 6: new_advertise |= 0x0200; break;
- }
- if (p[1] == 2 && leaf->media == 0) {
- if (p[2] & 0x40) {
- u32 base15 = get_unaligned((u16*)&p[7]);
- mtable->csr15dir =
- (get_unaligned((u16*)&p[9])<<16) + base15;
- mtable->csr15val =
- (get_unaligned((u16*)&p[11])<<16) + base15;
- } else {
- mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
- mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
- }
- }
- }
- leaf->leafdata = p + 2;
- p += (p[0] & 0x3f) + 1;
- }
- if (tulip_debug > 1 && leaf->media == 11) {
- unsigned char *bp = leaf->leafdata;
- printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
- "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
- dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
- bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
- }
- printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
- "by a %s (%d) block.\n",
- dev->name, i, medianame[leaf->media], leaf->media,
- block_name[leaf->type], leaf->type);
- }
- if (new_advertise)
- tp->to_advertise = new_advertise;
- }
-}
-/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
-
-/* EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
-#define EE_CS 0x01 /* EEPROM chip select. */
-#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */
-#define EE_WRITE_0 0x01
-#define EE_WRITE_1 0x05
-#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */
-#define EE_ENB (0x4800 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
- Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
- We add a bus turn-around to insure that this remains true. */
-#define eeprom_delay() inl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_READ_CMD (6)
-
-/* Note: this routine returns extra data bits for size detection. */
-static int __devinit read_eeprom(long ioaddr, int location, int addr_len)
-{
- int i;
- unsigned retval = 0;
- long ee_addr = ioaddr + CSR9;
- int read_cmd = location | (EE_READ_CMD << addr_len);
-
- outl(EE_ENB & ~EE_CS, ee_addr);
- outl(EE_ENB, ee_addr);
-
- /* Shift the read command bits out. */
- for (i = 4 + addr_len; i >= 0; i--) {
- short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
- outl(EE_ENB | dataval, ee_addr);
- eeprom_delay();
- outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
- retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
- }
- outl(EE_ENB, ee_addr);
-
- for (i = 16; i > 0; i--) {
- outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
- eeprom_delay();
- retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
- outl(EE_ENB, ee_addr);
- eeprom_delay();
- }
-
- /* Terminate the EEPROM access. */
- outl(EE_ENB & ~EE_CS, ee_addr);
- return retval;
-}
-
-/* MII transceiver control section.
- Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details. */
-
-/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
- met by back-to-back PCI I/O cycles, but we insert a delay to avoid
- "overclocking" issues or future 66Mhz PCI. */
-#define mdio_delay() inl(mdio_addr)
-
-/* Read and write the MII registers using software-generated serial
- MDIO protocol. It is just different enough from the EEPROM protocol
- to not share code. The maxium data clock rate is 2.5 Mhz. */
-#define MDIO_SHIFT_CLK 0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
-#define MDIO_ENB_IN 0x40000
-#define MDIO_DATA_READ 0x80000
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
- int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- int retval = 0;
- long ioaddr = dev->base_addr;
- long mdio_addr = ioaddr + CSR9;
-
- if (tp->chip_id == LC82C168) {
- int i = 1000;
- outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
- inl(ioaddr + 0xA0);
- inl(ioaddr + 0xA0);
- while (--i > 0)
- if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
- return retval & 0xffff;
- return 0xffff;
- }
-
- if (tp->chip_id == COMET) {
- if (phy_id == 1) {
- if (location < 7)
- return inl(ioaddr + 0xB4 + (location<<2));
- else if (location == 17)
- return inl(ioaddr + 0xD0);
- else if (location >= 29 && location <= 31)
- return inl(ioaddr + 0xD4 + ((location-29)<<2));
- }
- return 0xffff;
- }
-
- /* Establish sync by sending at least 32 logic ones. */
- for (i = 32; i >= 0; i--) {
- outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Shift the read command bits out. */
- for (i = 15; i >= 0; i--) {
- int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-
- outl(MDIO_ENB | dataval, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Read the two transition, 16 data, and wire-idle bits. */
- for (i = 19; i > 0; i--) {
- outl(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
- int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
- long ioaddr = dev->base_addr;
- long mdio_addr = ioaddr + CSR9;
-
- if (tp->chip_id == LC82C168) {
- int i = 1000;
- outl(cmd, ioaddr + 0xA0);
- do
- if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
- break;
- while (--i > 0);
- return;
- }
-
- if (tp->chip_id == COMET) {
- if (phy_id != 1)
- return;
- if (location < 7)
- outl(value, ioaddr + 0xB4 + (location<<2));
- else if (location == 17)
- outl(value, ioaddr + 0xD0);
- else if (location >= 29 && location <= 31)
- outl(value, ioaddr + 0xD4 + ((location-29)<<2));
- return;
- }
-
- /* Establish sync by sending 32 logic ones. */
- for (i = 32; i >= 0; i--) {
- outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Shift the command bits out. */
- for (i = 31; i >= 0; i--) {
- int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
- outl(MDIO_ENB | dataval, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- /* Clear out extra bits. */
- for (i = 2; i > 0; i--) {
- outl(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- }
- return;
-}
-
-
-/* The Xircom cards are picky about when certain bits in CSR6 can be
- manipulated. Keith Owens <kaos@ocs.com.au>. */
-
-static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
-{
- long ioaddr = tp->base_addr;
- const int strict_bits = 0x0060e202;
- int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
- long flags;
-
- /* really a hw lock */
- spin_lock_irqsave (&tp->tx_lock, flags);
-
- if (tp->chip_id != X3201_3)
- goto out_write;
-
- newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
- /* read 0 on the Xircom cards */
- newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
- currcsr6 = inl (ioaddr + CSR6);
- if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
- ((currcsr6 & ~0x2002) == 0))
- goto out_write;
-
- /* make sure the transmitter and receiver are stopped first */
- currcsr6 &= ~0x2002;
- while (1) {
- csr5 = inl (ioaddr + CSR5);
- if (csr5 == 0xffffffff)
- break; /* cannot read csr5, card removed? */
- csr5_22_20 = csr5 & 0x700000;
- csr5_19_17 = csr5 & 0x0e0000;
- if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
- (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
- break; /* both are stopped or suspended */
- if (!--attempts) {
- printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
- "csr5=0x%08x\n", csr5);
- goto out_write;
- }
- outl (currcsr6, ioaddr + CSR6);
- udelay (1);
- }
-
-out_write:
- /* now it is safe to change csr6 */
- outl (newcsr6, ioaddr + CSR6);
-
- spin_unlock_irqrestore (&tp->lock, flags);
-}
-
-
-static void tulip_up(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 3*HZ;
- int i;
-
- /* Wake the chip from sleep/snooze mode. */
- if (tp->flags & HAS_ACPI)
- pci_write_config_dword(tp->pdev, 0x40, 0);
-
- /* On some chip revs we must set the MII/SYM port before the reset!? */
- if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
- outl_CSR6 (tp, 0x00040000);
-
- /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
- outl(0x00000001, ioaddr + CSR0);
-
- /* Deassert reset.
- Wait the specified 50 PCI cycles after a reset by initializing
- Tx and Rx queues and the address filter list. */
- outl(tp->csr0, ioaddr + CSR0);
-
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
-
- if (tp->flags & MC_HASH_ONLY) {
- u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
- u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
- if (tp->chip_id == AX88140) {
- outl(0, ioaddr + CSR13);
- outl(addr_low, ioaddr + CSR14);
- outl(1, ioaddr + CSR13);
- outl(addr_high, ioaddr + CSR14);
- } else if (tp->chip_id == COMET) {
- outl(addr_low, ioaddr + 0xA4);
- outl(addr_high, ioaddr + 0xA8);
- outl(0, ioaddr + 0xAC);
- outl(0, ioaddr + 0xB0);
- }
- } else {
- /* This is set_rx_mode(), but without starting the transmitter. */
- u16 *eaddrs = (u16 *)dev->dev_addr;
- u16 *setup_frm = &tp->setup_frame[15*6];
-
- /* 21140 bug: you must add the broadcast address. */
- memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));
- /* Fill the final entry of the table with our physical address. */
- *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
- /* Put the setup frame on the Tx list. */
- tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
- tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
- tp->tx_ring[0].status = cpu_to_le32(DescOwned);
-
- tp->cur_tx++;
- }
-
- outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
- outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
-
- tp->saved_if_port = dev->if_port;
- if (dev->if_port == 0)
- dev->if_port = tp->default_port;
-
- /* Allow selecting a default media. */
- i = 0;
- if (tp->mtable == NULL)
- goto media_picked;
- if (dev->if_port) {
- int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
- (dev->if_port == 12 ? 0 : dev->if_port);
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using user-specified media %s.\n",
- dev->name, medianame[dev->if_port]);
- goto media_picked;
- }
- }
- if ((tp->mtable->defaultmedia & 0x0800) == 0) {
- int looking_for = tp->mtable->defaultmedia & 15;
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
- dev->name, medianame[looking_for]);
- goto media_picked;
- }
- }
- /* Start sensing first non-full-duplex media. */
- for (i = tp->mtable->leafcount - 1;
- (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
- ;
-media_picked:
-
- tp->csr6 = 0;
- tp->cur_index = i;
- tp->nwayset = 0;
- if (dev->if_port == 0 && tp->chip_id == DC21041) {
- tp->nway = 1;
- }
- if (dev->if_port == 0 && tp->chip_id == DC21142) {
- if (tp->mii_cnt) {
- select_media(dev, 1);
- if (tulip_debug > 1)
- printk(KERN_INFO "%s: Using MII transceiver %d, status "
- "%4.4x.\n",
- dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
- outl_CSR6(tp, 0x82020000);
- tp->csr6 = 0x820E0000;
- dev->if_port = 11;
- outl(0x0000, ioaddr + CSR13);
- outl(0x0000, ioaddr + CSR14);
- } else
- t21142_start_nway(dev);
- } else if (tp->chip_id == PNIC2) {
- t21142_start_nway(dev);
- } else if (tp->chip_id == LC82C168 && ! tp->medialock) {
- if (tp->mii_cnt) {
- dev->if_port = 11;
- tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
- outl(0x0001, ioaddr + CSR15);
- } else if (inl(ioaddr + CSR5) & TPLnkPass)
- pnic_do_nway(dev);
- else {
- /* Start with 10mbps to do autonegotiation. */
- outl(0x32, ioaddr + CSR12);
- tp->csr6 = 0x00420000;
- outl(0x0001B078, ioaddr + 0xB8);
- outl(0x0201B078, ioaddr + 0xB8);
- next_tick = 1*HZ;
- }
- } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
- && ! tp->medialock) {
- dev->if_port = 0;
- tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
- outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
- } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
- /* Provided by BOLO, Macronix - 12/10/1998. */
- dev->if_port = 0;
- tp->csr6 = 0x01a80200;
- outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
- outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
- } else if (tp->chip_id == DC21143 &&
- media_cap[dev->if_port] & MediaIsMII) {
- /* We must reset the media CSRs when we force-select MII mode. */
- outl(0x0000, ioaddr + CSR13);
- outl(0x0000, ioaddr + CSR14);
- outl(0x0008, ioaddr + CSR15);
- } else if (tp->chip_id == COMET) {
- dev->if_port = 0;
- tp->csr6 = 0x00040000;
- } else if (tp->chip_id == AX88140) {
- tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
- } else
- select_media(dev, 1);
-
- /* Start the chip's Tx to process setup frame. */
- outl_CSR6(tp, tp->csr6);
- outl_CSR6(tp, tp->csr6 | 0x2000);
-
- /* Enable interrupts by setting the interrupt mask. */
- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- outl(0, ioaddr + CSR2); /* Rx poll demand */
-
- if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
- dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
- inl(ioaddr + CSR6));
- }
- /* Set the timer to switch to check for link beat and perhaps switch
- to an alternate media type. */
- init_timer(&tp->timer);
- tp->timer.expires = RUN_AT(next_tick);
- tp->timer.data = (unsigned long)dev;
- tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
- add_timer(&tp->timer);
-
- netif_device_attach(dev);
-}
-
-
-static int
-tulip_open(struct net_device *dev)
-{
- MOD_INC_USE_COUNT;
-
- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
- MOD_DEC_USE_COUNT;
- return -EBUSY;
- }
-
- tulip_init_ring (dev);
-
- tulip_up (dev);
-
- return 0;
-}
-
-
-/* Set up the transceiver control registers for the selected media type. */
-static void select_media(struct net_device *dev, int startup)
-{
- long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- struct mediatable *mtable = tp->mtable;
- u32 new_csr6;
- int i;
-
- if (mtable) {
- struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
- unsigned char *p = mleaf->leafdata;
- switch (mleaf->type) {
- case 0: /* 21140 non-MII xcvr. */
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
- " with control setting %2.2x.\n",
- dev->name, p[1]);
- dev->if_port = p[0];
- if (startup)
- outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
- outl(p[1], ioaddr + CSR12);
- new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
- break;
- case 2: case 4: {
- u16 setup[5];
- u32 csr13val, csr14val, csr15dir, csr15val;
- for (i = 0; i < 5; i++)
- setup[i] = get_u16(&p[i*2 + 1]);
-
- dev->if_port = p[0] & 15;
- if (media_cap[dev->if_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
-
- if (startup && mtable->has_reset) {
- struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
- unsigned char *rst = rleaf->leafdata;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
- dev->name);
- for (i = 0; i < rst[0]; i++)
- outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
- }
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
- "%4.4x/%4.4x.\n",
- dev->name, medianame[dev->if_port], setup[0], setup[1]);
- if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
- csr13val = setup[0];
- csr14val = setup[1];
- csr15dir = (setup[3]<<16) | setup[2];
- csr15val = (setup[4]<<16) | setup[2];
- outl(0, ioaddr + CSR13);
- outl(csr14val, ioaddr + CSR14);
- outl(csr15dir, ioaddr + CSR15); /* Direction */
- outl(csr15val, ioaddr + CSR15); /* Data */
- outl(csr13val, ioaddr + CSR13);
- } else {
- csr13val = 1;
- csr14val = 0x0003FF7F;
- csr15dir = (setup[0]<<16) | 0x0008;
- csr15val = (setup[1]<<16) | 0x0008;
- if (dev->if_port <= 4)
- csr14val = t21142_csr14[dev->if_port];
- if (startup) {
- outl(0, ioaddr + CSR13);
- outl(csr14val, ioaddr + CSR14);
- }
- outl(csr15dir, ioaddr + CSR15); /* Direction */
- outl(csr15val, ioaddr + CSR15); /* Data */
- if (startup) outl(csr13val, ioaddr + CSR13);
- }
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
- dev->name, csr15dir, csr15val);
- if (mleaf->type == 4)
- new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
- else
- new_csr6 = 0x82420000;
- break;
- }
- case 1: case 3: {
- int phy_num = p[0];
- int init_length = p[1];
- u16 *misc_info;
- u16 to_advertise;
-
- dev->if_port = 11;
- new_csr6 = 0x020E0000;
- if (mleaf->type == 3) { /* 21142 */
- u16 *init_sequence = (u16*)(p+2);
- u16 *reset_sequence = &((u16*)(p+3))[init_length];
- int reset_length = p[2 + init_length*2];
- misc_info = reset_sequence + reset_length;
- if (startup)
- for (i = 0; i < reset_length; i++)
- outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
- for (i = 0; i < init_length; i++)
- outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
- } else {
- u8 *init_sequence = p + 2;
- u8 *reset_sequence = p + 3 + init_length;
- int reset_length = p[2 + init_length];
- misc_info = (u16*)(reset_sequence + reset_length);
- if (startup) {
- outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
- for (i = 0; i < reset_length; i++)
- outl(reset_sequence[i], ioaddr + CSR12);
- }
- for (i = 0; i < init_length; i++)
- outl(init_sequence[i], ioaddr + CSR12);
- }
- to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
- tp->advertising[phy_num] = to_advertise;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
- dev->name, to_advertise, phy_num, tp->phys[phy_num]);
- /* Bogus: put in by a committee? */
- mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
- break;
- }
- default:
- printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
- dev->name, mleaf->type);
- new_csr6 = 0x020E0000;
- }
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
- dev->name, medianame[dev->if_port],
- inl(ioaddr + CSR12) & 0xff);
- } else if (tp->chip_id == DC21041) {
- int port = dev->if_port <= 4 ? dev->if_port : 0;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
- dev->name, medianame[port == 3 ? 12: port],
- inl(ioaddr + CSR12));
- outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
- outl(t21041_csr14[port], ioaddr + CSR14);
- outl(t21041_csr15[port], ioaddr + CSR15);
- outl(t21041_csr13[port], ioaddr + CSR13);
- new_csr6 = 0x80020000;
- } else if (tp->chip_id == LC82C168) {
- if (startup && ! tp->medialock)
- dev->if_port = tp->mii_cnt ? 11 : 0;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
- dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
- if (tp->mii_cnt) {
- new_csr6 = 0x810C0000;
- outl(0x0001, ioaddr + CSR15);
- outl(0x0201B07A, ioaddr + 0xB8);
- } else if (startup) {
- /* Start with 10mbps to do autonegotiation. */
- outl(0x32, ioaddr + CSR12);
- new_csr6 = 0x00420000;
- outl(0x0001B078, ioaddr + 0xB8);
- outl(0x0201B078, ioaddr + 0xB8);
- } else if (dev->if_port == 3 || dev->if_port == 5) {
- outl(0x33, ioaddr + CSR12);
- new_csr6 = 0x01860000;
- /* Trigger autonegotiation. */
- outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
- } else {
- outl(0x32, ioaddr + CSR12);
- new_csr6 = 0x00420000;
- outl(0x1F078, ioaddr + 0xB8);
- }
- } else if (tp->chip_id == DC21040) { /* 21040 */
- /* Turn on the xcvr interface. */
- int csr12 = inl(ioaddr + CSR12);
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
- dev->name, medianame[dev->if_port], csr12);
- if (media_cap[dev->if_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
- new_csr6 = 0x20000;
- /* Set the full duplux match frame. */
- outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
- outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
- if (t21040_csr13[dev->if_port] & 8) {
- outl(0x0705, ioaddr + CSR14);
- outl(0x0006, ioaddr + CSR15);
- } else {
- outl(0xffff, ioaddr + CSR14);
- outl(0x0000, ioaddr + CSR15);
- }
- outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
- } else { /* Unknown chip type with no media table. */
- if (tp->default_port == 0)
- dev->if_port = tp->mii_cnt ? 11 : 3;
- if (media_cap[dev->if_port] & MediaIsMII) {
- new_csr6 = 0x020E0000;
- } else if (media_cap[dev->if_port] & MediaIsFx) {
- new_csr6 = 0x028600000;
- } else
- new_csr6 = 0x038600000;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No media description table, assuming "
- "%s transceiver, CSR12 %2.2x.\n",
- dev->name, medianame[dev->if_port],
- inl(ioaddr + CSR12));
- }
-
- tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
- return;
-}
-
-/*
- Check the MII negotiated duplex, and change the CSR6 setting if
- required.
- Return 0 if everything is OK.
- Return < 0 if the transceiver is missing or has no link beat.
- */
-static int check_duplex(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int mii_reg1, mii_reg5, negotiated, duplex;
-
- if (tp->full_duplex_lock)
- return 0;
- mii_reg1 = mdio_read(dev, tp->phys[0], 1);
- mii_reg5 = mdio_read(dev, tp->phys[0], 5);
- if (tulip_debug > 1)
- printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
- "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
- if (mii_reg1 == 0xffff)
- return -2;
- if ((mii_reg1 & 0x0004) == 0) {
- int new_reg1 = mdio_read(dev, tp->phys[0], 1);
- if ((new_reg1 & 0x0004) == 0) {
- if (tulip_debug > 1)
- printk(KERN_INFO "%s: No link beat on the MII interface,"
- " status %4.4x.\n", dev->name, new_reg1);
- return -1;
- }
- }
- negotiated = mii_reg5 & tp->advertising[0];
- duplex = ((negotiated & 0x0300) == 0x0100
- || (negotiated & 0x00C0) == 0x0040);
- /* 100baseTx-FD or 10T-FD, but not 100-HD */
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
- if (negotiated & 0x038) /* 100mbps. */
- tp->csr6 &= ~0x00400000;
- if (tp->full_duplex) tp->csr6 |= 0x0200;
- else tp->csr6 &= ~0x0200;
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- if (tulip_debug > 0)
- printk(KERN_INFO "%s: Setting %s-duplex based on MII"
- "#%d link partner capability of %4.4x.\n",
- dev->name, tp->full_duplex ? "full" : "half",
- tp->phys[0], mii_reg5);
- return 1;
- }
- return 0;
-}
-
-static void tulip_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u32 csr12 = inl(ioaddr + CSR12);
- int next_tick = 2*HZ;
-
- if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
- " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
- dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
- inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
- inl(ioaddr + CSR14), inl(ioaddr + CSR15));
- }
- switch (tp->chip_id) {
- case DC21040:
- if (!tp->medialock && csr12 & 0x0002) { /* Network error */
- printk(KERN_INFO "%s: No link beat found.\n",
- dev->name);
- dev->if_port = (dev->if_port == 2 ? 0 : 2);
- select_media(dev, 0);
- dev->trans_start = jiffies;
- }
- break;
- case DC21041:
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
- dev->name, csr12);
- if (tp->medialock) break;
- switch (dev->if_port) {
- case 0: case 3: case 4:
- if (csr12 & 0x0004) { /*LnkFail */
- /* 10baseT is dead. Check for activity on alternate port. */
- tp->mediasense = 1;
- if (csr12 & 0x0200)
- dev->if_port = 2;
- else
- dev->if_port = 1;
- printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
- dev->name, medianame[dev->if_port]);
- outl(0, ioaddr + CSR13); /* Reset */
- outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
- outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
- outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
- next_tick = 10*HZ; /* 2.4 sec. */
- } else
- next_tick = 30*HZ;
- break;
- case 1: /* 10base2 */
- case 2: /* AUI */
- if (csr12 & 0x0100) {
- next_tick = (30*HZ); /* 30 sec. */
- tp->mediasense = 0;
- } else if ((csr12 & 0x0004) == 0) {
- printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
- dev->name);
- dev->if_port = 0;
- select_media(dev, 0);
- next_tick = (24*HZ)/10; /* 2.4 sec. */
- } else if (tp->mediasense || (csr12 & 0x0002)) {
- dev->if_port = 3 - dev->if_port; /* Swap ports. */
- select_media(dev, 0);
- next_tick = 20*HZ;
- } else {
- next_tick = 20*HZ;
- }
- break;
- }
- break;
- case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
- struct medialeaf *mleaf;
- unsigned char *p;
- if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
- /* Not much that can be done.
- Assume this a generic MII or SYM transceiver. */
- next_tick = 60*HZ;
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
- "CSR12 0x%2.2x.\n",
- dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
- break;
- }
- mleaf = &tp->mtable->mleaf[tp->cur_index];
- p = mleaf->leafdata;
- switch (mleaf->type) {
- case 0: case 4: {
- /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */
- int offset = mleaf->type == 4 ? 5 : 2;
- s8 bitnum = p[offset];
- if (p[offset+1] & 0x80) {
- if (tulip_debug > 1)
- printk(KERN_DEBUG"%s: Transceiver monitor tick "
- "CSR12=%#2.2x, no media sense.\n",
- dev->name, csr12);
- if (mleaf->type == 4) {
- if (mleaf->media == 3 && (csr12 & 0x02))
- goto select_next_media;
- }
- break;
- }
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
- " bit %d is %d, expecting %d.\n",
- dev->name, csr12, (bitnum >> 1) & 7,
- (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
- (bitnum >= 0));
- /* Check that the specified bit has the proper value. */
- if ((bitnum < 0) !=
- ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
- medianame[mleaf->media]);
- if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
- goto actually_mii;
- break;
- }
- if (tp->medialock)
- break;
- select_next_media:
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
- if (media_cap[dev->if_port] & MediaIsFD)
- goto select_next_media; /* Skip FD entries. */
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No link beat on media %s,"
- " trying transceiver type %s.\n",
- dev->name, medianame[mleaf->media & 15],
- medianame[tp->mtable->mleaf[tp->cur_index].media]);
- select_media(dev, 0);
- /* Restart the transmit process. */
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- next_tick = (24*HZ)/10;
- break;
- }
- case 1: case 3: /* 21140, 21142 MII */
- actually_mii:
- check_duplex(dev);
- next_tick = 60*HZ;
- break;
- case 2: /* 21142 serial block has no link beat. */
- default:
- break;
- }
- }
- break;
- }
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
-}
-
-
-/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
- of available transceivers. */
-static void t21142_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr12 = inl(ioaddr + CSR12);
- int next_tick = 60*HZ;
- int new_csr6 = 0;
-
- if (tulip_debug > 2)
- printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
- dev->name, csr12, medianame[dev->if_port]);
- if (media_cap[dev->if_port] & MediaIsMII) {
- check_duplex(dev);
- next_tick = 60*HZ;
- } else if (tp->nwayset) {
- /* Don't screw up a negotiated session! */
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
- dev->name, medianame[dev->if_port], csr12);
- } else if (tp->medialock) {
- ;
- } else if (dev->if_port == 3) {
- if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
- "trying NWay.\n", dev->name, csr12);
- t21142_start_nway(dev);
- next_tick = 3*HZ;
- }
- } else if ((csr12 & 0x7000) != 0x5000) {
- /* Negotiation failed. Search media types. */
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
- dev->name, csr12);
- if (!(csr12 & 4)) { /* 10mbps link beat good. */
- new_csr6 = 0x82420000;
- dev->if_port = 0;
- outl(0, ioaddr + CSR13);
- outl(0x0003FFFF, ioaddr + CSR14);
- outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
- outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
- } else {
- /* Select 100mbps port to check for link beat. */
- new_csr6 = 0x83860000;
- dev->if_port = 3;
- outl(0, ioaddr + CSR13);
- outl(0x0003FF7F, ioaddr + CSR14);
- outw(8, ioaddr + CSR15);
- outl(1, ioaddr + CSR13);
- }
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
- dev->name, medianame[dev->if_port]);
- if (new_csr6 != (tp->csr6 & ~0x00D5)) {
- tp->csr6 &= 0x00D5;
- tp->csr6 |= new_csr6;
- outl(0x0301, ioaddr + CSR12);
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- }
- next_tick = 3*HZ;
- }
-
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
-}
-
-
-static void t21142_start_nway(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr14 = ((tp->to_advertise & 0x0780) << 9) |
- ((tp->to_advertise&0x0020)<<1) | 0xffbf;
-
- dev->if_port = 0;
- tp->nway = tp->mediasense = 1;
- tp->nwayset = tp->lpar = 0;
- if (debug > 1)
- printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
- dev->name, csr14);
- outl(0x0001, ioaddr + CSR13);
- outl(csr14, ioaddr + CSR14);
- tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
- outl_CSR6(tp, tp->csr6);
- if (tp->mtable && tp->mtable->csr15dir) {
- outl(tp->mtable->csr15dir, ioaddr + CSR15);
- outl(tp->mtable->csr15val, ioaddr + CSR15);
- } else
- outw(0x0008, ioaddr + CSR15);
- outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
-}
-
-
-static void t21142_lnk_change(struct net_device *dev, int csr5)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr12 = inl(ioaddr + CSR12);
-
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
- "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
-
- /* If NWay finished and we have a negotiated partner capability. */
- if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
- int setup_done = 0;
- int negotiated = tp->to_advertise & (csr12 >> 16);
- tp->lpar = csr12 >> 16;
- tp->nwayset = 1;
- if (negotiated & 0x0100) dev->if_port = 5;
- else if (negotiated & 0x0080) dev->if_port = 3;
- else if (negotiated & 0x0040) dev->if_port = 4;
- else if (negotiated & 0x0020) dev->if_port = 0;
- else {
- tp->nwayset = 0;
- if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180))
- dev->if_port = 3;
- }
- tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
-
- if (tulip_debug > 1) {
- if (tp->nwayset)
- printk(KERN_INFO "%s: Switching to %s based on link "
- "negotiation %4.4x & %4.4x = %4.4x.\n",
- dev->name, medianame[dev->if_port], tp->to_advertise,
- tp->lpar, negotiated);
- else
- printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
- " link beat status %4.4x.\n",
- dev->name, medianame[dev->if_port], csr12);
- }
-
- if (tp->mtable) {
- int i;
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == dev->if_port) {
- tp->cur_index = i;
- select_media(dev, 0);
- setup_done = 1;
- break;
- }
- }
- if ( ! setup_done) {
- tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
- if (tp->full_duplex)
- tp->csr6 |= 0x0200;
- outl(1, ioaddr + CSR13);
- }
-#if 0 /* Restart shouldn't be needed. */
- outl_CSR6(tp, tp->csr6 | 0x0000);
- if (debug > 2)
- printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
- dev->name, inl(ioaddr + CSR5));
-#endif
- outl_CSR6(tp, tp->csr6 | 0x2002);
- if (debug > 2)
- printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
- dev->name, tp->csr6, inl(ioaddr + CSR6),
- inl(ioaddr + CSR12));
- } else if ((tp->nwayset && (csr5 & 0x08000000)
- && (dev->if_port == 3 || dev->if_port == 5)
- && (csr12 & 2) == 2) ||
- (tp->nway && (csr5 & (TPLnkFail)))) {
- /* Link blew? Maybe restart NWay. */
- del_timer(&tp->timer);
- t21142_start_nway(dev);
- tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
- } else if (dev->if_port == 3 || dev->if_port == 5) {
- if (tulip_debug > 1)
- printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
- dev->name, medianame[dev->if_port],
- (csr12 & 2) ? "failed" : "good");
- if ((csr12 & 2) && ! tp->medialock) {
- del_timer(&tp->timer);
- t21142_start_nway(dev);
- tp->timer.expires = RUN_AT(3*HZ);
- add_timer(&tp->timer);
- }
- } else if (dev->if_port == 0 || dev->if_port == 4) {
- if ((csr12 & 4) == 0)
- printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
- dev->name);
- } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
- if (tulip_debug)
- printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
- dev->name);
- dev->if_port = 0;
- } else if (tp->nwayset) {
- if (tulip_debug)
- printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
- dev->name, medianame[dev->if_port], tp->csr6);
- } else { /* 100mbps link beat good. */
- if (tulip_debug)
- printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
- dev->name);
- dev->if_port = 3;
- tp->csr6 = 0x83860000;
- outl(0x0003FF7F, ioaddr + CSR14);
- outl(0x0301, ioaddr + CSR12);
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- }
-}
-
-
-static void mxic_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-
- if (tulip_debug > 3) {
- printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
- inl(ioaddr + CSR12));
- }
- if (next_tick) {
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
- }
-}
-
-
-static void pnic_do_nway(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u32 phy_reg = inl(ioaddr + 0xB8);
- u32 new_csr6 = tp->csr6 & ~0x40C40200;
-
- if (phy_reg & 0x78000000) { /* Ignore baseT4 */
- if (phy_reg & 0x20000000) dev->if_port = 5;
- else if (phy_reg & 0x40000000) dev->if_port = 3;
- else if (phy_reg & 0x10000000) dev->if_port = 4;
- else if (phy_reg & 0x08000000) dev->if_port = 0;
- tp->nwayset = 1;
- new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
- outl(0x32 | (dev->if_port & 1), ioaddr + CSR12);
- if (dev->if_port & 1)
- outl(0x1F868, ioaddr + 0xB8);
- if (phy_reg & 0x30000000) {
- tp->full_duplex = 1;
- new_csr6 |= 0x00000200;
- }
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
- dev->name, phy_reg, medianame[dev->if_port]);
- if (tp->csr6 != new_csr6) {
- tp->csr6 = new_csr6;
- /* Restart Tx */
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- dev->trans_start = jiffies;
- }
- }
-}
-
-
-static void pnic_lnk_change(struct net_device *dev, int csr5)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int phy_reg = inl(ioaddr + 0xB8);
-
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
- dev->name, phy_reg, csr5);
- if (inl(ioaddr + CSR5) & TPLnkFail) {
- outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
- if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) {
- tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
- outl_CSR6(tp, tp->csr6);
- outl(0x30, ioaddr + CSR12);
- outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
- dev->trans_start = jiffies;
- }
- } else if (inl(ioaddr + CSR5) & TPLnkPass) {
- pnic_do_nway(dev);
- outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
- }
-}
-
-
-static void pnic_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-
- if (media_cap[dev->if_port] & MediaIsMII) {
- if (check_duplex(dev) > 0)
- next_tick = 3*HZ;
- } else {
- int csr12 = inl(ioaddr + CSR12);
- int new_csr6 = tp->csr6 & ~0x40C40200;
- int phy_reg = inl(ioaddr + 0xB8);
- int csr5 = inl(ioaddr + CSR5);
-
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
- "CSR5 %8.8x.\n",
- dev->name, phy_reg, medianame[dev->if_port], csr5);
- if (phy_reg & 0x04000000) { /* Remote link fault */
- outl(0x0201F078, ioaddr + 0xB8);
- next_tick = 1*HZ;
- tp->nwayset = 0;
- } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
- pnic_do_nway(dev);
- next_tick = 60*HZ;
- } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
- "CSR5 %8.8x, PHY %3.3x.\n",
- dev->name, medianame[dev->if_port], csr12,
- inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
- next_tick = 3*HZ;
- if (tp->medialock) {
- } else if (tp->nwayset && (dev->if_port & 1)) {
- next_tick = 1*HZ;
- } else if (dev->if_port == 0) {
- dev->if_port = 3;
- outl(0x33, ioaddr + CSR12);
- new_csr6 = 0x01860000;
- outl(0x1F868, ioaddr + 0xB8);
- } else {
- dev->if_port = 0;
- outl(0x32, ioaddr + CSR12);
- new_csr6 = 0x00420000;
- outl(0x1F078, ioaddr + 0xB8);
- }
- if (tp->csr6 != new_csr6) {
- tp->csr6 = new_csr6;
- /* Restart Tx */
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- dev->trans_start = jiffies;
- if (tulip_debug > 1)
- printk(KERN_INFO "%s: Changing PNIC configuration to %s "
- "%s-duplex, CSR6 %8.8x.\n",
- dev->name, medianame[dev->if_port],
- tp->full_duplex ? "full" : "half", new_csr6);
- }
- }
- }
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
-}
-
-static void comet_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int next_tick = 60*HZ;
-
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
- "%4.4x.\n",
- dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
- tp->timer.expires = RUN_AT(next_tick);
- add_timer(&tp->timer);
-}
-
-static void tulip_tx_timeout(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
- if (media_cap[dev->if_port] & MediaIsMII) {
- /* Do nothing -- the media monitor should handle this. */
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
- dev->name);
- } else if (tp->chip_id == DC21040) {
- if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
- dev->if_port = (dev->if_port == 2 ? 0 : 2);
- printk(KERN_INFO "%s: transmit timed out, switching to "
- "%s.\n",
- dev->name, medianame[dev->if_port]);
- select_media(dev, 0);
- }
- dev->trans_start = jiffies;
- return;
- } else if (tp->chip_id == DC21041) {
- int csr12 = inl(ioaddr + CSR12);
-
- printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
- "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), csr12,
- inl(ioaddr + CSR13), inl(ioaddr + CSR14));
- tp->mediasense = 1;
- if ( ! tp->medialock) {
- if (dev->if_port == 1 || dev->if_port == 2)
- if (csr12 & 0x0004) {
- dev->if_port = 2 - dev->if_port;
- } else
- dev->if_port = 0;
- else
- dev->if_port = 1;
- select_media(dev, 0);
- }
- } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
- || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
- inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
- if ( ! tp->medialock && tp->mtable) {
- do
- --tp->cur_index;
- while (tp->cur_index >= 0
- && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
- & MediaIsFD));
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- select_media(dev, 0);
- printk(KERN_WARNING "%s: transmit timed out, switching to %s "
- "media.\n", dev->name, medianame[dev->if_port]);
- }
- } else {
- printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
- "%8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
- dev->if_port = 0;
- }
-
-#if defined(way_too_many_messages)
- if (tulip_debug > 3) {
- int i;
- for (i = 0; i < RX_RING_SIZE; i++) {
- u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
- int j;
- printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
- "%2.2x %2.2x %2.2x.\n",
- i, (unsigned int)tp->rx_ring[i].status,
- (unsigned int)tp->rx_ring[i].length,
- (unsigned int)tp->rx_ring[i].buffer1,
- (unsigned int)tp->rx_ring[i].buffer2,
- buf[0], buf[1], buf[2]);
- for (j = 0; buf[j] != 0xee && j < 1600; j++)
- if (j < 100) printk(" %2.2x", buf[j]);
- printk(" j=%d.\n", j);
- }
- printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
- for (i = 0; i < RX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
- printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
- for (i = 0; i < TX_RING_SIZE; i++)
- printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
- printk("\n");
- }
-#endif
-
- /* Stop and restart the chip's Tx processes . */
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);
-
- dev->trans_start = jiffies;
- tp->stats.tx_errors++;
- return;
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void tulip_init_ring(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int i;
-
- tp->tx_full = 0;
- tp->cur_rx = tp->cur_tx = 0;
- tp->dirty_rx = tp->dirty_tx = 0;
- tp->susp_rx = 0;
- tp->ttimer = 0;
- tp->nir = 0;
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- tp->rx_ring[i].status = 0x00000000;
- tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
- tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
- tp->rx_skbuff[i] = NULL;
- }
- /* Mark the last entry as wrapping the ring. */
- tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
- tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- /* Note the receive buffer must be longword aligned.
- dev_alloc_skb() provides 16 byte alignment. But do *not*
- use skb_reserve() to align the IP header! */
- struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
- tp->rx_skbuff[i] = skb;
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
- tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */
- tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
- }
- tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
- /* The Tx buffer descriptor is filled in as needed, but we
- do need to clear the ownership bit. */
- for (i = 0; i < TX_RING_SIZE; i++) {
- tp->tx_skbuff[i] = 0;
- tp->tx_ring[i].status = 0x00000000;
- tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]);
- }
- tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]);
-}
-
-static int
-tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int entry;
- u32 flag;
- unsigned long cpuflags;
-
- /* Caution: the write order is important here, set the field
- with the ownership bits last. */
-
- spin_lock_irqsave(&tp->tx_lock, cpuflags);
-
- /* Calculate the next Tx descriptor entry. */
- entry = tp->cur_tx % TX_RING_SIZE;
-
- tp->tx_skbuff[entry] = skb;
- tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
-
- if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
- flag = 0x60000000; /* No interrupt */
- } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
- flag = 0xe0000000; /* Tx-done intr. */
- } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
- flag = 0x60000000; /* No Tx-done intr. */
- } else { /* Leave room for set_rx_mode() to fill entries. */
- tp->tx_full = 1;
- flag = 0xe0000000; /* Tx-done intr. */
- netif_stop_queue(dev);
- }
- if (entry == TX_RING_SIZE-1)
- flag = 0xe0000000 | DESC_RING_WRAP;
-
- tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- tp->cur_tx++;
- spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
-
- /* Trigger an immediate transmit demand. */
- outl(0, dev->base_addr + CSR1);
-
- dev->trans_start = jiffies;
-
- return 0;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
- after the Tx thread. */
-static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *)dev_instance;
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr5;
- int entry;
- int missed;
- int rx = 0;
- int tx = 0;
- int oi = 0;
- int maxrx = RX_RING_SIZE;
- int maxtx = TX_RING_SIZE;
- int maxoi = TX_RING_SIZE;
-
- tp->nir++;
-
- do {
- csr5 = inl(ioaddr + CSR5);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outl(csr5 & 0x0001ffff, ioaddr + CSR5);
-
- if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
- dev->name, csr5, inl(dev->base_addr + CSR5));
-
- if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
- break;
-
- if (csr5 & (RxIntr | RxNoBuf)) {
- rx += tulip_rx(dev);
- tulip_refill_rx(dev);
- }
-
- if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
- unsigned int dirty_tx;
-
- spin_lock(&tp->tx_lock);
-
- for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
- dirty_tx++) {
- int entry = dirty_tx % TX_RING_SIZE;
- int status = le32_to_cpu(tp->tx_ring[entry].status);
-
- if (status < 0)
- break; /* It still has not been Txed */
- /* Check for Rx filter setup frames. */
- if (tp->tx_skbuff[entry] == NULL)
- continue;
-
- if (status & 0x8000) {
- /* There was an major error, log it. */
-#ifndef final_version
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
- dev->name, status);
-#endif
- tp->stats.tx_errors++;
- if (status & 0x4104) tp->stats.tx_aborted_errors++;
- if (status & 0x0C00) tp->stats.tx_carrier_errors++;
- if (status & 0x0200) tp->stats.tx_window_errors++;
- if (status & 0x0002) tp->stats.tx_fifo_errors++;
- if ((status & 0x0080) && tp->full_duplex == 0)
- tp->stats.tx_heartbeat_errors++;
-#ifdef ETHER_STATS
- if (status & 0x0100) tp->stats.collisions16++;
-#endif
- } else {
-#ifdef ETHER_STATS
- if (status & 0x0001) tp->stats.tx_deferred++;
-#endif
- tp->stats.tx_bytes += tp->tx_skbuff[entry]->len;
- tp->stats.collisions += (status >> 3) & 15;
- tp->stats.tx_packets++;
- }
-
- /* Free the original skb. */
- dev_kfree_skb_irq(tp->tx_skbuff[entry]);
- tp->tx_skbuff[entry] = 0;
- tx++;
- }
-
-#ifndef final_version
- if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
- printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
- dirty_tx += TX_RING_SIZE;
- }
-#endif
-
- if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
- /* The ring is no longer full, clear tbusy. */
- tp->tx_full = 0;
- netif_wake_queue(dev);
- }
-
- tp->dirty_tx = dirty_tx;
- if (csr5 & TxDied) {
- if (tulip_debug > 2)
- printk(KERN_WARNING "%s: The transmitter stopped."
- " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
- dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- }
- spin_unlock(&tp->tx_lock);
- }
-
- /* Log errors. */
- if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
- if (csr5 == 0xffffffff)
- break;
- if (csr5 & TxJabber) tp->stats.tx_errors++;
- if (csr5 & TxFIFOUnderflow) {
- if ((tp->csr6 & 0xC000) != 0xC000)
- tp->csr6 += 0x4000; /* Bump up the Tx threshold */
- else
- tp->csr6 |= 0x00200000; /* Store-n-forward. */
- /* Restart the transmit process. */
- outl_CSR6(tp, tp->csr6 | 0x0002);
- outl_CSR6(tp, tp->csr6 | 0x2002);
- outl(0, ioaddr + CSR1);
- }
- if (csr5 & RxDied) { /* Missed a Rx frame. */
- tp->stats.rx_errors++;
- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
- outl_CSR6(tp, tp->csr6 | 0x2002);
- }
- if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
- if (tp->link_change)
- (tp->link_change)(dev, csr5);
- }
- if (csr5 & SytemError) {
- printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
- }
- /* Clear all error sources, included undocumented ones! */
- outl(0x0800f7ba, ioaddr + CSR5);
- oi++;
- }
- if (csr5 & TimerInt) {
-#if 0
- if (tulip_debug > 2)
- printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
- dev->name, csr5);
- outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-#endif
- tp->ttimer = 0;
- oi++;
- }
- if (tx > maxtx || rx > maxrx || oi > maxoi) {
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Too much work during an interrupt, "
- "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
- /* Acknowledge all interrupt sources. */
-#if 0
- /* Clear all interrupting sources, set timer to re-enable. */
- outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
- ioaddr + CSR7);
- outl(12, ioaddr + CSR11);
- tp->ttimer = 1;
-#endif
- break;
- }
- } while (1);
-
- tulip_refill_rx(dev);
-
- /* check if we card is in suspend mode */
- entry = tp->dirty_rx % RX_RING_SIZE;
- if (tp->rx_skbuff[entry] == NULL) {
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
- if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
- outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
- ioaddr + CSR7);
- outl(TimerInt, ioaddr + CSR5);
- outl(12, ioaddr + CSR11);
- tp->ttimer = 1;
- }
- }
-
- if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
- tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
- }
-
- if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
- dev->name, inl(ioaddr + CSR5));
-
-}
-
-static int tulip_refill_rx(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int entry;
- int refilled = 0;
-
- /* Refill the Rx ring buffers. */
- for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
- entry = tp->dirty_rx % RX_RING_SIZE;
- if (tp->rx_skbuff[entry] == NULL) {
- struct sk_buff *skb;
- skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
- if (skb == NULL)
- break;
- skb->dev = dev; /* Mark as being used by this device. */
- tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
- refilled++;
- }
- tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
- }
- return refilled;
-}
-
-static int tulip_rx(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int entry = tp->cur_rx % RX_RING_SIZE;
- int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
- int received = 0;
-
- if (tulip_debug > 4)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
- tp->rx_ring[entry].status);
- /* If we own the next entry, it is a new packet. Send it up. */
- while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
- s32 status = le32_to_cpu(tp->rx_ring[entry].status);
-
- if (tulip_debug > 5)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
- dev->name, entry, status);
- if (--rx_work_limit < 0)
- break;
- if ((status & 0x38008300) != 0x0300) {
- if ((status & 0x38000300) != 0x0300) {
- /* Ingore earlier buffers. */
- if ((status & 0xffff) != 0x7fff) {
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Oversized Ethernet frame "
- "spanned multiple buffers, status %8.8x!\n",
- dev->name, status);
- tp->stats.rx_length_errors++;
- }
- } else if (status & RxDescFatalErr) {
- /* There was a fatal error. */
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
- dev->name, status);
- tp->stats.rx_errors++; /* end of a packet.*/
- if (status & 0x0890) tp->stats.rx_length_errors++;
- if (status & 0x0004) tp->stats.rx_frame_errors++;
- if (status & 0x0002) tp->stats.rx_crc_errors++;
- if (status & 0x0001) tp->stats.rx_fifo_errors++;
- }
- } else {
- /* Omit the four octet CRC from the length. */
- short pkt_len = ((status >> 16) & 0x7ff) - 4;
- struct sk_buff *skb;
-
-#ifndef final_version
- if (pkt_len > 1518) {
- printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
- dev->name, pkt_len, pkt_len);
- pkt_len = 1518;
- tp->stats.rx_length_errors++;
- }
-#endif
- /* Check if the packet is long enough to accept without copying
- to a minimally-sized skbuff. */
- if (pkt_len < rx_copybreak
- && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte align the IP header */
-#if ! defined(__alpha__)
- eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
- skb_put(skb, pkt_len);
-#else
- memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
- pkt_len);
-#endif
- } else { /* Pass up the skb already on the Rx ring. */
- char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
- tp->rx_skbuff[entry] = NULL;
-#ifndef final_version
- if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
- printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
- "do not match in tulip_rx: %p vs. %p / %p.\n",
- dev->name,
- le32desc_to_virt(tp->rx_ring[entry].buffer1),
- skb->head, temp);
-#endif
- }
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- tp->stats.rx_packets++;
- tp->stats.rx_bytes += pkt_len;
- }
- received++;
- entry = (++tp->cur_rx) % RX_RING_SIZE;
- }
-
- return received;
-}
-
-
-static void tulip_down (struct net_device *dev)
-{
- long ioaddr = dev->base_addr;
- struct tulip_private *tp = (struct tulip_private *) dev->priv;
-
- netif_device_detach (dev);
-
- del_timer (&tp->timer);
-
- /* Disable interrupts by clearing the interrupt mask. */
- outl (0x00000000, ioaddr + CSR7);
-
- /* Stop the Tx and Rx processes. */
- outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002);
-
- /* 21040 -- Leave the card in 10baseT state. */
- if (tp->chip_id == DC21040)
- outl (0x00000004, ioaddr + CSR13);
-
- if (inl (ioaddr + CSR6) != 0xffffffff)
- tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff;
-
- dev->if_port = tp->saved_if_port;
-
- /* Leave the driver in snooze, not sleep, mode. */
- 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;
-
- tulip_down (dev);
-
- if (tulip_debug > 1)
- printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, inl (ioaddr + CSR5));
-
- free_irq (dev->irq, dev);
-
- /* Free all the skbuffs in the Rx queue. */
- for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = tp->rx_skbuff[i];
- tp->rx_skbuff[i] = 0;
- tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
- tp->rx_ring[i].length = 0;
- tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
- if (skb) {
- dev_kfree_skb (skb);
- }
- }
- for (i = 0; i < TX_RING_SIZE; i++) {
- if (tp->tx_skbuff[i])
- dev_kfree_skb (tp->tx_skbuff[i]);
- tp->tx_skbuff[i] = 0;
- }
-
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
-static struct enet_statistics *tulip_get_stats(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
-
- if (netif_running(dev))
- tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-
- return &tp->stats;
-}
-
-
-/* Provide ioctl() calls to examine the MII xcvr state. */
-static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- u16 *data = (u16 *)&rq->ifr_data;
- int phy = tp->phys[0] & 0x1f;
- long flags;
-
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- if (tp->mii_cnt)
- data[0] = phy;
- else if (tp->flags & HAS_NWAY143)
- data[0] = 32;
- else if (tp->chip_id == COMET)
- data[0] = 1;
- else
- return -ENODEV;
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
- int csr12 = inl(ioaddr + CSR12);
- int csr14 = inl(ioaddr + CSR14);
- switch (data[1]) {
- case 0: {
- data[3] = (csr14<<5) & 0x1000;
- break; }
- case 1:
- data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
- + (csr12&0x06 ? 0x04 : 0);
- break;
- case 4: {
- data[3] = ((csr14>>9)&0x07C0) +
- ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
- break;
- }
- case 5: data[3] = csr12 >> 16; break;
- default: data[3] = 0; break;
- }
- } else {
- save_flags(flags);
- cli();
- data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
- restore_flags(flags);
- }
- return 0;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
- if (data[1] == 5)
- tp->to_advertise = data[2];
- } else {
- save_flags(flags);
- cli();
- mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- restore_flags(flags);
- }
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-
- return -EOPNOTSUPP;
-}
-
-
-/* Set or clear the multicast filter for this adaptor.
- Note that we only use exclusion around actually queueing the
- new frame, not around filling tp->setup_frame. This is non-deterministic
- when re-entered but still correct. */
-
-/* The little-endian AUTODIN32 ethernet CRC calculation.
- N.B. Do not use for bulk data, use a table-based routine instead.
- This is common code and should be moved to net/core/crc.c */
-static unsigned const ethernet_polynomial_le = 0xedb88320U;
-static inline u32 ether_crc_le(int length, unsigned char *data)
-{
- u32 crc = 0xffffffff; /* Initial value. */
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 8; --bit >= 0; current_octet >>= 1) {
- if ((crc ^ current_octet) & 1) {
- crc >>= 1;
- crc ^= ethernet_polynomial_le;
- } else
- crc >>= 1;
- }
- }
- return crc;
-}
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1)
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- return crc;
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
- unsigned long cpuflags;
-
- tp->csr6 &= ~0x00D5;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- tp->csr6 |= 0x00C0;
- csr6 |= 0x00C0;
- /* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
- } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
- /* Too many to filter well -- accept all multicasts. */
- tp->csr6 |= 0x0080;
- csr6 |= 0x0080;
- } else if (tp->flags & MC_HASH_ONLY) {
- /* Some work-alikes have only a 64-entry hash filter table. */
- /* Should verify correctness on big-endian/__powerpc__ */
- struct dev_mc_list *mclist;
- int i;
- u32 mc_filter[2]; /* Multicast hash filter */
- if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
- tp->csr6 |= 0x0080;
- csr6 |= 0x0080;
- } else {
- mc_filter[1] = mc_filter[0] = 0;
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist = mclist->next)
- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
- if (tp->chip_id == AX88140) {
- outl(2, ioaddr + CSR13);
- outl(mc_filter[0], ioaddr + CSR14);
- outl(3, ioaddr + CSR13);
- outl(mc_filter[1], ioaddr + CSR14);
- } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
- outl(mc_filter[0], ioaddr + 0xAC);
- outl(mc_filter[1], ioaddr + 0xB0);
- }
- }
- } else {
- u16 *eaddrs, *setup_frm = tp->setup_frame;
- struct dev_mc_list *mclist;
- u32 tx_flags = 0x08000000 | 192;
- int i;
-
- /* Note that only the low-address shortword of setup_frame is valid!
- The values are doubled for big-endian architectures. */
- if (dev->mc_count > 14) { /* 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++ = *setup_frm++ = hash_table[i];
- setup_frm = &tp->setup_frame[13*6];
- } 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) {
- eaddrs = (u16 *)mclist->dmi_addr;
- *setup_frm++ = *setup_frm++ = *eaddrs++;
- *setup_frm++ = *setup_frm++ = *eaddrs++;
- *setup_frm++ = *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++ = *setup_frm++ = eaddrs[0];
- *setup_frm++ = *setup_frm++ = eaddrs[1];
- *setup_frm++ = *setup_frm++ = eaddrs[2];
- /* Now add this frame to the Tx list. */
- spin_lock_irqsave(&tp->tx_lock, cpuflags);
- if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
- /* Same setup recently queued, we need not add it. */
- } else {
- unsigned long flags;
- unsigned int entry;
-
- save_flags(flags); cli();
- entry = tp->cur_tx++ % TX_RING_SIZE;
-
- if (entry != 0) {
- /* Avoid a chip errata by prefixing a dummy entry. */
- tp->tx_skbuff[entry] = 0;
- tp->tx_ring[entry].length =
- (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
- tp->tx_ring[entry].buffer1 = 0;
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- entry = tp->cur_tx++ % TX_RING_SIZE;
- }
-
- tp->tx_skbuff[entry] = 0;
- /* Put the setup frame on the Tx list. */
- if (entry == TX_RING_SIZE-1)
- tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
- tp->tx_ring[entry].length = cpu_to_le32(tx_flags);
- tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
- tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
- if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
- netif_stop_queue(dev);
- tp->tx_full = 1;
- }
- spin_unlock_irqrestore(&tp->tx_lock, cpuflags);
- /* Trigger an immediate transmit demand. */
- outl(0, ioaddr + CSR1);
- }
- }
- outl_CSR6(tp, csr6 | 0x0000);
-}
-
-
-static int __devinit tulip_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- static int did_version = 0; /* Already printed version info. */
- struct tulip_private *tp;
- /* See note below on the multiport cards. */
- static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
- static int last_irq = 0;
- static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
- u8 chip_rev;
- int i, irq;
- unsigned short sum;
- u8 ee_data[EEPROM_SIZE];
- struct net_device *dev;
- long ioaddr;
- static int board_idx = -1;
- int chip_idx = ent->driver_data;
-
- board_idx++;
-
- if (tulip_debug > 0 && did_version++ == 0)
- printk (KERN_INFO "%s", version);
-
- if( pdev->subsystem_vendor == 0x1376 ){
- printk (KERN_ERR PFX "skipping LMC card.\n");
- return -ENODEV;
- }
-
- ioaddr = pci_resource_start (pdev, 0);
- irq = pdev->irq;
-
- /* Make certain the data structures are quadword aligned. */
- dev = init_etherdev (NULL, sizeof (*tp));
- if (!dev) {
- printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
- return -ENOMEM;
- }
-
- /* We do a request_region() only to register /proc/ioports info. */
- /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
- if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) {
- printk (KERN_ERR PFX "unable to allocate ether device, aborting\n");
- goto err_out_free_netdev;
- }
-
- if (pci_enable_device(pdev)) {
- printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n",
- pdev->vendor, pdev->device,
- pdev->bus->number, pdev->devfn);
- goto err_out_free_netdev;
- }
-
- pci_set_master(pdev);
-
- tp = dev->priv;
- memset(tp, 0, sizeof(*tp));
-
- pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
-
- printk(KERN_INFO "%s: %s rev %d at %#3lx,",
- dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
-
- /* Stop the chip's Tx and Rx processes. */
- outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002);
- /* Clear the missed-packet counter. */
- (volatile int)inl(ioaddr + CSR8);
-
- if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
- printk(" 21040 compatible mode,");
- chip_idx = DC21040;
- }
-
- /* The station address ROM is read byte serially. The register must
- be polled, waiting for the value to be read bit serially from the
- EEPROM.
- */
- sum = 0;
- if (chip_idx == DC21040) {
- outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
- for (i = 0; i < 6; i++) {
- int value, boguscnt = 100000;
- do
- value = inl(ioaddr + CSR9);
- while (value < 0 && --boguscnt > 0);
- dev->dev_addr[i] = value;
- sum += value & 0xff;
- }
- } else if (chip_idx == LC82C168) {
- for (i = 0; i < 3; i++) {
- int value, boguscnt = 100000;
- outl(0x600 | i, ioaddr + 0x98);
- do
- value = inl(ioaddr + CSR9);
- while (value < 0 && --boguscnt > 0);
- put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
- sum += value & 0xffff;
- }
- } else if (chip_idx == COMET) {
- /* No need to read the EEPROM. */
- put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
- put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
- for (i = 0; i < 6; i ++)
- sum += dev->dev_addr[i];
- } else {
- /* A serial EEPROM interface, we read now and sort it out later. */
- int sa_offset = 0;
- int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
-
- for (i = 0; i < sizeof(ee_data)/2; i++)
- ((u16 *)ee_data)[i] =
- le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
-
- /* DEC now has a specification (see Notes) but early board makers
- just put the address in the first EEPROM locations. */
- /* This does memcmp(eedata, eedata+16, 8) */
- for (i = 0; i < 8; i ++)
- if (ee_data[i] != ee_data[16+i])
- sa_offset = 20;
- if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
- sa_offset = 2; /* Grrr, damn Matrox boards. */
- multiport_cnt = 4;
- }
- for (i = 0; i < 6; i ++) {
- dev->dev_addr[i] = ee_data[i + sa_offset];
- sum += ee_data[i + sa_offset];
- }
- }
- /* Lite-On boards have the address byte-swapped. */
- if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0)
- && dev->dev_addr[1] == 0x00)
- for (i = 0; i < 6; i+=2) {
- char tmp = dev->dev_addr[i];
- dev->dev_addr[i] = dev->dev_addr[i+1];
- dev->dev_addr[i+1] = tmp;
- }
- /* On the Zynx 315 Etherarray and other multiport boards only the
- first Tulip has an EEPROM.
- The addresses of the subsequent ports are derived from the first.
- Many PCI BIOSes also incorrectly report the IRQ line, so we correct
- that here as well. */
- if (sum == 0 || sum == 6*0xff) {
- printk(" EEPROM not present,");
- for (i = 0; i < 5; i++)
- dev->dev_addr[i] = last_phys_addr[i];
- dev->dev_addr[i] = last_phys_addr[i] + 1;
-#if defined(__i386__) /* Patch up x86 BIOS bug. */
- if (last_irq)
- irq = last_irq;
-#endif
- }
-
- for (i = 0; i < 6; i++)
- printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
- printk(", IRQ %d.\n", irq);
- last_irq = irq;
-
- pdev->driver_data = dev;
- dev->base_addr = ioaddr;
- dev->irq = irq;
-
- tp->chip_id = chip_idx;
- tp->revision = chip_rev;
- tp->flags = tulip_tbl[chip_idx].flags;
- tp->csr0 = csr0;
- tp->pdev = pdev;
- tp->base_addr = dev->base_addr;
-
- /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
- And the ASIX must have a burst limit or horrible things happen. */
- if (chip_idx == DC21143 && chip_rev == 65)
- tp->csr0 &= ~0x01000000;
- else if (chip_idx == AX88140)
- tp->csr0 |= 0x2000;
-
-#ifdef TULIP_FULL_DUPLEX
- tp->full_duplex = 1;
- tp->full_duplex_lock = 1;
-#endif
-#ifdef TULIP_DEFAULT_MEDIA
- tp->default_port = TULIP_DEFAULT_MEDIA;
-#endif
-#ifdef TULIP_NO_MEDIA_SWITCH
- tp->medialock = 1;
-#endif
- tp->tx_lock = SPIN_LOCK_UNLOCKED;
-
- /* The lower four bits are the media type. */
- if (board_idx >= 0 && board_idx < MAX_UNITS) {
- tp->default_port = options[board_idx] & 15;
- if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
- tp->full_duplex = 1;
- if (mtu[board_idx] > 0)
- dev->mtu = mtu[board_idx];
- }
- if (dev->mem_start)
- tp->default_port = dev->mem_start;
- if (tp->default_port) {
- tp->medialock = 1;
- if (media_cap[tp->default_port] & MediaAlwaysFD)
- tp->full_duplex = 1;
- }
- if (tp->full_duplex)
- tp->full_duplex_lock = 1;
-
- if (media_cap[tp->default_port] & MediaIsMII) {
- u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
- tp->to_advertise = media2advert[tp->default_port - 9];
- } else if (tp->flags & HAS_8023X)
- tp->to_advertise = 0x05e1;
- else
- tp->to_advertise = 0x01e1;
-
- /* This is logically part of probe1(), but too complex to write inline. */
- if (tp->flags & HAS_MEDIA_TABLE) {
- memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
- parse_eeprom(dev);
- }
-
- if ((tp->flags & ALWAYS_CHECK_MII) ||
- (tp->mtable && tp->mtable->has_mii) ||
- ( ! tp->mtable && (tp->flags & HAS_MII))) {
- int phy, phy_idx;
- if (tp->mtable && tp->mtable->has_mii) {
- for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == 11) {
- tp->cur_index = i;
- tp->saved_if_port = dev->if_port;
- select_media(dev, 1);
- dev->if_port = tp->saved_if_port;
- break;
- }
- }
- /* Find the connected MII xcvrs.
- Doing this in open() would allow detecting external xcvrs later,
- but takes much time. */
- for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
- phy++) {
- int mii_status = mdio_read(dev, phy, 1);
- if ((mii_status & 0x8301) == 0x8001 ||
- ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
- int mii_reg0 = mdio_read(dev, phy, 0);
- int mii_advert = mdio_read(dev, phy, 4);
- int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
- tp->phys[phy_idx] = phy;
- tp->advertising[phy_idx++] = reg4;
- printk(KERN_INFO "%s: MII transceiver #%d "
- "config %4.4x status %4.4x advertising %4.4x.\n",
- dev->name, phy, mii_reg0, mii_status, mii_advert);
- /* Fixup for DLink with miswired PHY. */
- if (mii_advert != reg4) {
- printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
- " previously advertising %4.4x.\n",
- dev->name, reg4, phy, mii_advert);
- printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise"
- " is %4.4x).\n",
- dev->name, reg4, tp->to_advertise);
- mdio_write(dev, phy, 4, reg4);
- }
- /* Enable autonegotiation: some boards default to off. */
- mdio_write(dev, phy, 0, mii_reg0 |
- (tp->full_duplex ? 0x1100 : 0x1000) |
- (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
- }
- }
- tp->mii_cnt = phy_idx;
- if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
- printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
- dev->name);
- tp->phys[0] = 1;
- }
- }
-
- /* The Tulip-specific entries in the device structure. */
- dev->open = tulip_open;
- dev->hard_start_xmit = tulip_start_xmit;
- dev->tx_timeout = tulip_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->stop = tulip_close;
- dev->get_stats = tulip_get_stats;
- dev->do_ioctl = private_ioctl;
- dev->set_multicast_list = set_rx_mode;
-
- if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
- tp->link_change = t21142_lnk_change;
- else if (tp->flags & HAS_PNICNWAY)
- tp->link_change = pnic_lnk_change;
-
- /* Reset the xcvr interface and turn on heartbeat. */
- switch (chip_idx) {
- case DC21041:
- tp->to_advertise = 0x0061;
- outl(0x00000000, ioaddr + CSR13);
- outl(0xFFFFFFFF, ioaddr + CSR14);
- outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
- outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200);
- outl(0x0000EF05, ioaddr + CSR13);
- break;
- case DC21040:
- outl(0x00000000, ioaddr + CSR13);
- outl(0x00000004, ioaddr + CSR13);
- break;
- case DC21140: default:
- if (tp->mtable)
- outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
- break;
- case DC21142:
- case PNIC2:
- if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) {
- outl_CSR6(tp, 0x82020000);
- outl(0x0000, ioaddr + CSR13);
- outl(0x0000, ioaddr + CSR14);
- outl_CSR6(tp, 0x820E0000);
- } else
- t21142_start_nway(dev);
- break;
- case LC82C168:
- if ( ! tp->mii_cnt) {
- tp->nway = 1;
- tp->nwayset = 0;
- outl_CSR6(tp, 0x00420000);
- outl(0x30, ioaddr + CSR12);
- outl_CSR6(tp, 0x0001F078);
- outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */
- }
- break;
- case MX98713: case COMPEX9881:
- outl_CSR6(tp, 0x00000000);
- outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
- outl(0x00000001, ioaddr + CSR13);
- break;
- case MX98715: case MX98725:
- outl_CSR6(tp, 0x01a80000);
- outl(0xFFFFFFFF, ioaddr + CSR14);
- outl(0x00001000, ioaddr + CSR12);
- break;
- case COMET:
- /* No initialization necessary. */
- break;
- }
-
- /* put the chip in snooze mode until opened */
- if (tulip_tbl[chip_idx].flags & HAS_ACPI)
- pci_write_config_dword(pdev, 0x40, 0x40000000);
-
- return 0;
-
-err_out_free_netdev:
- unregister_netdev (dev);
- kfree (dev);
- return -ENODEV;
-}
-
-
-static void tulip_suspend (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
-
- if (dev && netif_device_present (dev))
- tulip_down (dev);
-}
-
-
-static void tulip_resume (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
-
- if (dev && !netif_device_present (dev))
- tulip_up (dev);
-}
-
-
-static void __devexit tulip_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pdev->driver_data;
-
- if (dev) {
- struct tulip_private *tp = (struct tulip_private *)dev->priv;
- unregister_netdev(dev);
- release_region(dev->base_addr,
- tulip_tbl[tp->chip_id].io_size);
- kfree(dev);
- }
-}
-
-
-static struct pci_driver tulip_driver = {
- name: TULIP_MODULE_NAME,
- id_table: tulip_pci_tbl,
- probe: tulip_init_one,
- remove: tulip_remove_one,
- suspend: tulip_suspend,
- resume: tulip_resume,
-};
-
-
-static int __init tulip_init (void)
-{
- return pci_module_init (&tulip_driver);
-}
-
-
-static void __exit tulip_cleanup (void)
-{
- pci_unregister_driver (&tulip_driver);
-}
-
-
-module_init(tulip_init);
-module_exit(tulip_cleanup);
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
new file mode 100644
index 000000000..57b3aa252
--- /dev/null
+++ b/drivers/net/tulip/21142.c
@@ -0,0 +1,235 @@
+/*
+ drivers/net/tulip/21142.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include "tulip.h"
+#include <asm/io.h>
+
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+void t21142_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = 0;
+
+ if (tulip_debug > 2)
+ printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
+ dev->name, csr12, medianame[dev->if_port]);
+ if (tulip_media_cap[dev->if_port] & MediaIsMII) {
+ tulip_check_duplex(dev);
+ next_tick = 60*HZ;
+ } else if (tp->nwayset) {
+ /* Don't screw up a negotiated session! */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ } else if (tp->medialock) {
+ ;
+ } else if (dev->if_port == 3) {
+ if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+ "trying NWay.\n", dev->name, csr12);
+ t21142_start_nway(dev);
+ next_tick = 3*HZ;
+ }
+ } else if ((csr12 & 0x7000) != 0x5000) {
+ /* Negotiation failed. Search media types. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
+ dev->name, csr12);
+ if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ new_csr6 = 0x82420000;
+ dev->if_port = 0;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ } else {
+ /* Select 100mbps port to check for link beat. */
+ new_csr6 = 0x83860000;
+ dev->if_port = 3;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outw(8, ioaddr + CSR15);
+ outl(1, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+ tp->csr6 &= 0x00D5;
+ tp->csr6 |= new_csr6;
+ outl(0x0301, ioaddr + CSR12);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ }
+ next_tick = 3*HZ;
+ }
+
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+
+void t21142_start_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr14 = ((tp->to_advertise & 0x0780) << 9) |
+ ((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+ dev->if_port = 0;
+ tp->nway = tp->mediasense = 1;
+ tp->nwayset = tp->lpar = 0;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+ dev->name, csr14);
+ outl(0x0001, ioaddr + CSR13);
+ outl(csr14, ioaddr + CSR14);
+ tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+ tulip_outl_CSR6(tp, tp->csr6);
+ if (tp->mtable && tp->mtable->csr15dir) {
+ outl(tp->mtable->csr15dir, ioaddr + CSR15);
+ outl(tp->mtable->csr15val, ioaddr + CSR15);
+ } else
+ outw(0x0008, ioaddr + CSR15);
+ outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
+}
+
+
+void t21142_lnk_change(struct net_device *dev, int csr5)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+ "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
+
+ /* If NWay finished and we have a negotiated partner capability. */
+ if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
+ int setup_done = 0;
+ int negotiated = tp->to_advertise & (csr12 >> 16);
+ tp->lpar = csr12 >> 16;
+ tp->nwayset = 1;
+ if (negotiated & 0x0100) dev->if_port = 5;
+ else if (negotiated & 0x0080) dev->if_port = 3;
+ else if (negotiated & 0x0040) dev->if_port = 4;
+ else if (negotiated & 0x0020) dev->if_port = 0;
+ else {
+ tp->nwayset = 0;
+ if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180))
+ dev->if_port = 3;
+ }
+ tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
+
+ if (tulip_debug > 1) {
+ if (tp->nwayset)
+ printk(KERN_INFO "%s: Switching to %s based on link "
+ "negotiation %4.4x & %4.4x = %4.4x.\n",
+ dev->name, medianame[dev->if_port], tp->to_advertise,
+ tp->lpar, negotiated);
+ else
+ printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
+ " link beat status %4.4x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ }
+
+ if (tp->mtable) {
+ int i;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == dev->if_port) {
+ tp->cur_index = i;
+ tulip_select_media(dev, 0);
+ setup_done = 1;
+ break;
+ }
+ }
+ if ( ! setup_done) {
+ tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ outl(1, ioaddr + CSR13);
+ }
+#if 0 /* Restart shouldn't be needed. */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0000);
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n",
+ dev->name, inl(ioaddr + CSR5));
+#endif
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
+ dev->name, tp->csr6, inl(ioaddr + CSR6),
+ inl(ioaddr + CSR12));
+ } else if ((tp->nwayset && (csr5 & 0x08000000)
+ && (dev->if_port == 3 || dev->if_port == 5)
+ && (csr12 & 2) == 2) ||
+ (tp->nway && (csr5 & (TPLnkFail)))) {
+ /* Link blew? Maybe restart NWay. */
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+ dev->name, medianame[dev->if_port],
+ (csr12 & 2) ? "failed" : "good");
+ if ((csr12 & 2) && ! tp->medialock) {
+ del_timer(&tp->timer);
+ t21142_start_nway(dev);
+ tp->timer.expires = RUN_AT(3*HZ);
+ add_timer(&tp->timer);
+ }
+ } else if (dev->if_port == 0 || dev->if_port == 4) {
+ if ((csr12 & 4) == 0)
+ printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
+ dev->name);
+ } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+ dev->name);
+ dev->if_port = 0;
+ } else if (tp->nwayset) {
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+ dev->name, medianame[dev->if_port], tp->csr6);
+ } else { /* 100mbps link beat good. */
+ if (tulip_debug)
+ printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
+ dev->name);
+ dev->if_port = 3;
+ tp->csr6 = 0x83860000;
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outl(0x0301, ioaddr + CSR12);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ }
+}
+
+
diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile
new file mode 100644
index 000000000..6e1368e32
--- /dev/null
+++ b/drivers/net/tulip/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Tulip ethernet driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := tulip.o
+O_OBJS := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
new file mode 100644
index 000000000..7ac6aa08d
--- /dev/null
+++ b/drivers/net/tulip/eeprom.c
@@ -0,0 +1,270 @@
+/*
+ drivers/net/tulip/eeprom.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include "tulip.h"
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+ Search www.digital.com for "21X4 SROM" to get details.
+ This code is very complex, and will require changes to support
+ additional cards, so I'll be verbose about what is going on.
+ */
+
+/* Known cards that have old-style EEPROMs. */
+static struct eeprom_fixup eeprom_fixups[] __devinitdata = {
+ {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+ 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+ {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0903, 0x006D, /* 100baseTx */
+ 0x0905, 0x006D, /* 100baseTx-FD */ }},
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
+ 0x0100, 0x009E, /* 10baseT */
+ 0x0104, 0x009E, /* 10baseT-FD */
+ 0x0103, 0x006D, /* 100baseTx */
+ 0x0105, 0x006D, /* 100baseTx-FD */ }},
+ {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
+ 0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+ 0x0000, 0x009E, /* 10baseT */
+ 0x0004, 0x009E, /* 10baseT-FD */
+ 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+ 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+ {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
+ 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
+ 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
+ 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+ 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+ 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
+ }},
+ {0, 0, 0, 0, {}}};
+
+
+static const char *block_name[] __devinitdata = {
+ "21140 non-MII",
+ "21140 MII PHY",
+ "21142 Serial PHY",
+ "21142 MII PHY",
+ "21143 SYM PHY",
+ "21143 reset method"
+};
+
+
+void __devinit tulip_parse_eeprom(struct net_device *dev)
+{
+ /* The last media info list parsed, for multiport boards. */
+ static struct mediatable *last_mediatable = NULL;
+ static unsigned char *last_ee_data = NULL;
+ static int controller_index = 0;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ unsigned char *ee_data = tp->eeprom;
+ int i;
+
+ tp->mtable = 0;
+ /* Detect an old-style (SA only) EEPROM layout:
+ memcmp(eedata, eedata+16, 8). */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ break;
+ if (i >= 8) {
+ if (ee_data[0] == 0xff) {
+ if (last_mediatable) {
+ controller_index++;
+ printk(KERN_INFO "%s: Controller %d of multiport board.\n",
+ dev->name, controller_index);
+ tp->mtable = last_mediatable;
+ ee_data = last_ee_data;
+ goto subsequent_board;
+ } else
+ printk(KERN_INFO "%s: Missing EEPROM, this interface may "
+ "not work correctly!\n",
+ dev->name);
+ return;
+ }
+ /* Do a fix-up based on the vendor half of the station address prefix. */
+ for (i = 0; eeprom_fixups[i].name; i++) {
+ if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+ && dev->dev_addr[1] == eeprom_fixups[i].addr1
+ && dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+ if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
+ i++; /* An Accton EN1207, not an outlaw Maxtech. */
+ memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+ sizeof(eeprom_fixups[i].newtable));
+ printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using"
+ " substitute media control info.\n",
+ dev->name, eeprom_fixups[i].name);
+ break;
+ }
+ }
+ if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+ printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+ "information.\n",
+ dev->name);
+ return;
+ }
+ }
+
+ controller_index = 0;
+ if (ee_data[19] > 1) { /* Multiport board. */
+ last_ee_data = ee_data;
+ }
+subsequent_board:
+
+ if (ee_data[27] == 0) { /* No valid media table. */
+ } else if (tp->chip_id == DC21041) {
+ unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+ int media = get_u16(p);
+ int count = p[2];
+ p += 3;
+
+ printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
+ dev->name, media,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ unsigned char media_code = *p++;
+ if (media_code & 0x40)
+ p += 6;
+ printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
+ dev->name, media_code & 15, medianame[media_code & 15]);
+ }
+ } else {
+ unsigned char *p = (void *)ee_data + ee_data[27];
+ unsigned char csr12dir = 0;
+ int count, new_advertise = 0;
+ struct mediatable *mtable;
+ u16 media = get_u16(p);
+
+ p += 2;
+ if (tp->flags & CSR12_IN_SROM)
+ csr12dir = *p++;
+ count = *p++;
+ mtable = (struct mediatable *)
+ kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+ GFP_KERNEL);
+ if (mtable == NULL)
+ return; /* Horrible, impossible failure. */
+ last_mediatable = tp->mtable = mtable;
+ mtable->defaultmedia = media;
+ mtable->leafcount = count;
+ mtable->csr12dir = csr12dir;
+ mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+ mtable->csr15dir = mtable->csr15val = 0;
+
+ printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
+ media & 0x0800 ? "Autosense" : medianame[media & 15]);
+ for (i = 0; i < count; i++) {
+ struct medialeaf *leaf = &mtable->mleaf[i];
+
+ if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+ leaf->type = 0;
+ leaf->media = p[0] & 0x3f;
+ leaf->leafdata = p;
+ if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */
+ mtable->has_mii = 1;
+ p += 4;
+ } else {
+ leaf->type = p[1];
+ if (p[1] == 0x05) {
+ mtable->has_reset = i;
+ leaf->media = p[2] & 0x0f;
+ } else if (p[1] & 1) {
+ mtable->has_mii = 1;
+ leaf->media = 11;
+ } else {
+ mtable->has_nonmii = 1;
+ leaf->media = p[2] & 0x0f;
+ switch (leaf->media) {
+ case 0: new_advertise |= 0x0020; break;
+ case 4: new_advertise |= 0x0040; break;
+ case 3: new_advertise |= 0x0080; break;
+ case 5: new_advertise |= 0x0100; break;
+ case 6: new_advertise |= 0x0200; break;
+ }
+ if (p[1] == 2 && leaf->media == 0) {
+ if (p[2] & 0x40) {
+ u32 base15 = get_unaligned((u16*)&p[7]);
+ mtable->csr15dir =
+ (get_unaligned((u16*)&p[9])<<16) + base15;
+ mtable->csr15val =
+ (get_unaligned((u16*)&p[11])<<16) + base15;
+ } else {
+ mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+ mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+ }
+ }
+ }
+ leaf->leafdata = p + 2;
+ p += (p[0] & 0x3f) + 1;
+ }
+ if (tulip_debug > 1 && leaf->media == 11) {
+ unsigned char *bp = leaf->leafdata;
+ printk(KERN_INFO "%s: MII interface PHY %d, setup/reset "
+ "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+ dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
+ bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+ }
+ printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described "
+ "by a %s (%d) block.\n",
+ dev->name, i, medianame[leaf->media], leaf->media,
+ block_name[leaf->type], leaf->type);
+ }
+ if (new_advertise)
+ tp->to_advertise = new_advertise;
+ }
+}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/* Note: this routine returns extra data bits for size detection. */
+int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ long ee_addr = ioaddr + CSR9;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ outl(EE_ENB, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outl(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ }
+ outl(EE_ENB, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outl(EE_ENB, ee_addr);
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ return retval;
+}
+
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
new file mode 100644
index 000000000..6d70ffd70
--- /dev/null
+++ b/drivers/net/tulip/interrupt.c
@@ -0,0 +1,337 @@
+/*
+ drivers/net/tulip/interrupt.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include "tulip.h"
+#include <asm/io.h>
+#include <linux/etherdevice.h>
+
+
+int tulip_rx_copybreak;
+int tulip_max_interrupt_work;
+
+
+
+static int tulip_refill_rx(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry;
+ int refilled = 0;
+
+ /* Refill the Rx ring buffers. */
+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
+ refilled++;
+ }
+ tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
+ }
+ return refilled;
+}
+
+
+static int tulip_rx(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry = tp->cur_rx % RX_RING_SIZE;
+ int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+ int received = 0;
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+ tp->rx_ring[entry].status);
+ /* If we own the next entry, it is a new packet. Send it up. */
+ while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
+ s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+
+ if (tulip_debug > 5)
+ printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+ dev->name, entry, status);
+ if (--rx_work_limit < 0)
+ break;
+ if ((status & 0x38008300) != 0x0300) {
+ if ((status & 0x38000300) != 0x0300) {
+ /* Ingore earlier buffers. */
+ if ((status & 0xffff) != 0x7fff) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame "
+ "spanned multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
+ }
+ } else if (status & RxDescFatalErr) {
+ /* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+ dev->name, status);
+ tp->stats.rx_errors++; /* end of a packet.*/
+ if (status & 0x0890) tp->stats.rx_length_errors++;
+ if (status & 0x0004) tp->stats.rx_frame_errors++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
+ }
+ } else {
+ /* Omit the four octet CRC from the length. */
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;
+ struct sk_buff *skb;
+
+#ifndef final_version
+ if (pkt_len > 1518) {
+ printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+ dev->name, pkt_len, pkt_len);
+ pkt_len = 1518;
+ tp->stats.rx_length_errors++;
+ }
+#endif
+ /* Check if the packet is long enough to accept without copying
+ to a minimally-sized skbuff. */
+ if (pkt_len < tulip_rx_copybreak
+ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP header */
+#if ! defined(__alpha__)
+ eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
+ skb_put(skb, pkt_len);
+#else
+ memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
+ pkt_len);
+#endif
+ } else { /* Pass up the skb already on the Rx ring. */
+ char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
+ tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+ if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+ "do not match in tulip_rx: %p vs. %p / %p.\n",
+ dev->name,
+ le32desc_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
+#endif
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ tp->stats.rx_packets++;
+ tp->stats.rx_bytes += pkt_len;
+ }
+ received++;
+ entry = (++tp->cur_rx) % RX_RING_SIZE;
+ }
+
+ return received;
+}
+
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+ after the Tx thread. */
+void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)dev_instance;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr5;
+ int entry;
+ int missed;
+ int rx = 0;
+ int tx = 0;
+ int oi = 0;
+ int maxrx = RX_RING_SIZE;
+ int maxtx = TX_RING_SIZE;
+ int maxoi = TX_RING_SIZE;
+ int work_count = tulip_max_interrupt_work;
+
+ tp->nir++;
+
+ do {
+ csr5 = inl(ioaddr + CSR5);
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
+ dev->name, csr5, inl(dev->base_addr + CSR5));
+
+ if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+ break;
+
+ if (csr5 & (RxIntr | RxNoBuf)) {
+ rx += tulip_rx(dev);
+ tulip_refill_rx(dev);
+ }
+
+ if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
+ unsigned int dirty_tx;
+
+ spin_lock(&tp->lock);
+
+ for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+ dirty_tx++) {
+ int entry = dirty_tx % TX_RING_SIZE;
+ int status = le32_to_cpu(tp->tx_ring[entry].status);
+
+ if (status < 0)
+ break; /* It still has not been Txed */
+ /* Check for Rx filter setup frames. */
+ if (tp->tx_skbuff[entry] == NULL)
+ continue;
+
+ if (status & 0x8000) {
+ /* There was an major error, log it. */
+#ifndef final_version
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+ dev->name, status);
+#endif
+ tp->stats.tx_errors++;
+ if (status & 0x4104) tp->stats.tx_aborted_errors++;
+ if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+ if (status & 0x0200) tp->stats.tx_window_errors++;
+ if (status & 0x0002) tp->stats.tx_fifo_errors++;
+ if ((status & 0x0080) && tp->full_duplex == 0)
+ tp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+ if (status & 0x0100) tp->stats.collisions16++;
+#endif
+ } else {
+#ifdef ETHER_STATS
+ if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+ tp->stats.tx_bytes += tp->tx_skbuff[entry]->len;
+ tp->stats.collisions += (status >> 3) & 15;
+ tp->stats.tx_packets++;
+ }
+
+ /* Free the original skb. */
+ dev_kfree_skb_irq(tp->tx_skbuff[entry]);
+ tp->tx_skbuff[entry] = 0;
+ tx++;
+ }
+
+#ifndef final_version
+ if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+ dirty_tx += TX_RING_SIZE;
+ }
+#endif
+
+ if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
+ /* The ring is no longer full, clear tbusy. */
+ tp->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+
+ tp->dirty_tx = dirty_tx;
+ if (csr5 & TxDied) {
+ if (tulip_debug > 2)
+ printk(KERN_WARNING "%s: The transmitter stopped."
+ " CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+ dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ }
+ spin_unlock(&tp->lock);
+ }
+
+ /* Log errors. */
+ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 == 0xffffffff)
+ break;
+ if (csr5 & TxJabber) tp->stats.tx_errors++;
+ if (csr5 & TxFIFOUnderflow) {
+ if ((tp->csr6 & 0xC000) != 0xC000)
+ tp->csr6 += 0x4000; /* Bump up the Tx threshold */
+ else
+ tp->csr6 |= 0x00200000; /* Store-n-forward. */
+ /* Restart the transmit process. */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ outl(0, ioaddr + CSR1);
+ }
+ if (csr5 & RxDied) { /* Missed a Rx frame. */
+ tp->stats.rx_errors++;
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ }
+ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+ if (tp->link_change)
+ (tp->link_change)(dev, csr5);
+ }
+ if (csr5 & SytemError) {
+ printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
+ }
+ /* Clear all error sources, included undocumented ones! */
+ outl(0x0800f7ba, ioaddr + CSR5);
+ oi++;
+ }
+ if (csr5 & TimerInt) {
+#if 0
+ if (tulip_debug > 2)
+ printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+ dev->name, csr5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+#endif
+ tp->ttimer = 0;
+ oi++;
+ }
+ if (tx > maxtx || rx > maxrx || oi > maxoi) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Too much work during an interrupt, "
+ "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
+ /* Acknowledge all interrupt sources. */
+#if 0
+ /* Clear all interrupting sources, set timer to re-enable. */
+ outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
+ ioaddr + CSR7);
+ outl(12, ioaddr + CSR11);
+ tp->ttimer = 1;
+#endif
+ break;
+ }
+ } while (work_count-- > 0);
+
+ tulip_refill_rx(dev);
+
+ /* check if we card is in suspend mode */
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+ if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+ outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+ ioaddr + CSR7);
+ outl(TimerInt, ioaddr + CSR5);
+ outl(12, ioaddr + CSR11);
+ tp->ttimer = 1;
+ }
+ }
+
+ if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+ tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+ }
+
+ if (tulip_debug > 4)
+ printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+ dev->name, inl(ioaddr + CSR5));
+
+}
+
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
new file mode 100644
index 000000000..1d4c3b2e4
--- /dev/null
+++ b/drivers/net/tulip/media.c
@@ -0,0 +1,403 @@
+/*
+ drivers/net/tulip/media.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include "tulip.h"
+#include <asm/io.h>
+
+
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+ to support a pre-NWay full-duplex signaling mechanism using short frames.
+ No one knows what it should be, but if left at its default value some
+ 10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC 0x6969
+
+
+/* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+ MDIO protocol. See the MII specifications or DP83840A data sheet
+ for details. */
+
+int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ while (--i > 0)
+ if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+ return retval & 0xffff;
+ return 0xffff;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the read command bits out. */
+ for (i = 15; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return (retval>>1) & 0xffff;
+}
+
+void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ long ioaddr = dev->base_addr;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ int i = 1000;
+ outl(cmd, ioaddr + 0xA0);
+ do
+ if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+ break;
+ while (--i > 0);
+ return;
+ }
+
+ if (tp->chip_id == COMET) {
+ if (phy_id != 1)
+ return;
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ return;
+ }
+
+ /* Establish sync by sending 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+}
+
+
+/* Set up the transceiver control registers for the selected media type. */
+void tulip_select_media(struct net_device *dev, int startup)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ struct mediatable *mtable = tp->mtable;
+ u32 new_csr6;
+ int i;
+
+ if (mtable) {
+ struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+ unsigned char *p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: /* 21140 non-MII xcvr. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+ " with control setting %2.2x.\n",
+ dev->name, p[1]);
+ dev->if_port = p[0];
+ if (startup)
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ outl(p[1], ioaddr + CSR12);
+ new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+ break;
+ case 2: case 4: {
+ u16 setup[5];
+ u32 csr13val, csr14val, csr15dir, csr15val;
+ for (i = 0; i < 5; i++)
+ setup[i] = get_u16(&p[i*2 + 1]);
+
+ dev->if_port = p[0] & 15;
+ if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+
+ if (startup && mtable->has_reset) {
+ struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+ unsigned char *rst = rleaf->leafdata;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+ dev->name);
+ for (i = 0; i < rst[0]; i++)
+ outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+ "%4.4x/%4.4x.\n",
+ dev->name, medianame[dev->if_port], setup[0], setup[1]);
+ if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
+ csr13val = setup[0];
+ csr14val = setup[1];
+ csr15dir = (setup[3]<<16) | setup[2];
+ csr15val = (setup[4]<<16) | setup[2];
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ outl(csr13val, ioaddr + CSR13);
+ } else {
+ csr13val = 1;
+ csr14val = 0x0003FF7F;
+ csr15dir = (setup[0]<<16) | 0x0008;
+ csr15val = (setup[1]<<16) | 0x0008;
+ if (dev->if_port <= 4)
+ csr14val = t21142_csr14[dev->if_port];
+ if (startup) {
+ outl(0, ioaddr + CSR13);
+ outl(csr14val, ioaddr + CSR14);
+ }
+ outl(csr15dir, ioaddr + CSR15); /* Direction */
+ outl(csr15val, ioaddr + CSR15); /* Data */
+ if (startup) outl(csr13val, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n",
+ dev->name, csr15dir, csr15val);
+ if (mleaf->type == 4)
+ new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+ else
+ new_csr6 = 0x82420000;
+ break;
+ }
+ case 1: case 3: {
+ int phy_num = p[0];
+ int init_length = p[1];
+ u16 *misc_info;
+ u16 to_advertise;
+
+ dev->if_port = 11;
+ new_csr6 = 0x020E0000;
+ if (mleaf->type == 3) { /* 21142 */
+ u16 *init_sequence = (u16*)(p+2);
+ u16 *reset_sequence = &((u16*)(p+3))[init_length];
+ int reset_length = p[2 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+ if (startup)
+ for (i = 0; i < reset_length; i++)
+ outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+ for (i = 0; i < init_length; i++)
+ outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+ } else {
+ u8 *init_sequence = p + 2;
+ u8 *reset_sequence = p + 3 + init_length;
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ outl(reset_sequence[i], ioaddr + CSR12);
+ }
+ for (i = 0; i < init_length; i++)
+ outl(init_sequence[i], ioaddr + CSR12);
+ }
+ to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+ tp->advertising[phy_num] = to_advertise;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
+ dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+ /* Bogus: put in by a committee? */
+ tulip_mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
+ break;
+ }
+ default:
+ printk(KERN_DEBUG "%s: Invalid media table selection %d.\n",
+ dev->name, mleaf->type);
+ new_csr6 = 0x020E0000;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12) & 0xff);
+ } else if (tp->chip_id == DC21041) {
+ int port = dev->if_port <= 4 ? dev->if_port : 0;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+ dev->name, medianame[port == 3 ? 12: port],
+ inl(ioaddr + CSR12));
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ outl(t21041_csr14[port], ioaddr + CSR14);
+ outl(t21041_csr15[port], ioaddr + CSR15);
+ outl(t21041_csr13[port], ioaddr + CSR13);
+ new_csr6 = 0x80020000;
+ } else if (tp->chip_id == LC82C168) {
+ if (startup && ! tp->medialock)
+ dev->if_port = tp->mii_cnt ? 11 : 0;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
+ dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
+ if (tp->mii_cnt) {
+ new_csr6 = 0x810C0000;
+ outl(0x0001, ioaddr + CSR15);
+ outl(0x0201B07A, ioaddr + 0xB8);
+ } else if (startup) {
+ /* Start with 10mbps to do autonegotiation. */
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ /* Trigger autonegotiation. */
+ outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
+ } else {
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ } else if (tp->chip_id == DC21040) { /* 21040 */
+ /* Turn on the xcvr interface. */
+ int csr12 = inl(ioaddr + CSR12);
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+ dev->name, medianame[dev->if_port], csr12);
+ if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ new_csr6 = 0x20000;
+ /* Set the full duplux match frame. */
+ outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+ outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+ if (t21040_csr13[dev->if_port] & 8) {
+ outl(0x0705, ioaddr + CSR14);
+ outl(0x0006, ioaddr + CSR15);
+ } else {
+ outl(0xffff, ioaddr + CSR14);
+ outl(0x0000, ioaddr + CSR15);
+ }
+ outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
+ } else { /* Unknown chip type with no media table. */
+ if (tp->default_port == 0)
+ dev->if_port = tp->mii_cnt ? 11 : 3;
+ if (tulip_media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (tulip_media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No media description table, assuming "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
+ }
+
+ tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+ return;
+}
+
+/*
+ Check the MII negotiated duplex, and change the CSR6 setting if
+ required.
+ Return 0 if everything is OK.
+ Return < 0 if the transceiver is missing or has no link beat.
+ */
+int tulip_check_duplex(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int mii_reg1, mii_reg5, negotiated, duplex;
+
+ if (tp->full_duplex_lock)
+ return 0;
+ mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1);
+ mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+ "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+ if (mii_reg1 == 0xffff)
+ return -2;
+ if ((mii_reg1 & 0x0004) == 0) {
+ int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: No link beat on the MII interface,"
+ " status %4.4x.\n", dev->name, new_reg1);
+ return -1;
+ }
+ }
+ negotiated = mii_reg5 & tp->advertising[0];
+ duplex = ((negotiated & 0x0300) == 0x0100
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ if (negotiated & 0x038) /* 100mbps. */
+ tp->csr6 &= ~0x00400000;
+ if (tp->full_duplex) tp->csr6 |= 0x0200;
+ else tp->csr6 &= ~0x0200;
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ if (tulip_debug > 0)
+ printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+ "#%d link partner capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
new file mode 100644
index 000000000..445d4a440
--- /dev/null
+++ b/drivers/net/tulip/pnic.c
@@ -0,0 +1,146 @@
+/*
+ drivers/net/tulip/pnic.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include <linux/kernel.h>
+#include "tulip.h"
+#include <asm/io.h>
+
+
+void pnic_do_nway(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u32 phy_reg = inl(ioaddr + 0xB8);
+ u32 new_csr6 = tp->csr6 & ~0x40C40200;
+
+ if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+ if (phy_reg & 0x20000000) dev->if_port = 5;
+ else if (phy_reg & 0x40000000) dev->if_port = 3;
+ else if (phy_reg & 0x10000000) dev->if_port = 4;
+ else if (phy_reg & 0x08000000) dev->if_port = 0;
+ tp->nwayset = 1;
+ new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
+ outl(0x32 | (dev->if_port & 1), ioaddr + CSR12);
+ if (dev->if_port & 1)
+ outl(0x1F868, ioaddr + 0xB8);
+ if (phy_reg & 0x30000000) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x00000200;
+ }
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
+ dev->name, phy_reg, medianame[dev->if_port]);
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ /* Restart Tx */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ dev->trans_start = jiffies;
+ }
+ }
+}
+
+
+void pnic_lnk_change(struct net_device *dev, int csr5)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int phy_reg = inl(ioaddr + 0xB8);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, csr5);
+ if (inl(ioaddr + CSR5) & TPLnkFail) {
+ outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
+ if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) {
+ tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
+ tulip_outl_CSR6(tp, tp->csr6);
+ outl(0x30, ioaddr + CSR12);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ dev->trans_start = jiffies;
+ }
+ } else if (inl(ioaddr + CSR5) & TPLnkPass) {
+ pnic_do_nway(dev);
+ outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
+ }
+}
+
+
+void pnic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_media_cap[dev->if_port] & MediaIsMII) {
+ if (tulip_check_duplex(dev) > 0)
+ next_tick = 3*HZ;
+ } else {
+ int csr12 = inl(ioaddr + CSR12);
+ int new_csr6 = tp->csr6 & ~0x40C40200;
+ int phy_reg = inl(ioaddr + 0xB8);
+ int csr5 = inl(ioaddr + CSR5);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
+ "CSR5 %8.8x.\n",
+ dev->name, phy_reg, medianame[dev->if_port], csr5);
+ if (phy_reg & 0x04000000) { /* Remote link fault */
+ outl(0x0201F078, ioaddr + 0xB8);
+ next_tick = 1*HZ;
+ tp->nwayset = 0;
+ } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+ pnic_do_nway(dev);
+ next_tick = 60*HZ;
+ } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+ "CSR5 %8.8x, PHY %3.3x.\n",
+ dev->name, medianame[dev->if_port], csr12,
+ inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ next_tick = 3*HZ;
+ if (tp->medialock) {
+ } else if (tp->nwayset && (dev->if_port & 1)) {
+ next_tick = 1*HZ;
+ } else if (dev->if_port == 0) {
+ dev->if_port = 3;
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ dev->if_port = 0;
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ /* Restart Tx */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ dev->trans_start = jiffies;
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Changing PNIC configuration to %s "
+ "%s-duplex, CSR6 %8.8x.\n",
+ dev->name, medianame[dev->if_port],
+ tp->full_duplex ? "full" : "half", new_csr6);
+ }
+ }
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
new file mode 100644
index 000000000..796fdd136
--- /dev/null
+++ b/drivers/net/tulip/timer.c
@@ -0,0 +1,208 @@
+/*
+ drivers/net/tulip/timer.c
+
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please refer to Documentation/networking/tulip.txt for more
+ information on this driver.
+
+*/
+
+#include "tulip.h"
+#include <asm/io.h>
+
+
+void tulip_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u32 csr12 = inl(ioaddr + CSR12);
+ int next_tick = 2*HZ;
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+ " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
+ dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
+ inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ }
+ switch (tp->chip_id) {
+ case DC21040:
+ if (!tp->medialock && csr12 & 0x0002) { /* Network error */
+ printk(KERN_INFO "%s: No link beat found.\n",
+ dev->name);
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ tulip_select_media(dev, 0);
+ dev->trans_start = jiffies;
+ }
+ break;
+ case DC21041:
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n",
+ dev->name, csr12);
+ if (tp->medialock) break;
+ switch (dev->if_port) {
+ case 0: case 3: case 4:
+ if (csr12 & 0x0004) { /*LnkFail */
+ /* 10baseT is dead. Check for activity on alternate port. */
+ tp->mediasense = 1;
+ if (csr12 & 0x0200)
+ dev->if_port = 2;
+ else
+ dev->if_port = 1;
+ printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+ dev->name, medianame[dev->if_port]);
+ outl(0, ioaddr + CSR13); /* Reset */
+ outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+ outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+ next_tick = 10*HZ; /* 2.4 sec. */
+ } else
+ next_tick = 30*HZ;
+ break;
+ case 1: /* 10base2 */
+ case 2: /* AUI */
+ if (csr12 & 0x0100) {
+ next_tick = (30*HZ); /* 30 sec. */
+ tp->mediasense = 0;
+ } else if ((csr12 & 0x0004) == 0) {
+ printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+ dev->name);
+ dev->if_port = 0;
+ tulip_select_media(dev, 0);
+ next_tick = (24*HZ)/10; /* 2.4 sec. */
+ } else if (tp->mediasense || (csr12 & 0x0002)) {
+ dev->if_port = 3 - dev->if_port; /* Swap ports. */
+ tulip_select_media(dev, 0);
+ next_tick = 20*HZ;
+ } else {
+ next_tick = 20*HZ;
+ }
+ break;
+ }
+ break;
+ case DC21140: case DC21142: case MX98713: case COMPEX9881: default: {
+ struct medialeaf *mleaf;
+ unsigned char *p;
+ if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
+ /* Not much that can be done.
+ Assume this a generic MII or SYM transceiver. */
+ next_tick = 60*HZ;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+ "CSR12 0x%2.2x.\n",
+ dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+ break;
+ }
+ mleaf = &tp->mtable->mleaf[tp->cur_index];
+ p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: case 4: {
+ /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */
+ int offset = mleaf->type == 4 ? 5 : 2;
+ s8 bitnum = p[offset];
+ if (p[offset+1] & 0x80) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG"%s: Transceiver monitor tick "
+ "CSR12=%#2.2x, no media sense.\n",
+ dev->name, csr12);
+ if (mleaf->type == 4) {
+ if (mleaf->media == 3 && (csr12 & 0x02))
+ goto select_next_media;
+ }
+ break;
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+ " bit %d is %d, expecting %d.\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
+ /* Check that the specified bit has the proper value. */
+ if ((bitnum < 0) !=
+ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ medianame[mleaf->media]);
+ if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
+ goto actually_mii;
+ break;
+ }
+ if (tp->medialock)
+ break;
+ select_next_media:
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+ if (tulip_media_cap[dev->if_port] & MediaIsFD)
+ goto select_next_media; /* Skip FD entries. */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No link beat on media %s,"
+ " trying transceiver type %s.\n",
+ dev->name, medianame[mleaf->media & 15],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
+ tulip_select_media(dev, 0);
+ /* Restart the transmit process. */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ next_tick = (24*HZ)/10;
+ break;
+ }
+ case 1: case 3: /* 21140, 21142 MII */
+ actually_mii:
+ tulip_check_duplex(dev);
+ next_tick = 60*HZ;
+ break;
+ case 2: /* 21142 serial block has no link beat. */
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+
+void mxic_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 3) {
+ printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+ inl(ioaddr + CSR12));
+ }
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
+
+
+void comet_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+ "%4.4x.\n",
+ dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
new file mode 100644
index 000000000..3642a13b4
--- /dev/null
+++ b/drivers/net/tulip/tulip.h
@@ -0,0 +1,342 @@
+/*
+ drivers/net/tulip/tulip.h
+
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+*/
+
+#ifndef __NET_TULIP_H__
+#define __NET_TULIP_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+
+
+struct tulip_chip_table {
+ char *chip_name;
+ int io_size;
+ int valid_intrs; /* CSR7 interrupt enable settings */
+ int flags;
+ void (*media_timer) (unsigned long data);
+};
+
+
+enum tbl_flag {
+ HAS_MII = 1,
+ HAS_MEDIA_TABLE = 2,
+ CSR12_IN_SROM = 4,
+ ALWAYS_CHECK_MII = 8,
+ HAS_ACPI = 0x10,
+ MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */
+ HAS_PNICNWAY = 0x80,
+ HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */
+ HAS_8023X = 0x100,
+};
+
+
+/* chip types. careful! order is VERY IMPORTANT here, as these
+ * are used throughout the driver as indices into arrays */
+/* Note 21142 == 21143. */
+enum chips {
+ DC21040 = 0,
+ DC21041 = 1,
+ DC21140 = 2,
+ DC21142 = 3, DC21143 = 3,
+ LC82C168,
+ NGMC169,
+ MX98713,
+ MX98715,
+ MX98725,
+ AX88140,
+ PNIC2,
+ COMET,
+ COMPEX9881,
+ I21145,
+ X3201_3,
+};
+
+
+enum MediaIs {
+ MediaIsFD = 1,
+ MediaAlwaysFD = 2,
+ MediaIsMII = 4,
+ MediaIsFx = 8,
+ MediaIs100 = 16
+};
+
+
+/* Offsets to the Command and Status Registers, "CSRs". All accesses
+ must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+ CSR0 = 0,
+ CSR1 = 0x08,
+ CSR2 = 0x10,
+ CSR3 = 0x18,
+ CSR4 = 0x20,
+ CSR5 = 0x28,
+ CSR6 = 0x30,
+ CSR7 = 0x38,
+ CSR8 = 0x40,
+ CSR9 = 0x48,
+ CSR10 = 0x50,
+ CSR11 = 0x58,
+ CSR12 = 0x60,
+ CSR13 = 0x68,
+ CSR14 = 0x70,
+ CSR15 = 0x78
+};
+
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+ TimerInt = 0x800,
+ SytemError = 0x2000,
+ TPLnkFail = 0x1000,
+ TPLnkPass = 0x10,
+ NormalIntr = 0x10000,
+ AbnormalIntr = 0x8000,
+ RxJabber = 0x200,
+ RxDied = 0x100,
+ RxNoBuf = 0x80,
+ RxIntr = 0x40,
+ TxFIFOUnderflow = 0x20,
+ TxJabber = 0x08,
+ TxNoBuf = 0x04,
+ TxDied = 0x02,
+ TxIntr = 0x01,
+};
+
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1;
+ u32 buffer2;
+};
+
+
+struct tulip_tx_desc {
+ s32 status;
+ s32 length;
+ u32 buffer1;
+ u32 buffer2; /* We use only buffer 1. */
+};
+
+
+enum desc_status_bits {
+ DescOwned = 0x80000000,
+ RxDescFatalErr = 0x8000,
+ RxWholePkt = 0x0300,
+};
+
+
+/* Keep the ring sizes a power of two for efficiency.
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE 16
+#define RX_RING_SIZE 32
+
+
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
+
+
+/* Ring-wrap flag in length field, use for last ring entry.
+ 0x01000000 means chain on buffer2 address,
+ 0x02000000 means use the ring start address in CSR2/3.
+ Note: Some work-alike chips do not function correctly in chained mode.
+ The ASIX chip works only in chained mode.
+ Thus we indicates ring mode, but always write the 'next' field for
+ chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */
+#define EE_WRITE_0 0x01
+#define EE_WRITE_1 0x05
+#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+ We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay() inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_READ_CMD (6)
+
+#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
+
+
+/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. It is just different enough from the EEPROM protocol
+ to not share code. The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+
+
+#define RUN_AT(x) (jiffies + (x))
+
+
+#if defined(__i386__) /* AKA get_unaligned() */
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
+
+
+struct medialeaf {
+ u8 type;
+ u8 media;
+ unsigned char *leafdata;
+};
+
+
+struct mediatable {
+ u16 defaultmedia;
+ u8 leafcount;
+ u8 csr12dir; /* General purpose pin directions. */
+ unsigned has_mii:1;
+ unsigned has_nonmii:1;
+ unsigned has_reset:6;
+ u32 csr15dir;
+ u32 csr15val; /* 21143 NWay setting. */
+ struct medialeaf mleaf[0];
+};
+
+
+struct mediainfo {
+ struct mediainfo *next;
+ int info_type;
+ int index;
+ unsigned char *info;
+};
+
+
+struct tulip_private {
+ const char *product_name;
+ struct net_device *next_module;
+ struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+ struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ char *rx_buffs; /* Address of temporary Rx buffers. */
+ u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */
+ int chip_id;
+ int revision;
+ int flags;
+ struct net_device_stats stats;
+ struct timer_list timer; /* Media selection timer. */
+ 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. */
+ unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int media2:4; /* Secondary monitored media port. */
+ unsigned int medialock:1; /* Don't sense media type. */
+ unsigned int mediasense:1; /* Media sensing in progress. */
+ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
+ unsigned int csr0; /* CSR0 setting. */
+ unsigned int csr6; /* Current CSR6 control settings. */
+ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
+ void (*link_change) (struct net_device * dev, int csr5);
+ u16 to_advertise; /* NWay capabilities advertised. */
+ u16 lpar; /* 21143 Link partner ability. */
+ u16 advertising[4];
+ signed char phys[4], mii_cnt; /* MII device addresses. */
+ struct mediatable *mtable;
+ int cur_index; /* Current media index. */
+ int saved_if_port;
+ struct pci_dev *pdev;
+ int ttimer;
+ int susp_rx;
+ unsigned long nir;
+ unsigned long base_addr;
+ int pad0, pad1; /* Used for 8-byte alignment */
+};
+
+
+struct eeprom_fixup {
+ char *name;
+ unsigned char addr0;
+ unsigned char addr1;
+ unsigned char addr2;
+ u16 newtable[32]; /* Max length below. */
+};
+
+
+/* 21142.c */
+extern u16 t21142_csr14[];
+void t21142_timer(unsigned long data);
+void t21142_start_nway(struct net_device *dev);
+void t21142_lnk_change(struct net_device *dev, int csr5);
+
+/* eeprom.c */
+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 int tulip_rx_copybreak;
+void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+
+/* media.c */
+int tulip_mdio_read(struct net_device *dev, int phy_id, int location);
+void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value);
+void tulip_select_media(struct net_device *dev, int startup);
+int tulip_check_duplex(struct net_device *dev);
+
+/* pnic.c */
+void pnic_do_nway(struct net_device *dev);
+void pnic_lnk_change(struct net_device *dev, int csr5);
+void pnic_timer(unsigned long data);
+
+/* timer.c */
+void tulip_timer(unsigned long data);
+void mxic_timer(unsigned long data);
+void comet_timer(unsigned long data);
+
+/* tulip_core.c */
+extern int tulip_debug;
+extern const char * const medianame[];
+extern const char tulip_media_cap[];
+extern struct tulip_chip_table tulip_tbl[];
+extern u8 t21040_csr13[];
+extern u16 t21041_csr13[];
+extern u16 t21041_csr14[];
+extern u16 t21041_csr15[];
+void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6);
+
+
+#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
new file mode 100644
index 000000000..3be78468b
--- /dev/null
+++ b/drivers/net/tulip/tulip_core.c
@@ -0,0 +1,1391 @@
+/* tulip_core.c: A DEC 21040-family ethernet driver for Linux. */
+
+/*
+ Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+ Copyright 2000 The Linux Kernel Team
+ Written/copyright 1994-1999 by Donald Becker.
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ Please read Documentation/networking/tulip.txt for more
+ information.
+
+ For this specific driver variant please use linux-kernel for
+ bug reports.
+
+ Additional information available at
+ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+
+*/
+
+static const char version[] = "Linux Tulip driver version 0.9.3 (Feb 23, 2000)\n";
+
+#include <linux/module.h>
+#include "tulip.h"
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
+
+/* The possible media types that can be set in options[] are: */
+const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+ Set the bus performance register.
+ Typical: Set 16 longword cache alignment, no burst limit.
+ Cache alignment bits 15:14 Burst length 13:8
+ 0000 No alignment 0x00000000 unlimited 0800 8 longwords
+ 4000 8 longwords 0100 1 longword 1000 16 longwords
+ 8000 16 longwords 0200 2 longwords 2000 32 longwords
+ C000 32 longwords 0400 4 longwords
+ Warning: many older 486 systems are broken and require setting 0x00A04800
+ 8 longword cache alignment, 8 longword burst.
+ ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+
+
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+ This is only in the support-all-kernels source code. */
+
+MODULE_AUTHOR("The Linux Kernel Team");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(tulip_debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+#define TULIP_MODULE_NAME "tulip"
+#define PFX TULIP_MODULE_NAME ": "
+
+#ifdef TULIP_DEBUG
+int tulip_debug = TULIP_DEBUG;
+#else
+int tulip_debug = 1;
+#endif
+
+
+
+/*
+ * This table use during operation for capabilities and media timer.
+ *
+ * It is indexed via the values in 'enum chips'
+ */
+
+struct tulip_chip_table tulip_tbl[] = {
+ { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+ { "Digital DS21140 Tulip", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+ { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ t21142_timer },
+ { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+ HAS_MII | HAS_PNICNWAY, pnic_timer },
+ { "NETGEAR NGMC169 MAC", 256, 0x0001ebef,
+ HAS_MII | HAS_PNICNWAY, pnic_timer },
+ { "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Macronix 98715 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "Macronix 98725 PMAC", 256, 0x0001ebef,
+ HAS_MEDIA_TABLE, mxic_timer },
+ { "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+ { "Lite-On PNIC-II", 256, 0x0801fbff,
+ HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+ { "ADMtek Comet", 256, 0x0001abef,
+ MC_HASH_ONLY, comet_timer },
+ { "Compex 9881 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ { "Intel DS21145 Tulip", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143,
+ t21142_timer },
+ { "Xircom tulip work-alike", 128, 0x0801fbff,
+ HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143,
+ t21142_timer },
+ {0},
+};
+
+
+static struct pci_device_id tulip_pci_tbl[] __devinitdata = {
+ { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },
+ { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },
+ { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },
+ { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },
+ { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },
+ { 0x1385, 0xf004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NGMC169 },
+ { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
+ { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },
+ { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },
+ { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },
+ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },
+ { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
+ { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+ {0},
+};
+MODULE_DEVICE_TABLE(pci,tulip_pci_tbl);
+
+
+/* A full-duplex map for media types. */
+const char tulip_media_cap[] =
+{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
+u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
+
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+
+static void tulip_tx_timeout(struct net_device *dev);
+static void tulip_init_ring(struct net_device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int tulip_open(struct net_device *dev);
+static int tulip_close(struct net_device *dev);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void set_rx_mode(struct net_device *dev);
+
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+ manipulated. Keith Owens <kaos@ocs.com.au>. */
+
+void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6)
+{
+ long ioaddr = tp->base_addr;
+ const int strict_bits = 0x0060e202;
+ int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+
+ /* common path */
+ if (tp->chip_id != X3201_3) {
+ outl (newcsr6, ioaddr + CSR6);
+ return;
+ }
+
+ newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+ /* read 0 on the Xircom cards */
+ newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
+ currcsr6 = inl (ioaddr + CSR6);
+ if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+ ((currcsr6 & ~0x2002) == 0))
+ goto out_write;
+
+ /* make sure the transmitter and receiver are stopped first */
+ currcsr6 &= ~0x2002;
+ while (1) {
+ csr5 = inl (ioaddr + CSR5);
+ if (csr5 == 0xffffffff)
+ break; /* cannot read csr5, card removed? */
+ csr5_22_20 = csr5 & 0x700000;
+ csr5_19_17 = csr5 & 0x0e0000;
+ if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+ (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+ break; /* both are stopped or suspended */
+ if (!--attempts) {
+ printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts,"
+ "csr5=0x%08x\n", csr5);
+ goto out_write;
+ }
+ outl (currcsr6, ioaddr + CSR6);
+ udelay (1);
+ }
+
+out_write:
+ /* now it is safe to change csr6 */
+ outl (newcsr6, ioaddr + CSR6);
+}
+
+
+static void tulip_up(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 3*HZ;
+ int i;
+
+ /* Wake the chip from sleep/snooze mode. */
+ if (tp->flags & HAS_ACPI)
+ pci_write_config_dword(tp->pdev, 0x40, 0);
+
+ /* On some chip revs we must set the MII/SYM port before the reset!? */
+ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
+ tulip_outl_CSR6 (tp, 0x00040000);
+
+ /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+ outl(0x00000001, ioaddr + CSR0);
+
+ /* Deassert reset.
+ Wait the specified 50 PCI cycles after a reset by initializing
+ Tx and Rx queues and the address filter list. */
+ outl(tp->csr0, ioaddr + CSR0);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);
+
+ if (tp->flags & MC_HASH_ONLY) {
+ u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+ u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+ if (tp->chip_id == AX88140) {
+ outl(0, ioaddr + CSR13);
+ outl(addr_low, ioaddr + CSR14);
+ outl(1, ioaddr + CSR13);
+ outl(addr_high, ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) {
+ outl(addr_low, ioaddr + 0xA4);
+ outl(addr_high, ioaddr + 0xA8);
+ outl(0, ioaddr + 0xAC);
+ outl(0, ioaddr + 0xB0);
+ }
+ } else {
+ /* This is set_rx_mode(), but without starting the transmitter. */
+ u16 *eaddrs = (u16 *)dev->dev_addr;
+ u16 *setup_frm = &tp->setup_frame[15*6];
+
+ /* 21140 bug: you must add the broadcast address. */
+ memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));
+ /* Fill the final entry of the table with our physical address. */
+ *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+ /* Put the setup frame on the Tx list. */
+ tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
+ tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
+ tp->tx_ring[0].status = cpu_to_le32(DescOwned);
+
+ tp->cur_tx++;
+ }
+
+ outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+ outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+ tp->saved_if_port = dev->if_port;
+ if (dev->if_port == 0)
+ dev->if_port = tp->default_port;
+
+ /* Allow selecting a default media. */
+ i = 0;
+ if (tp->mtable == NULL)
+ goto media_picked;
+ if (dev->if_port) {
+ int looking_for = tulip_media_cap[dev->if_port] & MediaIsMII ? 11 :
+ (dev->if_port == 12 ? 0 : dev->if_port);
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using user-specified media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ goto media_picked;
+ }
+ }
+ if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+ int looking_for = tp->mtable->defaultmedia & 15;
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+ dev->name, medianame[looking_for]);
+ goto media_picked;
+ }
+ }
+ /* Start sensing first non-full-duplex media. */
+ for (i = tp->mtable->leafcount - 1;
+ (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+ ;
+media_picked:
+
+ tp->csr6 = 0;
+ tp->cur_index = i;
+ tp->nwayset = 0;
+ if (dev->if_port == 0 && tp->chip_id == DC21041) {
+ tp->nway = 1;
+ }
+ if (dev->if_port == 0 && tp->chip_id == DC21142) {
+ if (tp->mii_cnt) {
+ tulip_select_media(dev, 1);
+ if (tulip_debug > 1)
+ printk(KERN_INFO "%s: Using MII transceiver %d, status "
+ "%4.4x.\n",
+ dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1));
+ tulip_outl_CSR6(tp, 0x82020000);
+ tp->csr6 = 0x820E0000;
+ dev->if_port = 11;
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ } else
+ t21142_start_nway(dev);
+ } else if (tp->chip_id == PNIC2) {
+ t21142_start_nway(dev);
+ } else if (tp->chip_id == LC82C168 && ! tp->medialock) {
+ if (tp->mii_cnt) {
+ dev->if_port = 11;
+ tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0001, ioaddr + CSR15);
+ } else if (inl(ioaddr + CSR5) & TPLnkPass)
+ pnic_do_nway(dev);
+ else {
+ /* Start with 10mbps to do autonegotiation. */
+ outl(0x32, ioaddr + CSR12);
+ tp->csr6 = 0x00420000;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ next_tick = 1*HZ;
+ }
+ } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+ && ! tp->medialock) {
+ dev->if_port = 0;
+ tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+ /* Provided by BOLO, Macronix - 12/10/1998. */
+ dev->if_port = 0;
+ tp->csr6 = 0x01a80200;
+ outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+ outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+ } else if (tp->chip_id == DC21143 &&
+ tulip_media_cap[dev->if_port] & MediaIsMII) {
+ /* We must reset the media CSRs when we force-select MII mode. */
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ } else if (tp->chip_id == COMET) {
+ dev->if_port = 0;
+ tp->csr6 = 0x00040000;
+ } else if (tp->chip_id == AX88140) {
+ tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
+ } else
+ tulip_select_media(dev, 1);
+
+ /* Start the chip's Tx to process setup frame. */
+ tulip_outl_CSR6(tp, tp->csr6);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2000);
+
+ /* Enable interrupts by setting the interrupt mask. */
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ outl(0, ioaddr + CSR2); /* Rx poll demand */
+
+ if (tulip_debug > 2) {
+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+ dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+ inl(ioaddr + CSR6));
+ }
+ /* Set the timer to switch to check for link beat and perhaps switch
+ to an alternate media type. */
+ init_timer(&tp->timer);
+ tp->timer.expires = RUN_AT(next_tick);
+ tp->timer.data = (unsigned long)dev;
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+ add_timer(&tp->timer);
+
+ netif_device_attach(dev);
+}
+
+
+static int
+tulip_open(struct net_device *dev)
+{
+ MOD_INC_USE_COUNT;
+
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
+
+ tulip_init_ring (dev);
+
+ tulip_up (dev);
+
+ return 0;
+}
+
+
+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;
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ if (tulip_media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ } else if (tp->chip_id == DC21040) {
+ if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) {
+ dev->if_port = (dev->if_port == 2 ? 0 : 2);
+ printk(KERN_INFO "%s: 21040 transmit timed out, switching to "
+ "%s.\n",
+ dev->name, medianame[dev->if_port]);
+ tulip_select_media(dev, 0);
+ }
+ goto out;
+ } else if (tp->chip_id == DC21041) {
+ int csr12 = inl(ioaddr + CSR12);
+
+ printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+ "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), csr12,
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+ tp->mediasense = 1;
+ if ( ! tp->medialock) {
+ if (dev->if_port == 1 || dev->if_port == 2)
+ if (csr12 & 0x0004) {
+ dev->if_port = 2 - dev->if_port;
+ } else
+ dev->if_port = 0;
+ else
+ dev->if_port = 1;
+ tulip_select_media(dev, 0);
+ }
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if ( ! tp->medialock && tp->mtable) {
+ do
+ --tp->cur_index;
+ while (tp->cur_index >= 0
+ && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media]
+ & MediaIsFD));
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ tulip_select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+ "media.\n", dev->name, medianame[dev->if_port]);
+ }
+ } else {
+ printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+ "%8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+ dev->if_port = 0;
+ }
+
+#if defined(way_too_many_messages)
+ if (tulip_debug > 3) {
+ int i;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+ int j;
+ printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x "
+ "%2.2x %2.2x %2.2x.\n",
+ i, (unsigned int)tp->rx_ring[i].status,
+ (unsigned int)tp->rx_ring[i].length,
+ (unsigned int)tp->rx_ring[i].buffer1,
+ (unsigned int)tp->rx_ring[i].buffer2,
+ buf[0], buf[1], buf[2]);
+ for (j = 0; buf[j] != 0xee && j < 1600; j++)
+ if (j < 100) printk(" %2.2x", buf[j]);
+ printk(" j=%d.\n", j);
+ }
+ printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring);
+ for (i = 0; i < RX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+ printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring);
+ for (i = 0; i < TX_RING_SIZE; i++)
+ printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+ printk("\n");
+ }
+#endif
+
+ /* Stop and restart the chip's Tx processes . */
+ tulip_outl_CSR6(tp, tp->csr6 | 0x0002);
+ tulip_outl_CSR6(tp, tp->csr6 | 0x2002);
+ /* Trigger an immediate transmit demand. */
+ outl(0, ioaddr + CSR1);
+
+ tp->stats.tx_errors++;
+
+out:
+ dev->trans_start = jiffies;
+ netif_start_queue (dev);
+ spin_unlock_irqrestore (&tp->lock, flags);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void tulip_init_ring(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+
+ tp->tx_full = 0;
+ tp->cur_rx = tp->cur_tx = 0;
+ tp->dirty_rx = tp->dirty_tx = 0;
+ tp->susp_rx = 0;
+ tp->ttimer = 0;
+ tp->nir = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ tp->rx_ring[i].status = 0x00000000;
+ tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
+ tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
+ tp->rx_skbuff[i] = NULL;
+ }
+ /* Mark the last entry as wrapping the ring. */
+ tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
+ tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* Note the receive buffer must be longword aligned.
+ dev_alloc_skb() provides 16 byte alignment. But do *not*
+ use skb_reserve() to align the IP header! */
+ struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+ tp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+ tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */
+ tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
+ }
+ tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+ /* The Tx buffer descriptor is filled in as needed, but we
+ do need to clear the ownership bit. */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tp->tx_skbuff[i] = 0;
+ tp->tx_ring[i].status = 0x00000000;
+ tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]);
+ }
+ tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]);
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry;
+ u32 flag;
+ unsigned long cpuflags;
+
+ /* Caution: the write order is important here, set the field
+ with the ownership bits last. */
+
+ spin_lock_irqsave(&tp->lock, cpuflags);
+
+ /* Calculate the next Tx descriptor entry. */
+ entry = tp->cur_tx % TX_RING_SIZE;
+
+ tp->tx_skbuff[entry] = skb;
+ tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
+
+ if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+ flag = 0x60000000; /* No interrupt */
+ } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+ flag = 0xe0000000; /* Tx-done intr. */
+ } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+ flag = 0x60000000; /* No Tx-done intr. */
+ } else { /* Leave room for set_rx_mode() to fill entries. */
+ tp->tx_full = 1;
+ flag = 0xe0000000; /* Tx-done intr. */
+ netif_stop_queue(dev);
+ }
+ if (entry == TX_RING_SIZE-1)
+ flag = 0xe0000000 | DESC_RING_WRAP;
+
+ tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+ tp->cur_tx++;
+
+ /* Trigger an immediate transmit demand. */
+ outl(0, dev->base_addr + CSR1);
+
+ spin_unlock_irqrestore(&tp->lock, cpuflags);
+
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+static void tulip_down (struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+ struct tulip_private *tp = (struct tulip_private *) dev->priv;
+ unsigned long flags;
+
+ netif_device_detach (dev);
+
+ del_timer (&tp->timer);
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ outl (0x00000000, ioaddr + CSR7);
+
+ /* Stop the Tx and Rx processes. */
+ tulip_outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002);
+
+ /* 21040 -- Leave the card in 10baseT state. */
+ if (tp->chip_id == DC21040)
+ outl (0x00000004, ioaddr + CSR13);
+
+ if (inl (ioaddr + CSR6) != 0xffffffff)
+ tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff;
+
+ spin_unlock_irqrestore (&tp->lock, flags);
+
+ dev->if_port = tp->saved_if_port;
+
+ /* Leave the driver in snooze, not sleep, mode. */
+ 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;
+
+ tulip_down (dev);
+
+ if (tulip_debug > 1)
+ printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+ dev->name, inl (ioaddr + CSR5));
+
+ free_irq (dev->irq, dev);
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ struct sk_buff *skb = tp->rx_skbuff[i];
+ tp->rx_skbuff[i] = 0;
+ tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */
+ tp->rx_ring[i].length = 0;
+ tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+ if (skb) {
+ dev_kfree_skb (skb);
+ }
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (tp->tx_skbuff[i])
+ dev_kfree_skb (tp->tx_skbuff[i]);
+ tp->tx_skbuff[i] = 0;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static struct enet_statistics *tulip_get_stats(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+
+ if (netif_running(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave (&tp->lock, flags);
+
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+ spin_unlock_irqrestore(&tp->lock, flags);
+ }
+
+ return &tp->stats;
+}
+
+
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = tp->phys[0] & 0x1f;
+ long flags;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ if (tp->mii_cnt)
+ data[0] = phy;
+ else if (tp->flags & HAS_NWAY143)
+ data[0] = 32;
+ else if (tp->chip_id == COMET)
+ data[0] = 1;
+ else
+ return -ENODEV;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ int csr12 = inl(ioaddr + CSR12);
+ int csr14 = inl(ioaddr + CSR14);
+ switch (data[1]) {
+ case 0: {
+ data[3] = (csr14<<5) & 0x1000;
+ break; }
+ case 1:
+ data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+ + (csr12&0x06 ? 0x04 : 0);
+ break;
+ case 4: {
+ data[3] = ((csr14>>9)&0x07C0) +
+ ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
+ break;
+ }
+ case 5: data[3] = csr12 >> 16; break;
+ default: data[3] = 0; break;
+ }
+ } else {
+ spin_lock_irqsave (&tp->lock, flags);
+ data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+ spin_unlock_irqrestore (&tp->lock, flags);
+ }
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (data[0] == 32 && (tp->flags & HAS_NWAY143)) {
+ if (data[1] == 5)
+ tp->to_advertise = data[2];
+ } else {
+ spin_lock_irqsave (&tp->lock, flags);
+ tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ spin_unlock_irqrestore(&tp->lock, flags);
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+ Note that we only use exclusion around actually queueing the
+ new frame, not around filling tp->setup_frame. This is non-deterministic
+ when re-entered but still correct. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+ N.B. Do not use for bulk data, use a table-based routine instead.
+ This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline u32 ether_crc_le(int length, unsigned char *data)
+{
+ u32 crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+ int crc = -1;
+
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+
+ tp->csr6 &= ~0x00D5;
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ tp->csr6 |= 0x00C0;
+ csr6 |= 0x00C0;
+ /* Unconditionally log net taps. */
+ printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+ } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter well -- accept all multicasts. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else if (tp->flags & MC_HASH_ONLY) {
+ /* Some work-alikes have only a 64-entry hash filter table. */
+ /* Should verify correctness on big-endian/__powerpc__ */
+ struct dev_mc_list *mclist;
+ int i;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */
+ tp->csr6 |= 0x0080;
+ csr6 |= 0x0080;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next)
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+ if (tp->chip_id == AX88140) {
+ outl(2, ioaddr + CSR13);
+ outl(mc_filter[0], ioaddr + CSR14);
+ outl(3, ioaddr + CSR13);
+ outl(mc_filter[1], ioaddr + CSR14);
+ } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+ outl(mc_filter[0], ioaddr + 0xAC);
+ outl(mc_filter[1], ioaddr + 0xB0);
+ }
+ }
+ } else {
+ u16 *eaddrs, *setup_frm = tp->setup_frame;
+ struct dev_mc_list *mclist;
+ u32 tx_flags = 0x08000000 | 192;
+ int i;
+ 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++ = *setup_frm++ = hash_table[i];
+ setup_frm = &tp->setup_frame[13*6];
+ } 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) {
+ eaddrs = (u16 *)mclist->dmi_addr;
+ *setup_frm++ = *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *setup_frm++ = *eaddrs++;
+ *setup_frm++ = *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++ = *setup_frm++ = eaddrs[0];
+ *setup_frm++ = *setup_frm++ = eaddrs[1];
+ *setup_frm++ = *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 {
+ unsigned int entry;
+
+ /* Now add this frame to the Tx list. */
+
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+
+ if (entry != 0) {
+ /* Avoid a chip errata by prefixing a dummy entry. */
+ tp->tx_skbuff[entry] = 0;
+ tp->tx_ring[entry].length =
+ (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
+ tp->tx_ring[entry].buffer1 = 0;
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+ entry = tp->cur_tx++ % TX_RING_SIZE;
+ }
+
+ tp->tx_skbuff[entry] = 0;
+ /* Put the setup frame on the Tx list. */
+ if (entry == TX_RING_SIZE-1)
+ tx_flags |= DESC_RING_WRAP; /* Wrap ring. */
+ tp->tx_ring[entry].length = cpu_to_le32(tx_flags);
+ tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
+ tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+ 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);
+ }
+ tulip_outl_CSR6(tp, csr6 | 0x0000);
+}
+
+
+static int __devinit tulip_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int did_version = 0; /* Already printed version info. */
+ struct tulip_private *tp;
+ /* See note below on the multiport cards. */
+ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+ static int last_irq = 0;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
+ u8 chip_rev;
+ int i, irq;
+ unsigned short sum;
+ u8 ee_data[EEPROM_SIZE];
+ struct net_device *dev;
+ long ioaddr;
+ static int board_idx = -1;
+ int chip_idx = ent->driver_data;
+
+ board_idx++;
+
+ if (tulip_debug > 0 && did_version++ == 0)
+ printk (KERN_INFO "%s", version);
+
+ if( pdev->subsystem_vendor == 0x1376 ){
+ printk (KERN_ERR PFX "skipping LMC card.\n");
+ return -ENODEV;
+ }
+
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+
+ /* init_etherdev ensures qword aligned structures */
+ dev = init_etherdev (NULL, sizeof (*tp));
+ if (!dev) {
+ printk (KERN_ERR PFX "ether device alloc failed, aborting\n");
+ return -ENOMEM;
+ }
+
+ /* We do a request_region() only to register /proc/ioports info. */
+ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+ if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) {
+ printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, "
+ "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr);
+ goto err_out_free_netdev;
+ }
+
+ if (pci_enable_device(pdev)) {
+ printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, "
+ "bus %d, devfn %d), aborting\n",
+ pdev->vendor, pdev->device,
+ pdev->bus->number, pdev->devfn);
+ goto err_out_free_netdev;
+ }
+
+ pci_set_master(pdev);
+
+ pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
+
+ /*
+ * initialize priviate data structure 'tp'
+ * it is zeroed and aligned in init_etherdev
+ */
+ tp = dev->priv;
+
+ tp->chip_id = chip_idx;
+ tp->flags = tulip_tbl[chip_idx].flags;
+ tp->pdev = pdev;
+ tp->base_addr = ioaddr;
+ tp->revision = chip_rev;
+ spin_lock_init(&tp->lock);
+
+#ifdef TULIP_FULL_DUPLEX
+ tp->full_duplex = 1;
+ tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+ tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+ tp->medialock = 1;
+#endif
+
+ printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+ dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+
+ /* Stop the chip's Tx and Rx processes. */
+ tulip_outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002);
+ /* Clear the missed-packet counter. */
+ (volatile int)inl(ioaddr + CSR8);
+
+ if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) {
+ printk(" 21040 compatible mode,");
+ chip_idx = DC21040;
+ }
+
+ /* The station address ROM is read byte serially. The register must
+ be polled, waiting for the value to be read bit serially from the
+ EEPROM.
+ */
+ sum = 0;
+ if (chip_idx == DC21040) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 6; i++) {
+ int value, boguscnt = 100000;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ dev->dev_addr[i] = value;
+ sum += value & 0xff;
+ }
+ } else if (chip_idx == LC82C168) {
+ for (i = 0; i < 3; i++) {
+ int value, boguscnt = 100000;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ sum += value & 0xffff;
+ }
+ } else if (chip_idx == COMET) {
+ /* No need to read the EEPROM. */
+ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+ put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+ for (i = 0; i < 6; i ++)
+ sum += dev->dev_addr[i];
+ } else {
+ /* A serial EEPROM interface, we read now and sort it out later. */
+ int sa_offset = 0;
+ int ee_addr_size = tulip_read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+ for (i = 0; i < sizeof(ee_data)/2; i++)
+ ((u16 *)ee_data)[i] =
+ le16_to_cpu(tulip_read_eeprom(ioaddr, i, ee_addr_size));
+
+ /* DEC now has a specification (see Notes) but early board makers
+ just put the address in the first EEPROM locations. */
+ /* This does memcmp(eedata, eedata+16, 8) */
+ for (i = 0; i < 8; i ++)
+ if (ee_data[i] != ee_data[16+i])
+ sa_offset = 20;
+ if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
+ sa_offset = 2; /* Grrr, damn Matrox boards. */
+ multiport_cnt = 4;
+ }
+ for (i = 0; i < 6; i ++) {
+ dev->dev_addr[i] = ee_data[i + sa_offset];
+ sum += ee_data[i + sa_offset];
+ }
+ }
+ /* Lite-On boards have the address byte-swapped. */
+ if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0)
+ && dev->dev_addr[1] == 0x00)
+ for (i = 0; i < 6; i+=2) {
+ char tmp = dev->dev_addr[i];
+ dev->dev_addr[i] = dev->dev_addr[i+1];
+ dev->dev_addr[i+1] = tmp;
+ }
+ /* On the Zynx 315 Etherarray and other multiport boards only the
+ first Tulip has an EEPROM.
+ The addresses of the subsequent ports are derived from the first.
+ Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+ that here as well. */
+ if (sum == 0 || sum == 6*0xff) {
+ printk(" EEPROM not present,");
+ for (i = 0; i < 5; i++)
+ dev->dev_addr[i] = last_phys_addr[i];
+ dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__) /* Patch up x86 BIOS bug. */
+ if (last_irq)
+ irq = last_irq;
+#endif
+ }
+
+ for (i = 0; i < 6; i++)
+ printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
+
+ pdev->driver_data = dev;
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+ tp->csr0 = csr0;
+
+ /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+ And the ASIX must have a burst limit or horrible things happen. */
+ if (chip_idx == DC21143 && chip_rev == 65)
+ tp->csr0 &= ~0x01000000;
+ else if (chip_idx == AX88140)
+ tp->csr0 |= 0x2000;
+
+ /* The lower four bits are the media type. */
+ if (board_idx >= 0 && board_idx < MAX_UNITS) {
+ tp->default_port = options[board_idx] & 15;
+ if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+ tp->full_duplex = 1;
+ if (mtu[board_idx] > 0)
+ dev->mtu = mtu[board_idx];
+ }
+ if (dev->mem_start)
+ tp->default_port = dev->mem_start;
+ if (tp->default_port) {
+ tp->medialock = 1;
+ if (tulip_media_cap[tp->default_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ }
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
+
+ if (tulip_media_cap[tp->default_port] & MediaIsMII) {
+ u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ tp->to_advertise = media2advert[tp->default_port - 9];
+ } else if (tp->flags & HAS_8023X)
+ tp->to_advertise = 0x05e1;
+ else
+ tp->to_advertise = 0x01e1;
+
+ /* This is logically part of probe1(), but too complex to write inline. */
+ if (tp->flags & HAS_MEDIA_TABLE) {
+ memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+ tulip_parse_eeprom(dev);
+ }
+
+ if ((tp->flags & ALWAYS_CHECK_MII) ||
+ (tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tp->flags & HAS_MII))) {
+ int phy, phy_idx;
+ if (tp->mtable && tp->mtable->has_mii) {
+ for (i = 0; i < tp->mtable->leafcount; i++)
+ if (tp->mtable->mleaf[i].media == 11) {
+ tp->cur_index = i;
+ tp->saved_if_port = dev->if_port;
+ tulip_select_media(dev, 1);
+ dev->if_port = tp->saved_if_port;
+ break;
+ }
+ }
+ /* Find the connected MII xcvrs.
+ Doing this in open() would allow detecting external xcvrs later,
+ but takes much time. */
+ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+ phy++) {
+ int mii_status = tulip_mdio_read(dev, phy, 1);
+ if ((mii_status & 0x8301) == 0x8001 ||
+ ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
+ int mii_reg0 = tulip_mdio_read(dev, phy, 0);
+ int mii_advert = tulip_mdio_read(dev, phy, 4);
+ int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+ tp->phys[phy_idx] = phy;
+ tp->advertising[phy_idx++] = reg4;
+ printk(KERN_INFO "%s: MII transceiver #%d "
+ "config %4.4x status %4.4x advertising %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status, mii_advert);
+ /* Fixup for DLink with miswired PHY. */
+ if (mii_advert != reg4) {
+ printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
+ " previously advertising %4.4x.\n",
+ dev->name, reg4, phy, mii_advert);
+ printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise"
+ " is %4.4x).\n",
+ dev->name, reg4, tp->to_advertise);
+ tulip_mdio_write(dev, phy, 4, reg4);
+ }
+ /* Enable autonegotiation: some boards default to off. */
+ tulip_mdio_write(dev, phy, 0, mii_reg0 |
+ (tp->full_duplex ? 0x1100 : 0x1000) |
+ (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+ }
+ }
+ tp->mii_cnt = phy_idx;
+ if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
+ printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+ dev->name);
+ tp->phys[0] = 1;
+ }
+ }
+
+ /* The Tulip-specific entries in the device structure. */
+ dev->open = tulip_open;
+ dev->hard_start_xmit = tulip_start_xmit;
+ dev->tx_timeout = tulip_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->stop = tulip_close;
+ dev->get_stats = tulip_get_stats;
+ dev->do_ioctl = private_ioctl;
+ dev->set_multicast_list = set_rx_mode;
+
+ if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041)
+ tp->link_change = t21142_lnk_change;
+ else if (tp->flags & HAS_PNICNWAY)
+ tp->link_change = pnic_lnk_change;
+
+ /* Reset the xcvr interface and turn on heartbeat. */
+ switch (chip_idx) {
+ case DC21041:
+ tp->to_advertise = 0x0061;
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+ tulip_outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200);
+ outl(0x0000EF05, ioaddr + CSR13);
+ break;
+ case DC21040:
+ outl(0x00000000, ioaddr + CSR13);
+ outl(0x00000004, ioaddr + CSR13);
+ break;
+ case DC21140:
+ default:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+ break;
+ case DC21142:
+ case PNIC2:
+ if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) {
+ tulip_outl_CSR6(tp, 0x82020000);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0000, ioaddr + CSR14);
+ tulip_outl_CSR6(tp, 0x820E0000);
+ } else
+ t21142_start_nway(dev);
+ break;
+ case LC82C168:
+ if ( ! tp->mii_cnt) {
+ tp->nway = 1;
+ tp->nwayset = 0;
+ tulip_outl_CSR6(tp, 0x00420000);
+ outl(0x30, ioaddr + CSR12);
+ tulip_outl_CSR6(tp, 0x0001F078);
+ tulip_outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */
+ }
+ break;
+ case MX98713: case COMPEX9881:
+ tulip_outl_CSR6(tp, 0x00000000);
+ outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+ outl(0x00000001, ioaddr + CSR13);
+ break;
+ case MX98715: case MX98725:
+ tulip_outl_CSR6(tp, 0x01a80000);
+ outl(0xFFFFFFFF, ioaddr + CSR14);
+ outl(0x00001000, ioaddr + CSR12);
+ break;
+ case COMET:
+ /* No initialization necessary. */
+ break;
+ }
+
+ /* put the chip in snooze mode until opened */
+ if (tulip_tbl[chip_idx].flags & HAS_ACPI)
+ pci_write_config_dword(pdev, 0x40, 0x40000000);
+
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdev (dev);
+ kfree (dev);
+ return -ENODEV;
+}
+
+
+static void tulip_suspend (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (dev && netif_device_present (dev))
+ tulip_down (dev);
+}
+
+
+static void tulip_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (dev && !netif_device_present (dev))
+ tulip_up (dev);
+}
+
+
+static void __devexit tulip_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+
+ if (dev) {
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ unregister_netdev(dev);
+ release_region(dev->base_addr,
+ tulip_tbl[tp->chip_id].io_size);
+ kfree(dev);
+ }
+}
+
+
+static struct pci_driver tulip_driver = {
+ name: TULIP_MODULE_NAME,
+ id_table: tulip_pci_tbl,
+ probe: tulip_init_one,
+ remove: tulip_remove_one,
+ suspend: tulip_suspend,
+ resume: tulip_resume,
+};
+
+
+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);
+}
+
+
+static void __exit tulip_cleanup (void)
+{
+ pci_unregister_driver (&tulip_driver);
+}
+
+
+module_init(tulip_init);
+module_exit(tulip_cleanup);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 873a561ef..72aeae112 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1,4 +1,4 @@
-/* $Id: cosa.c,v 1.28 1999/10/11 21:06:58 kas Exp $ */
+/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */
/*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
@@ -222,6 +222,8 @@ static int cosa_major = 117;
#undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */
#undef DEBUG_IO 1 /* Dump the I/O traffic */
+#define TX_TIMEOUT (5*HZ)
+
/* Maybe the following should be allocated dynamically */
static struct cosa_data cosa_cards[MAX_CARDS];
static int nr_cards = 0;
@@ -286,6 +288,7 @@ static void sppp_channel_init(struct channel_data *chan);
static void sppp_channel_delete(struct channel_data *chan);
static int cosa_sppp_open(struct net_device *d);
static int cosa_sppp_close(struct net_device *d);
+static void cosa_sppp_timeout(struct net_device *d);
static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d);
static char *sppp_setup_rx(struct channel_data *channel, int size);
static int sppp_rx_done(struct channel_data *channel);
@@ -370,7 +373,7 @@ static int __init cosa_init(void)
{
int i;
- printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
+ printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef __SMP__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
@@ -406,7 +409,6 @@ static int __init cosa_init(void)
#ifdef MODULE
void cleanup_module (void)
{
- int i;
struct cosa_data *cosa;
printk(KERN_INFO "Unloading the cosa module\n");
@@ -595,6 +597,8 @@ static void sppp_channel_init(struct channel_data *chan)
d->hard_start_xmit = cosa_sppp_tx;
d->do_ioctl = cosa_sppp_ioctl;
d->get_stats = cosa_net_stats;
+ d->tx_timeout = cosa_sppp_timeout;
+ d->watchdog_timeo = TX_TIMEOUT;
dev_init_buffers(d);
if (register_netdev(d) == -1) {
printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
@@ -609,7 +613,6 @@ static void sppp_channel_delete(struct channel_data *chan)
unregister_netdev(chan->pppdev.dev);
}
-
static int cosa_sppp_open(struct net_device *d)
{
struct channel_data *chan = d->priv;
@@ -646,7 +649,7 @@ static int cosa_sppp_open(struct net_device *d)
return err;
}
- d->tbusy = 0;
+ netif_start_queue(d);
cosa_enable_rx(chan);
return 0;
}
@@ -655,41 +658,39 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev)
{
struct channel_data *chan = dev->priv;
- if (dev->tbusy) {
- if (time_before(jiffies, dev->trans_start+2*HZ))
- return 1; /* Two seconds timeout */
- if (test_bit(RXBIT, &chan->cosa->rxtx)) {
- chan->stats.rx_errors++;
- chan->stats.rx_missed_errors++;
- } else {
- chan->stats.tx_errors++;
- chan->stats.tx_aborted_errors++;
- }
- cosa_kick(chan->cosa);
- if (chan->tx_skb) {
- dev_kfree_skb(chan->tx_skb);
- chan->tx_skb = 0;
- }
- dev->tbusy = 0;
- }
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
+ netif_stop_queue(dev);
+
chan->tx_skb = skb;
- dev->trans_start = jiffies;
cosa_start_tx(chan, skb->data, skb->len);
return 0;
}
+static void cosa_sppp_timeout(struct net_device *dev)
+{
+ struct channel_data *chan = dev->priv;
+
+ if (test_bit(RXBIT, &chan->cosa->rxtx)) {
+ chan->stats.rx_errors++;
+ chan->stats.rx_missed_errors++;
+ } else {
+ chan->stats.tx_errors++;
+ chan->stats.tx_aborted_errors++;
+ }
+ cosa_kick(chan->cosa);
+ if (chan->tx_skb) {
+ dev_kfree_skb(chan->tx_skb);
+ chan->tx_skb = 0;
+ }
+ netif_wake_queue(dev);
+}
+
static int cosa_sppp_close(struct net_device *d)
{
struct channel_data *chan = d->priv;
int flags;
+ netif_stop_queue(d);
sppp_close(d);
- d->tbusy = 1;
cosa_disable_rx(chan);
spin_lock_irqsave(&chan->cosa->lock, flags);
if (chan->rx_skb) {
@@ -760,8 +761,7 @@ static int sppp_tx_done(struct channel_data *chan, int size)
chan->tx_skb = 0;
chan->stats.tx_packets++;
chan->stats.tx_bytes += size;
- chan->pppdev.dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(chan->pppdev.dev);
return 1;
}
@@ -1350,14 +1350,14 @@ static void put_driver_status_nolock(struct cosa_data *cosa)
static void cosa_kick(struct cosa_data *cosa)
{
unsigned flags, flags1;
- char *s = "Unknown";
+ char *s = "(probably) IRQ";
if (test_bit(RXBIT, &cosa->rxtx))
- s = "RX";
+ s = "RX DMA";
if (test_bit(TXBIT, &cosa->rxtx))
- s = "TX";
+ s = "TX DMA";
- printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s);
+ printk(KERN_INFO "%s: %s timeout - restarting.\n", cosa->name, s);
spin_lock_irqsave(&cosa->lock, flags);
cosa->rxtx = 0;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 6113365c1..e039bbc28 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -50,6 +50,7 @@
#include <linux/random.h>
#include <linux/pkt_sched.h>
#include <asm/byteorder.h>
+#include <linux/spinlock.h>
#include "syncppp.h"
#define MAXALIVECNT 6 /* max. alive packets */
@@ -126,6 +127,7 @@ struct cisco_packet {
static struct sppp *spppq;
static struct timer_list sppp_keepalive_timer;
+static spinlock_t spppq_lock;
static void sppp_keepalive (unsigned long dummy);
static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type,
@@ -359,8 +361,8 @@ static void sppp_keepalive (unsigned long dummy)
{
struct sppp *sp;
unsigned long flags;
- save_flags(flags);
- cli();
+
+ spin_lock_irqsave(&spppq_lock, flags);
for (sp=spppq; sp; sp=sp->pp_next)
{
@@ -402,7 +404,7 @@ static void sppp_keepalive (unsigned long dummy)
sp->lcp.echoid, 4, &nmagic);
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&spppq_lock, flags);
sppp_keepalive_timer.expires=jiffies+10*HZ;
add_timer(&sppp_keepalive_timer);
}
@@ -915,7 +917,9 @@ void sppp_attach(struct ppp_device *pd)
{
struct net_device *dev = pd->dev;
struct sppp *sp = &pd->sppp;
-
+ unsigned long flags;
+
+ spin_lock_irqsave(&spppq_lock, flags);
/* Initialize keepalive handler. */
if (! spppq)
{
@@ -927,6 +931,7 @@ void sppp_attach(struct ppp_device *pd)
/* Insert new entry into the keepalive list. */
sp->pp_next = spppq;
spppq = sp;
+ spin_unlock_irqrestore(&spppq_lock, flags);
sp->pp_loopcnt = 0;
sp->pp_alivecnt = 0;
@@ -971,7 +976,9 @@ EXPORT_SYMBOL(sppp_attach);
void sppp_detach (struct net_device *dev)
{
struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev);
+ unsigned long flags;
+ spin_lock_irqsave(&spppq_lock, flags);
/* Remove the entry from the keepalive list. */
for (q = &spppq; (p = *q); q = &p->pp_next)
if (p == sp) {
@@ -983,6 +990,7 @@ void sppp_detach (struct net_device *dev)
if (! spppq)
del_timer(&sppp_keepalive_timer);
sppp_clear_timeout (sp);
+ spin_unlock_irqrestore(&spppq_lock, flags);
}
EXPORT_SYMBOL(sppp_detach);
@@ -1292,6 +1300,7 @@ void sync_ppp_init(void)
{
printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
+ spin_lock_init(&spppq_lock);
sppp_packet_type.type=htons(ETH_P_WAN_PPP);
dev_add_pack(&sppp_packet_type);
}
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index cd5b7caa0..17b285ba4 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -24,24 +24,24 @@
/*------------------------------------------------------------------*/
/*
- * Wrapper for disabling interrupts.
+ * Wrapper for disabling interrupts and locking the driver.
+ * (note : inline, so optimised away)
*/
-
-static inline unsigned long wv_splhi(void)
+static inline void wv_splhi(net_local * lp,
+ unsigned long * pflags)
{
- unsigned long flags;
- save_flags(flags);
- cli();
- return (flags);
+ spin_lock_irqsave(&lp->spinlock, *pflags);
+ /* Note : above does the cli(); itself */
}
/*------------------------------------------------------------------*/
/*
- * Wrapper for re-enabling interrupts.
+ * Wrapper for re-enabling interrupts and un-locking the driver.
*/
-static inline void wv_splx(unsigned long flags)
+static inline void wv_splx(net_local * lp,
+ unsigned long * pflags)
{
- restore_flags(flags);
+ spin_unlock_irqrestore(&lp->spinlock, *pflags);
}
/*------------------------------------------------------------------*/
@@ -180,13 +180,12 @@ static inline void wv_ints_off(device * dev)
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
- save_flags(flags);
- cli();
+ wv_splhi(lp, &flags);
lp->hacr &= ~HACR_INTRON;
hacr_write(ioaddr, lp->hacr);
- restore_flags(flags);
+ wv_splx(lp, &flags);
} /* wv_ints_off */
/*------------------------------------------------------------------*/
@@ -199,11 +198,12 @@ static inline void wv_ints_on(device * dev)
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
- save_flags(flags);
- cli();
+ wv_splhi(lp, &flags);
+
lp->hacr |= HACR_INTRON;
hacr_write(ioaddr, lp->hacr);
- restore_flags(flags);
+
+ wv_splx(lp, &flags);
} /* wv_ints_on */
/******************* MODEM MANAGEMENT SUBROUTINES *******************/
@@ -707,7 +707,7 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
printk(KERN_INFO
"%s: wv_config_complete(): configure failed; status = 0x%x\n",
dev->name, status);
-#endif /* DEBUG_CONFIG_ERROR */
+#endif /* DEBUG_CONFIG_ERROR */
ret = 1; /* Ready to be scrapped */
}
@@ -723,6 +723,8 @@ wv_config_complete(device * dev, unsigned long ioaddr, net_local * lp)
/*
* Command completion interrupt.
* Reclaim as many freed tx buffers as we can.
+ * (called in wavelan_interrupt()).
+ * Note : the spinlock is already grabbed for us.
*/
static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp)
{
@@ -870,16 +872,20 @@ static inline void wv_82586_reconfig(device * dev)
{
net_local *lp = (net_local *) dev->priv;
+ /* Arm the flag, will be cleard in wv_82586_config() */
+ lp->reconfig_82586 = 1;
+
/* Check if we can do it now ! */
- if (!netif_running(dev) && netif_queue_stopped(dev)) {
- lp->reconfig_82586 = 1;
+ if((netif_running(dev)) && !(netif_queue_stopped(dev)))
+ /* May fail */
+ wv_82586_config(dev);
+ else {
#ifdef DEBUG_CONFIG_INFO
printk(KERN_DEBUG
"%s: wv_82586_reconfig(): delayed (state = %lX)\n",
dev->name, dev->state);
#endif
- } else
- wv_82586_config(dev);
+ }
}
/********************* DEBUG & INFO SUBROUTINES *********************/
@@ -1806,9 +1812,9 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
#endif
/* Disable interrupts and save flags. */
- save_flags(flags);
- cli();
+ wv_splhi(lp, &flags);
/* FIXME: can't copy*user when cli this is broken! */
+ /* Note : is it still valid ? Jean II */
/* Look what is the request */
switch (cmd) {
@@ -2271,7 +2277,7 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* Enable interrupts and restore flags. */
- restore_flags(flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2297,15 +2303,12 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
dev->name);
#endif
- /* Disable interrupts and save flags. */
- save_flags(flags);
- cli();
-
+ /* Check */
if (lp == (net_local *) NULL)
- {
- restore_flags(flags);
return (iw_stats *) NULL;
- }
+
+ /* Disable interrupts and save flags. */
+ wv_splhi(lp, &flags);
wstats = &lp->wstats;
@@ -2333,7 +2336,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L;
/* Enable interrupts and restore flags. */
- restore_flags(flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
@@ -2455,7 +2458,8 @@ wv_packet_read(device * dev, u16 buf_off, int sksize)
/*
* Transfer as many packets as we can
* from the device RAM.
- * Called by the interrupt handler.
+ * (called in wavelan_interrupt()).
+ * Note : the spinlock is already grabbed for us.
*/
static inline void wv_receive(device * dev)
{
@@ -2640,7 +2644,7 @@ static inline void wv_receive(device * dev)
*
* (called in wavelan_packet_xmit())
*/
-static inline void wv_packet_write(device * dev, void *buf, short length)
+static inline int wv_packet_write(device * dev, void *buf, short length)
{
net_local *lp = (net_local *) dev->priv;
unsigned long ioaddr = dev->base_addr;
@@ -2665,9 +2669,18 @@ static inline void wv_packet_write(device * dev, void *buf, short length)
if (clen < ETH_ZLEN)
clen = ETH_ZLEN;
- save_flags(flags);
- cli();
-
+ wv_splhi(lp, &flags);
+
+ /* Check nothing bad has happened */
+ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
+#ifdef DEBUG_TX_ERROR
+ printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n",
+ dev->name);
+#endif
+ wv_splx(lp, &flags);
+ return 1;
+ }
+
/* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
@@ -2736,20 +2749,13 @@ static inline void wv_packet_write(device * dev, void *buf, short length)
/* Keep stats up to date. */
lp->stats.tx_bytes += length;
- /* If watchdog not already active, activate it... */
- if (lp->watchdog.prev == (timer_list *) NULL) {
- /* Set timer to expire in WATCHDOG_JIFFIES. */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
if (lp->tx_first_in_use == I82586NULL)
lp->tx_first_in_use = txblock;
if (lp->tx_n_in_use < NTXBLOCKS - 1)
netif_wake_queue(dev);
- restore_flags(flags);
+ wv_splx(lp, &flags);
#ifdef DEBUG_TX_INFO
wv_packet_info((u8 *) buf, length, dev->name,
@@ -2759,6 +2765,8 @@ static inline void wv_packet_write(device * dev, void *buf, short length)
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
#endif
+
+ return 0;
}
/*------------------------------------------------------------------*/
@@ -2781,7 +2789,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
* Block a timer-based transmit from overlapping.
* In other words, prevent reentering this routine.
*/
-
netif_stop_queue(dev);
/* If somebody has asked to reconfigure the controller,
@@ -2789,13 +2796,18 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
*/
if (lp->reconfig_82586) {
wv_82586_config(dev);
+ /* Check that we can continue */
+ if (lp->tx_n_in_use == (NTXBLOCKS - 1))
+ return 1;
}
#ifdef DEBUG_TX_ERROR
if (skb->next)
printk(KERN_INFO "skb has next\n");
#endif
- wv_packet_write(dev, skb->data, skb->len);
+ /* Write packet on the card */
+ if(wv_packet_write(dev, skb->data, skb->len))
+ return 1; /* We failed */
dev_kfree_skb(skb);
@@ -3161,7 +3173,7 @@ static inline int wv_cu_start(device * dev)
}
lp->tx_n_in_use = 0;
- netif_wake_queue(dev);
+ netif_start_queue(dev);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name);
#endif
@@ -3310,7 +3322,7 @@ static inline int wv_82586_start(device * dev)
* as usual to the NOP command.
* Note that only the last command (mc_set) will generate an interrupt.
*
- * (called by wv_hw_reset(), wv_82586_reconfig())
+ * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit())
*/
static void wv_82586_config(device * dev)
{
@@ -3336,9 +3348,18 @@ static void wv_82586_config(device * dev)
printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
#endif
- save_flags(flags);
- cli();
+ wv_splhi(lp, &flags);
+ /* Check nothing bad has happened */
+ if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
+#ifdef DEBUG_CONFIG_ERROR
+ printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n",
+ dev->name);
+#endif
+ wv_splx(lp, &flags);
+ return;
+ }
+
/* Calculate addresses of next block and previous block. */
txblock = lp->tx_first_free;
txpred = txblock - TXBLOCKZ;
@@ -3467,22 +3488,17 @@ static void wv_82586_config(device * dev)
(unsigned char *) &nop.nop_h.ac_link,
sizeof(nop.nop_h.ac_link));
- /* If watchdog not already active, activate it... */
- if (lp->watchdog.prev == (timer_list *) NULL) {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
-
+ /* Job done, clear the flag */
lp->reconfig_82586 = 0;
if (lp->tx_first_in_use == I82586NULL)
lp->tx_first_in_use = txblock;
- if (lp->tx_n_in_use < NTXBLOCKS - 1)
- netif_wake_queue(dev);
+ if (lp->tx_n_in_use == (NTXBLOCKS - 1))
+ netif_stop_queue(dev);
+
+ wv_splx(lp, &flags);
- restore_flags(flags);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name);
#endif
@@ -3539,10 +3555,6 @@ static int wv_hw_reset(device * dev)
(unsigned int) dev);
#endif
- /* If watchdog was activated, kill it! */
- if (lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
-
/* Increase the number of resets done. */
lp->nresets++;
@@ -3637,8 +3649,19 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp = (net_local *) dev->priv;
ioaddr = dev->base_addr;
- /* Prevent reentrance. What should we do here? */
+#ifdef DEBUG_INTERRUPT_ERROR
+ /* Check state of our spinlock (it should be cleared) */
+ if(spin_is_locked(&lp->spinlock))
+ printk(KERN_INFO
+ "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+ dev->name);
+#endif
+
+ /* Prevent reentrancy. It is safe because wv_splhi disable interrupts
+ * before aquiring the spinlock */
+ spin_lock(&lp->spinlock);
+ /* Check modem interupt */
if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
u8 dce_status;
@@ -3655,6 +3678,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
}
+ /* Check if not controller interrupt */
if ((hasr & HASR_82586_INTR) == 0) {
#ifdef DEBUG_INTERRUPT_ERROR
printk(KERN_INFO
@@ -3689,15 +3713,6 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->name);
#endif
wv_complete(dev, ioaddr, lp);
-
- /* If watchdog was activated, kill it ! */
- if (lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
- if (lp->tx_n_in_use > 0) {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
- }
}
/* Frame received. */
@@ -3710,9 +3725,13 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
wv_receive(dev);
}
+ /* Release spinlock here so that wv_hw_reset() can grab it */
+ spin_unlock (&lp->lock);
+
/* Check the state of the command unit. */
if (((status & SCB_ST_CNA) == SCB_ST_CNA) ||
- (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) {
+ (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) &&
+ (netif_running(dev)))) {
#ifdef DEBUG_INTERRUPT_ERROR
printk(KERN_INFO
"%s: wavelan_interrupt(): CU inactive -- restarting\n",
@@ -3723,7 +3742,8 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Check the state of the command unit. */
if (((status & SCB_ST_RNR) == SCB_ST_RNR) ||
- (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) {
+ (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) &&
+ (netif_running(dev)))) {
#ifdef DEBUG_INTERRUPT_ERROR
printk(KERN_INFO
"%s: wavelan_interrupt(): RU not ready -- restarting\n",
@@ -3739,26 +3759,16 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*------------------------------------------------------------------*/
/*
- * Watchdog: when we start a transmission, we set a timer in the
+ * Watchdog: when we start a transmission, a timer is set for us in the
* kernel. If the transmission completes, this timer is disabled. If
- * the timer expires, we try to unlock the hardware.
- *
- * Note: this watchdog doesn't work on the same principle as the
- * watchdog in the previous version of the ISA driver. I made it this
- * way because the overhead of add_timer() and del_timer() is nothing
- * and because it avoids calling the watchdog, saving some CPU.
+ * the timer expires, we are called and we try to unlock the hardware.
*/
-static void wavelan_watchdog(unsigned long a)
+static void wavelan_watchdog(device * dev)
{
- device *dev;
- net_local *lp;
- unsigned long ioaddr;
- unsigned long flags;
- unsigned int nreaped;
-
- dev = (device *) a;
- ioaddr = dev->base_addr;
- lp = (net_local *) dev->priv;
+ net_local * lp = (net_local *)dev->priv;
+ u_long ioaddr = dev->base_addr;
+ unsigned long flags;
+ unsigned int nreaped;
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -3769,18 +3779,16 @@ static void wavelan_watchdog(unsigned long a)
dev->name);
#endif
- save_flags(flags);
- cli();
-
- dev = (device *) a;
- ioaddr = dev->base_addr;
- lp = (net_local *) dev->priv;
+ wv_splhi(lp, &flags);
+ /* Check that we came here for something */
if (lp->tx_n_in_use <= 0) {
- restore_flags(flags);
+ wv_splx(lp, &flags);
return;
}
+ /* Try to see if some buffers are not free (in case we missed
+ * an interrupt */
nreaped = wv_complete(dev, ioaddr, lp);
#ifdef DEBUG_INTERRUPT_INFO
@@ -3811,15 +3819,13 @@ static void wavelan_watchdog(unsigned long a)
dev->name);
#endif
wv_hw_reset(dev);
- } else
- /* Reset watchdog for next transmission. */
- if (lp->tx_n_in_use > 0) {
- /* set timer to expire in WATCHDOG_JIFFIES */
- lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
- add_timer(&lp->watchdog);
}
- restore_flags(flags);
+ /* At this point, we should have some free Tx buffer ;-) */
+ if (lp->tx_n_in_use < NTXBLOCKS - 1)
+ netif_wake_queue(dev);
+
+ wv_splx(lp, &flags);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -3840,7 +3846,8 @@ static void wavelan_watchdog(unsigned long a)
*/
static int wavelan_open(device * dev)
{
- unsigned long flags;
+ net_local * lp = (net_local *)dev->priv;
+ unsigned long flags;
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
@@ -3865,8 +3872,7 @@ static int wavelan_open(device * dev)
return -EAGAIN;
}
- save_flags(flags);
- cli();
+ wv_splhi(lp, &flags);
if (wv_hw_reset(dev) != -1) {
netif_start_queue(dev);
@@ -3879,7 +3885,7 @@ static int wavelan_open(device * dev)
#endif
return -EAGAIN;
}
- restore_flags(flags);
+ wv_splx(lp, &flags);
MOD_INC_USE_COUNT;
@@ -3896,8 +3902,6 @@ static int wavelan_open(device * dev)
*/
static int wavelan_close(device * dev)
{
- net_local *lp = (net_local *) dev->priv;
-
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
(unsigned int) dev);
@@ -3905,10 +3909,6 @@ static int wavelan_close(device * dev)
netif_stop_queue(dev);
- /* If watchdog was activated, kill it! */
- if (lp->watchdog.prev != (timer_list *) NULL)
- del_timer(&lp->watchdog);
-
/*
* Flush the Tx and disable Rx.
*/
@@ -4001,11 +4001,13 @@ static int __init wavelan_config(device * dev)
lp->hacr = HACR_DEFAULT;
- lp->watchdog.function = wavelan_watchdog;
- lp->watchdog.data = (unsigned long) dev;
+ /* Multicast stuff */
lp->promiscuous = 0;
lp->mc_count = 0;
+ /* Init spinlock */
+ spin_lock_init(&lp->lock);
+
/*
* Fill in the fields of the device structure
* with generic Ethernet values.
@@ -4017,6 +4019,8 @@ static int __init wavelan_config(device * dev)
dev->hard_start_xmit = wavelan_packet_xmit;
dev->get_stats = wavelan_get_stats;
dev->set_multicast_list = &wavelan_set_multicast_list;
+ dev->tx_timeout = &wavelan_watchdog;
+ dev->watchdog_timeo = WATCHDOG_JIFFIES;
#ifdef SET_MAC_ADDRESS
dev->set_mac_address = &wavelan_set_mac_address;
#endif /* SET_MAC_ADDRESS */
diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h
index e4b722cf1..3e20776fb 100644
--- a/drivers/net/wavelan.p.h
+++ b/drivers/net/wavelan.p.h
@@ -34,6 +34,25 @@
* I try to maintain a web page with the Wireless LAN Howto at :
* http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
*
+ * SMP
+ * ---
+ * We now *should* be SMP compliant.
+ * I don't have a SMP box to verify that (my Pentium 90 is not), so
+ * someone has to certify that from me.
+ * Anyway, I spent enough time chasing interrupt re-entrancy during
+ * errors or reconfigure, and I designed the locked/unlocked sections
+ * of the driver with great care, and with the recent addition of
+ * the spinlock (thanks to the new API), we should be quite close to
+ * the truth.
+ * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ * but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ * I have also looked into disabling only our interrupt on the card
+ * (via HACR) instead of all interrupts in the processor (via cli),
+ * so that other driver are not impacted, and it look like it's
+ * possible, but it's very tricky to do right (full of races). As
+ * the gain would be mostly for SMP systems, it can wait...
+ *
* Debugging and options
* ---------------------
* You will find below a set of '#define" allowing a very fine control
@@ -171,7 +190,7 @@
*
* Thanks go also to:
* James Ashton <jaa101@syseng.anu.edu.au>,
- * Alan Cox <iialan@iiit.swan.ac.uk>,
+ * Alan Cox <alan@redhat.com>,
* Allan Creighton <allanc@cs.usyd.edu.au>,
* Matthew Geier <matthew@cs.usyd.edu.au>,
* Remo di Giovanni <remo@cs.usyd.edu.au>,
@@ -188,8 +207,9 @@
*
* Additional Credits:
*
- * My development has been done under Linux 2.0.x (Debian 1.1) with
- * an HP Vectra XP/60.
+ * My development has been done initially under Debian 1.1 (Linux 2.0.x)
+ * and now under Debian 2.2, initially with an HP Vectra XP/60, and now
+ * an HP Vectra XP/90.
*
*/
@@ -305,6 +325,21 @@
* - Fix check for root permission (break instead of exit)
* - New nwid & encoding setting (Wireless Extension 9)
*
+ * Changes made for release in 2.3.49 :
+ * ----------------------------------
+ * - Indentation reformating (Alan)
+ * - Update to new network API (softnet - 2.3.43) :
+ * o replace dev->tbusy (Alan)
+ * o replace dev->tstart (Alan)
+ * o remove dev->interrupt (Alan)
+ * o add SMP locking via spinlock in splxx (me)
+ * o add spinlock in interrupt handler (me)
+ * o use kernel watchdog instead of ours (me)
+ * o increase watchdog timeout (kernel is more sensitive) (me)
+ * o verify that all the changes make sense and work (me)
+ * - Fixup a potential gotcha when reconfiguring and thighten a bit
+ * the interactions with Tx queue.
+ *
* Wishes & dreams:
* ----------------
* - roaming (see Pcmcia driver)
@@ -395,11 +430,11 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan.c : v21 (wireless extensions) 16/10/99\n";
+static const char *version = "wavelan.c : v22 (wireless extensions) 21/02/00\n";
#endif
/* Watchdog temporisation */
-#define WATCHDOG_JIFFIES (256*HZ/100)
+#define WATCHDOG_JIFFIES (512*HZ/100)
/* Macro to get the number of elements in an array */
#define NELS(a) (sizeof(a) / sizeof(a[0]))
@@ -441,12 +476,12 @@ struct net_local
{
net_local * next; /* linked list of the devices */
device * dev; /* reverse link */
+ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */
en_stats stats; /* Ethernet interface statistics */
int nresets; /* number of hardware resets */
u_char reconfig_82586; /* We need to reconfigure the controller. */
u_char promiscuous; /* promiscuous mode */
int mc_count; /* number of multicast addresses */
- timer_list watchdog; /* to avoid blocking state */
u_short hacr; /* current host interface state */
int tx_n_in_use;
@@ -475,10 +510,12 @@ struct net_local
/**************************** PROTOTYPES ****************************/
/* ----------------------- MISC. SUBROUTINES ------------------------ */
-static inline unsigned long /* flags */
- wv_splhi(void); /* Disable interrupts */
static inline void
- wv_splx(unsigned long); /* Enable interrupts: flags */
+ wv_splhi(net_local *, /* Disable interrupts, lock driver */
+ unsigned long *); /* flags */
+static inline void
+ wv_splx(net_local *, /* Enable interrupts, unlock driver */
+ unsigned long *); /* flags */
static u_char
wv_irq_to_psa(int);
static int
@@ -580,7 +617,7 @@ static inline void
int),
wv_receive(device *); /* Read all packets waiting. */
/* --------------------- PACKET TRANSMISSION --------------------- */
-static inline void
+static inline int
wv_packet_write(device *, /* Write a packet to the Tx buffer. */
void *,
short);
@@ -607,7 +644,7 @@ static void
void *,
struct pt_regs *);
static void
- wavelan_watchdog(u_long); /* transmission watchdog */
+ wavelan_watchdog(device *); /* transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
static int
wavelan_open(device *), /* Open the device. */
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index 830d9d400..c4003dd27 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -1,7 +1,7 @@
/*
* IEEE 1284.3 Parallel port daisy chain and multiplexor code
*
- * Copyright (C) 1999 Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -12,6 +12,7 @@
* 31-01-1999: Make port-cloning transparent.
* 13-02-1999: Move DeviceID technique from parport_probe.
* 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ * 22-02-2000: Count devices that are actually detected.
*
*/
@@ -80,9 +81,11 @@ static struct parport *clone_parport (struct parport *real, int muxport)
return extra;
}
-/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
+ * Return value is number of devices actually detected. */
int parport_daisy_init (struct parport *port)
{
+ int detected = 0;
char *deviceid;
static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
int num_ports;
@@ -128,7 +131,7 @@ int parport_daisy_init (struct parport *port)
select_port (port);
parport_daisy_deselect_all (port);
- assign_addrs (port);
+ detected += assign_addrs (port);
/* Count the potential legacy device at the end. */
add_dev (numdevs++, port, -1);
@@ -136,25 +139,31 @@ int parport_daisy_init (struct parport *port)
/* Find out the legacy device's IEEE 1284 device ID. */
deviceid = kmalloc (1000, GFP_KERNEL);
if (deviceid) {
- parport_device_id (numdevs - 1, deviceid, 1000);
+ if (parport_device_id (numdevs - 1, deviceid, 1000) > 2)
+ detected++;
+
kfree (deviceid);
}
- return 0;
+ return detected;
}
/* Forget about devices on a physical port. */
void parport_daisy_fini (struct parport *port)
{
struct daisydev *dev, *prev = topology;
- while (prev && prev->port == port)
- prev = topology = topology->next;
+ while (prev && prev->port == port) {
+ topology = topology->next;
+ kfree (prev);
+ prev = topology;
+ }
while (prev) {
dev = prev->next;
if (dev && dev->port == port)
prev->next = dev->next;
+ kfree (dev);
prev = prev->next;
}
@@ -162,7 +171,8 @@ void parport_daisy_fini (struct parport *port)
someone enumerate through all IEEE1284.3 devices in the
topology?. */
if (!topology) numdevs = 0;
- return; }
+ return;
+}
/* Find a device by canonical device number. */
struct pardevice *parport_open (int devnum, const char *name,
@@ -371,7 +381,7 @@ static int assign_addrs (struct parport *port)
| PARPORT_STATUS_ERROR)) {
DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
port->name, s);
- return -ENXIO;
+ return 0;
}
parport_write_data (port, 0x87); udelay (2);
@@ -382,7 +392,7 @@ static int assign_addrs (struct parport *port)
if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
port->name, s);
- return -ENXIO;
+ return 0;
}
parport_write_data (port, 0x78); udelay (2);
@@ -421,7 +431,7 @@ static int assign_addrs (struct parport *port)
parport_device_id (thisdev, deviceid, 1000);
kfree (deviceid);
- return 0;
+ return numdevs - thisdev;
}
/* Find a device with a particular manufacturer and model string,
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index beb0a68b7..cf0e092bf 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -681,6 +681,7 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
/* Set up parallel port FIFO mode.*/
parport_pc_data_forward (port); /* Must be in PS2 mode */
+ parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0);
change_mode (port, ECR_PPF); /* Parallel port FIFO */
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
@@ -747,6 +748,10 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
/* Set up ECP parallel port mode.*/
parport_pc_data_forward (port); /* Must be in PS2 mode */
+ parport_pc_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD,
+ 0);
change_mode (port, ECR_ECP); /* ECP FIFO */
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
@@ -850,6 +855,10 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
/* Set up ECP parallel port mode.*/
parport_pc_data_reverse (port); /* Must be in PS2 mode */
+ parport_pc_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD,
+ 0);
change_mode (port, ECR_ECP); /* ECP FIFO */
port->ieee1284.phase = IEEE1284_PH_REV_DATA;
@@ -989,7 +998,7 @@ struct parport_operations parport_pc_ops =
/*
* Checks for port existence, all ports support SPP MODE
*/
-static int __maybe_init parport_SPP_supported(struct parport *pb)
+static int __devinit parport_SPP_supported(struct parport *pb)
{
unsigned char r, w;
@@ -1066,7 +1075,7 @@ static int __maybe_init parport_SPP_supported(struct parport *pb)
* two bits of ECR aren't writable, so we check by writing ECR and
* reading it back to see if it's what we expect.
*/
-static int __maybe_init parport_ECR_present(struct parport *pb)
+static int __devinit parport_ECR_present(struct parport *pb)
{
struct parport_pc_private *priv = pb->private_data;
unsigned char r = 0xc;
@@ -1118,7 +1127,7 @@ static int __maybe_init parport_ECR_present(struct parport *pb)
* be misdetected here is rather academic.
*/
-static int __maybe_init parport_PS2_supported(struct parport *pb)
+static int __devinit parport_PS2_supported(struct parport *pb)
{
int ok = 0;
@@ -1146,7 +1155,7 @@ static int __maybe_init parport_PS2_supported(struct parport *pb)
return ok;
}
-static int __maybe_init parport_ECP_supported(struct parport *pb)
+static int __devinit parport_ECP_supported(struct parport *pb)
{
int i;
int config;
@@ -1257,7 +1266,7 @@ static int __maybe_init parport_ECP_supported(struct parport *pb)
return 1;
}
-static int __maybe_init parport_ECPPS2_supported(struct parport *pb)
+static int __devinit parport_ECPPS2_supported(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
int result;
@@ -1277,7 +1286,7 @@ static int __maybe_init parport_ECPPS2_supported(struct parport *pb)
/* EPP mode detection */
-static int __maybe_init parport_EPP_supported(struct parport *pb)
+static int __devinit parport_EPP_supported(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
@@ -1320,7 +1329,7 @@ static int __maybe_init parport_EPP_supported(struct parport *pb)
return 1;
}
-static int __maybe_init parport_ECPEPP_supported(struct parport *pb)
+static int __devinit parport_ECPEPP_supported(struct parport *pb)
{
struct parport_pc_private *priv = pb->private_data;
int result;
@@ -1351,18 +1360,18 @@ static int __maybe_init parport_ECPEPP_supported(struct parport *pb)
#else /* No IEEE 1284 support */
/* Don't bother probing for modes we know we won't use. */
-static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; }
-static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;}
-static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;}
+static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
+static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
+static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
#endif /* No IEEE 1284 support */
/* --- IRQ detection -------------------------------------- */
/* Only if supports ECP mode */
-static int __maybe_init programmable_irq_support(struct parport *pb)
+static int __devinit programmable_irq_support(struct parport *pb)
{
int irq, intrLine;
unsigned char oecr = inb (ECONTROL (pb));
@@ -1379,7 +1388,7 @@ static int __maybe_init programmable_irq_support(struct parport *pb)
return irq;
}
-static int __maybe_init irq_probe_ECP(struct parport *pb)
+static int __devinit irq_probe_ECP(struct parport *pb)
{
int i;
unsigned long irqs;
@@ -1408,7 +1417,7 @@ static int __maybe_init irq_probe_ECP(struct parport *pb)
* This detection seems that only works in National Semiconductors
* This doesn't work in SMC, LGS, and Winbond
*/
-static int __maybe_init irq_probe_EPP(struct parport *pb)
+static int __devinit irq_probe_EPP(struct parport *pb)
{
#ifndef ADVANCED_DETECT
return PARPORT_IRQ_NONE;
@@ -1448,7 +1457,7 @@ static int __maybe_init irq_probe_EPP(struct parport *pb)
#endif /* Advanced detection */
}
-static int __maybe_init irq_probe_SPP(struct parport *pb)
+static int __devinit irq_probe_SPP(struct parport *pb)
{
/* Don't even try to do this. */
return PARPORT_IRQ_NONE;
@@ -1461,7 +1470,7 @@ static int __maybe_init irq_probe_SPP(struct parport *pb)
* When ECP is available we can autoprobe for IRQs.
* NOTE: If we can autoprobe it, we can register the IRQ.
*/
-static int __maybe_init parport_irq_probe(struct parport *pb)
+static int __devinit parport_irq_probe(struct parport *pb)
{
const struct parport_pc_private *priv = pb->private_data;
@@ -1495,7 +1504,7 @@ out:
/* --- DMA detection -------------------------------------- */
/* Only if supports ECP mode */
-static int __maybe_init programmable_dma_support (struct parport *p)
+static int __devinit programmable_dma_support (struct parport *p)
{
unsigned char oecr = inb (ECONTROL (p));
int dma;
@@ -1510,7 +1519,7 @@ static int __maybe_init programmable_dma_support (struct parport *p)
return dma;
}
-static int __maybe_init parport_dma_probe (struct parport *p)
+static int __devinit parport_dma_probe (struct parport *p)
{
const struct parport_pc_private *priv = p->private_data;
if (priv->ecr)
@@ -1521,7 +1530,7 @@ static int __maybe_init parport_dma_probe (struct parport *p)
/* --- Initialisation code -------------------------------- */
-struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
+struct parport *__devinit parport_pc_probe_port (unsigned long int base,
unsigned long int base_hi,
int irq, int dma,
struct pci_dev *dev)
@@ -1693,9 +1702,7 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
#endif /* CONFIG_PARPORT_PC_FIFO */
}
- /* Done probing. Now put the port into a sensible start-up state.
- * SELECT | INIT also puts IEEE1284-compliant devices into
- * compatibility mode. */
+ /* Done probing. Now put the port into a sensible start-up state. */
if (priv->ecr)
/*
* Put the ECP detected port in PS2 mode.
@@ -1714,9 +1721,143 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
return p;
}
+
+static int __devinit sio_via_686a_probe (struct pci_dev *pdev)
+{
+ u8 dma, irq, tmp;
+ unsigned port1, port2, have_eppecp;
+
+ /*
+ * unlock super i/o configuration, set 0x85_1
+ */
+ pci_read_config_byte (pdev, 0x85, &tmp);
+ tmp |= (1 << 1);
+ pci_write_config_byte (pdev, 0x85, tmp);
+
+ /*
+ * Super I/O configuration, index port == 3f0h, data port == 3f1h
+ */
+
+ /* 0xE2_1-0: Parallel Port Mode / Enable */
+ outb (0xE2, 0x3F0);
+ tmp = inb (0x3F1);
+
+ if ((tmp & 0x03) == 0x03) {
+ printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n");
+ return 0;
+ }
+
+ /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */
+ outb (0xE6, 0x3F0);
+ port1 = inb (0x3F1) << 2;
+
+ switch (port1) {
+ case 0x3bc: port2 = 0x7bc; break;
+ case 0x378: port2 = 0x778; break;
+ case 0x278: port2 = 0x678; break;
+ default:
+ printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n",
+ port1);
+ return 0;
+ }
+
+ /* 0xF0_5: EPP+ECP enable */
+ outb (0xF0, 0x3F0);
+ have_eppecp = (inb (0x3F1) & (1 << 5));
+
+ /*
+ * lock super i/o configuration, clear 0x85_1
+ */
+ pci_read_config_byte (pdev, 0x85, &tmp);
+ tmp &= ~(1 << 1);
+ pci_write_config_byte (pdev, 0x85, tmp);
+
+ /*
+ * Get DMA and IRQ from PCI->ISA bridge PCI config registers
+ */
+
+ /* 0x50_3-2: PnP Routing for Parallel Port DRQ */
+ pci_read_config_byte (pdev, 0x50, &dma);
+ dma = ((dma >> 2) & 0x03);
+
+ /* 0x51_7-4: PnP Routing for Parallel Port IRQ */
+ pci_read_config_byte (pdev, 0x51, &irq);
+ irq = ((irq >> 4) & 0x0F);
+
+ /* filter bogus IRQs */
+ switch (irq) {
+ case 0:
+ case 2:
+ case 8:
+ case 13:
+ irq = PARPORT_IRQ_NONE;
+ break;
+
+ default: /* do nothing */
+ break;
+ }
+
+ /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */
+ if (!have_eppecp)
+ dma = PARPORT_DMA_NONE;
+
+ /* finally, do the probe with values obtained */
+ if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
+ printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n",
+ port1, irq, dma);
+ return 1;
+ }
+
+ printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n",
+ port1, irq, dma);
+ return 0;
+}
+
+
+enum parport_pc_sio_types {
+ sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */
+};
+
+
+/* each element directly indexed from enum list, above */
+static struct parport_pc_superio {
+ int (*probe) (struct pci_dev *pdev);
+} parport_pc_superio_info[] __devinitdata = {
+ { sio_via_686a_probe, },
+};
+
+
+static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
+ { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a },
+ { 0, }, /* terminate list */
+};
+
+
+static int __devinit parport_pc_init_superio(void)
+{
+ const struct pci_device_id *id;
+ struct pci_dev *pdev;
+
+ pci_for_each_dev(pdev) {
+ id = pci_match_device (parport_pc_pci_tbl, pdev);
+ if (id == NULL)
+ continue;
+
+ return parport_pc_superio_info[id->driver_data].probe (pdev);
+ }
+
+ return 0; /* zero devices found */
+}
+
+
/* Look for PCI parallel port cards. */
static int __init parport_pc_init_pci (int irq, int dma)
{
+#ifndef PCI_VENDOR_ID_AFAVLAB
+#define PCI_VENDOR_ID_AFAVLAB 0x14db
+#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120
+#endif
+
struct {
unsigned int vendor;
unsigned int device;
@@ -1800,6 +1941,9 @@ static int __init parport_pc_init_pci (int irq, int dma)
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014,
2, { { 4, -1 }, { 5, -1 }, } },
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 1, { { 0, 1 }, } },
{ 0, }
};
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index 6772ea6d8..9ab6d97e2 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -150,13 +150,11 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len)
if (!retval) {
int idlen;
unsigned char length[2];
- mm_segment_t oldfs = get_fs ();
- set_fs (get_ds ());
/* First two bytes are MSB,LSB of inclusive length. */
retval = parport_read (dev->port, length, 2);
- if (retval != 2) goto restore_fs;
+ if (retval != 2) goto end_id;
idlen = (length[0] << 8) + length[1] - 2;
if (idlen < len)
@@ -169,8 +167,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len)
len);
/* Some printer manufacturers mistakenly believe that
- the length field is supposed to be _exclusive_. */
- /* In addition, there are broken devices out there
+ the length field is supposed to be _exclusive_.
+ In addition, there are broken devices out there
that don't even finish off with a semi-colon. */
if (buffer[len - 1] != ';') {
ssize_t diff;
@@ -196,9 +194,8 @@ ssize_t parport_device_id (int devnum, char *buffer, size_t len)
}
}
- restore_fs:
+ end_id:
buffer[len] = '\0';
- set_fs (oldfs);
parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
}
parport_release (dev);
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 8059dfa22..fe5ea143b 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -247,7 +247,19 @@ void parport_announce_port (struct parport *port)
{
#ifdef CONFIG_PARPORT_1284
/* Analyse the IEEE1284.3 topology of the port. */
- parport_daisy_init (port);
+ if (parport_daisy_init (port) == 0) {
+ /* No devices were detected. Perhaps they are in some
+ funny state; let's try to reset them and see if
+ they wake up. */
+ parport_daisy_fini (port);
+ parport_write_control (port, PARPORT_CONTROL_SELECT);
+ udelay (50);
+ parport_write_control (port,
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_INIT);
+ udelay (50);
+ parport_daisy_init (port);
+ }
#endif
/* Let drivers know that a new port has arrived. */
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 9556874c1..1dfedc0dd 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -2682,6 +2682,7 @@
13c0 Microgate Corporation
0010 SyncLink WAN Adapter
13c1 3ware Inc
+ 1000 3ware ATA-RAID
13c2 Technotrend Systemtechnik GmbH
13c3 Janz Computer AG
13c4 Phase Metrics
@@ -3424,6 +3425,7 @@
71a0 440GX - 82443GX Host bridge
71a1 440GX - 82443GX AGP bridge
71a2 440GX - 82443GX Host bridge (AGP disabled)
+ 7601 82372FB PIIX4 IDE
7602 82372FB [PCI-to-USB UHCI]
7800 i740
1092 0100 Stealth II G460
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 36c3be081..067e25647 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -197,10 +197,6 @@ static struct file_operations proc_bus_pci_operations = {
write: proc_bus_pci_write,
};
-static struct inode_operations proc_bus_pci_inode_operations = {
- &proc_bus_pci_operations, /* default base directory file-ops */
-};
-
#if BITS_PER_LONG == 32
#define LONG_FORMAT "\t%08lx"
#else
@@ -265,7 +261,7 @@ int pci_proc_attach_device(struct pci_dev *dev)
e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de);
if (!e)
return -ENOMEM;
- e->ops = &proc_bus_pci_inode_operations;
+ e->proc_fops = &proc_bus_pci_operations;
e->data = dev;
e->size = PCI_CFG_SPACE_SIZE;
return 0;
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 18d47d9a8..6ea612b84 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -165,25 +165,6 @@ typedef struct vg46x_state_t {
u_char ctl, ema;
} vg46x_state_t;
-typedef struct ti113x_state_t {
- u_int sysctl;
- u_char cardctl, devctl, diag;
-} ti113x_state_t;
-
-typedef struct rl5c4xx_state_t {
- u_short misc, ctl, io, mem;
-} rl5c4xx_state_t;
-
-typedef struct o2micro_state_t {
- u_char mode_a, mode_b, mode_c, mode_d;
- u_char mhpg, fifo, mode_e;
-} o2micro_state_t;
-
-typedef struct topic_state_t {
- u_char slot, ccr, cdr;
- u_int rcr;
-} topic_state_t;
-
typedef struct socket_info_t {
u_short type, flags;
socket_cap_t cap;
@@ -276,22 +257,6 @@ static pcic_t pcic[] = {
/*====================================================================*/
-/* Some PCI shortcuts */
-
-#define config_readb(sock, r, v) pci_read_config_byte((sock)->pdev, r, v)
-#define config_readw(sock, r, v) pci_read_config_word((sock)->pdev, r, v)
-#define config_readl(sock, r, v) pci_read_config_dword((sock)->pdev, r, v)
-#define config_writeb(sock, r, v) pci_write_config_byte((sock)->pdev, r, v)
-#define config_writew(sock, r, v) pci_write_config_word((sock)->pdev, r, v)
-#define config_writel(sock, r, v) pci_write_config_dword((sock)->pdev, r, v)
-
-#define cb_readb(s, r) readb(socket[s].cb_virt + (r))
-#define cb_readl(s, r) readl(socket[s].cb_virt + (r))
-#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r))
-#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r))
-
-/*====================================================================*/
-
static u_char i365_get(u_short sock, u_short reg)
{
{
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index 28821cbcf..3531348bb 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -17,6 +17,12 @@
#include "yenta.h"
#include "i82365.h"
+#if 0
+#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args)
+#else
+#define DEBUG(x,args...)
+#endif
+
/* Don't ask.. */
#define to_cycles(ns) ((ns)/120)
#define to_ns(cycles) ((cycles)*120)
@@ -26,13 +32,24 @@
* regular memory space ("cb_xxx"), configuration space
* ("config_xxx") and compatibility space ("exca_xxxx")
*/
-#define cb_readl(sock,reg) readl((sock)->base + (reg))
-#define cb_writel(sock,reg,val) writel(val,(sock)->base + (reg))
+static inline u32 cb_readl(pci_socket_t *socket, unsigned reg)
+{
+ u32 val = readl(socket->base + reg);
+ DEBUG("%p %04x %08x\n", socket, reg, val);
+ return val;
+}
+
+static inline void cb_writel(pci_socket_t *socket, unsigned reg, u32 val)
+{
+ DEBUG("%p %04x %08x\n", socket, reg, val);
+ writel(val, socket->base + reg);
+}
static inline u8 config_readb(pci_socket_t *socket, unsigned offset)
{
u8 val;
pci_read_config_byte(socket->dev, offset, &val);
+ DEBUG("%p %04x %02x\n", socket, offset, val);
return val;
}
@@ -40,6 +57,7 @@ static inline u16 config_readw(pci_socket_t *socket, unsigned offset)
{
u16 val;
pci_read_config_word(socket->dev, offset, &val);
+ DEBUG("%p %04x %04x\n", socket, offset, val);
return val;
}
@@ -47,25 +65,55 @@ static inline u32 config_readl(pci_socket_t *socket, unsigned offset)
{
u32 val;
pci_read_config_dword(socket->dev, offset, &val);
+ DEBUG("%p %04x %08x\n", socket, offset, val);
return val;
}
-#define config_writeb(s,off,val) pci_write_config_byte((s)->dev, (off), (val))
-#define config_writew(s,off,val) pci_write_config_word((s)->dev, (off), (val))
-#define config_writel(s,off,val) pci_write_config_dword((s)->dev, (off), (val))
+static inline void config_writeb(pci_socket_t *socket, unsigned offset, u8 val)
+{
+ DEBUG("%p %04x %02x\n", socket, offset, val);
+ pci_write_config_byte(socket->dev, offset, val);
+}
+
+static inline void config_writew(pci_socket_t *socket, unsigned offset, u16 val)
+{
+ DEBUG("%p %04x %04x\n", socket, offset, val);
+ pci_write_config_word(socket->dev, offset, val);
+}
-#define exca_readb(sock,reg) readb((sock)->base + 0x800 + (reg))
-#define exca_writeb(sock,reg,v) writeb((v), (sock)->base + 0x800 + (reg))
+static inline void config_writel(pci_socket_t *socket, unsigned offset, u32 val)
+{
+ DEBUG("%p %04x %08x\n", socket, offset, val);
+ pci_write_config_dword(socket->dev, offset, val);
+}
+
+static inline u8 exca_readb(pci_socket_t *socket, unsigned reg)
+{
+ u8 val = readb(socket->base + 0x800 + reg);
+ DEBUG("%p %04x %02x\n", socket, reg, val);
+ return val;
+}
+
+static inline u8 exca_readw(pci_socket_t *socket, unsigned reg)
+{
+ u16 val;
+ val = readb(socket->base + 0x800 + reg);
+ val |= readb(socket->base + 0x800 + reg + 1) << 8;
+ DEBUG("%p %04x %04x\n", socket, reg, val);
+ return val;
+}
-static u16 exca_readw(pci_socket_t *socket, unsigned reg)
+static inline void exca_writeb(pci_socket_t *socket, unsigned reg, u8 val)
{
- return exca_readb(socket, reg) | (exca_readb(socket, reg+1) << 8);
+ DEBUG("%p %04x %02x\n", socket, reg, val);
+ writeb(val, socket->base + 0x800 + reg);
}
static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val)
{
- exca_writeb(socket, reg, val);
- exca_writeb(socket, reg+1, val >> 8);
+ DEBUG("%p %04x %04x\n", socket, reg, val);
+ writeb(val, socket->base + 0x800 + reg);
+ writeb(val >> 8, socket->base + 0x800 + reg + 1);
}
/*
diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c
index d9f73819f..658fa2ede 100644
--- a/drivers/pnp/isapnp_proc.c
+++ b/drivers/pnp/isapnp_proc.c
@@ -210,11 +210,6 @@ static struct file_operations isapnp_info_entry_operations =
release: isapnp_info_entry_release,
};
-static struct inode_operations isapnp_info_entry_inode_operations =
-{
- &isapnp_info_entry_operations, /* default sound info directory file-ops */
-};
-
static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
{
loff_t new;
@@ -274,11 +269,6 @@ static struct file_operations isapnp_proc_bus_file_operations =
read: isapnp_proc_bus_read,
};
-static struct inode_operations isapnp_proc_bus_inode_operations =
-{
- &isapnp_proc_bus_file_operations,
-};
-
static int isapnp_proc_attach_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
@@ -295,7 +285,7 @@ static int isapnp_proc_attach_device(struct pci_dev *dev)
e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
if (!e)
return -ENOMEM;
- e->ops = &isapnp_proc_bus_inode_operations;
+ e->proc_fops = &isapnp_proc_bus_file_operations;
e->data = dev;
e->size = 256;
return 0;
@@ -378,7 +368,7 @@ int __init isapnp_proc_init(void)
isapnp_proc_entry = NULL;
p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
if (p)
- p->ops = &isapnp_info_entry_inode_operations;
+ p->proc_fops = &isapnp_info_entry_operations;
isapnp_proc_entry = p;
isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
isapnp_proc_devices_entry = create_proc_info_entry("devices", 0,
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 5477bb1ac..42b86930d 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -85,7 +85,7 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len);
static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
/* Globals */
-char *tw_driver_version="0.4.001";
+char *tw_driver_version="1.0.000";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
@@ -2051,12 +2051,16 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
command_packet->status = 0;
command_packet->flags = 0;
+ if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) {
+ if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
+ command_packet->flags = 1;
+ }
+
if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
num_sectors = (u32)srb->cmnd[4];
} else {
- lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) |
- ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
+ lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
}
diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx
index ed169320a..4abf98759 100644
--- a/drivers/scsi/ChangeLog.sym53c8xx
+++ b/drivers/scsi/ChangeLog.sym53c8xx
@@ -1,3 +1,17 @@
+Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5j
+ - Add support for the new dynamic dma mapping kernel interface.
+ Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+ Many thanks to David S. Miller for his preliminary changes
+ that have been useful guidelines, for having reviewed the
+ code and having tested this driver version on Ultra-Sparc.
+ - 2 tiny bugs fixed in the PCI wrapper that provides support
+ for early kernels without pci device structure.
+ - Get data transfer direction from the scsi command structure
+ (Scsi_Cmnd) with kernels that provide this information.
+ - Fix an old bug that only affected 896 rev. 1 when driver
+ profile support option was set in kernel configuration.
+
Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.5h
- Add year 2000 copyright.
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 9faa91e1b..4395cd682 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -44,6 +44,19 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then
dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
fi
+if [ "$CONFIG_SGI_IP22" = "y" ]; then
+ dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI
+fi
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+ if [ "$CONFIG_TC" = "y" ]; then
+ dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI
+ fi
+ dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
+fi
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
+fi
dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI
dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
@@ -188,9 +201,6 @@ fi
if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP
fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate '3Ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
-fi
endmenu
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index 725a70a4a..8768db48c 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -167,7 +167,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
cmnd[9] = 0;
scmd->cmd_len = 10;
- scmd->sc_data_direction = DATA_READ;
+ scmd->sc_data_direction = SCSI_DATA_READ;
/*
* Do the command and wait for it to finish.
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index e07417b7e..6aef8ae63 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -60,9 +60,6 @@
#include <linux/bios32.h>
#endif
-struct proc_dir_entry Proc_Scsi_Pci2000 =
- { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
-
//#define DEBUG 1
#ifdef DEBUG
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index a3daa5f76..15652ca9f 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -200,59 +200,25 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
-extern struct proc_dir_entry Proc_Scsi_Pci2000;
-
-#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
-#define PCI2000 { \
- next: NULL, \
- module: NULL, \
- proc_dir: &Proc_Scsi_Pci2000, \
- proc_info: NULL, /* let's not bloat the kernel */ \
- name: "PCI-2000 SCSI Intelligent Disk Controller",\
- detect: Pci2000_Detect, \
- release: Pci2000_Release, \
- info: NULL, /* let's not bloat the kernel */ \
- command: Pci2000_Command, \
- queuecommand: Pci2000_QueueCommand, \
- eh_strategy_handler: NULL, \
- eh_abort_handler: NULL, \
- eh_device_reset_handler: NULL, \
- eh_bus_reset_handler: NULL, \
- eh_host_reset_handler: NULL, \
- abort: Pci2000_Abort, \
- reset: Pci2000_Reset, \
- slave_attach: NULL, \
- bios_param: Pci2000_BiosParam, \
- can_queue: 16, \
- this_id: -1, \
- sg_tablesize: 16, \
- cmd_per_lun: 1, \
- present: 0, \
- unchecked_isa_dma: 0, \
- use_clustering: DISABLE_CLUSTERING, \
- use_new_eh_code: 0 \
- }
-#else
-#define PCI2000 { NULL, NULL, \
- &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
- NULL, \
- "PCI-2000 SCSI Intelligent Disk Controller",\
- Pci2000_Detect, \
- Pci2000_Release, \
- NULL, \
- Pci2000_Command, \
- Pci2000_QueueCommand, \
- Pci2000_Abort, \
- Pci2000_Reset, \
- NULL, \
- Pci2000_BiosParam, \
- 16, \
- -1, \
- 16, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
-#endif
+/* screen is 80 columns wide, damnit! */
+#define PCI2000 { \
+ proc_name: "pci2000", \
+ name: "PCI-2000 SCSI Intelligent Disk Controller", \
+ detect: Pci2000_Detect, \
+ release: Pci2000_Release, \
+ command: Pci2000_Command, \
+ queuecommand: Pci2000_QueueCommand, \
+ abort: Pci2000_Abort, \
+ reset: Pci2000_Reset, \
+ bios_param: Pci2000_BiosParam, \
+ can_queue: 16, \
+ this_id: -1, \
+ sg_tablesize: 16, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma:0, \
+ use_clustering: DISABLE_CLUSTERING, \
+ use_new_eh_code:0 \
+}
#endif
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
index 80f58cb8e..fabb61c0c 100644
--- a/drivers/scsi/pci2220i.c
+++ b/drivers/scsi/pci2220i.c
@@ -67,9 +67,6 @@
#define WRITE_CMD IDE_CMD_WRITE_MULTIPLE
#define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master
-struct proc_dir_entry Proc_Scsi_Pci2220i =
- { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
-
#ifdef DEBUG
#define DEB(x) x
#define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}}
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
index aaa8457fc..689e62573 100644
--- a/drivers/scsi/pci2220i.h
+++ b/drivers/scsi/pci2220i.h
@@ -39,59 +39,23 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
#define NULL 0
#endif
-extern struct proc_dir_entry Proc_Scsi_Pci2220i;
-
-#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75)
-#define PCI2220I { \
- next: NULL, \
- module: NULL, \
- proc_dir: &Proc_Scsi_Pci2220i, \
- proc_info: NULL, /* let's not bloat the kernel */\
- name: "PCI-2220I/PCI-2240I", \
- detect: Pci2220i_Detect, \
- release: Pci2220i_Release, \
- info: NULL, /* let's not bloat the kernel */\
- command: Pci2220i_Command, \
- queuecommand: Pci2220i_QueueCommand, \
- eh_strategy_handler: NULL, \
- eh_abort_handler: NULL, \
- eh_device_reset_handler: NULL, \
- eh_bus_reset_handler: NULL, \
- eh_host_reset_handler: NULL, \
- abort: Pci2220i_Abort, \
- reset: Pci2220i_Reset, \
- slave_attach: NULL, \
- bios_param: Pci2220i_BiosParam, \
- can_queue: 1, \
- this_id: -1, \
- sg_tablesize: SG_ALL, \
- cmd_per_lun: 1, \
- present: 0, \
- unchecked_isa_dma: 0, \
- use_clustering: DISABLE_CLUSTERING, \
- use_new_eh_code: 0 \
- }
-#else
-#define PCI2220I { NULL, NULL, \
- &Proc_Scsi_Pci2220i,/* proc_dir_entry */\
- NULL, \
- "PCI-2220I/PCI-2240I", \
- Pci2220i_Detect, \
- Pci2220i_Release, \
- NULL, \
- Pci2220i_Command, \
- Pci2220i_QueueCommand, \
- Pci2220i_Abort, \
- Pci2220i_Reset, \
- NULL, \
- Pci2220i_BiosParam, \
- 1, \
- -1, \
- SG_ALL, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
-#endif
-
+#define PCI2220I { \
+ proc_name: "pci2220i", \
+ name: "PCI-2220I/PCI-2240I", \
+ detect: Pci2220i_Detect, \
+ release: Pci2220i_Release, \
+ command: Pci2220i_Command, \
+ queuecommand: Pci2220i_QueueCommand, \
+ abort: Pci2220i_Abort, \
+ reset: Pci2220i_Reset, \
+ bios_param: Pci2220i_BiosParam, \
+ can_queue: 1, \
+ this_id: -1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: DISABLE_CLUSTERING, \
+ use_new_eh_code: 0 \
+}
#endif
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index e216ef03a..42f208062 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -426,25 +426,6 @@ static char dummy_buffer[60] = "Please don't add commas in your insmod command!!
#endif
-
-/*
- * Our directory Entry in /proc/scsi for the user to
- * access the driver.
- */
-
-#if 0
-
-/* Need to add in proc_fs.h PROC_SCSI_QL1280 */
-#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP
-
-struct proc_dir_entry proc_scsi_qla1280 = {
- PROC_SCSI_QL1280, 7, "qla1280",
- S_IFDIR | S_IRUGO | S_IXUGO, 2,
- 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
-
-#endif
-
/* We use the Scsi_Pointer structure that's included with each command
* SCSI_Cmnd as a scratchpad for our SRB.
*
@@ -2749,13 +2730,13 @@ qla1280_setup_chip(scsi_qla_host_t *ha)
long risc_code_size;
uint16_t mb[MAILBOX_REGISTER_COUNT];
#ifdef QLA1280_UNUSED
+ uint8_t *sp;
int i;
#endif
uint16_t cnt;
int num;
- uint8_t *tbuf, *sp;
+ uint8_t *tbuf;
u_long p_tbuf;
- int i;
#ifdef QL_DEBUG_LEVEL_3
ENTER("qla1280_setup_chip");
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
index 283fe9c3d..df9ba38d4 100644
--- a/drivers/scsi/qlogicfc.c
+++ b/drivers/scsi/qlogicfc.c
@@ -18,6 +18,9 @@
/* This is a version of the isp1020 driver which was modified by
* Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
+ *
+ * Big endian support and dynamic DMA mapping added
+ * by Jakub Jelinek <jakub@redhat.com>.
*/
/*
@@ -59,6 +62,24 @@
#include "sd.h"
#include "hosts.h"
+
+#if 1
+/* Once pci64_ DMA mapping interface is in, kill this. */
+typedef dma_addr_t dma64_addr_t;
+#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p))
+#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a))
+#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir))
+#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir))
+#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir))
+#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir))
+#define pci64_dma_hi32(a) 0
+#define pci64_dma_lo32(a) (a)
+#define pci64_dma_build(hi,lo) (lo)
+#define sg_dma64_address(s) sg_dma_address(s)
+#define sg_dma64_len(s) sg_dma_len(s)
+#define PCI64_DMA_BITS 32
+#endif
+
#include "qlogicfc.h"
/* Configuration section **************************************************** */
@@ -157,18 +178,6 @@ struct {
#endif /* DEBUG ISP2x00_INTR */
-#if BITS_PER_LONG > 32
-#define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x)))
-#define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32)))
-#define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x)))
-#define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32)))
-#else
-#define virt_to_bus_low32(x) virt_to_bus(x)
-#define virt_to_bus_high32(x) 0x0
-#define bus_to_virt_low32(x) bus_to_virt(x)
-#define bus_to_virt_high32(x) 0x0
-#endif
-
#define ISP2100_REV_ID1 1
#define ISP2100_REV_ID3 3
#define ISP2200_REV_ID5 5
@@ -230,7 +239,7 @@ struct Entry_header {
};
/* entry header type commands */
-#if BITS_PER_LONG > 32
+#if PCI64_DMA_BITS > 32
#define ENTRY_COMMAND 0x19
#define ENTRY_CONTINUATION 0x0a
#else
@@ -247,34 +256,23 @@ struct Entry_header {
#define EFLAG_BAD_HEADER 4
#define EFLAG_BAD_PAYLOAD 8
-#if BITS_PER_LONG > 32
+#if PCI64_DMA_BITS > 32
+
struct dataseg {
u_int d_base;
u_int d_base_hi;
u_int d_count;
};
-struct Command_Entry {
- struct Entry_header hdr;
- u_int handle;
- u_char target_lun;
- u_char target_id;
- u_short expanded_lun;
- u_short control_flags;
- u_short rsvd2;
- u_short time_out;
- u_short segment_cnt;
- u_char cdb[16];
- u_int total_byte_cnt;
- struct dataseg dataseg[DATASEGS_PER_COMMAND];
-};
-
#else
+
struct dataseg {
u_int d_base;
u_int d_count;
};
+#endif
+
struct Command_Entry {
struct Entry_header hdr;
u_int handle;
@@ -290,9 +288,6 @@ struct Command_Entry {
struct dataseg dataseg[DATASEGS_PER_COMMAND];
};
-#endif
-
-
/* command entry control flag definitions */
#define CFLAG_NODISC 0x01
#define CFLAG_HEAD_TAG 0x02
@@ -302,7 +297,7 @@ struct Command_Entry {
#define CFLAG_READ 0x20
#define CFLAG_WRITE 0x40
-#if BITS_PER_LONG > 32
+#if PCI64_DMA_BITS > 32
struct Continuation_Entry {
struct Entry_header hdr;
struct dataseg dataseg[DATASEGS_PER_CONT];
@@ -650,6 +645,9 @@ struct init_cb {
#define AS_REDO_FABRIC_PORTDB 2
#define AS_REDO_LOOP_PORTDB 4
+#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)
+#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)
+
struct isp2x00_hostdata {
u_char revision;
struct pci_dev *pci_dev;
@@ -730,6 +728,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
struct isp2x00_hostdata *hostdata;
struct pci_dev *pdev = NULL;
unsigned short device_ids[2];
+ dma64_addr_t busaddr;
int i;
@@ -756,50 +755,43 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
memset(hostdata, 0, sizeof(struct isp2x00_hostdata));
hostdata->pci_dev = pdev;
- hostdata->res = (char *) kmalloc((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL);
+ hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr);
+
if (!hostdata->res){
- printk("qlogicfc%d : could not allocate memory for response queue.\n", hostdata->host_id);
- scsi_unregister(host);
- continue;
- }
- hostdata->req = (char *) kmalloc((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL);
- if (!hostdata->req){
- printk("qlogicfc%d : could not allocate memory for request queue.\n", hostdata->host_id);
- kfree(hostdata->res);
+ printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id);
scsi_unregister(host);
continue;
}
-
+ hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN;
hostdata->queued = 0;
/* set up the control block */
hostdata->control_block.version = 0x1;
- hostdata->control_block.firm_opts = 0x800e;
- hostdata->control_block.max_frame_len = 2048;
- hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN;
- hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
+ hostdata->control_block.firm_opts = cpu_to_le16(0x800e);
+ hostdata->control_block.max_frame_len = cpu_to_le16(2048);
+ hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN);
+ hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN);
hostdata->control_block.retry_delay = 5;
hostdata->control_block.retry_cnt = 1;
- hostdata->control_block.node_name[0] = 0x0020;
- hostdata->control_block.node_name[1] = 0xE000;
- hostdata->control_block.node_name[2] = 0x008B;
- hostdata->control_block.node_name[3] = 0x0000;
- hostdata->control_block.hard_addr = 0x0003;
- hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1;
- hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1;
- hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(hostdata->res);
- hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(hostdata->res);
- hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req);
- hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req);
-
-
- hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4;
+ hostdata->control_block.node_name[0] = cpu_to_le16(0x0020);
+ hostdata->control_block.node_name[1] = cpu_to_le16(0xE000);
+ hostdata->control_block.node_name[2] = cpu_to_le16(0x008B);
+ hostdata->control_block.node_name[3] = cpu_to_le16(0x0000);
+ hostdata->control_block.hard_addr = cpu_to_le16(0x0003);
+ hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1);
+ hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1);
+ hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr));
+ hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr));
+ hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE));
+ hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE));
+
+
+ hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4);
hostdata->adapter_state = AS_LOOP_DOWN;
hostdata->explore_timer.data = 1;
hostdata->host_id = hosts;
if (isp2x00_init(host) || isp2x00_reset_hardware(host)) {
- kfree(hostdata->res);
- kfree(hostdata->req);
+ pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
scsi_unregister(host);
continue;
}
@@ -808,8 +800,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) {
printk("qlogicfc%d : interrupt %d already in use\n",
hostdata->host_id, host->irq);
- kfree(hostdata->res);
- kfree(hostdata->req);
+ pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
scsi_unregister(host);
continue;
}
@@ -818,8 +809,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
"in use\n",
hostdata->host_id, host->io_port, host->io_port + 0xff);
free_irq(host->irq, host);
- kfree(hostdata->res);
- kfree(hostdata->req);
+ pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
scsi_unregister(host);
continue;
}
@@ -977,12 +967,13 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
u_short loop_id = 0x81;
u_short scsi_id = cur_scsi_id;
u_int port_id;
- struct sns_cb req;
- u_char sns_response[608];
+ struct sns_cb *req;
+ u_char *sns_response;
+ dma64_addr_t busaddr;
struct isp2x00_hostdata *hostdata;
hostdata = (struct isp2x00_hostdata *) host->hostdata;
-
+
DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id));
param[0] = MBOX_GET_PORT_NAME;
param[1] = (u16)FABRIC_PORT << 8;
@@ -995,52 +986,60 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
}
printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
+ req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr);
+
+ if (!req){
+ printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id);
+ return 0;
+ }
+ sns_response = (u_char *)(req + 1);
+
if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){
- memset(&req, 0, sizeof(req));
+ memset(req, 0, sizeof(*req));
- req.len = 8;
- req.response_low = virt_to_bus_low32(sns_response);
- req.response_high = virt_to_bus_high32(sns_response);
- req.sub_len = 22;
- req.data[0] = 0x17;
- req.data[1] = 0x02;
- req.data[8] = (u_char) (hostdata->port_id & 0xff);
- req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
- req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
- req.data[13] = 0x01;
+ req->len = cpu_to_le16(8);
+ req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req)));
+ req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req)));
+ req->sub_len = cpu_to_le16(22);
+ req->data[0] = 0x17;
+ req->data[1] = 0x02;
+ req->data[8] = (u_char) (hostdata->port_id & 0xff);
+ req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
+ req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
+ req->data[13] = 0x01;
param[0] = MBOX_SEND_SNS;
param[1] = 30;
- param[2] = virt_to_bus_low32(&req) >> 16;
- param[3] = virt_to_bus_low32(&req);
- param[6] = virt_to_bus_high32(&req) >> 16;
- param[7] = virt_to_bus_high32(&req);
-
+ param[2] = pci64_dma_lo32(busaddr) >> 16;
+ param[3] = pci64_dma_lo32(busaddr);
+ param[6] = pci64_dma_hi32(busaddr) >> 16;
+ param[7] = pci64_dma_hi32(busaddr);
+
isp2x00_mbox_command(host, param);
if (param[0] != MBOX_COMMAND_COMPLETE)
- printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);
+ printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);
}
port_id = hostdata->port_id;
while (!done) {
- memset(&req, 0, sizeof(req));
-
- req.len = 304;
- req.response_low = virt_to_bus_low32(sns_response);
- req.response_high = virt_to_bus_high32(sns_response);
- req.sub_len = 6;
- req.data[0] = 0x00;
- req.data[1] = 0x01;
- req.data[8] = (u_char) (port_id & 0xff);
- req.data[9] = (u_char) (port_id >> 8 & 0xff);
- req.data[10] = (u_char) (port_id >> 16 & 0xff);
+ memset(req, 0, sizeof(*req));
+
+ req->len = cpu_to_le16(304);
+ req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req)));
+ req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req)));
+ req->sub_len = cpu_to_le16(6);
+ req->data[0] = 0x00;
+ req->data[1] = 0x01;
+ req->data[8] = (u_char) (port_id & 0xff);
+ req->data[9] = (u_char) (port_id >> 8 & 0xff);
+ req->data[10] = (u_char) (port_id >> 16 & 0xff);
param[0] = MBOX_SEND_SNS;
param[1] = 14;
- param[2] = virt_to_bus_low32(&req) >> 16;
- param[3] = virt_to_bus_low32(&req);
- param[6] = virt_to_bus_high32(&req) >> 16;
- param[7] = virt_to_bus_high32(&req);
+ param[2] = pci64_dma_lo32(busaddr) >> 16;
+ param[3] = pci64_dma_lo32(busaddr);
+ param[6] = pci64_dma_hi32(busaddr) >> 16;
+ param[7] = pci64_dma_hi32(busaddr);
isp2x00_mbox_command(host, param);
@@ -1089,10 +1088,12 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
done = 1;
} else {
printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]);
+ pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
return 0;
}
}
+ pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
return 1;
}
@@ -1102,6 +1103,7 @@ int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int
int isp2x00_release(struct Scsi_Host *host)
{
struct isp2x00_hostdata *hostdata;
+ dma64_addr_t busaddr;
ENTER("isp2x00_release");
@@ -1112,8 +1114,9 @@ int isp2x00_release(struct Scsi_Host *host)
release_region(host->io_port, 0xff);
- kfree(hostdata->res);
- kfree(hostdata->req);
+ busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high),
+ le32_to_cpu(hostdata->control_block.res_queue_addr_lo));
+ pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
LEAVE("isp2x00_release");
@@ -1245,19 +1248,20 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
cmd->hdr.entry_type = ENTRY_COMMAND;
cmd->hdr.entry_cnt = 1;
cmd->target_lun = Cmnd->lun;
- cmd->expanded_lun = Cmnd->lun;
+ cmd->expanded_lun = cpu_to_le16(Cmnd->lun);
#if ISP2x00_PORTDB
cmd->target_id = hostdata->port_db[Cmnd->target].loop_id;
#else
cmd->target_id = Cmnd->target;
#endif
- cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen;
+ cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen);
cmd->time_out = 0;
memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
if (Cmnd->use_sg) {
- cmd->segment_cnt = sg_count = Cmnd->use_sg;
sg = (struct scatterlist *) Cmnd->request_buffer;
+ sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ cmd->segment_cnt = cpu_to_le16(sg_count);
ds = cmd->dataseg;
/* fill in first two sg entries: */
n = sg_count;
@@ -1265,11 +1269,11 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
n = DATASEGS_PER_COMMAND;
for (i = 0; i < n; i++) {
- ds[i].d_base = virt_to_bus_low32(sg->address);
-#if BITS_PER_LONG > 32
- ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+ ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg)));
+#if PCI64_DMA_BITS > 32
+ ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg)));
#endif
- ds[i].d_count = sg->length;
+ ds[i].d_count = cpu_to_le32(sg_dma64_len(sg));
++sg;
}
sg_count -= DATASEGS_PER_COMMAND;
@@ -1291,22 +1295,32 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
if (n > DATASEGS_PER_CONT)
n = DATASEGS_PER_CONT;
for (i = 0; i < n; ++i) {
- ds[i].d_base = virt_to_bus_low32(sg->address);
-#if BITS_PER_LONG > 32
- ds[i].d_base_hi = virt_to_bus_high32(sg->address);
+ ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg)));
+#if PCI64_DMA_BITS > 32
+ ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg)));
#endif
- ds[i].d_count = sg->length;
+ ds[i].d_count = cpu_to_le32(sg_dma64_len(sg));
++sg;
}
sg_count -= n;
}
+ } else if (Cmnd->request_bufflen) {
+ dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+ *(dma64_addr_t *)&Cmnd->SCp = busaddr;
+ cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr));
+#if PCI64_DMA_BITS > 32
+ cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr));
+#endif
+ cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen);
+ cmd->segment_cnt = cpu_to_le16(1);
} else {
- cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer);
-#if BITS_PER_LONG > 32
- cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+ cmd->dataseg[0].d_base = 0;
+#if PCI64_DMA_BITS > 32
+ cmd->dataseg[0].d_base_hi = 0;
#endif
- cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen;
- cmd->segment_cnt = 1;
+ cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
}
switch (Cmnd->cmnd[0]) {
@@ -1317,38 +1331,28 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
case WRITE_6:
case WRITE_BUFFER:
case MODE_SELECT:
- cmd->control_flags = CFLAG_WRITE;
- break;
- case REQUEST_SENSE:
- /* scsi.c expects sense info in a different buffer */
- cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer);
-#if BITS_PER_LONG > 32
- cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer);
-#endif
- cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer);
- cmd->segment_cnt = 1;
- cmd->control_flags = CFLAG_READ;
+ cmd->control_flags = cpu_to_le16(CFLAG_WRITE);
break;
default:
- cmd->control_flags = CFLAG_READ;
+ cmd->control_flags = cpu_to_le16(CFLAG_READ);
break;
}
if (Cmnd->device->tagged_supported) {
if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) {
- cmd->control_flags |= CFLAG_ORDERED_TAG;
+ cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
hostdata->tag_ages[Cmnd->target] = jiffies;
} else
switch (Cmnd->tag) {
case HEAD_OF_QUEUE_TAG:
- cmd->control_flags |= CFLAG_HEAD_TAG;
+ cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG);
break;
case ORDERED_QUEUE_TAG:
- cmd->control_flags |= CFLAG_ORDERED_TAG;
+ cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
break;
default:
- cmd->control_flags |= CFLAG_SIMPLE_TAG;
+ cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG);
break;
}
}
@@ -1543,6 +1547,16 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) {
Cmnd->result = isp2x00_return_status(Cmnd, sts);
hostdata->queued--;
+
+ if (Cmnd->use_sg)
+ pci64_unmap_sg(hostdata->pci_dev,
+ (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ else if (Cmnd->request_bufflen)
+ pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp,
+ Cmnd->request_bufflen,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
/*
* if any of the following are true we do not
* call scsi_done. if the status is CS_ABORTED
@@ -1550,7 +1564,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
* level should already know its aborted.
*/
if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number
- || sts->completion_status == CS_ABORTED){
+ || le16_to_cpu(sts->completion_status) == CS_ABORTED){
hostdata->handle_serials[sts->handle] = 0;
hostdata->handle_ptrs[sts->handle] = NULL;
outw(out_ptr, host->io_port + MBOX5);
@@ -1564,7 +1578,7 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
* the device may well be back in a couple of
* seconds.
*/
- if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){
+ if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->target].wwn){
outw(out_ptr, host->io_port + MBOX5);
continue;
}
@@ -1575,12 +1589,11 @@ void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
hostdata->handle_ptrs[sts->handle] = NULL;
- if (sts->completion_status == CS_RESET_OCCURRED
- || (sts->status_flags & STF_BUS_RESET))
+ if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED)
+ || (sts->status_flags & cpu_to_le16(STF_BUS_RESET)))
hostdata->send_marker = 1;
- memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer));
- if (sts->scsi_status & 0x0200)
+ if (le16_to_cpu(sts->scsi_status) & 0x0200)
memcpy(Cmnd->sense_buffer, sts->req_sense_data,
sizeof(Cmnd->sense_buffer));
@@ -1638,9 +1651,9 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts)
ENTER("isp2x00_return_status");
DEBUG(printk("qlogicfc : completion status = 0x%04x\n",
- sts->completion_status));
+ le16_to_cpu(sts->completion_status)));
- switch (sts->completion_status) {
+ switch (le16_to_cpu(sts->completion_status)) {
case CS_COMPLETE:
host_status = DID_OK;
break;
@@ -1660,7 +1673,7 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts)
host_status = DID_ERROR;
break;
case CS_DATA_UNDERRUN:
- if (Cmnd->underflow <= (Cmnd->request_bufflen - sts->residual))
+ if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual)))
host_status = DID_OK;
else
host_status = DID_ERROR;
@@ -1675,17 +1688,17 @@ static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts)
break;
default:
printk("qlogicfc : unknown completion status 0x%04x\n",
- sts->completion_status);
+ le16_to_cpu(sts->completion_status));
host_status = DID_ERROR;
break;
}
DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n",
- reason[host_status], sts->scsi_status));
+ reason[host_status], le16_to_cpu(sts->scsi_status)));
LEAVE("isp2x00_return_status");
- return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
+ return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);
}
@@ -1802,6 +1815,7 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host)
u_short param[8];
struct isp2x00_hostdata *hostdata;
int loop_count;
+ dma64_addr_t busaddr;
ENTER("isp2x00_reset_hardware");
@@ -1896,6 +1910,14 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host)
}
#endif
+#ifdef __BIG_ENDIAN
+ {
+ u64 val;
+ memcpy(&val, &hostdata->control_block.node_name, sizeof(u64));
+ hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8)
+ | ((val & 0x00ff00ff00ff00ffULL) << 8);
+ }
+#else
hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56;
hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48;
hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24;
@@ -1904,26 +1926,37 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host)
hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8;
hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8;
hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8;
+#endif
+
+ /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */
+ busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block),
+ PCI_DMA_BIDIRECTIONAL);
param[0] = MBOX_INIT_FIRMWARE;
- param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16);
- param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff);
+ param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16);
+ param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff);
param[4] = 0;
param[5] = 0;
- param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16);
- param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff);
+ param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16);
+ param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff);
isp2x00_mbox_command(host, param);
if (param[0] != MBOX_COMMAND_COMPLETE) {
printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]);
+ pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
+ PCI_DMA_BIDIRECTIONAL);
return 1;
}
param[0] = MBOX_GET_FIRMWARE_STATE;
isp2x00_mbox_command(host, param);
if (param[0] != MBOX_COMMAND_COMPLETE) {
printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]);
+ pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
+ PCI_DMA_BIDIRECTIONAL);
return 1;
}
+ pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block),
+ PCI_DMA_BIDIRECTIONAL);
LEAVE("isp2x00_reset_hardware");
return 0;
@@ -1939,11 +1972,11 @@ static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *co
return 1;
value = isp2x00_read_nvram_word(host, 8);
- control_block->node_name[0] = isp2x00_read_nvram_word(host, 9);
- control_block->node_name[1] = isp2x00_read_nvram_word(host, 10);
- control_block->node_name[2] = isp2x00_read_nvram_word(host, 11);
- control_block->node_name[3] = isp2x00_read_nvram_word(host, 12);
- control_block->hard_addr = isp2x00_read_nvram_word(host, 13);
+ control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9));
+ control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10));
+ control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11));
+ control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12));
+ control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13));
return 0;
@@ -2156,12 +2189,12 @@ void isp2x00_print_status_entry(struct Status_Entry *status)
printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n",
- status->scsi_status, status->completion_status);
+ le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status));
printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n",
- status->state_flags, status->status_flags);
+ le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags));
printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n",
- status->res_info_len, status->req_sense_len);
- printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]);
+ le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len));
+ printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]);
}
diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h
index 10539d3db..e00e8c645 100644
--- a/drivers/scsi/qlogicfc.h
+++ b/drivers/scsi/qlogicfc.h
@@ -62,7 +62,7 @@
* determined for each queue request anew.
*/
-#if BITS_PER_LONG > 32
+#if PCI64_DMA_BITS > 32
#define DATASEGS_PER_COMMAND 2
#define DATASEGS_PER_CONT 5
#else
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 32e71e06f..bbb24f4eb 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -149,7 +149,7 @@ static int test_unit_ready(int minor)
sr_cmd[0] = GPCMD_TEST_UNIT_READY;
sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5);
sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
- return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE);
+ return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE);
}
int sr_tray_move(struct cdrom_device_info *cdi, int pos)
@@ -161,7 +161,7 @@ int sr_tray_move(struct cdrom_device_info *cdi, int pos)
sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
- return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE);
+ return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE);
}
int sr_lock_door(struct cdrom_device_info *cdi, int lock)
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 45f504fa3..741c86d52 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -121,10 +121,6 @@ static Scsi_Cmnd *sun3_dma_setup_done = NULL;
/* minimum number of bytes to to dma on */
#define SUN3_DMA_MINSIZE 128
-static struct proc_dir_entry proc_scsi_sun3_5380 = {
- PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2
-};
-
static volatile unsigned char *sun3_scsi_regp;
static volatile struct sun3_dma_regs *dregs;
static unsigned char *dmabuf = NULL; /* dma memory buffer */
@@ -196,7 +192,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt)
if(called)
return 0;
- tpnt->proc_dir = &proc_scsi_sun3_5380;
+ tpnt->proc_name = "Sun3 5380 SCSI";
/* setup variables */
tpnt->can_queue =
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index f56d66756..36eb7b0c1 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -55,7 +55,7 @@
*/
/*
-** January 9 2000, sym53c8xx 1.5h
+** February 20 2000, sym53c8xx 1.5j
**
** Supported SCSI features:
** Synchronous data transfers
@@ -84,7 +84,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5h"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5j"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -174,6 +174,15 @@ typedef u64 u_int64;
#include "sym53c8xx.h"
+/*
+** Hmmm... What complex some PCI-HOST bridges actually are,
+** despite the fact that the PCI specifications are looking
+** so smart and simple! ;-)
+*/
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47)
+#define SCSI_NCR_DYNAMIC_DMA_MAPPING
+#endif
+
/*==========================================================
**
** A la VMS/CAM-3 queue management.
@@ -501,7 +510,7 @@ pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
typedef unsigned int pcidev_t;
#define PCIDEV_NULL (~0u)
#define PciBusNumber(d) ((d)>>8)
-#define PciDeviceFn(n) ((d)&0xff)
+#define PciDeviceFn(d) ((d)&0xff)
#define __PciDev(busn, devfn) (((busn)<<8)+(devfn))
#define pci_present pcibios_present
@@ -539,7 +548,7 @@ pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
static u_short __init PciVendorId(pcidev_t dev)
{
u_short vendor_id;
- pcibios_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
return vendor_id;
}
@@ -552,7 +561,7 @@ static u_short __init PciDeviceId(pcidev_t dev)
static u_int __init PciIrqLine(pcidev_t dev)
{
- u_short irq;
+ u_char irq;
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
return irq;
}
@@ -652,17 +661,6 @@ spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;
#endif
/*
-** Address translation
-**
-** The driver has to provide bus memory addresses to
-** the script processor. Because some architectures use
-** different physical addressing scheme from the PCI BUS,
-** we use virt_to_bus() instead of virt_to_phys().
-*/
-
-#define vtobus(p) virt_to_bus(p)
-
-/*
** Memory mapped IO
**
** Since linux-2.1, we must use ioremap() to map the io memory space.
@@ -736,44 +734,76 @@ static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
** this allocator allows simple and fast address calculations
** from the SCRIPTS code. In addition, cache line alignment
** is guaranteed for power of 2 cache line size.
+** Enhanced in linux-2.3.44 to provide a memory pool per pcidev
+** to support dynamic dma mapping. (I would have preferred a
+** real bus astraction, btw).
*/
-#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
-#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum (for now (ever?) */
-typedef unsigned long addr; /* Enough bits to bit-hack addresses */
-
-#define MEMO_FREE_UNUSED /* Free unused pages immediately */
-
-struct m_link {
- struct m_link *next; /* Simple links are enough */
-};
-
-#ifndef GFP_DMA_32BIT
-#define GFP_DMA_32BIT 0 /* Will this flag ever exist */
-#endif
-
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
-#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order)
#else
-#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0)
#endif
-/*
-** Lists of available memory chunks.
-** Starts with 16 bytes chunks until 1 PAGE chunks.
-*/
-static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
+#if PAGE_SIZE >= 8192
+#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */
+#else
+#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */
+#endif
+#define MEMO_FREE_UNUSED /* Free unused pages immediately */
+#define MEMO_WARN 1
+#define MEMO_GFP_FLAGS GFP_ATOMIC
+#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER)
+#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT)
+#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1)
+
+typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */
+typedef pcidev_t m_bush_t; /* Something that addresses DMAable */
+
+typedef struct m_link { /* Link between free memory chunks */
+ struct m_link *next;
+} m_link_s;
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+typedef struct m_vtob { /* Virtual to Bus address translation */
+ struct m_vtob *next;
+ m_addr_t vaddr;
+ m_addr_t baddr;
+} m_vtob_s;
+#define VTOB_HASH_SHIFT 5
+#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m) \
+ ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+#endif
+
+typedef struct m_pool { /* Memory pool of a given kind */
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ m_bush_t bush;
+ m_addr_t (*getp)(struct m_pool *);
+ void (*freep)(struct m_pool *, m_addr_t);
+#define M_GETP() mp->getp(mp)
+#define M_FREEP(p) mp->freep(mp, p)
+#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER)
+ int nump;
+ m_vtob_s *(vtob[VTOB_HASH_SIZE]);
+ struct m_pool *next;
+#else
+#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER)
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+ struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+} m_pool_s;
-/*
-** Allocate a memory area aligned on the lowest power of 2
-** greater than the requested size.
-*/
-static void *__m_alloc(int size)
+static void *___m_alloc(m_pool_s *mp, int size)
{
int i = 0;
int s = (1 << MEMO_SHIFT);
int j;
- addr a ;
+ m_addr_t a;
+ m_link_s *h = mp->h;
if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
return 0;
@@ -786,7 +816,7 @@ static void *__m_alloc(int size)
j = i;
while (!h[j].next) {
if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
- h[j].next = (struct m_link *) GetPages(MEMO_PAGE_ORDER);
+ h[j].next = (m_link_s *) M_GETP();
if (h[j].next)
h[j].next->next = 0;
break;
@@ -794,36 +824,32 @@ static void *__m_alloc(int size)
++j;
s <<= 1;
}
- a = (addr) h[j].next;
+ a = (m_addr_t) h[j].next;
if (a) {
h[j].next = h[j].next->next;
while (j > i) {
j -= 1;
s >>= 1;
- h[j].next = (struct m_link *) (a+s);
+ h[j].next = (m_link_s *) (a+s);
h[j].next->next = 0;
}
}
#ifdef DEBUG
- printk("m_alloc(%d) = %p\n", size, (void *) a);
+ printk("___m_alloc(%d) = %p\n", size, (void *) a);
#endif
return (void *) a;
}
-/*
-** Free a memory area allocated using m_alloc().
-** Coalesce buddies.
-** Free pages that become unused if MEMO_FREE_UNUSED is defined.
-*/
-static void __m_free(void *ptr, int size)
+static void ___m_free(m_pool_s *mp, void *ptr, int size)
{
int i = 0;
int s = (1 << MEMO_SHIFT);
- struct m_link *q;
- addr a, b;
+ m_link_s *q;
+ m_addr_t a, b;
+ m_link_s *h = mp->h;
#ifdef DEBUG
- printk("m_free(%p, %d)\n", ptr, size);
+ printk("___m_free(%p, %d)\n", ptr, size);
#endif
if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
@@ -834,23 +860,23 @@ static void __m_free(void *ptr, int size)
++i;
}
- a = (addr) ptr;
+ a = (m_addr_t) ptr;
while (1) {
#ifdef MEMO_FREE_UNUSED
if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
- free_pages(a, MEMO_PAGE_ORDER);
+ M_FREEP(a);
break;
}
#endif
b = a ^ s;
q = &h[i];
- while (q->next && q->next != (struct m_link *) b) {
+ while (q->next && q->next != (m_link_s *) b) {
q = q->next;
}
if (!q->next) {
- ((struct m_link *) a)->next = h[i].next;
- h[i].next = (struct m_link *) a;
+ ((m_link_s *) a)->next = h[i].next;
+ h[i].next = (m_link_s *) a;
break;
}
q->next = q->next->next;
@@ -860,45 +886,338 @@ static void __m_free(void *ptr, int size)
}
}
-#define MEMO_WARN 1
-
-/*
-** The memory pool is shared by all instances.
-** We use a global SMP LOCK to be SMP safe.
-*/
-
-static void *m_calloc(int size, char *name, int uflags)
+static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
{
- u_long flags;
void *p;
- NCR_LOCK_DRIVER(flags);
- p = __m_alloc(size);
- NCR_UNLOCK_DRIVER(flags);
+ p = ___m_alloc(mp, size);
if (DEBUG_FLAGS & DEBUG_ALLOC)
printk ("new %-10s[%4d] @%p.\n", name, size, p);
if (p)
- memset(p, 0, size);
+ bzero(p, size);
else if (uflags & MEMO_WARN)
printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
return p;
}
+#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN)
+
+static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
+{
+ if (DEBUG_FLAGS & DEBUG_ALLOC)
+ printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+
+ ___m_free(mp, ptr, size);
+
+}
+
+/*
+ * With pci bus iommu support, we use a default pool of unmapped memory
+ * for memory we donnot need to DMA from/to and one pool per pcidev for
+ * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+static m_pool_s mp0;
+
+#else
+
+static m_addr_t ___mp0_getp(m_pool_s *mp)
+{
+ m_addr_t m = GetPages();
+ if (m)
+ ++mp->nump;
+ return m;
+}
+
+static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
+{
+ FreePages(m);
+ --mp->nump;
+}
+
+static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep};
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+static void *m_calloc(int size, char *name)
+{
+ u_long flags;
+ void *m;
+ NCR_LOCK_DRIVER(flags);
+ m = __m_calloc(&mp0, size, name);
+ NCR_UNLOCK_DRIVER(flags);
+ return m;
+}
+
static void m_free(void *ptr, int size, char *name)
{
u_long flags;
+ NCR_LOCK_DRIVER(flags);
+ __m_free(&mp0, ptr, size, name);
+ NCR_UNLOCK_DRIVER(flags);
+}
- if (DEBUG_FLAGS & DEBUG_ALLOC)
- printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+/*
+ * DMAable pools.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Without pci bus iommu support, all the memory is assumed DMAable */
+
+#define __m_calloc_dma(b, s, n) m_calloc(s, n)
+#define __m_free_dma(b, p, s, n) m_free(p, s, n)
+#define __vtobus(b, p) virt_to_bus(p)
+
+#else
+
+/*
+ * With pci bus iommu support, we maintain one pool per pcidev and a
+ * hashed reverse table for virtual to bus physical address translations.
+ */
+static m_addr_t ___dma_getp(m_pool_s *mp)
+{
+ m_addr_t vp;
+ m_vtob_s *vbp;
+
+ vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
+ if (vbp) {
+ dma_addr_t daddr;
+ vp = (m_addr_t) pci_alloc_consistent(mp->bush,
+ PAGE_SIZE<<MEMO_PAGE_ORDER,
+ &daddr);
+ if (vp) {
+ int hc = VTOB_HASH_CODE(vp);
+ vbp->vaddr = vp;
+ vbp->baddr = daddr;
+ vbp->next = mp->vtob[hc];
+ mp->vtob[hc] = vbp;
+ ++mp->nump;
+ return vp;
+ }
+ }
+ __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+ return 0;
+}
+
+static void ___dma_freep(m_pool_s *mp, m_addr_t m)
+{
+ m_vtob_s **vbpp, *vbp;
+ int hc = VTOB_HASH_CODE(m);
+
+ vbpp = &mp->vtob[hc];
+ while (*vbpp && (*vbpp)->vaddr != m)
+ vbpp = &(*vbpp)->next;
+ if (*vbpp) {
+ vbp = *vbpp;
+ *vbpp = (*vbpp)->next;
+ pci_free_consistent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
+ (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
+ __m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+ --mp->nump;
+ }
+}
+
+static inline m_pool_s *___get_dma_pool(m_bush_t bush)
+{
+ m_pool_s *mp;
+ for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
+ return mp;
+}
+
+static m_pool_s *___cre_dma_pool(m_bush_t bush)
+{
+ m_pool_s *mp;
+ mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
+ if (mp) {
+ bzero(mp, sizeof(*mp));
+ mp->bush = bush;
+ mp->getp = ___dma_getp;
+ mp->freep = ___dma_freep;
+ mp->next = mp0.next;
+ mp0.next = mp;
+ }
+ return mp;
+}
+
+static void ___del_dma_pool(m_pool_s *p)
+{
+ struct m_pool **pp = &mp0.next;
+
+ while (*pp && *pp != p)
+ pp = &(*pp)->next;
+ if (*pp) {
+ *pp = (*pp)->next;
+ __m_free(&mp0, p, sizeof(*p), "MPOOL");
+ }
+}
+
+static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
+{
+ u_long flags;
+ struct m_pool *mp;
+ void *m = 0;
+
+ NCR_LOCK_DRIVER(flags);
+ mp = ___get_dma_pool(bush);
+ if (!mp)
+ mp = ___cre_dma_pool(bush);
+ if (mp)
+ m = __m_calloc(mp, size, name);
+ if (mp && !mp->nump)
+ ___del_dma_pool(mp);
+ NCR_UNLOCK_DRIVER(flags);
+
+ return m;
+}
+
+static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
+{
+ u_long flags;
+ struct m_pool *mp;
NCR_LOCK_DRIVER(flags);
- __m_free(ptr, size);
+ mp = ___get_dma_pool(bush);
+ if (mp)
+ __m_free(mp, m, size, name);
+ if (mp && !mp->nump)
+ ___del_dma_pool(mp);
NCR_UNLOCK_DRIVER(flags);
}
+static m_addr_t __vtobus(m_bush_t bush, void *m)
+{
+ u_long flags;
+ m_pool_s *mp;
+ int hc = VTOB_HASH_CODE(m);
+ m_vtob_s *vp = 0;
+ m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
+
+ NCR_LOCK_DRIVER(flags);
+ mp = ___get_dma_pool(bush);
+ if (mp) {
+ vp = mp->vtob[hc];
+ while (vp && (m_addr_t) vp->vaddr != a)
+ vp = vp->next;
+ }
+ NCR_UNLOCK_DRIVER(flags);
+ return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
+}
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n)
+#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n)
+#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n)
+#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n)
+#define _vtobus(np, p) __vtobus(np->pdev, p)
+#define vtobus(p) _vtobus(np, p)
+
+/*
+ * Deal with DMA mapping/unmapping.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Linux versions prior to pci bus iommu kernel interface */
+
+#define __unmap_scsi_data(pdev, cmd) do {; } while (0)
+#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer))
+#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg)
+#define __sync_scsi_data(pdev, cmd) do {; } while (0)
+
+#define scsi_sg_dma_address(sc) vtobus((sc)->address)
+#define scsi_sg_dma_len(sc) ((sc)->length)
+
+#else
+
+/* Linux version with pci bus iommu kernel interface */
+
+/* To keep track of the dma mapping (sg/single) that has been set */
+#define __data_mapped SCp.phase
+#define __data_mapping SCp.have_data_in
+
+static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ switch(cmd->__data_mapped) {
+ case 2:
+ pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ break;
+ case 1:
+ pci_unmap_single(pdev, cmd->__data_mapping,
+ cmd->request_bufflen, dma_dir);
+ break;
+ }
+ cmd->__data_mapped = 0;
+}
+
+static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ dma_addr_t mapping;
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ if (cmd->request_bufflen == 0)
+ return 0;
+
+ mapping = pci_map_single(pdev, cmd->request_buffer,
+ cmd->request_bufflen, dma_dir);
+ cmd->__data_mapped = 1;
+ cmd->__data_mapping = mapping;
+
+ return mapping;
+}
+
+static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int use_sg;
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ if (cmd->use_sg == 0)
+ return 0;
+
+ use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ cmd->__data_mapped = 2;
+ cmd->__data_mapping = use_sg;
+
+ return use_sg;
+}
+
+static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+ int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+ switch(cmd->__data_mapped) {
+ case 2:
+ pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+ break;
+ case 1:
+ pci_dma_sync_single(pdev, cmd->__data_mapping,
+ cmd->request_bufflen, dma_dir);
+ break;
+ }
+}
+
+#define scsi_sg_dma_address(sc) sg_dma_address(sc)
+#define scsi_sg_dma_len(sc) sg_dma_len(sc)
+
+#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd)
+#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd)
+#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd)
+#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd)
+
+
+/*
+ * Print out some buffer.
+ */
static void ncr_print_hex(u_char *p, int n)
{
while (n-- > 0)
@@ -915,21 +1234,49 @@ static void ncr_printl_hex(char *label, u_char *p, int n)
/*
** Transfer direction
**
-** Low-level scsi drivers under Linux do not receive the expected
-** data transfer direction from upper scsi drivers.
-** The driver will only check actual data direction for common
-** scsi opcodes. Other ones may cause problem, since they may
-** depend on device type or be vendor specific.
-** I would prefer to never trust the device for data direction,
-** but that is not possible.
-**
-** The original driver requires the expected direction to be known.
-** The Linux version of the driver has been enhanced in order to
-** be able to transfer data in the direction choosen by the target.
+** Until some linux kernel version near 2.3.40, low-level scsi
+** drivers were not told about data transfer direction.
+** We check the existence of this feature that has been expected
+** for a _long_ time by all SCSI driver developers by just
+** testing against the definition of SCSI_DATA_UNKNOWN. Indeed
+** this is a hack, but testing against a kernel version would
+** have been a shame. ;-)
*/
+#ifdef SCSI_DATA_UNKNOWN
+
+#define scsi_data_direction(cmd) (cmd->sc_data_direction)
+
+#else
+
+#define SCSI_DATA_UNKNOWN 0
+#define SCSI_DATA_WRITE 1
+#define SCSI_DATA_READ 2
+#define SCSI_DATA_NONE 3
-#define XFER_IN (1)
-#define XFER_OUT (2)
+static __inline__ scsi_data_direction(Scsi_Cmnd *cmd)
+{
+ int direction;
+
+ switch((int) cmd->cmnd[0]) {
+ case 0x08: /* READ(6) 08 */
+ case 0x28: /* READ(10) 28 */
+ case 0xA8: /* READ(12) A8 */
+ direction = SCSI_DATA_READ;
+ break;
+ case 0x0A: /* WRITE(6) 0A */
+ case 0x2A: /* WRITE(10) 2A */
+ case 0xAA: /* WRITE(12) AA */
+ direction = SCSI_DATA_WRITE;
+ break;
+ default:
+ direction = SCSI_DATA_UNKNOWN;
+ break;
+ }
+
+ return direction;
+}
+
+#endif /* SCSI_DATA_UNKNOWN */
/*
** Head of list of NCR boards
@@ -1039,6 +1386,7 @@ typedef struct {
** to save data on each detected board for ncr_attach().
*/
typedef struct {
+ pcidev_t pdev;
ncr_slot slot;
ncr_chip chip;
ncr_nvram *nvram;
@@ -1796,6 +2144,8 @@ struct ccb {
**----------------------------------------------------------------
*/
Scsi_Cmnd *cmd; /* SCSI command */
+ u_char cdb_buf[16]; /* Copy of CDB */
+ u_char sense_buf[64];
int data_len; /* Total data length */
int segments; /* Number of SG segments */
@@ -1964,6 +2314,7 @@ struct ncb {
** General controller parameters and configuration.
**----------------------------------------------------------------
*/
+ pcidev_t pdev;
u_short device_id; /* PCI device id */
u_char revision_id; /* PCI device revision id */
u_char bus; /* PCI BUS number */
@@ -1995,7 +2346,8 @@ struct ncb {
** SCRIPTS processor in order to start SCSI commands.
**----------------------------------------------------------------
*/
- u_int32 *squeue; /* Start queue */
+ u_long p_squeue; /* Start queue BUS address */
+ u_int32 *squeue; /* Start queue virtual address */
u_short squeueput; /* Next free slot of the queue */
u_short actccbs; /* Number of allocated CCBs */
u_short queuedepth; /* Start queue depth */
@@ -2045,6 +2397,7 @@ struct ncb {
u_char order; /* Tag order to use */
u_char verbose; /* Verbosity for this controller*/
u_int32 ncr_cache; /* Used for cache test at init. */
+ u_long p_ncb; /* BUS address of this NCB */
/*----------------------------------------------------------------
** CCB lists and queue.
@@ -2085,7 +2438,7 @@ struct ncb {
** We use a different scatter function for 896 rev 1.
**----------------------------------------------------------------
*/
- int (*scatter) (ccb_p, Scsi_Cmnd *);
+ int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *);
/*----------------------------------------------------------------
** Command abort handling.
@@ -2106,6 +2459,7 @@ struct ncb {
u_char release_stage; /* Synchronisation stage on release */
};
+#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl))
#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl))
#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl))
#define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl))
@@ -2336,8 +2690,8 @@ static void ncb_profile (ncb_p np, ccb_p cp);
static void ncr_script_copy_and_bind
(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
static void ncr_script_fill (struct script * scr, struct scripth * scripth);
-static int ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd);
-static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd);
+static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
+static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln);
@@ -4529,7 +4883,7 @@ ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
new = (old & ~RELOC_MASK) + np->p_scripth;
break;
case RELOC_SOFTC:
- new = (old & ~RELOC_MASK) + vtobus(np);
+ new = (old & ~RELOC_MASK) + np->p_ncb;
break;
#ifdef RELOC_KVAR
case RELOC_KVAR:
@@ -5191,10 +5545,12 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
/*
** Allocate the host control block.
*/
- np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN);
+ np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB");
if (!np)
goto attach_error;
NCR_INIT_LOCK_NCB(np);
+ np->pdev = device->pdev;
+ np->p_ncb = __vtobus(device->pdev, np);
host_data->ncb = np;
/*
@@ -5218,22 +5574,23 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
** Allocate the start queue.
*/
np->squeue = (ncrcmd *)
- m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN);
+ m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
if (!np->squeue)
goto attach_error;
+ np->p_squeue = vtobus(np->squeue);
/*
** Allocate the done queue.
*/
np->dqueue = (ncrcmd *)
- m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN);
+ m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE");
if (!np->dqueue)
goto attach_error;
/*
** Allocate the target bus address array.
*/
- np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN);
+ np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL");
if (!np->targtbl)
goto attach_error;
@@ -5241,11 +5598,11 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
** Allocate SCRIPTS areas
*/
np->script0 = (struct script *)
- m_calloc(sizeof(struct script), "SCRIPT", MEMO_WARN);
+ m_calloc_dma(sizeof(struct script), "SCRIPT");
if (!np->script0)
goto attach_error;
np->scripth0 = (struct scripth *)
- m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN);
+ m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
if (!np->scripth0)
goto attach_error;
@@ -5457,24 +5814,24 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
*/
np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
- np->p_idletask = vtobus(&np->idletask);
+ np->p_idletask = NCB_PHYS(np, idletask);
np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
- np->p_notask = vtobus(&np->notask);
+ np->p_notask = NCB_PHYS(np, notask);
np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
- np->p_bad_i_t_l = vtobus(&np->bad_i_t_l);
+ np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l);
np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q));
- np->p_bad_i_t_l_q = vtobus(&np->bad_i_t_l_q);
+ np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q);
/*
** Allocate and prepare the bad lun table.
*/
- np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN);
+ np->badluntbl = m_calloc_dma(256, "BADLUNTBL");
if (!np->badluntbl)
goto attach_error;
@@ -5482,16 +5839,16 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify));
for (i = 0 ; i < 64 ; i++)
- np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+ np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun));
/*
** Prepare the target bus address array.
*/
np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
for (i = 0 ; i < MAX_TARGET ; i++) {
- np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
+ np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i]));
np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
- np->target[i].b_lun0 = cpu_to_scr(vtobus(&np->resel_badlun));
+ np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun));
}
/*
@@ -5533,7 +5890,7 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
#ifndef SCSI_NCR_PROFILE_SUPPORT
#define XXX 0
#else
-#define XXX 3
+#define XXX 2
#endif
np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP);
np->script0->dataphase[XXX+1] =
@@ -5699,21 +6056,21 @@ static void ncr_free_resources(ncb_p np)
unmap_pci_mem(np->base2_va, np->base2_ws);
#endif
if (np->scripth0)
- m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+ m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
if (np->script0)
- m_free(np->script0, sizeof(struct script), "SCRIPT");
+ m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
if (np->squeue)
- m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
+ m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
if (np->dqueue)
- m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE");
+ m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE");
while ((cp = np->ccbc) != NULL) {
np->ccbc = cp->link_ccb;
- m_free(cp, sizeof(*cp), "CCB");
+ m_free_dma(cp, sizeof(*cp), "CCB");
}
if (np->badluntbl)
- m_free(np->badluntbl, 256,"BADLUNTBL");
+ m_free_dma(np->badluntbl, 256,"BADLUNTBL");
for (target = 0; target < MAX_TARGET ; target++) {
tp = &np->target[target];
@@ -5722,18 +6079,23 @@ static void ncr_free_resources(ncb_p np)
if (!lp)
continue;
if (lp->tasktbl != &lp->tasktbl_0)
- m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
+ m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
if (lp->cb_tags)
m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS");
- m_free(lp, sizeof(*lp), "LCB");
+ m_free_dma(lp, sizeof(*lp), "LCB");
}
#if MAX_LUN > 1
if (tp->lmp)
m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP");
+ if (tp->luntbl)
+ m_free_dma(tp->luntbl, 256, "LUNTBL");
#endif
}
- m_free(np, sizeof(*np), "NCB");
+ if (np->targtbl)
+ m_free_dma(np->targtbl, 256, "TARGTBL");
+
+ m_free_dma(np, sizeof(*np), "NCB");
}
@@ -5761,13 +6123,14 @@ static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
np->done_list = cmd;
}
-static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd)
+static inline void ncr_flush_done_cmds(pcidev_t pdev, Scsi_Cmnd *lcmd)
{
Scsi_Cmnd *cmd;
while (lcmd) {
cmd = lcmd;
lcmd = (Scsi_Cmnd *) cmd->host_scribble;
+ __unmap_scsi_data(pdev, cmd);
cmd->scsi_done(cmd);
}
}
@@ -6013,7 +6376,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
- cp->segments = segments = np->scatter (cp, cp->cmd);
+ cp->segments = segments = np->scatter (np, cp, cp->cmd);
if (segments < 0) {
ncr_free_ccb(np, cp);
@@ -6027,61 +6390,34 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
if (!cp->data_len)
- direction = 0;
- else {
- switch((int) cmd->cmnd[0]) {
- case 0x08: /* READ(6) 08 */
- case 0x28: /* READ(10) 28 */
- case 0xA8: /* READ(12) A8 */
- direction = XFER_IN;
- break;
- case 0x0A: /* WRITE(6) 0A */
- case 0x2A: /* WRITE(10) 2A */
- case 0xAA: /* WRITE(12) AA */
- direction = XFER_OUT;
- break;
- default:
- direction = (XFER_IN|XFER_OUT);
- break;
- }
- }
-
- /*----------------------------------------------------
- **
- ** Set the DATA POINTER.
- **
- **----------------------------------------------------
- */
-
- /*
- ** Default to no data transfer.
- */
- lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data);
+ direction = SCSI_DATA_NONE;
+ else
+ direction = scsi_data_direction(cmd);
/*
- ** Compute data out pointers, if needed.
+ ** If data direction is UNKNOWN, speculate DATA_READ
+ ** but prepare alternate pointers for WRITE in case
+ ** of our speculation will be just wrong.
+ ** SCRIPTS will swap values if needed.
*/
- if (direction & XFER_OUT) {
+ switch(direction) {
+ case SCSI_DATA_UNKNOWN:
+ case SCSI_DATA_WRITE:
goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-
- /*
- ** If actual data direction is unknown, save pointers
- ** in header. The SCRIPTS will swap them to current
- ** if target decision will be data out.
- */
- if (direction & XFER_IN) {
- cp->phys.header.wgoalp = cpu_to_scr(goalp);
- cp->phys.header.wlastp = cpu_to_scr(lastp);
- }
- }
-
- /*
- ** Compute data in pointers, if needed.
- */
- if (direction & XFER_IN) {
+ if (direction != SCSI_DATA_UNKNOWN)
+ break;
+ cp->phys.header.wgoalp = cpu_to_scr(goalp);
+ cp->phys.header.wlastp = cpu_to_scr(lastp);
+ /* fall through */
+ case SCSI_DATA_READ:
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
+ break;
+ default:
+ case SCSI_DATA_NONE:
+ lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data);
+ break;
}
/*
@@ -6091,7 +6427,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
cp->phys.header.lastp = cpu_to_scr(lastp);
cp->phys.header.goalp = cpu_to_scr(goalp);
- if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT))
+ if (direction == SCSI_DATA_UNKNOWN)
cp->phys.header.savep =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
else
@@ -6152,7 +6488,8 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
/*
** command
*/
- cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0]));
+ memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len);
+ cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0]));
cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
/*
@@ -6719,6 +7056,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
*/
if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+ sync_scsi_data(np, cmd); /* SYNC the data */
ncr_setup_lcb (np, cp->target, cp->lun,
(char *) cmd->request_buffer);
}
@@ -6941,7 +7279,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
/*
** Clear Start Queue
*/
- phys = vtobus(np->squeue);
+ phys = np->p_squeue;
np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */
for (i = 0; i < MAX_START*2; i += 2) {
np->squeue[i] = cpu_to_scr(np->p_idletask);
@@ -7131,7 +7469,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
np->istat_sem = 0;
- OUTL (nc_dsa, vtobus(np));
+ OUTL (nc_dsa, np->p_ncb);
OUTL (nc_dsp, phys);
}
@@ -8733,7 +9071,7 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
** them back in the LUN CCB wait queue.
*/
busyccbs = lp->queuedccbs;
- i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+ i = (INL (nc_scratcha) - np->p_squeue) / 4;
j = i;
while (i != np->squeueput) {
cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i]));
@@ -8888,11 +9226,9 @@ next:
/*
** sense data
*/
- bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer));
- cp->phys.sense.addr =
- cpu_to_scr(vtobus (&cmd->sense_buffer[0]));
- cp->phys.sense.size =
- cpu_to_scr(sizeof(cmd->sense_buffer));
+ bzero(cp->sense_buf, sizeof(cp->sense_buf));
+ cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
+ cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf));
/*
** requeue the command.
@@ -9073,7 +9409,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num)
np->abrt_sel.sel_id = target;
np->abrt_sel.sel_scntl3 = tp->wval;
np->abrt_sel.sel_sxfer = tp->sval;
- OUTL(nc_dsa, vtobus(np));
+ OUTL(nc_dsa, np->p_ncb);
OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
return;
}
@@ -9114,7 +9450,7 @@ static void ncr_sir_task_recovery(ncb_p np, int num)
** Compute index of next position in the start
** queue the SCRIPTS will schedule.
*/
- i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+ i = (INL (nc_scratcha) - np->p_squeue) / 4;
/*
** Remove the job from the start queue.
@@ -9315,11 +9651,17 @@ static void ncr_sir_task_recovery(ncb_p np, int num)
*/
case SIR_AUTO_SENSE_DONE:
cp = ncr_ccb_from_dsa(np, INL (nc_dsa));
+ if (!cp)
+ break;
+ memcpy(cp->cmd->sense_buffer, cp->sense_buf,
+ sizeof(cp->cmd->sense_buffer));
p = &cp->cmd->sense_buffer[0];
if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
break;
+#if 0
(void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+#endif
break;
}
@@ -10036,6 +10378,7 @@ void ncr_int_sir (ncb_p np)
case SIR_SCRIPT_STOPPED:
case SIR_TARGET_SELECTED:
case SIR_ABORT_SENT:
+ case SIR_AUTO_SENSE_DONE:
ncr_sir_task_recovery(np, num);
return;
/*
@@ -10397,7 +10740,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np)
/*
** Allocate memory for this CCB.
*/
- cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN);
+ cp = m_calloc_dma(sizeof(struct ccb), "CCB");
if (!cp)
return 0;
@@ -10427,7 +10770,7 @@ static ccb_p ncr_alloc_ccb(ncb_p np)
/*
** Initilialyze some other fields.
*/
- cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
+ cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2]));
/*
** Chain into wakeup list and free ccb queue.
@@ -10519,11 +10862,11 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
if (ln && !tp->luntbl) {
int i;
- tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
+ tp->luntbl = m_calloc_dma(256, "LUNTBL");
if (!tp->luntbl)
goto fail;
for (i = 0 ; i < 64 ; i++)
- tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+ tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun));
tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
}
@@ -10531,7 +10874,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
** Allocate the table of pointers for LUN(s) > 0, if needed.
*/
if (ln && !tp->lmp) {
- tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN);
+ tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP");
if (!tp->lmp)
goto fail;
}
@@ -10540,7 +10883,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
** Allocate the lcb.
** Make it available to the chip.
*/
- lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
+ lp = m_calloc_dma(sizeof(struct lcb), "LCB");
if (!lp)
goto fail;
if (ln) {
@@ -10652,7 +10995,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
** initialyze the task table if not yet.
*/
if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) {
- lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN);
+ lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL");
if (!lp->tasktbl) {
lp->tasktbl = &lp->tasktbl_0;
goto fail;
@@ -10661,7 +11004,7 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
for (i = 0 ; i < MAX_TASKS ; i++)
lp->tasktbl[i] = cpu_to_scr(np->p_notask);
- lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN);
+ lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS");
if (!lp->cb_tags)
goto fail;
for (i = 0 ; i < MAX_TAGS ; i++)
@@ -10741,7 +11084,7 @@ fail:
#define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff)
-static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
{
struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1];
int segment;
@@ -10749,7 +11092,8 @@ static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd)
cp->data_len = cmd->request_bufflen;
if (cmd->request_bufflen) {
- u_long baddr = vtobus(cmd->request_buffer);
+ u_long baddr = map_scsi_single_data(np, cmd);
+
SCATTER_ONE(data, baddr, cmd->request_bufflen);
if (CROSS_16MB(baddr, cmd->request_bufflen)) {
cp->host_flags |= HF_PM_TO_C;
@@ -10780,7 +11124,7 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n",
** nicely power-of-two sized and aligned. But, since this may change
** at any time, a work-around was required.
*/
-static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
{
int segn;
int use_sg = (int) cmd->use_sg;
@@ -10788,18 +11132,23 @@ static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd)
cp->data_len = 0;
if (!use_sg)
- segn = ncr_scatter_no_sglist(cp, cmd);
+ segn = ncr_scatter_no_sglist(np, cp, cmd);
else if (use_sg > MAX_SCATTER)
segn = -1;
else {
struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
- struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg];
+ struct scr_tblmove *data;
+
+ use_sg = map_scsi_sg_data(np, cmd);
+ data = &cp->phys.data[MAX_SCATTER - use_sg];
for (segn = 0; segn < use_sg; segn++) {
- u_long baddr = vtobus(scatter[segn].address);
+ u_long baddr = scsi_sg_dma_address(&scatter[segn]);
+ unsigned int len = scsi_sg_dma_len(&scatter[segn]);
+
SCATTER_ONE(&data[segn],
baddr,
- scatter[segn].length);
+ len);
if (CROSS_16MB(baddr, scatter[segn].length)) {
cp->host_flags |= HF_PM_TO_C;
#ifdef DEBUG_896R1
@@ -10807,14 +11156,14 @@ printk("He! we are crossing a 16 MB boundary (0x%lx, 0x%x)\n",
baddr, scatter[segn].length);
#endif
}
- cp->data_len += scatter[segn].length;
+ cp->data_len += len;
}
}
return segn;
}
-static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
{
int segment;
int use_sg = (int) cmd->use_sg;
@@ -10822,19 +11171,24 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
cp->data_len = 0;
if (!use_sg)
- segment = ncr_scatter_no_sglist(cp, cmd);
+ segment = ncr_scatter_no_sglist(np, cp, cmd);
else if (use_sg > MAX_SCATTER)
segment = -1;
else {
struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
- struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg];
+ struct scr_tblmove *data;
+
+ use_sg = map_scsi_sg_data(np, cmd);
+ data = &cp->phys.data[MAX_SCATTER - use_sg];
for (segment = 0; segment < use_sg; segment++) {
- u_long baddr = vtobus(scatter[segment].address);
+ u_long baddr = scsi_sg_dma_address(&scatter[segment]);
+ unsigned int len = scsi_sg_dma_len(&scatter[segment]);
+
SCATTER_ONE(&data[segment],
baddr,
- scatter[segment].length);
- cp->data_len += scatter[segment].length;
+ len);
+ cp->data_len += len;
}
}
@@ -10901,7 +11255,7 @@ static int __init ncr_snooptest (struct ncb* np)
/*
** Start script (exchange values)
*/
- OUTL (nc_dsa, vtobus(np));
+ OUTL (nc_dsa, np->p_ncb);
OUTL (nc_dsp, pc);
/*
** Wait 'til done (with timeout)
@@ -11580,7 +11934,7 @@ if (sym53c8xx)
** overflow the kernel stack.
** 1 x 4K PAGE is enough for more than 40 devices for i386.
*/
- devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN);
+ devtbl = m_calloc(PAGE_SIZE, "devtbl");
if (!devtbl)
return 0;
@@ -11745,6 +12099,15 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
PciBusNumber(pdev),
(int) (PciDeviceFn(pdev) & 0xf8) >> 3,
(int) (PciDeviceFn(pdev) & 7));
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+ printk(KERN_WARNING NAME53C8XX
+ "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+ return -1;
+ }
+#endif
+
/*
** Read info from the PCI config space.
** pci_read_config_xxx() functions are assumed to be used for
@@ -12032,6 +12395,7 @@ sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
/*
** Initialise ncr_device structure with items required by ncr_attach.
*/
+ device->pdev = pdev;
device->slot.bus = PciBusNumber(pdev);
device->slot.device_fn = PciDeviceFn(pdev);
device->slot.base = base;
@@ -12232,6 +12596,10 @@ printk("sym53c8xx_queue_command\n");
cmd->host_scribble = NULL;
cmd->SCp.ptr = NULL;
cmd->SCp.buffer = NULL;
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+ cmd->__data_mapped = 0;
+ cmd->__data_mapping = 0;
+#endif
NCR_LOCK_NCB(np, flags);
@@ -12267,6 +12635,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
unsigned long flags;
ncb_p np = (ncb_p) dev_id;
Scsi_Cmnd *done_list;
+ pcidev_t pdev;
#ifdef DEBUG_SYM53C8XX
printk("sym53c8xx : interrupt received\n");
@@ -12276,6 +12645,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
NCR_LOCK_NCB(np, flags);
ncr_exception(np);
+ pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
@@ -12284,7 +12654,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
if (done_list) {
NCR_LOCK_SCSI_DONE(np, flags);
- ncr_flush_done_cmds(done_list);
+ ncr_flush_done_cmds(pdev, done_list);
NCR_UNLOCK_SCSI_DONE(np, flags);
}
}
@@ -12297,17 +12667,19 @@ static void sym53c8xx_timeout(unsigned long npref)
{
ncb_p np = (ncb_p) npref;
unsigned long flags;
+ pcidev_t pdev;
Scsi_Cmnd *done_list;
NCR_LOCK_NCB(np, flags);
ncr_timeout((ncb_p) np);
+ pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
if (done_list) {
NCR_LOCK_SCSI_DONE(np, flags);
- ncr_flush_done_cmds(done_list);
+ ncr_flush_done_cmds(pdev, done_list);
NCR_UNLOCK_SCSI_DONE(np, flags);
}
}
@@ -12325,6 +12697,7 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd)
ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
int sts;
unsigned long flags;
+ pcidev_t pdev;
Scsi_Cmnd *done_list;
#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
@@ -12369,11 +12742,12 @@ int sym53c8xx_reset(Scsi_Cmnd *cmd)
#endif
out:
+ pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
- ncr_flush_done_cmds(done_list);
+ ncr_flush_done_cmds(pdev, done_list);
return sts;
}
@@ -12387,6 +12761,7 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd)
ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
int sts;
unsigned long flags;
+ pcidev_t pdev;
Scsi_Cmnd *done_list;
#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
@@ -12410,11 +12785,12 @@ int sym53c8xx_abort(Scsi_Cmnd *cmd)
sts = ncr_abort_command(np, cmd);
out:
+ pdev = np->pdev;
done_list = np->done_list;
np->done_list = 0;
NCR_UNLOCK_NCB(np, flags);
- ncr_flush_done_cmds(done_list);
+ ncr_flush_done_cmds(pdev, done_list);
return sts;
}
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index b9ae751bf..41b55ea4c 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -66,7 +66,7 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_SB) += sb.o uart401.o
obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o
obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o
-obj-$(CONFIG_SOUND_AD1816) += ad1816.o
+obj-$(CONFIG_SOUND_AD1816) += ad1816.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o
obj-$(CONFIG_SOUND_UART6850) += uart6850.o
@@ -104,7 +104,7 @@ pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o \
sb_ess.o
softoss2-objs := softoss.o softoss_rs.o
-vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o
+vidc_mod-objs := vidc.o vidc_fill.o
wavefront-objs := wavfront.o wf_midi.o yss225.o
nm256-objs := nm256_audio.o ac97.o
diff --git a/drivers/sound/README.CONFIG b/drivers/sound/README.CONFIG
deleted file mode 100644
index 5cd199230..000000000
--- a/drivers/sound/README.CONFIG
+++ /dev/null
@@ -1,75 +0,0 @@
-Sound Driver Configuration Notes
-Michael Chastain, <mailto:mec@shout.net>
-18 Apr 1998
-
-The Linux sound driver is derived from OSS/Free, a multi-platform
-Unix sound driver by Hannu Savolainen. You can find out
-more about OSS/Free and the commercial version, OSS/Linux, at
-<http://www.opensound.com/ossfree>.
-
-OSS/Free comes with the configuration program 'configure.c'. We have
-discarded that program in favor of a standard Linux configuration file
-Config.in.
-
-Config.in defines a set of symbols with the form CONFIG_SOUND_*.
-These are the -native symbols-. Here is a description:
-
- CONFIG_SOUND
-
- This is the master symbol. It controls whether the basic
- sound-driver code is resident, modular, or not present at all.
-
- If the basic driver is resident, each primary and secondary
- driver can be resident, modular, or not present.
-
- If the basic driver is modular, each primary and secondary driver
- can be modular or not present.
-
- And if the basic driver is not present, all other drivers are
- not present, too.
-
- Primary drivers
-
- These are symbols such as CONFIG_SOUND_SB, CONFIG_SOUND_SB_MODULE,
- CONFIG_SOUND_TRIX, or CONFIG_SOUND_TRIX_MODULE. Each driver
- that the user can directly select is a primary driver and has
- the usual pair of symbols: one resident and one modular.
-
- Each primary driver can be either resident or modular.
-
- Secondary drivers
-
- Primary drivers require the support of secondary drivers, such
- as ad1848.o and uart401.o.
-
- In Makefile, each primary driver has a list of required secondary
- drivers. The secondary driver requirements are merged and a
- single definition is emitted at the end.
-
- For each secondary driver: if any resident primary driver
- requires it, that secondary driver will be resident. If no
- resident primary driver requires it but some modular primary
- driver requires it, then that secondary driver will be modular.
- Otherwise that secondary driver will be not present.
-
- OSS/Free also contains tests for secondary drivers. The Makefile
- defines symbols for these drivers in EXTRA_CFLAGS.
-
- CONFIG_AUDIO, CONFIG_MIDI, CONFIG_SEQUENCER
-
- These three drivers are like secondary drivers, but not quite.
- They can not yet be separated into modules. They are always
- linked into the basic sound driver, whether they are needed
- or not. (This is in case a primary driver is added to the
- system later, as a module, and needs these facilities. If it
- were possible to modularise them, then they would get built as
- additional modules at that time).
-
-The OSS/Free code does not use the native symbols directly, primarily
-because it does not know about modules. I could edit the code, but that
-would make it harder to upgrade to new versions of OSS/Free. Instead,
-the OSS/Free code continues to use -legacy symbols-.
-
-legacy.h defines all the legacy symbols to 1. This is because, whenever
-OSS/Free tests a symbol, the Makefile has already arranged for that
-driver to be included.
diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c
index 56ee3df89..175cd38e0 100644
--- a/drivers/sound/ac97_codec.c
+++ b/drivers/sound/ac97_codec.c
@@ -28,8 +28,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
-
-#include "ac97_codec.h"
+#include <linux/ac97_codec.h>
static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c
index c94481524..e45609e5c 100644
--- a/drivers/sound/ad1816.c
+++ b/drivers/sound/ad1816.c
@@ -59,8 +59,6 @@ Changes:
#include "soundmodule.h"
#include "sound_config.h"
-#ifdef CONFIG_AD1816
-
#define DEBUGNOISE(x)
#define DEBUGINFO(x)
#define DEBUGLOG(x) x
@@ -1429,5 +1427,3 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
-#endif /* CONFIG_AD1816 */
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
index 498db82f0..b7d93fdb4 100644
--- a/drivers/sound/ad1848.c
+++ b/drivers/sound/ad1848.c
@@ -40,9 +40,6 @@
#define DEB(x)
#define DEB1(x)
#include "sound_config.h"
-
-#ifdef CONFIG_AD1848
-
#include "ad1848_mixer.h"
typedef struct
@@ -113,7 +110,7 @@ static volatile signed char irq2dev[17] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1
};
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) || defined(MODULE)
+#ifdef MODULE
static int timer_installed = -1;
@@ -167,7 +164,7 @@ static void ad1848_halt_input(int dev);
static void ad1848_halt_output(int dev);
static void ad1848_trigger(int dev, int bits);
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
static int ad1848_tmr_install(int dev);
static void ad1848_tmr_reprogram(int dev);
@@ -1131,7 +1128,7 @@ static int ad1848_prepare_for_output(int dev, int bsize, int bcount)
restore_flags(flags);
devc->xfer_count = 0;
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
if (dev == timer_installed && devc->timer_running)
if ((fs & 0x01) != (old_fs & 0x01))
{
@@ -1245,7 +1242,7 @@ static int ad1848_prepare_for_input(int dev, int bsize, int bcount)
restore_flags(flags);
devc->xfer_count = 0;
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
if (dev == timer_installed && devc->timer_running)
{
if ((fs & 0x01) != (old_fs & 0x01))
@@ -1931,7 +1928,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
}
if (capabilities[devc->model].flags & CAP_F_TIMER)
{
-#ifndef __SMP__
+#ifndef CONFIG_SMP
int x;
unsigned char tmp = ad_read(devc, 16);
#endif
@@ -1940,7 +1937,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
ad_write(devc, 21, 0x00); /* Timer MSB */
ad_write(devc, 20, 0x10); /* Timer LSB */
-#ifndef __SMP__
+#ifndef CONFIG_SMP
ad_write(devc, 16, tmp | 0x40); /* Enable timer */
for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
ad_write(devc, 16, tmp & ~0x40); /* Disable timer */
@@ -1961,7 +1958,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt
} else if (irq < 0)
irq2dev[-irq] = devc->dev_no = my_dev;
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
if ((capabilities[devc->model].flags & CAP_F_TIMER) &&
devc->irq_ok)
ad1848_tmr_install(my_dev);
@@ -2146,7 +2143,7 @@ interrupt_again: /* Jump back here if int status doesn't reset */
if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */
{
devc->timer_ticks++;
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
if (timer_installed == dev && devc->timer_running)
sound_timer_interrupt();
#endif
@@ -2583,7 +2580,7 @@ void unload_ms_sound(struct address_info *hw_config)
release_region(hw_config->io_base, 4);
}
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)
+#ifndef EXCLUDE_TIMERS
/*
* Timer stuff (for /dev/music).
@@ -2693,7 +2690,7 @@ static int ad1848_tmr_install(int dev)
return 1;
}
-#endif
+#endif /* EXCLUDE_TIMERS */
EXPORT_SYMBOL(ad1848_detect);
@@ -2757,5 +2754,4 @@ void cleanup_module(void)
unload_ms_sound(&hw_config);
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/adlib_card.c b/drivers/sound/adlib_card.c
index c48fb5eb8..087c57b68 100644
--- a/drivers/sound/adlib_card.c
+++ b/drivers/sound/adlib_card.c
@@ -65,4 +65,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c
index b15a9423c..ba7231aa9 100644
--- a/drivers/sound/audio.c
+++ b/drivers/sound/audio.c
@@ -29,8 +29,6 @@
#include <linux/kmod.h>
#include "sound_config.h"
-
-#ifdef CONFIG_AUDIO
#include "ulaw.h"
#include "coproc.h"
@@ -517,8 +515,6 @@ void audio_init_devices(void)
*/
}
-#endif
-
void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
{
/*
diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c
index 11feddccc..0778273f9 100644
--- a/drivers/sound/cs4232.c
+++ b/drivers/sound/cs4232.c
@@ -176,7 +176,6 @@ int probe_cs4232(struct address_info *hw_config)
* Initialize logical device 3 (MPU)
*/
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
if (mpu_base != 0 && mpu_irq != 0)
{
CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */
@@ -184,7 +183,6 @@ int probe_cs4232(struct address_info *hw_config)
CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */
}
-#endif
if(synth_base != 0)
{
@@ -238,7 +236,6 @@ void attach_cs4232(struct address_info *hw_config)
AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */
}
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
if (mpu_base != 0 && mpu_irq != 0)
{
static struct address_info hw_config2 = {
@@ -266,7 +263,6 @@ void attach_cs4232(struct address_info *hw_config)
}
hw_config->slots[1] = hw_config2.slots[1];
}
-#endif
}
void unload_cs4232(struct address_info *hw_config)
@@ -284,7 +280,6 @@ void unload_cs4232(struct address_info *hw_config)
0);
sound_unload_audiodev(hw_config->slots[0]);
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
{
static struct address_info hw_config2 =
@@ -305,7 +300,6 @@ void unload_cs4232(struct address_info *hw_config)
unload_uart401(&hw_config2);
}
-#endif
}
void unload_cs4232_mpu(struct address_info *hw_config)
@@ -397,4 +391,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 603886504..5e9657c8a 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -43,7 +43,6 @@ static void start_services(void)
return; /* No cards detected */
#endif
-#ifdef CONFIG_AUDIO
if (num_audiodevs) /* Audio devices present */
{
int dev;
@@ -52,7 +51,6 @@ static void start_services(void)
}
audio_init_devices();
}
-#endif
return;
}
@@ -410,7 +408,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
int driver_size, int flags, unsigned int format_mask,
void *devc, int dma1, int dma2)
{
-#ifdef CONFIG_AUDIO
struct audio_driver *d;
struct audio_operations *op;
int l, num;
@@ -470,9 +467,6 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
audio_init_devices();
return num;
-#else
- return -EINVAL;
-#endif
}
int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
@@ -544,7 +538,6 @@ int sound_alloc_audiodev(void)
int sound_alloc_mididev(void)
{
-#ifdef CONFIG_MIDI
int i = register_sound_midi(&oss_sound_fops, -1);
if(i==-1)
return i;
@@ -552,9 +545,6 @@ int sound_alloc_mididev(void)
if(i>=num_midis)
num_midis = i + 1;
return i;
-#else
- return (-1);
-#endif
}
int sound_alloc_synthdev(void)
@@ -611,13 +601,11 @@ void sound_unload_mixerdev(int dev)
void sound_unload_mididev(int dev)
{
-#ifdef CONFIG_MIDI
if (dev != -1)
{
midi_devs[dev] = NULL;
unregister_sound_midi((dev<<4)+2);
}
-#endif
}
void sound_unload_synthdev(int dev)
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
index 427c6f4db..5c0cf1d0f 100644
--- a/drivers/sound/dev_table.h
+++ b/drivers/sound/dev_table.h
@@ -357,7 +357,7 @@ struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0;
struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
-#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) && !defined(VMIDI)
+#ifndef EXCLUDE_TIMERS
extern struct sound_timer_operations default_sound_timer;
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
&default_sound_timer, NULL
@@ -386,11 +386,9 @@ struct driver_info sound_drivers[] =
#ifdef CONFIG_GUS16
{"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16},
#endif
-#ifdef CONFIG_GUS
{"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus},
{"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus},
#endif
-#endif
#ifdef CONFIG_SOUND_MSS
{"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound},
@@ -433,11 +431,11 @@ probe_ad1816, unload_ad1816},
{"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas},
#endif
-#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) && defined(CONFIG_MIDI)
+#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU))
{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401},
#endif
-#if defined(CONFIG_SOUND_UART401) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SOUND_UART401)
{"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)",
attach_uart401, probe_uart401, unload_uart401},
#endif
@@ -450,7 +448,7 @@ probe_ad1816, unload_ad1816},
{"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui},
#endif
-#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI)
+#if defined(CONFIG_SOUND_UART6850)
{"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850},
#endif
@@ -461,10 +459,8 @@ probe_ad1816, unload_ad1816},
{"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb},
{"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb},
-#ifdef CONFIG_MIDI
{"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu},
#endif
-#endif
#ifdef CONFIG_SOUND_SSCAPE
{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape},
@@ -488,7 +484,7 @@ probe_ad1816, unload_ad1816},
attach_softsyn_card, probe_softsyn, unload_softsyn},
#endif
-#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI)
+#ifdef CONFIG_SOUND_VMIDI
{"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi},
#endif
#ifdef CONFIG_SOUND_VIDC
@@ -503,8 +499,6 @@ probe_ad1816, unload_ad1816},
int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info);
-#ifndef FULL_SOUND
-
/*
* List of devices actually configured in the system.
*
@@ -632,7 +626,7 @@ struct card_info snd_installed_cards[] =
{SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_SOUND_MPU401) && defined(CONFIG_MIDI)
+#ifdef CONFIG_SOUND_MPU401
{SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#ifdef MPU2_BASE
{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
@@ -642,12 +636,12 @@ struct card_info snd_installed_cards[] =
#endif
#endif
-#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI)
+#ifdef CONFIG_SOUND_UART6850
{SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
#ifdef CONFIG_SOUND_SB
-#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE)
+#ifdef CONFIG_SB_MPU_BASE
{SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
#endif
@@ -666,7 +660,7 @@ struct card_info snd_installed_cards[] =
{SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI)
+#ifdef CONFIG_SOUND_VMIDI
{SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
@@ -683,13 +677,7 @@ struct card_info snd_installed_cards[] =
int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info);
static int max_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info);
-#else
-int num_sound_cards = 0;
-struct card_info snd_installed_cards[20] = {{0}};
-static int max_sound_cards = 20;
-#endif
-
-#if defined(MODULE) || (!defined(linux) && !defined(_AIX))
+#if defined(MODULE)
int trace_init = 0;
#else
int trace_init = 1;
diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c
index e70c10841..1296da1ea 100644
--- a/drivers/sound/dmabuf.c
+++ b/drivers/sound/dmabuf.c
@@ -29,8 +29,6 @@
#include "sound_config.h"
-#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
-
#define DMAP_FREE_ON_CLOSE 0
#define DMAP_KEEP_ON_CLOSE 1
extern int sound_dmap_flag;
@@ -1286,5 +1284,3 @@ void DMAbuf_deinit(int dev)
sound_free_dmap(adev->dmap_in);
}
}
-
-#endif
diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c
index feeb11956..95158296a 100644
--- a/drivers/sound/es1371.c
+++ b/drivers/sound/es1371.c
@@ -119,11 +119,11 @@
#include <linux/bitops.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
+#include <linux/ac97_codec.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
-#include "ac97_codec.h"
/* --------------------------------------------------------------------- */
@@ -376,6 +376,9 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 };
#define SND_DEV_DSP16 5
+#define ES1371_MODULE_NAME "es1371"
+#define PFX ES1371_MODULE_NAME ": "
+
/* --------------------------------------------------------------------- */
struct es1371_state {
@@ -496,7 +499,7 @@ static unsigned wait_src_ready(struct es1371_state *s)
return r;
udelay(1);
}
- printk(KERN_DEBUG "es1371: sample rate converter timeout r = 0x%08x\n", r);
+ printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r);
return r;
}
@@ -1113,7 +1116,7 @@ static void es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* --------------------------------------------------------------------- */
-static const char invalid_magic[] = KERN_CRIT "es1371: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n";
#define VALIDATE_STATE(s) \
({ \
@@ -1216,7 +1219,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock)
tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");)
+ DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac1.wait, &wait);
set_current_state(TASK_RUNNING);
@@ -1251,7 +1254,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock)
tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");)
+ DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");)
}
remove_wait_queue(&s->dma_dac2.wait, &wait);
set_current_state(TASK_RUNNING);
@@ -2502,7 +2505,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file)
}
tmo = (count * HZ) / 3100;
if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "es1371: midi timed out??\n");
+ printk(KERN_DEBUG PFX "midi timed out??\n");
}
remove_wait_queue(&s->midi.owait, &wait);
set_current_state(TASK_RUNNING);
@@ -2629,7 +2632,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
return -1;
}
if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
- printk(KERN_WARNING "es1371: out of memory\n");
+ printk(KERN_WARNING PFX "out of memory\n");
return -1;
}
memset(s, 0, sizeof(struct es1371_state));
@@ -2652,19 +2655,19 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
s->codec.id = 0;
s->codec.codec_read = rdcodec;
s->codec.codec_write = wrcodec;
- printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n",
+ printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n",
s->vendor, s->device, s->rev);
if (!request_region(s->io, ES1371_EXTENT, "es1371")) {
- printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
+ printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
goto err_region;
}
if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
- printk(KERN_ERR "es1371: irq %u in use\n", s->irq);
+ printk(KERN_ERR PFX "irq %u in use\n", s->irq);
goto err_irq;
}
pci_enable_device(pcidev);
- printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n"
- KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
+ printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n"
+ KERN_INFO PFX "features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
goto err_dev1;
@@ -2683,7 +2686,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
s->ctrl = 0;
if ((joystick[devindex] & ~0x18) == 0x200) {
if (check_region(joystick[devindex], JOY_EXTENT))
- printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[devindex]);
+ printk(KERN_ERR PFX "joystick address 0x%x already in use\n", joystick[devindex]);
else {
s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
}
@@ -2693,11 +2696,11 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* check to see if s/pdif mode is being requested */
if (spdif[devindex]) {
if (s->rev >= 4) {
- printk(KERN_INFO "es1371: enabling S/PDIF output\n");
+ printk(KERN_INFO PFX "enabling S/PDIF output\n");
cssr |= STAT_EN_SPDIF;
s->ctrl |= CTRL_SPDIFEN_B;
} else {
- printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev);
+ printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev);
}
}
/* initialize the chips */
@@ -2731,6 +2734,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
if (!ac97_probe_codec(&s->codec))
goto err_dev4;
/* set default values */
+
fs = get_fs();
set_fs(KERNEL_DS);
val = SOUND_MASK_LINE;
@@ -2759,7 +2763,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
err_dev2:
unregister_sound_dsp(s->dev_audio);
err_dev1:
- printk(KERN_ERR "es1371: cannot register misc device\n");
+ printk(KERN_ERR PFX "cannot register misc device\n");
free_irq(s->irq, s);
err_irq:
release_region(s->io, ES1371_EXTENT);
@@ -2822,7 +2826,7 @@ static int __init init_es1371(void)
static void __exit cleanup_es1371(void)
{
- printk(KERN_INFO "es1371: unloading\n");
+ printk(KERN_INFO PFX "unloading\n");
pci_unregister_driver(&es1371_driver);
}
diff --git a/drivers/sound/finetune.h b/drivers/sound/finetune.h
deleted file mode 100644
index f3253cab9..000000000
--- a/drivers/sound/finetune.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifdef SEQUENCER_C
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * 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.
- */
-
-
- unsigned short finetune_table[128] =
- {
-/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499,
-/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567,
-/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637,
-/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707,
-/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777,
-/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848,
-/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919,
-/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991,
-/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063,
-/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136,
-/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210,
-/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284,
-/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358,
-/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433,
-/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509,
-/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585
- };
-#else
- extern unsigned short finetune_table[128];
-#endif
diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c
index f1ab09179..6a42c4ce5 100644
--- a/drivers/sound/gus_card.c
+++ b/drivers/sound/gus_card.c
@@ -26,8 +26,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#ifdef CONFIG_GUS
-
#include "gus_hw.h"
void gusintr(int irq, void *dev_id, struct pt_regs *dummy);
@@ -55,9 +53,7 @@ void attach_gus_card(struct address_info *hw_config)
if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
-#ifdef CONFIG_MIDI
gus_midi_init(hw_config);
-#endif
if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0)
printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
@@ -156,28 +152,20 @@ void gusintr(int irq, void *dev_id, struct pt_regs *dummy)
}
if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
{
-#ifdef CONFIG_MIDI
gus_midi_interrupt(0);
-#endif
}
if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
{
-#ifdef CONFIG_SEQUENCER
if (gus_timer_enabled)
sound_timer_interrupt();
gus_write8(0x45, 0); /* Ack IRQ */
gus_timer_command(4, 0x80); /* Reset IRQ flags */
-#else
- gus_write8(0x45, 0); /* Stop timers */
-#endif
}
if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
gus_voice_irq();
}
}
-#endif
-
/*
* Some extra code for the 16 bit sampling option
*/
@@ -191,10 +179,8 @@ int probe_gus_db16(struct address_info *hw_config)
void attach_gus_db16(struct address_info *hw_config)
{
-#ifdef CONFIG_GUS
gus_pcm_volume = 100;
gus_wave_volume = 90;
-#endif
hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", hw_config->io_base,
hw_config->irq,
@@ -292,4 +278,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c
index 7f82d3997..175eeb6a1 100644
--- a/drivers/sound/gus_midi.c
+++ b/drivers/sound/gus_midi.c
@@ -12,14 +12,9 @@
*/
#include <linux/config.h>
-
#include "sound_config.h"
-
#include "gus_hw.h"
-#ifdef CONFIG_GUS
-#ifdef CONFIG_MIDI
-
static int midi_busy = 0, input_opened = 0;
static int my_dev;
static int output_used = 0;
@@ -265,6 +260,3 @@ void gus_midi_interrupt(int dummy)
}
restore_flags(flags);
}
-
-#endif
-#endif
diff --git a/drivers/sound/gus_vol.c b/drivers/sound/gus_vol.c
index 3e5752d8f..783ff7d03 100644
--- a/drivers/sound/gus_vol.c
+++ b/drivers/sound/gus_vol.c
@@ -12,7 +12,6 @@
#include <linux/config.h>
#include "sound_config.h"
-#ifdef CONFIG_GUS
#include "gus_linearvol.h"
#define GUS_VOLUME gus_wave_volume
@@ -152,5 +151,3 @@ unsigned short gus_linear_vol(int vol, int mainvol)
#endif
return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
}
-
-#endif
diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c
index 0dddaacaa..16eac5769 100644
--- a/drivers/sound/gus_wave.c
+++ b/drivers/sound/gus_wave.c
@@ -25,8 +25,6 @@
#include <linux/ultrasound.h>
#include "gus_hw.h"
-#ifdef CONFIG_GUS
-
#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
#define MAX_SAMPLE 150
@@ -3111,9 +3109,7 @@ void gus_wave_init(struct address_info *hw_config)
hw_config->slots[0] = sdev;
synth_devs[sdev] = &guswave_operations;
sequencer_init();
-#ifdef CONFIG_SEQUENCER
gus_tmr_install(gus_base + 8);
-#endif
}
reset_sample_memory();
@@ -3433,8 +3429,6 @@ void guswave_dma_irq(void)
}
}
-#ifdef CONFIG_SEQUENCER
-
/*
* Timer stuff
*/
@@ -3535,6 +3529,3 @@ static void gus_tmr_install(int io_base)
sound_timer_init(&gus_tmr, "GUS");
#endif
}
-#endif
-
-#endif
diff --git a/drivers/sound/ics2101.c b/drivers/sound/ics2101.c
index dffb83265..7cf9cc031 100644
--- a/drivers/sound/ics2101.c
+++ b/drivers/sound/ics2101.c
@@ -17,7 +17,6 @@
#include "sound_config.h"
-#ifdef CONFIG_GUS
#include <linux/ultrasound.h>
#include "gus_hw.h"
@@ -244,5 +243,3 @@ ics2101_mixer_init(void)
}
return n;
}
-
-#endif
diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h
deleted file mode 100644
index 6c3b87ce6..000000000
--- a/drivers/sound/legacy.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _SOUND_LEGACY_H_
-#define _SOUND_LEGACY_H_
-
-/*
- * Force on additional support
- */
-
-#define __SGNXPRO__
-#define DESKPROXL
-/* #define SM_GAMES */
-#define SM_WAVE
-
-/*
- * Define legacy options.
- */
-
-#define SELECTED_SOUND_OPTIONS 0x0
-
-#define HAVE_MAUI_BOOT
-#define PSS_HAVE_LD
-#define INCLUDE_TRIX_BOOT
-
-#define CONFIG_CS4232
-#define CONFIG_GUS
-#define CONFIG_MAD16
-#define CONFIG_MAUI
-#define CONFIG_MPU401
-#define CONFIG_MSS
-#define CONFIG_OPL3SA1
-#define CONFIG_OPL3SA2
-#define CONFIG_PAS
-#define CONFIG_PSS
-#define CONFIG_SB
-#define CONFIG_SOFTOSS
-#define CONFIG_SSCAPE
-#define CONFIG_AD1816
-#define CONFIG_TRIX
-#define CONFIG_VMIDI
-#define CONFIG_YM3812
-
-#define CONFIG_AUDIO
-#define CONFIG_MIDI
-#define CONFIG_SEQUENCER
-
-#define CONFIG_AD1848
-#define CONFIG_MPU_EMU
-#define CONFIG_SBDSP
-#define CONFIG_UART401
-
-#endif /* _SOUND_LEGACY_H */
diff --git a/drivers/sound/lowlevel/Config.in b/drivers/sound/lowlevel/Config.in
index 30f1713f9..091a8df33 100644
--- a/drivers/sound/lowlevel/Config.in
+++ b/drivers/sound/lowlevel/Config.in
@@ -2,6 +2,15 @@ dep_tristate ' ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS
dep_tristate ' AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS
+if [ "$CONFIG_AWE32_SYNTH" = "y" -o "$CONFIG_AWE32_SYNTH" = "m" ]; then
+ comment 'AWE32 PnP-ISA Cards are not always setup correctly'
+ bool 'Configure AWE32 synth Base Address and Default Memory Size' CONFIG_AWE32_SYNTH_DEFAULTS
+ if [ "$CONFIG_AWE32_SYNTH_DEFAULTS" = "y" ]; then
+ hex 'AWE32 synth Base Address 620' AWE_DEFAULT_BASE_ADDR 620
+ int 'AWE32 synth Default Memory Size 512 1024 or 4096' AWE_DEFAULT_MEM_SIZE 512
+ fi
+fi
+
if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND" = "m" ]; then
dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS
if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c
index 8dc338aec..dedf7c843 100644
--- a/drivers/sound/mad16.c
+++ b/drivers/sound/mad16.c
@@ -86,8 +86,6 @@ static int mad16_cdsel;
#endif
-#ifdef CONFIG_MAD16
-
#include "sb.h"
static int already_initialized = 0;
@@ -724,7 +722,7 @@ void attach_mad16(struct address_info *hw_config)
void attach_mad16_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
+#ifdef CONFIG_MAD16_OLDCARD
if (mad_read(MC1_PORT) & 0x20)
hw_config->io_base = 0x240;
@@ -746,7 +744,6 @@ void attach_mad16_mpu(struct address_info *hw_config)
int probe_mad16_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
static int mpu_attached = 0;
static int valid_ports[] = {
0x330, 0x320, 0x310, 0x300
@@ -766,7 +763,7 @@ int probe_mad16_mpu(struct address_info *hw_config)
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
-#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
+#ifdef CONFIG_MAD16_OLDCARD
unsigned char tmp;
tmp = mad_read(MC3_PORT);
@@ -899,9 +896,6 @@ int probe_mad16_mpu(struct address_info *hw_config)
mad_write(MC6_PORT, tmp); /* Write MPU401 config */
return probe_uart401(hw_config);
-#else
- return 0;
-#endif
}
void unload_mad16(struct address_info *hw_config)
@@ -917,7 +911,7 @@ void unload_mad16(struct address_info *hw_config)
void
unload_mad16_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
+#ifdef CONFIG_MAD16_OLDCARD
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
sb_dsp_unload(hw_config, 0);
@@ -925,9 +919,7 @@ unload_mad16_mpu(struct address_info *hw_config)
}
#endif
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unload_uart401(hw_config);
-#endif
}
#ifdef MODULE
@@ -1126,9 +1118,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
-
-
-
-/* That's all folks */
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c
index 75ea6c118..532e7573b 100644
--- a/drivers/sound/maui.c
+++ b/drivers/sound/maui.c
@@ -32,8 +32,6 @@
#include "soundmodule.h"
#include "sound_firmware.h"
-#ifdef CONFIG_MAUI
-
static int maui_base = 0x330;
static volatile int irq_ok = 0;
@@ -53,12 +51,7 @@ static int *maui_osp;
static int (*orig_load_patch) (int dev, int format, const char *addr,
int offs, int count, int pmgr_flag) = NULL;
-#ifdef HAVE_MAUI_BOOT
#include "maui_boot.h"
-#else
-static unsigned char *maui_os = NULL;
-static int maui_osLen = 0;
-#endif
static int maui_wait(int mask)
{
@@ -190,7 +183,7 @@ failure:
static int maui_init(int irq)
{
-#ifdef __SMP__
+#ifdef CONFIG_SMP
int i;
#endif
unsigned char bits;
@@ -221,7 +214,7 @@ static int maui_init(int irq)
outb((0x80), HOST_CTRL_PORT); /* Leave reset */
outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
for (i = 0; i < 1000000 && !irq_ok; i++);
if (!irq_ok)
@@ -500,5 +493,4 @@ void cleanup_module(void)
unload_maui(&cfg);
SOUND_LOCK_END;
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c
index 03d7d284f..6e524e21d 100644
--- a/drivers/sound/midi_synth.c
+++ b/drivers/sound/midi_synth.c
@@ -21,8 +21,6 @@
#include "sound_config.h"
-#ifdef CONFIG_MIDI
-
#define _MIDI_SYNTH_C_
#include "midi_synth.h"
@@ -32,9 +30,6 @@ static int sysex_state[MAX_MIDI_DEV] =
{0};
static unsigned char prev_out_status[MAX_MIDI_DEV];
-#ifndef CONFIG_SEQUENCER
-#define STORE(cmd)
-#else
#define STORE(cmd) \
{ \
int len; \
@@ -42,7 +37,6 @@ static unsigned char prev_out_status[MAX_MIDI_DEV];
cmd; \
seq_input_event(obuf, len); \
}
-#endif
#define _seqbuf obuf
#define _seqbufptr 0
@@ -709,6 +703,3 @@ midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
return 0;
}
-
-
-#endif
diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c
index 426821753..32549ed2a 100644
--- a/drivers/sound/midibuf.c
+++ b/drivers/sound/midibuf.c
@@ -21,7 +21,6 @@
#include "sound_config.h"
-#ifdef CONFIG_MIDI
/*
* Don't make MAX_QUEUE_SIZE larger than 4000
@@ -431,6 +430,3 @@ int MIDIbuf_avail(int dev)
return DATA_AVAIL (midi_in_buf[dev]);
return 0;
}
-
-
-#endif
diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c
index 17089b0ad..b57c2dbca 100644
--- a/drivers/sound/mpu401.c
+++ b/drivers/sound/mpu401.c
@@ -24,15 +24,11 @@
#include "sound_config.h"
#include "soundmodule.h"
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
#include "coproc.h"
-#ifdef CONFIG_SEQUENCER
static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
-#endif
-
struct mpu_config
{
int base; /*
@@ -159,9 +155,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status
0 /* Fx */
};
-#ifndef CONFIG_SEQUENCER
-#define STORE(cmd)
-#else
#define STORE(cmd) \
{ \
int len; \
@@ -169,7 +162,6 @@ static unsigned char len_tab[] = /* # of data bytes following a status
cmd; \
seq_input_event(obuf, len); \
}
-#endif
#define _seqbuf obuf
#define _seqbufptr 0
@@ -1225,8 +1217,6 @@ void unload_mpu401(struct address_info *hw_config)
* Timer stuff
****************************************************/
-#if defined(CONFIG_SEQUENCER)
-
static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0;
static volatile int curr_tempo, curr_timebase, hw_timebase;
static int max_timebase = 8; /* 8*24=192 ppqn */
@@ -1718,9 +1708,6 @@ static int mpu_timer_init(int midi_dev)
}
-#endif
-
-
EXPORT_SYMBOL(probe_mpu401);
EXPORT_SYMBOL(attach_mpu401);
EXPORT_SYMBOL(unload_mpu401);
@@ -1762,5 +1749,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c
index 7e005e754..acaf989ca 100644
--- a/drivers/sound/opl3.c
+++ b/drivers/sound/opl3.c
@@ -1204,7 +1204,7 @@ int init_module (void)
void cleanup_module(void)
{
- if (devc)
+ if (devc && io != -1)
{
if(devc->base)
release_region(devc->base,4);
@@ -1217,7 +1217,7 @@ void cleanup_module(void)
MODULE_PARM(io, "i");
-#endif
+#endif /* MODULE */
EXPORT_SYMBOL(opl3_init);
EXPORT_SYMBOL(opl3_detect);
diff --git a/drivers/sound/opl3sa.c b/drivers/sound/opl3sa.c
index 9e5fd5a6b..213a0a099 100644
--- a/drivers/sound/opl3sa.c
+++ b/drivers/sound/opl3sa.c
@@ -31,8 +31,6 @@ static int sb_initialized = 0;
#endif
-#ifdef CONFIG_OPL3SA1
-
static int kilroy_was_here = 0; /* Don't detect twice */
static int mpu_initialized = 0;
@@ -177,15 +175,12 @@ void attach_opl3sa_wss(struct address_info *hw_config)
void attach_opl3sa_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
hw_config->name = "OPL3-SA (MPU401)";
attach_uart401(hw_config);
-#endif
}
int probe_opl3sa_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unsigned char conf;
static signed char irq_bits[] = {
-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
@@ -240,9 +235,6 @@ int probe_opl3sa_mpu(struct address_info *hw_config)
mpu_initialized = 1;
return probe_uart401(hw_config);
-#else
- return 0;
-#endif
}
void unload_opl3sa_wss(struct address_info *hw_config)
@@ -265,17 +257,13 @@ void unload_opl3sa_wss(struct address_info *hw_config)
void unload_opl3sa_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unload_uart401(hw_config);
-#endif
}
#ifdef SB_OK
void unload_opl3sa_sb(struct address_info *hw_config)
{
-#ifdef CONFIG_SBDSP
sb_dsp_unload(hw_config);
-#endif
}
#endif
@@ -334,6 +322,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
-
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c
index 68c37778f..c3fff526f 100644
--- a/drivers/sound/opl3sa2.c
+++ b/drivers/sound/opl3sa2.c
@@ -67,8 +67,6 @@
#define CHIPSET_OPL3SAX 4
-#ifdef CONFIG_OPL3SA2
-
/* What's my version? */
static int chipset = CHIPSET_UNKNOWN;
@@ -443,27 +441,19 @@ static struct mixer_operations opl3sa2_mixer_operations =
int probe_opl3sa2_mpu(struct address_info *hw_config)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
return probe_mpu401(hw_config);
-#else
- return 0;
-#endif
}
void attach_opl3sa2_mpu(struct address_info *hw_config)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
attach_mpu401(hw_config);
-#endif
}
void unload_opl3sa2_mpu(struct address_info *hw_config)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
unload_mpu401(hw_config);
-#endif
}
@@ -706,7 +696,6 @@ int init_module(void)
attach_opl3sa2(&cfg);
attach_opl3sa2_mss(&mss_cfg);
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
if(mpu_io != -1)
{
/* MPU config: */
@@ -720,7 +709,6 @@ int init_module(void)
attach_opl3sa2_mpu(&mpu_cfg);
}
}
-#endif
SOUND_LOCK;
return 0;
}
@@ -728,16 +716,13 @@ int init_module(void)
void cleanup_module(void)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
if(mpu_cfg.slots[1] != -1)
{
unload_opl3sa2_mpu(&mpu_cfg);
}
-#endif
unload_opl3sa2_mss(&mss_cfg);
unload_opl3sa2(&cfg);
SOUND_LOCK_END;
}
#endif /* MODULE */
-#endif /* CONFIG_OPL3SA2 */
diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c
index 488e77a63..762871063 100644
--- a/drivers/sound/pas2_card.c
+++ b/drivers/sound/pas2_card.c
@@ -9,8 +9,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#ifdef CONFIG_PAS
-
static unsigned char dma_bits[] = {
4, 1, 2, 3, 0, 5, 6, 7
};
@@ -92,16 +90,12 @@ static void pasintr(int irq, void *dev_id, struct pt_regs *dummy)
if (status & 0x08)
{
-#ifdef CONFIG_AUDIO
pas_pcm_interrupt(status, 1);
-#endif
status &= ~0x08;
}
if (status & 0x10)
{
-#ifdef CONFIG_MIDI
pas_midi_interrupt();
-#endif
status &= ~0x10;
}
}
@@ -239,7 +233,7 @@ static int config_pas_hw(struct address_info *hw_config)
mix_write(0x80 | 5, 0x078B);
mix_write(5, 0x078B);
-#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
+#if !defined(DISABLE_SB_EMULATION)
{
struct address_info *sb_config;
@@ -351,18 +345,14 @@ void attach_pas_card(struct address_info *hw_config)
}
if (config_pas_hw(hw_config))
{
-#ifdef CONFIG_AUDIO
pas_pcm_init(hw_config);
-#endif
-#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB)
+#if !defined(MODULE) && !defined(DISABLE_SB_EMULATION)
sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */
#endif
-#ifdef CONFIG_MIDI
pas_midi_init();
-#endif
pas_init_mixer();
}
}
@@ -453,5 +443,4 @@ void cleanup_module(void)
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c
index d029d4c4d..0dda4df5c 100644
--- a/drivers/sound/pas2_midi.c
+++ b/drivers/sound/pas2_midi.c
@@ -12,12 +12,8 @@
*/
#include <linux/config.h>
-
#include "sound_config.h"
-#ifdef CONFIG_PAS
-#ifdef CONFIG_MIDI
-
static int midi_busy = 0, input_opened = 0;
static int my_dev;
@@ -264,6 +260,3 @@ void pas_midi_interrupt(void)
}
pas_write(stat, 0x1B88); /* Acknowledge interrupts */
}
-
-#endif
-#endif
diff --git a/drivers/sound/pas2_mixer.c b/drivers/sound/pas2_mixer.c
index 04a98fead..3b9b167c1 100644
--- a/drivers/sound/pas2_mixer.c
+++ b/drivers/sound/pas2_mixer.c
@@ -19,8 +19,6 @@
#include "sound_config.h"
-#ifdef CONFIG_PAS
-
#ifndef DEB
#define DEB(what) /* (what) */
#endif
@@ -332,5 +330,3 @@ pas_init_mixer(void)
}
return 1;
}
-
-#endif
diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c
index dc49d04b5..c0776ae4f 100644
--- a/drivers/sound/pas2_pcm.c
+++ b/drivers/sound/pas2_pcm.c
@@ -18,9 +18,6 @@
#include "sound_config.h"
-#ifdef CONFIG_PAS
-#ifdef CONFIG_AUDIO
-
#ifndef DEB
#define DEB(WHAT)
#endif
@@ -440,6 +437,3 @@ void pas_pcm_interrupt(unsigned char status, int cause)
}
}
}
-
-#endif
-#endif
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c
index 1fa943741..ffbb08b77 100644
--- a/drivers/sound/pss.c
+++ b/drivers/sound/pss.c
@@ -34,9 +34,6 @@
#include "sound_firmware.h"
#include "soundmodule.h"
-#ifdef CONFIG_PSS
-#ifdef CONFIG_AUDIO
-
/*
* PSS registers.
*/
@@ -82,14 +79,7 @@
#define NO_WSS_MIXER -1
#include "coproc.h"
-
-#ifdef PSS_HAVE_LD
#include "pss_boot.h"
-#else
-static int pss_synthLen = 0;
-static unsigned char *pss_synth =
-NULL;
-#endif
/* If compiled into kernel, it enable or disable pss mixer */
#ifdef CONFIG_PSS_MIXER
@@ -675,11 +665,7 @@ int probe_pss_mpu(struct address_info *hw_config)
break; /* No more input */
}
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
return probe_mpu401(hw_config);
-#else
- return 0;
-#endif
}
static int pss_coproc_open(void *dev_info, int sub_device)
@@ -926,11 +912,9 @@ static coproc_operations pss_coproc_operations =
void attach_pss_mpu(struct address_info *hw_config)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
attach_mpu401(hw_config); /* Slot 1 */
if (hw_config->slots[1] != -1) /* The MPU driver installed itself */
midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations;
-#endif
}
int probe_pss_mss(struct address_info *hw_config)
@@ -1015,9 +999,7 @@ void unload_pss(struct address_info *hw_config)
void unload_pss_mpu(struct address_info *hw_config)
{
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
unload_mpu401(hw_config);
-#endif
}
void unload_pss_mss(struct address_info *hw_config)
@@ -1114,6 +1096,4 @@ void cleanup_module(void)
unload_pss(&cfgpss);
SOUND_LOCK_END;
}
-#endif
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 2cb785565..13c1cce55 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -1,7 +1,5 @@
#include <linux/config.h>
-#include "legacy.h"
-#ifdef CONFIG_SBDSP
#define DSP_RESET (devc->base + 0x6)
#define DSP_READ (devc->base + 0xA)
#define DSP_WRITE (devc->base + 0xC)
@@ -168,4 +166,3 @@ void sb_audio_close(int dev);
extern int acer;
extern sb_devc *last_sb;
-#endif
diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c
index 84d35b444..672b8f408 100644
--- a/drivers/sound/sb_audio.c
+++ b/drivers/sound/sb_audio.c
@@ -24,8 +24,6 @@
#include <linux/config.h>
#include "sound_config.h"
-#ifdef CONFIG_SBDSP
-
#include "sb_mixer.h"
#include "sb.h"
@@ -1126,5 +1124,3 @@ void sb_audio_init(sb_devc * devc, char *name)
audio_devs[devc->dev]->mixer_dev = devc->my_mixerdev;
audio_devs[devc->dev]->min_fragment = 5;
}
-
-#endif
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 3a4a94247..49a55288f 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -37,8 +37,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#ifdef CONFIG_SBDSP
-
#include "sb_mixer.h"
#include "sb.h"
@@ -113,11 +111,11 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n",
}
#endif
- /* This is useless since is done by sb_dsp_detect - azummo*/
+ /* This is useless since is done by sb_dsp_detect - azummo */
if (check_region(hw_config->io_base, 16))
{
- printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base);
+ printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base);
return 0;
}
return sb_dsp_detect(hw_config, 0, 0);
@@ -138,11 +136,10 @@ static struct address_info config;
static struct address_info config_mpu;
struct pci_dev *sb_dev = NULL,
- *wss_dev = NULL,
- *jp_dev = NULL,
-/* *ide_dev = NULL, */
- *mpu_dev = NULL,
- *wt_dev = NULL;
+ *wss_dev = NULL,
+ *jp_dev = NULL,
+ *mpu_dev = NULL,
+ *wt_dev = NULL;
/*
* Note DMA2 of -1 has the right meaning in the SB16 driver as well
* as here. It will cause either an error if it is needed or a fallback
@@ -153,49 +150,49 @@ int mpu_io = 0;
int io = -1;
int irq = -1;
int dma = -1;
-int dma16 = -1; /* Set this for modules that need it */
-int type = 0; /* Can set this to a specific card type */
-int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */
-int trix = 0; /* Set trix=1 to load this as support for trix */
-int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */
-int support = 0; /* Set support to load this as a support module */
-int sm_games = 0; /* Mixer - see sb_mixer.c */
-int acer = 0; /* Do acer notebook init */
-
-#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
-int isapnp = 1;
-int isapnpjump = 0;
-int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */
+int dma16 = -1; /* Set this for modules that need it */
+int type = 0; /* Can set this to a specific card type */
+int mad16 = 0; /* Set mad16=1 to load this as support for mad16 */
+int trix = 0; /* Set trix=1 to load this as support for trix */
+int pas2 = 0; /* Set pas2=1 to load this as support for pas2 */
+int support = 0; /* Set support to load this as a support module */
+int sm_games = 0; /* Mixer - see sb_mixer.c */
+int acer = 0; /* Do acer notebook init */
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+int isapnp = 1;
+int isapnpjump = 0;
+int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */
#else
-int isapnp = 0;
+int isapnp = 0;
#endif
MODULE_DESCRIPTION("Soundblaster driver");
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-MODULE_PARM(dma16, "i");
-MODULE_PARM(mpu_io, "i");
-MODULE_PARM(type, "i");
-MODULE_PARM(mad16, "i");
-MODULE_PARM(support, "i");
-MODULE_PARM(trix, "i");
-MODULE_PARM(pas2, "i");
-MODULE_PARM(sm_games, "i");
-MODULE_PARM(esstype, "i");
-MODULE_PARM(acer, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
+MODULE_PARM(dma16, "i");
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(type, "i");
+MODULE_PARM(mad16, "i");
+MODULE_PARM(support, "i");
+MODULE_PARM(trix, "i");
+MODULE_PARM(pas2, "i");
+MODULE_PARM(sm_games, "i");
+MODULE_PARM(esstype, "i");
+MODULE_PARM(acer, "i");
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-MODULE_PARM(isapnp, "i");
-MODULE_PARM(isapnpjump, "i");
+MODULE_PARM(isapnp, "i");
+MODULE_PARM(isapnpjump, "i");
MODULE_PARM(nosbwave, "i");
MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled");
-MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
-MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
+MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke.");
+MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver.");
#endif
-MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
+MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)");
MODULE_PARM_DESC(irq, "IRQ (5,7,9,10)");
MODULE_PARM_DESC(dma, "8-bit DMA channel (0,1,3)");
MODULE_PARM_DESC(dma16, "16-bit DMA channel (5,6,7)");
@@ -211,7 +208,7 @@ MODULE_PARM_DESC(acer, "Set this to detect cards in some ACER notebooks");
void *smw_free = NULL;
-#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
/* That's useful. */
@@ -253,7 +250,7 @@ static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card
hw_config->irq = sb_dev->irq_resource[0].start;
hw_config->dma = sb_dev->dma_resource[0].start;
hw_config->dma2 = sb_dev->dma_resource[1].start;
- mpu_config->io_base = sb_dev->resource[1].start;
+ mpu_config->io_base = sb_dev->resource[1].start;
}
}
return(sb_dev);
@@ -270,8 +267,8 @@ static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, st
hw_config->io_base = sb_dev->resource[0].start;
hw_config->irq = sb_dev->irq_resource[0].start;
hw_config->dma = sb_dev->dma_resource[0].start;
- hw_config->dma2 = sb_dev->dma_resource[1].start;
- mpu_config->io_base = sb_dev->resource[2].start;
+ hw_config->dma2 = sb_dev->dma_resource[1].start;
+ mpu_config->io_base = sb_dev->resource[2].start;
}
}
return(sb_dev);
@@ -291,7 +288,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
*/
if((sb_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+ ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
#ifdef CMI8330_DMA0BAD
int dmahack = 0;
@@ -299,9 +296,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
sb_dev->prepare(sb_dev);
/* This device doesn't work with DMA 0, so we must allocate
- * it to prevent PnP routines to assign it to the card.
+ * it to prevent PnP routines to assign it to the card.
*
- * I know i could have inlined the following lines, but it's cleaner
+ * I know i could have inlined the following lines, but it's cleaner
* this way.
*/
@@ -327,12 +324,9 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
}
#ifdef CMI8330_DMA0BAD
- if(dmahack)
- free_dma(0);
+ if(dmahack) free_dma(0);
#endif
-
if(!sb_dev) return(NULL);
-
}
else
printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n");
@@ -340,9 +334,8 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
/* @H@0001:mpu
*/
-#ifdef CONFIG_MIDI
if((mpu_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+ ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
mpu_dev->prepare(mpu_dev);
@@ -359,17 +352,15 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
}
else
printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n");
-#endif
/* @P@:Gameport
*/
if((jp_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+ ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
jp_dev->prepare(jp_dev);
-
if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev)))
show_base("CMI8330", "gameport", &jp_dev->resource[0]);
@@ -382,7 +373,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
#if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE)
if((wss_dev = isapnp_find_dev(bus,
- ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
+ ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
wss_dev->prepare(wss_dev);
@@ -405,7 +396,7 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
/* Specific support for awe will be dropped when:
* a) The new awe_wawe driver with PnP support will be introduced in the kernel
- * b) The joystick driver will support PnP
+ * b) The joystick driver will support PnP - a little patch is available from me....hint, hint :-)
*/
static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config)
@@ -430,7 +421,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st
mpu_config->io_base = sb_dev->resource[1].start;
- show_base("AWE", "sb", &sb_dev->resource[0]);
+ show_base("AWE", "sb", &sb_dev->resource[0]);
show_base("AWE", "mpu", &sb_dev->resource[1]);
show_base("AWE", "opl3", &sb_dev->resource[2]);
}
@@ -445,7 +436,7 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st
* CTL7001:Game SB32
*/
- if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
+ if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) ||
(jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) )
{
jp_dev->prepare(jp_dev);
@@ -459,12 +450,13 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st
/* CTL0022:WaveTable SB64
* CTL0021:WaveTable SB32
+ * CTL0023:WaveTable Sb64
*/
if( nosbwave == 0 &&
- ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
- (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
- (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
+ ( ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) ||
+ ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) ||
+ ( wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) ))
{
wt_dev->prepare(wt_dev);
@@ -478,26 +470,6 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st
else
printk(KERN_ERR "sb: AWE panic: wavetable not found\n");
-
- /* CTL2011:IDE SB32/64
- */
-
-/* No reasons to enable this... or not? */
-/*
- if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) )
- {
- ide_dev->prepare(ide_dev);
-
- if((ide_dev = activate_dev("AWE", "IDE", ide_dev)))
- {
- show_base("AWE", "IDE 1", &ide_dev->resource[0]);
- show_base("AWE", "IDE 2", &ide_dev->resource[1]);
- }
- }
- else
- printk(KERN_ERR "sb: AWE panic: IDE not found\n");
-*/
-
printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo <azummo@ita.flashnet.it>\n");
return(sb_dev);
@@ -508,31 +480,31 @@ static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, st
static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; }
isapnp_sb_list[] __initdata = {
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
- {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
- {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
- {0}
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" },
+ {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" },
+ {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" },
+ {0}
};
static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot)
{
struct pci_dev *idev = NULL;
- /* You missed the init func? That's bad. */
+ /* You missed the init func? That's bad. */
if(isapnp_sb_list[slot].initfunc)
{
char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name;
@@ -587,9 +559,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address
struct pci_bus *bus = NULL;
while ((bus = isapnp_find_card(
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
- bus))) {
+ isapnp_sb_list[i].vendor,
+ isapnp_sb_list[i].function,
+ bus))) {
if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i))
return 0;
@@ -608,9 +580,9 @@ static int __init sb_probe_isapnp(struct address_info *hw_config, struct address
struct pci_dev *card = NULL;
while ((card = isapnp_find_dev(NULL,
- isapnp_sb_list[i].vendor,
- isapnp_sb_list[i].function,
- card))) {
+ isapnp_sb_list[i].vendor,
+ isapnp_sb_list[i].function,
+ card))) {
if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i))
return 0;
@@ -632,7 +604,7 @@ int init_module(void)
able to disable PNP support for this single driver!
*/
-#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) )
{
printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n");
@@ -647,10 +619,10 @@ int init_module(void)
return -EINVAL;
}
- config.io_base = io;
- config.irq = irq;
- config.dma = dma;
- config.dma2 = dma16;
+ config.io_base = io;
+ config.irq = irq;
+ config.dma = dma;
+ config.dma2 = dma16;
}
config.card_subtype = type;
@@ -686,7 +658,6 @@ void cleanup_module(void)
if(sb_dev) sb_dev->deactivate(sb_dev);
if(jp_dev) jp_dev->deactivate(jp_dev);
if(wt_dev) wt_dev->deactivate(wt_dev);
-/* if(ide_dev) wt_dev->deactivate(ide_dev); */
if(mpu_dev) mpu_dev->deactivate(mpu_dev);
if(wss_dev) wss_dev->deactivate(wss_dev);
}
@@ -716,5 +687,3 @@ EXPORT_SYMBOL(sb_be_quiet);
EXPORT_SYMBOL(attach_sbmpu);
EXPORT_SYMBOL(probe_sbmpu);
EXPORT_SYMBOL(unload_sbmpu);
-
-#endif
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 37dd03f4f..bda10bfad 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -23,12 +23,6 @@
#include "sound_config.h"
#include "sound_firmware.h"
-#ifdef CONFIG_SBDSP
-
-#ifndef CONFIG_AUDIO
-#error You will need to configure the sound driver with CONFIG_AUDIO option.
-#endif
-
#include "sb_mixer.h"
#include "sb.h"
@@ -114,11 +108,9 @@ static void sb_intr (sb_devc *devc)
{
src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */
-#if defined(CONFIG_MIDI)&& defined(CONFIG_UART401)
if (src & 4) /* MPU401 interrupt */
if(devc->midi_irq_cookie)
uart401intr(devc->irq, devc->midi_irq_cookie, NULL);
-#endif
if (!(src & 3))
return; /* Not a DSP interrupt */
@@ -139,9 +131,7 @@ static void sb_intr (sb_devc *devc)
break;
case IMODE_MIDI:
-#ifdef CONFIG_MIDI
sb_midi_interrupt(devc);
-#endif
break;
default:
@@ -284,7 +274,6 @@ static int sb16_set_dma_hw(sb_devc * devc)
return 1;
}
-#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config)
{
/*
@@ -307,7 +296,6 @@ static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config)
printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);
}
}
-#endif
static int sb16_set_irq_hw(sb_devc * devc, int level)
{
@@ -807,10 +795,8 @@ int sb_dsp_init(struct address_info *hw_config)
if (devc->major == 3 || devc->major == 4)
sb_mixer_init(devc);
-#ifdef CONFIG_MIDI
if (!(devc->caps & SB_NO_MIDI))
sb_dsp_midi_init(devc);
-#endif
if (hw_config->name == NULL)
hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)";
@@ -971,8 +957,6 @@ void sb_chgmixer
sb_setmixer(devc, reg, value);
}
-#ifdef CONFIG_MIDI
-
/*
* MPU401 MIDI initialization.
*/
@@ -1200,10 +1184,8 @@ void attach_sbmpu(struct address_info *hw_config)
#endif
return;
}
-#if defined(CONFIG_UART401)
attach_uart401(hw_config);
last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc;
-#endif
}
int probe_sbmpu(struct address_info *hw_config)
@@ -1244,7 +1226,6 @@ int probe_sbmpu(struct address_info *hw_config)
}
#endif
-#if defined(CONFIG_UART401)
if (check_region(hw_config->io_base, 4))
{
printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base);
@@ -1279,9 +1260,6 @@ int probe_sbmpu(struct address_info *hw_config)
return 0;
}
return probe_uart401(hw_config);
-#else
- return 0;
-#endif
}
void unload_sbmpu(struct address_info *hw_config)
@@ -1292,23 +1270,5 @@ void unload_sbmpu(struct address_info *hw_config)
return;
}
#endif
-#if defined(CONFIG_UART401)
unload_uart401(hw_config);
-#endif
-}
-#else /* !CONFIG_MIDI */
-
-void unload_sbmpu(struct address_info *hw_config)
-{
-}
-
-int probe_sbmpu(struct address_info *hw_config)
-{
- return 0;
}
-
-void attach_sbmpu(struct address_info *hw_config)
-{
-}
-#endif
-#endif
diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c
index 31a299a96..9c3cef2bb 100644
--- a/drivers/sound/sb_midi.c
+++ b/drivers/sound/sb_midi.c
@@ -14,9 +14,6 @@
#include <linux/config.h>
#include "sound_config.h"
-#ifdef CONFIG_SBDSP
-#ifdef CONFIG_MIDI
-
#include "sb.h"
#undef SB_TEST_IRQ
@@ -210,6 +207,3 @@ void sb_dsp_midi_init(sb_devc * devc)
midi_devs[dev]->converter->id = "SBMIDI";
sequencer_init();
}
-
-#endif
-#endif
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index 0bad5eb58..f786b69b5 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -19,7 +19,6 @@
#include <linux/config.h>
#include "sound_config.h"
-#ifdef CONFIG_SBDSP
#define __SB_MIXER_C__
#include "sb.h"
@@ -78,27 +77,6 @@ MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
};
-#ifdef __SGNXPRO__
-#if 0
-static mixer_tab sgnxpro_mix = { /* not used anywhere */
-MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
-MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
-MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
-MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
-MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
-MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0)
-};
-#endif
-#endif
-
static mixer_tab sb16_mix = {
MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
@@ -763,5 +741,3 @@ int sb_mixer_init(sb_devc * devc)
sb_mixer_reset(devc);
return 1;
}
-
-#endif
diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h
index d53df66ff..1e1a1b8d2 100644
--- a/drivers/sound/sb_mixer.h
+++ b/drivers/sound/sb_mixer.h
@@ -24,9 +24,6 @@
*
*/
#include <linux/config.h>
-#include "legacy.h"
-
-#ifdef CONFIG_SBDSP
/*
* Mixer registers
@@ -108,6 +105,3 @@
#define ALS007_LINE 6
#define ALS007_CD 2
#define ALS007_SYNTH 7
-
-#endif
-
diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c
index 8fee21c6b..0ef3b67ad 100644
--- a/drivers/sound/sequencer.c
+++ b/drivers/sound/sequencer.c
@@ -15,15 +15,12 @@
* Alan Cox : reformatted and fixed a pair of null pointer bugs
*/
#include <linux/config.h>
-
#include <linux/kmod.h>
-
#define SEQUENCER_C
#include "sound_config.h"
-
-#ifdef CONFIG_SEQUENCER
#include "softoss.h"
+
int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL;
#include "midi_ctrl.h"
@@ -719,9 +716,7 @@ static void seq_local_event(unsigned char *event_rec)
switch (cmd)
{
case LOCL_STARTAUDIO:
-#ifdef CONFIG_AUDIO
DMAbuf_start_devices(parm);
-#endif
break;
default:
@@ -1692,9 +1687,7 @@ void sequencer_init(void)
if (sequencer_ok)
return;
-#ifdef CONFIG_MIDI
MIDIbuf_init();
-#endif
queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
@@ -1724,5 +1717,3 @@ void sequencer_unload(void)
iqueue=NULL;
}
}
-
-#endif
diff --git a/drivers/sound/sequencer_syms.c b/drivers/sound/sequencer_syms.c
index 053cd1e01..014d77841 100644
--- a/drivers/sound/sequencer_syms.c
+++ b/drivers/sound/sequencer_syms.c
@@ -9,7 +9,6 @@
char sequencer_syms_symbol;
#include "sound_config.h"
-
#include "sound_calls.h"
EXPORT_SYMBOL(note_to_freq);
diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c
index 7bbd36657..1f23125a8 100644
--- a/drivers/sound/sgalaxy.c
+++ b/drivers/sound/sgalaxy.c
@@ -24,8 +24,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#if defined(CONFIG_SGALAXY) || defined (MODULE)
-
static void sleep( unsigned howlong )
{
current->state = TASK_INTERRUPTIBLE;
@@ -182,5 +180,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/softoss.c b/drivers/sound/softoss.c
index 2a9302bbc..ac8e4034f 100644
--- a/drivers/sound/softoss.c
+++ b/drivers/sound/softoss.c
@@ -30,8 +30,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-
-#ifdef CONFIG_SOFTOSS
#include "softoss.h"
#include <linux/ultrasound.h>
@@ -1529,5 +1527,4 @@ void cleanup_module(void)
sound_unload_timerdev(devc->timerdev);
SOUND_LOCK_END;
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/softoss_rs.c b/drivers/sound/softoss_rs.c
index 2fa95f748..75f1bbb90 100644
--- a/drivers/sound/softoss_rs.c
+++ b/drivers/sound/softoss_rs.c
@@ -17,8 +17,6 @@
#include "sound_config.h"
-
-#ifdef CONFIG_SOFTOSS
#include "softoss.h"
void softsynth_resample_loop(short *buf, int loops)
@@ -130,4 +128,3 @@ void softsynth_resample_loop(short *buf, int loops)
}
} /* Mix one sample */
}
-#endif
diff --git a/drivers/sound/sound_config.h b/drivers/sound/sound_config.h
index 18ff32e34..7621f33be 100644
--- a/drivers/sound/sound_config.h
+++ b/drivers/sound/sound_config.h
@@ -18,7 +18,6 @@
#include <linux/fs.h>
#include <linux/sound.h>
-#include "legacy.h"
#include "os.h"
#include "soundvers.h"
diff --git a/drivers/sound/sound_timer.c b/drivers/sound/sound_timer.c
index 60f031ac8..b32759008 100644
--- a/drivers/sound/sound_timer.c
+++ b/drivers/sound/sound_timer.c
@@ -17,8 +17,6 @@
#include "sound_config.h"
-#if defined(CONFIG_SEQUENCER)
-
static volatile int initialized = 0, opened = 0, tmr_running = 0;
static volatile time_t tmr_offs, tmr_ctr;
static volatile unsigned long ticks_offs;
@@ -318,5 +316,3 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name)
strcpy(sound_timer.info.name, name);
sound_timer_devs[n] = &sound_timer;
}
-
-#endif
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index a1d682969..81f9cdb19 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -45,8 +45,11 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
-
#include "soundmodule.h"
+
+/* From obsolete legacy.h */
+#define SELECTED_SOUND_OPTIONS 0x0
+
struct notifier_block *sound_locker=(struct notifier_block *)0;
static int lock_depth = 0;
@@ -219,9 +222,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
}
if (!sound_started)
len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n");
-#ifndef CONFIG_AUDIO
- len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n");
-#else
len += sprintf(buffer + len, "\nAudio devices:\n");
for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) {
if (audio_devs[i] == NULL)
@@ -234,11 +234,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
begin = pos;
}
}
-#endif
-#ifndef CONFIG_SEQUENCER
- len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n");
-#else
len += sprintf(buffer + len, "\nSynth devices:\n");
for (i = 0; (i < num_synths) && (pos <= offset + length); i++) {
if (synth_devs[i] == NULL)
@@ -250,11 +246,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
begin = pos;
}
}
-#endif
-#ifndef CONFIG_MIDI
- len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n");
-#else
len += sprintf(buffer + len, "\nMidi devices:\n");
for (i = 0; (i < num_midis) && (pos <= offset + length); i++) {
if (midi_devs[i] == NULL)
@@ -266,9 +258,7 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
begin = pos;
}
}
-#endif
-#ifdef CONFIG_SEQUENCER
len += sprintf(buffer + len, "\nTimers:\n");
for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) {
@@ -281,7 +271,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len
begin = pos;
}
}
-#endif
len += sprintf(buffer + len, "\nMixers:\n");
for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) {
@@ -388,25 +377,19 @@ static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *pp
ret = sndstat_file_read(file, buf, count, ppos);
break;
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
ret = audio_read(dev, file, buf, count);
break;
-#endif
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
ret = sequencer_read(dev, file, buf, count);
break;
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
ret = MIDIbuf_read(dev, file, buf, count);
-#endif
}
unlock_kernel();
return ret;
@@ -420,26 +403,20 @@ static ssize_t sound_write(struct file *file, const char *buf, size_t count, lof
lock_kernel();
DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
switch (dev & 0x0f) {
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
ret = sequencer_write(dev, file, buf, count);
break;
-#endif
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
ret = audio_write(dev, file, buf, count);
break;
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
ret = MIDIbuf_write(dev, file, buf, count);
break;
-#endif
}
unlock_kernel();
return ret;
@@ -483,29 +460,23 @@ static int sound_open(struct inode *inode, struct file *file)
return -ENXIO;
break;
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
if ((retval = sequencer_open(dev, file)) < 0)
return retval;
break;
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
if ((retval = MIDIbuf_open(dev, file)) < 0)
return retval;
break;
-#endif
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
if ((retval = audio_open(dev, file)) < 0)
return retval;
break;
-#endif
default:
printk(KERN_ERR "Invalid minor device %d\n", dev);
@@ -531,26 +502,20 @@ static int sound_release(struct inode *inode, struct file *file)
case SND_DEV_CTL:
break;
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
sequencer_release(dev, file);
break;
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
MIDIbuf_release(dev, file);
break;
-#endif
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
audio_release(dev, file);
break;
-#endif
default:
printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
@@ -641,13 +606,11 @@ static int sound_ioctl(struct inode *inode, struct file *file,
(dev & 0x0f) != SND_DEV_CTL) {
dtype = dev & 0x0f;
switch (dtype) {
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev,
cmd, (caddr_t)arg);
-#endif
default:
return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg);
@@ -661,25 +624,19 @@ static int sound_ioctl(struct inode *inode, struct file *file,
return set_mixer_levels((caddr_t)arg);
return sound_mixer_ioctl(dev >> 4, cmd, (caddr_t)arg);
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_ioctl(dev, file, cmd, (caddr_t)arg);
-#endif
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
return audio_ioctl(dev, file, cmd, (caddr_t)arg);
break;
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_ioctl(dev, file, cmd, (caddr_t)arg);
break;
-#endif
}
return -EINVAL;
@@ -692,23 +649,17 @@ static unsigned int sound_poll(struct file *file, poll_table * wait)
DEB(printk("sound_poll(dev=%d)\n", dev));
switch (dev & 0x0f) {
-#ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
return sequencer_poll(dev, file, wait);
-#endif
-#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
return MIDIbuf_poll(dev, file, wait);
-#endif
-#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
return DMAbuf_poll(file, dev >> 4, wait);
-#endif
}
return 0;
}
@@ -828,13 +779,11 @@ static const struct {
umode_t mode;
int *num;
} dev_list[] = { /* list of minor devices */
-#ifdef CONFIG_AUDIO
/* seems to be some confusion here -- this device is not in the device list */
{SND_DEV_DSP16, "dspW", S_IWUGO | S_IRUSR | S_IRGRP,
&num_audiodevs},
{SND_DEV_AUDIO, "audio", S_IWUGO | S_IRUSR | S_IRGRP,
&num_audiodevs},
-#endif /* CONFIG_AUDIO */
};
static char *
@@ -903,12 +852,10 @@ soundcard_init(void)
return; /* No cards detected */
#endif
-#ifdef CONFIG_AUDIO
if (num_audiodevs || modular) /* Audio devices present */
{
audio_init_devices();
}
-#endif
#ifdef CONFIG_PROC_FS
if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info))
printk(KERN_ERR "sound: registering /proc/sound failed\n");
@@ -1000,9 +947,7 @@ void cleanup_module(void)
if (chrdev_registered)
destroy_special_devices();
-#ifdef CONFIG_SEQUENCER
sound_stop_timer();
-#endif
#ifdef CONFIG_LOWLEVEL_SOUND
{
@@ -1093,8 +1038,6 @@ void sound_close_dma(int chn)
restore_flags(flags);
}
-#ifdef CONFIG_SEQUENCER
-
static void do_sequencer_timer(unsigned long dummy)
{
sequencer_timer(0);
@@ -1129,7 +1072,6 @@ void sound_stop_timer(void)
{
del_timer(&seq_timer);;
}
-#endif
void conf_printf(char *name, struct address_info *hw_config)
{
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 4dce39e81..1c06b7c31 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -41,9 +41,6 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
-
-#ifdef CONFIG_SSCAPE
-
#include "coproc.h"
/*
@@ -722,7 +719,6 @@ void attach_sscape(struct address_info *hw_config)
}
#endif
-#if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU)
if (probe_mpu401(hw_config))
hw_config->always_detect = 1;
hw_config->name = "SoundScape";
@@ -736,7 +732,6 @@ void attach_sscape(struct address_info *hw_config)
sscape_mididev = hw_config->slots[1];
midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations;
}
-#endif
sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */
devc->ok = 1;
devc->failed = 0;
@@ -1421,9 +1416,7 @@ void attach_ss_ms_sound(struct address_info *hw_config)
void unload_sscape(struct address_info *hw_config)
{
release_region(devc->base + 2, 6);
-#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI)
unload_mpu401(hw_config);
-#endif
}
void unload_ss_ms_sound(struct address_info *hw_config)
@@ -1516,5 +1509,4 @@ void cleanup_module(void)
unload_sscape(&mpu_config);
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/sys_timer.c b/drivers/sound/sys_timer.c
index e7ca0c84b..5a8a7787a 100644
--- a/drivers/sound/sys_timer.c
+++ b/drivers/sound/sys_timer.c
@@ -20,8 +20,6 @@
#include "sound_config.h"
-#ifdef CONFIG_SEQUENCER
-
static volatile int opened = 0, tmr_running = 0;
static volatile time_t tmr_offs, tmr_ctr;
static volatile unsigned long ticks_offs;
@@ -289,5 +287,3 @@ struct sound_timer_operations default_sound_timer =
def_tmr_ioctl,
def_tmr_arm
};
-
-#endif
diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c
index bbe991eb2..de01c6cbe 100644
--- a/drivers/sound/trident.c
+++ b/drivers/sound/trident.c
@@ -79,11 +79,11 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
+#include <linux/ac97_codec.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include "trident.h"
-#include "ac97_codec.h"
#undef DEBUG
@@ -1131,7 +1131,7 @@ static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Midi - TODO */
}
- /* manually clear interrupt status, bad hardware design, balme T^2 */
+ /* manually clear interrupt status, bad hardware design, blame T^2 */
outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
TRID_REG(card, T4D_MISCINT));
spin_unlock(&card->lock);
diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c
index b54d00992..107c6ca9e 100644
--- a/drivers/sound/trix.c
+++ b/drivers/sound/trix.c
@@ -23,15 +23,8 @@
#include "sb.h"
#include "sound_firmware.h"
-#ifdef CONFIG_TRIX
-
-#ifdef INCLUDE_TRIX_BOOT
#include <linux/init.h>
#include "trix_boot.h"
-#else
-static unsigned char *trix_boot = NULL;
-static int trix_boot_len = 0;
-#endif
static int kilroy_was_here = 0; /* Don't detect twice */
@@ -327,11 +320,7 @@ int probe_trix_sb(struct address_info *hw_config)
sb_initialized = 1;
hw_config->name = "AudioTrix SB";
-#ifdef CONFIG_SBDSP
return sb_dsp_detect(hw_config, 0, 0);
-#else
- return 0;
-#endif
}
void attach_trix_sb(struct address_info *hw_config)
@@ -339,7 +328,6 @@ void attach_trix_sb(struct address_info *hw_config)
extern int sb_be_quiet;
int old_quiet;
-#ifdef CONFIG_SBDSP
hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING;
/* Prevent false alarms */
@@ -349,20 +337,16 @@ void attach_trix_sb(struct address_info *hw_config)
sb_dsp_init(hw_config);
sb_be_quiet = old_quiet;
-#endif
}
void attach_trix_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
hw_config->name = "AudioTrix Pro";
attach_uart401(hw_config);
-#endif
}
int probe_trix_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unsigned char conf;
static char irq_bits[] = {
-1, -1, -1, 1, 2, 3, -1, 4, -1, 5
@@ -420,9 +404,6 @@ int probe_trix_mpu(struct address_info *hw_config)
trix_write(0x19, (trix_read(0x19) & 0x83) | conf);
mpu_initialized = 1;
return probe_uart401(hw_config);
-#else
- return 0;
-#endif
}
void unload_trix_wss(struct address_info *hw_config)
@@ -445,16 +426,12 @@ void unload_trix_wss(struct address_info *hw_config)
void unload_trix_mpu(struct address_info *hw_config)
{
-#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
unload_uart401(hw_config);
-#endif
}
void unload_trix_sb(struct address_info *hw_config)
{
-#ifdef CONFIG_SBDSP
sb_dsp_unload(hw_config, mpu);
-#endif
}
#ifdef MODULE
@@ -566,5 +543,4 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c
index 7ccc65a4f..a59fa7c99 100644
--- a/drivers/sound/uart401.c
+++ b/drivers/sound/uart401.c
@@ -25,9 +25,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#ifdef CONFIG_UART401
-#ifdef CONFIG_MIDI
-
typedef struct uart401_devc
{
int base;
@@ -482,12 +479,9 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
+#endif /* MODULE */
EXPORT_SYMBOL(attach_uart401);
EXPORT_SYMBOL(probe_uart401);
EXPORT_SYMBOL(unload_uart401);
EXPORT_SYMBOL(uart401intr);
-
-#endif
-#endif
diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c
index 13dcb5fc2..dfa6ed417 100644
--- a/drivers/sound/uart6850.c
+++ b/drivers/sound/uart6850.c
@@ -24,9 +24,6 @@
*/
#include "sound_config.h"
-
-#ifdef CONFIG_SOUND_UART6850
-#ifdef CONFIG_MIDI
#include "soundmodule.h"
static int uart6850_base = 0x330;
@@ -353,6 +350,4 @@ void cleanup_module(void)
unload_uart6850(&cfg);
SOUND_LOCK_END;
}
-#endif
-#endif
-#endif
+#endif /* MODULE */
diff --git a/drivers/sound/v_midi.c b/drivers/sound/v_midi.c
index c1d695c99..caeda1e41 100644
--- a/drivers/sound/v_midi.c
+++ b/drivers/sound/v_midi.c
@@ -24,8 +24,6 @@
#include "sound_config.h"
#include "soundmodule.h"
-#ifdef CONFIG_VMIDI
-
#include "v_midi.h"
static vmidi_devc *v_devc[2] = { NULL, NULL};
@@ -52,7 +50,7 @@ void cleanup_module(void)
SOUND_LOCK_END;
}
-#endif
+#endif /* MODULE */
/*
* The DSP channel can be used either for input or output. Variable
@@ -297,5 +295,3 @@ void unload_v_midi(struct address_info *hw_config)
sound_unload_mididev(midi2);
kfree(midi_mem);
}
-
-#endif
diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c
index 04fcd3413..4fed93e06 100644
--- a/drivers/sound/vidc.c
+++ b/drivers/sound/vidc.c
@@ -1,128 +1,534 @@
/*
- * drivers/sound/vidc.c
+ * drivers/sound/vidc.c
*
- * Detection routine for the VIDC.
+ * VIDC20 audio driver.
*
- * Copyright (C) 1997 by Russell King <rmk@arm.uk.linux.org>
+ * Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk>
+ *
+ * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA
+ * engine. The DMA transfers fixed-format (16-bit little-endian linear)
+ * samples to the VIDC20, which then transfers this data serially to the
+ * DACs. The samplerate is controlled by the VIDC.
+ *
+ * We currently support a mixer device, but it is currently non-functional.
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <asm/io.h>
+#include <asm/hardware.h>
#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+#include <asm/system.h>
+
#include "sound_config.h"
#include "soundmodule.h"
#include "vidc.h"
-int vidc_busy;
+#ifndef _SIOC_TYPE
+#define _SIOC_TYPE(x) _IOC_TYPE(x)
+#endif
+#ifndef _SIOC_NR
+#define _SIOC_NR(x) _IOC_NR(x)
+#endif
-void vidc_update_filler(int format, int channels)
+#define VIDC_SOUND_CLOCK (250000)
+
+/*
+ * When using SERIAL SOUND mode (external DAC), the number of physical
+ * channels is fixed at 2.
+ */
+static int vidc_busy;
+static int vidc_adev;
+static int vidc_audio_rate;
+static char vidc_audio_format;
+static char vidc_audio_channels;
+
+static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = {
+ 85, /* master */
+ 50, /* bass */
+ 50, /* treble */
+ 0, /* synth */
+ 75, /* pcm */
+ 0, /* speaker */
+ 100, /* ext line */
+ 0, /* mic */
+ 100, /* CD */
+ 0,
+};
+
+static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = {
+ 85, /* master */
+ 50, /* bass */
+ 50, /* treble */
+ 0, /* synth */
+ 75, /* pcm */
+ 0, /* speaker */
+ 100, /* ext line */
+ 0, /* mic */
+ 100, /* CD */
+ 0,
+};
+
+static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */
+static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */
+
+static void (*old_mksound)(unsigned int hz, unsigned int ticks);
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+extern void vidc_update_filler(int bits, int channels);
+extern int softoss_dev;
+
+static void
+vidc_mksound(unsigned int hz, unsigned int ticks)
{
- int fillertype;
+ printk("BEEP - %d %d!\n", hz, ticks);
+}
-#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+static void
+vidc_mixer_set(int mdev, unsigned int level)
+{
+ unsigned int lev_l = level & 0x007f;
+ unsigned int lev_r = (level & 0x7f00) >> 8;
+ unsigned int mlev_l, mlev_r;
+
+ if (lev_l > 100)
+ lev_l = 100;
+ if (lev_r > 100)
+ lev_r = 100;
+
+#define SCALE(lev,master) ((lev) * (master) * 65536 / 10000)
+
+ mlev_l = vidc_level_l[SOUND_MIXER_VOLUME];
+ mlev_r = vidc_level_r[SOUND_MIXER_VOLUME];
+
+ switch (mdev) {
+ case SOUND_MIXER_VOLUME:
+ case SOUND_MIXER_PCM:
+ vidc_level_l[mdev] = lev_l;
+ vidc_level_r[mdev] = lev_r;
+
+ vidc_audio_volume_l = SCALE(lev_l, mlev_l);
+ vidc_audio_volume_r = SCALE(lev_r, mlev_r);
+/*printk("VIDC: PCM vol %05X %05X\n", vidc_audio_volume_l, vidc_audio_volume_r);*/
+ break;
+ }
+#undef SCALE
+}
+
+static int vidc_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+ unsigned int val;
+ unsigned int mdev;
+
+ if (_SIOC_TYPE(cmd) != 'M')
+ return -EINVAL;
+
+ mdev = _SIOC_NR(cmd);
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+ if (get_user(val, (unsigned int *)arg))
+ return -EFAULT;
+
+ if (mdev < SOUND_MIXER_NRDEVICES)
+ vidc_mixer_set(mdev, val);
+ else
+ return -EINVAL;
+ }
+
+ /*
+ * Return parameters
+ */
+ switch (mdev) {
+ case SOUND_MIXER_RECSRC:
+ val = 0;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
+ break;
- fillertype = TYPE(format, channels);
+ case SOUND_MIXER_STEREODEVS:
+ val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
+ break;
- switch (fillertype)
- {
- default:
- case TYPE(AFMT_U8, 1):
- vidc_filler = vidc_fill_1x8_u;
- break;
+ case SOUND_MIXER_RECMASK:
+ val = 0;
+ break;
- case TYPE(AFMT_U8, 2):
- vidc_filler = vidc_fill_2x8_u;
- break;
+ case SOUND_MIXER_CAPS:
+ val = 0;
+ break;
- case TYPE(AFMT_S8, 1):
- vidc_filler = vidc_fill_1x8_s;
- break;
+ default:
+ if (mdev < SOUND_MIXER_NRDEVICES)
+ val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8;
+ else
+ return -EINVAL;
+ }
+
+ return put_user(val, (unsigned int *)arg) ? -EFAULT : 0;
+}
+
+static unsigned int vidc_audio_set_format(int dev, unsigned int fmt)
+{
+ switch (fmt) {
+ default:
+ fmt = AFMT_S16_LE;
+ case AFMT_U8:
+ case AFMT_S8:
+ case AFMT_S16_LE:
+ vidc_audio_format = fmt;
+ vidc_update_filler(vidc_audio_format, vidc_audio_channels);
+ case AFMT_QUERY:
+ break;
+ }
+ return vidc_audio_format;
+}
+
+static int vidc_audio_set_speed(int dev, int rate)
+{
+ if (rate) {
+ unsigned int hwctrl, hwrate;
+ unsigned int newsize, new2size;
- case TYPE(AFMT_S8, 2):
- vidc_filler = vidc_fill_2x8_s;
- break;
+ /*
+ * If we have selected 44.1kHz, use the DAC clock.
+ */
+ if (0 && rate == 44100) {
+ hwctrl = 0x00000002;
+ hwrate = 3;
+ } else {
+ hwctrl = 0x00000003;
- case TYPE(AFMT_S16_LE, 1):
- vidc_filler = vidc_fill_1x16_s;
- break;
+ hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1;
+ if (hwrate < 3)
+ hwrate = 3;
+ if (hwrate > 255)
+ hwrate = 255;
- case TYPE(AFMT_S16_LE, 2):
- vidc_filler = vidc_fill_2x16_s;
- break;
+ rate = VIDC_SOUND_CLOCK / hwrate;
+ }
+
+ outl(0xb0000000 | (hwrate - 2), IO_VIDC_BASE);
+ outl(0xb1000000 | hwctrl, IO_VIDC_BASE);
+
+ newsize = (10000 / hwrate) & ~3;
+ if (newsize < 208)
+ newsize = 208;
+ if (newsize > 4096)
+ newsize = 4096;
+ for (new2size = 128; new2size < newsize; new2size <<= 1);
+ if (new2size - newsize > newsize - (new2size >> 1))
+ new2size >>= 1;
+ if (new2size > 4096) {
+ printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n",
+ newsize, new2size);
+ new2size = 4096;
+ }
+ dma_bufsize = new2size;
+ vidc_audio_rate = rate;
+ }
+ return vidc_audio_rate;
+}
+
+static short vidc_audio_set_channels(int dev, short channels)
+{
+ switch (channels) {
+ default:
+ channels = 2;
+ case 1:
+ case 2:
+ vidc_audio_channels = channels;
+ vidc_update_filler(vidc_audio_format, vidc_audio_channels);
+ case 0:
+ break;
+ }
+ return vidc_audio_channels;
+}
+
+/*
+ * Open the device
+ */
+static int vidc_audio_open(int dev, int mode)
+{
+ /* This audio device does not have recording capability */
+ if (mode == OPEN_READ)
+ return -EPERM;
+
+ if (vidc_busy)
+ return -EBUSY;
+
+ vidc_busy = 1;
+ return 0;
+}
+
+/*
+ * Close the device
+ */
+static void vidc_audio_close(int dev)
+{
+ vidc_busy = 0;
+}
+
+/*
+ * Output a block via DMA to sound device.
+ *
+ * We just set the DMA start and count; the DMA interrupt routine
+ * will take care of formatting the samples (via the appropriate
+ * vidc_filler routine), and flag via vidc_audio_dma_interrupt when
+ * more data is required.
+ */
+static void
+vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ unsigned long flags;
+
+ save_flags_cli(flags);
+ dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf;
+ dma_count = total_count;
+ restore_flags(flags);
+}
+
+static void
+vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag)
+{
+}
+
+static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount)
+{
+ return -EINVAL;
+}
+
+static void vidc_audio_dma_interrupt(void)
+{
+ DMAbuf_outputintr(vidc_adev, 1);
+}
+
+/*
+ * Prepare for outputting samples.
+ *
+ * Each buffer that will be passed will be `bsize' bytes long,
+ * with a total of `bcount' buffers.
+ */
+static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount)
+{
+ struct audio_operations *adev = audio_devs[dev];
+
+ dma_interrupt = NULL;
+ adev->dmap_out->flags |= DMA_NODMA;
+
+ return 0;
+}
+
+/*
+ * Stop our current operation.
+ */
+static void vidc_audio_reset(int dev)
+{
+ dma_interrupt = NULL;
+}
+
+static int vidc_audio_local_qlen(int dev)
+{
+ return /*dma_count !=*/ 0;
+}
+
+static void vidc_audio_trigger(int dev, int enable_bits)
+{
+ struct audio_operations *adev = audio_devs[dev];
+
+ if (enable_bits & PCM_ENABLE_OUTPUT) {
+ if (!(adev->flags & DMA_ACTIVE)) {
+ unsigned long flags;
+
+ save_flags_cli(flags);
+
+ /* prevent recusion */
+ adev->flags |= DMA_ACTIVE;
+
+ dma_interrupt = vidc_audio_dma_interrupt;
+ vidc_sound_dma_irq(0, NULL, NULL);
+ outb(DMA_CR_E | 0x10, IOMD_SD0CR);
+
+ restore_flags(flags);
+ }
+ }
+}
+
+static struct audio_driver vidc_audio_driver =
+{
+ open: vidc_audio_open,
+ close: vidc_audio_close,
+ output_block: vidc_audio_output_block,
+ start_input: vidc_audio_start_input,
+ prepare_for_input: vidc_audio_prepare_for_input,
+ prepare_for_output: vidc_audio_prepare_for_output,
+ halt_io: vidc_audio_reset,
+ local_qlen: vidc_audio_local_qlen,
+ trigger: vidc_audio_trigger,
+ set_speed: vidc_audio_set_speed,
+ set_bits: vidc_audio_set_format,
+ set_channels: vidc_audio_set_channels
+};
+
+static struct mixer_operations vidc_mixer_operations = {
+ id: "VIDC",
+ name: "VIDCsound",
+ ioctl: vidc_mixer_ioctl
+};
+
+void vidc_update_filler(int format, int channels)
+{
+#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
+
+ switch (TYPE(format, channels)) {
+ default:
+ case TYPE(AFMT_U8, 1):
+ vidc_filler = vidc_fill_1x8_u;
+ break;
+
+ case TYPE(AFMT_U8, 2):
+ vidc_filler = vidc_fill_2x8_u;
+ break;
+
+ case TYPE(AFMT_S8, 1):
+ vidc_filler = vidc_fill_1x8_s;
+ break;
+
+ case TYPE(AFMT_S8, 2):
+ vidc_filler = vidc_fill_2x8_s;
+ break;
+
+ case TYPE(AFMT_S16_LE, 1):
+ vidc_filler = vidc_fill_1x16_s;
+ break;
+
+ case TYPE(AFMT_S16_LE, 2):
+ vidc_filler = vidc_fill_2x16_s;
+ break;
}
}
void attach_vidc(struct address_info *hw_config)
{
char name[32];
- int i;
+ int i, adev;
sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
conf_printf(name, hw_config);
memset(dma_buf, 0, sizeof(dma_buf));
- for (i = 0; i < 2; i++)
- {
+ adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,
+ &vidc_audio_driver, sizeof(vidc_audio_driver),
+ DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE,
+ NULL, hw_config->dma, hw_config->dma2);
+
+ if (adev < 0)
+ goto audio_failed;
+
+ /*
+ * 1024 bytes => 64 buffers
+ */
+ audio_devs[adev]->min_fragment = 10;
+ audio_devs[adev]->mixer_dev = num_mixers;
+
+ audio_devs[adev]->mixer_dev =
+ sound_install_mixer(MIXER_DRIVER_VERSION,
+ name, &vidc_mixer_operations,
+ sizeof(vidc_mixer_operations), NULL);
+
+ if (audio_devs[adev]->mixer_dev < 0)
+ goto mixer_failed;
+
+ for (i = 0; i < 2; i++) {
dma_buf[i] = get_free_page(GFP_KERNEL);
- if (!dma_buf[i])
- goto nomem;
- dma_pbuf[i] = virt_to_phys(dma_buf[i]);
+ if (!dma_buf[i]) {
+ printk(KERN_ERR "%s: can't allocate required buffers\n",
+ name);
+ goto mem_failed;
+ }
+ dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]);
}
- if (sound_alloc_dma(hw_config->dma, "VIDCsound"))
- {
- printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n");
- return;
+ if (sound_alloc_dma(hw_config->dma, hw_config->name)) {
+ printk(KERN_ERR "%s: DMA %d is in use\n", name, hw_config->dma);
+ goto dma_failed;
}
- if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", &dma_start))
- {
- printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n");
- return;
+
+ if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0,
+ hw_config->name, &dma_start)) {
+ printk(KERN_ERR "%s: IRQ %d is in use\n", name, hw_config->irq);
+ goto irq_failed;
}
+ old_mksound = kd_mksound;
+ kd_mksound = vidc_mksound;
+ vidc_adev = adev;
+ vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
-// vidc_synth_init(hw_config);
- vidc_audio_init(hw_config);
- vidc_mixer_init(hw_config);
+#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
+ softoss_dev = adev;
+#endif
return;
-nomem:
+irq_failed:
+ sound_free_dma(hw_config->dma);
+dma_failed:
+mem_failed:
for (i = 0; i < 2; i++)
free_page(dma_buf[i]);
- printk(KERN_ERR "VIDCsound: can't allocate required buffers\n");
+ sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
+mixer_failed:
+ sound_unload_audiodev(adev);
+audio_failed:
+ return;
}
int probe_vidc(struct address_info *hw_config)
{
- hw_config->irq = IRQ_DMAS0;
- hw_config->dma = DMA_VIRTUAL_SOUND;
- hw_config->dma2 = -1;
- hw_config->card_subtype = 16;
+ hw_config->irq = IRQ_DMAS0;
+ hw_config->dma = DMA_VIRTUAL_SOUND;
+ hw_config->dma2 = -1;
+ hw_config->card_subtype = 16;
+ hw_config->name = "VIDC20";
return 1;
}
void unload_vidc(struct address_info *hw_config)
{
- int i;
+ int i, adev = vidc_adev;
+
+ vidc_adev = -1;
- free_irq(hw_config->irq, NULL);
+ if (old_mksound)
+ kd_mksound = old_mksound;
+
+ free_irq(hw_config->irq, &dma_start);
sound_free_dma(hw_config->dma);
- for (i = 0; i < 2; i++)
- free_page(dma_buf[i]);
+ if (adev >= 0) {
+ sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
+ sound_unload_audiodev(adev);
+ for (i = 0; i < 2; i++)
+ free_page(dma_buf[i]);
+ }
}
#ifdef MODULE
static struct address_info config;
+/*
+ * Note! Module use count is handled by SOUNDLOCK/SOUND_LOCK_END
+ */
int init_module(void)
{
if (probe_vidc(&config) == 0)
return -ENODEV;
- printk("VIDC 16-bit serial sound\n");
+
SOUND_LOCK;
attach_vidc(&config);
+
return 0;
}
diff --git a/drivers/sound/vidc.h b/drivers/sound/vidc.h
index a79bdc85d..0b56e8b7a 100644
--- a/drivers/sound/vidc.h
+++ b/drivers/sound/vidc.h
@@ -55,18 +55,9 @@ extern void (*dma_interrupt) (void);
extern unsigned long dma_start, dma_count, dma_bufsize;
extern unsigned long dma_buf[2], dma_pbuf[2];
-/* vidc_audio.c */
-
-extern void vidc_audio_init(struct address_info *hw_config);
-extern int vidc_audio_get_volume(void);
-extern int vidc_audio_set_volume(int vol);
-
-/* vidc_mixer.c */
-
-extern void vidc_mixer_init(struct address_info *hw_config);
-
/* vidc_synth.c */
extern void vidc_synth_init(struct address_info *hw_config);
+extern void vidc_synth_exit(struct address_info *hw_config);
extern int vidc_synth_get_volume(void);
extern int vidc_synth_set_volume(int vol);
diff --git a/drivers/sound/vidc_audio.c b/drivers/sound/vidc_audio.c
deleted file mode 100644
index 3a1f162fb..000000000
--- a/drivers/sound/vidc_audio.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * drivers/sound/vidc_audio.c
- *
- * Audio routines for the VIDC
- *
- * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
- */
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/iomd.h>
-
-#include "sound_config.h"
-#include "vidc.h"
-
-/*
- * VIDC sound
- *
- * When using SERIAL SOUND mode (external DAC), the number of physical
- * channels is fixed at 2. Therefore, the sample rate = vidc sample rate.
- */
-
-static int vidc_adev;
-
-static int vidc_audio_volume;
-static int vidc_audio_rate;
-static char vidc_audio_format;
-static char vidc_audio_channels;
-
-extern void vidc_update_filler(int bits, int channels);
-
-int vidc_audio_get_volume(void)
-{
- return vidc_audio_volume;
-}
-
-int vidc_audio_set_volume(int newvol)
-{
- vidc_audio_volume = newvol;
- return vidc_audio_volume;
-}
-
-static int vidc_audio_set_bits(int fmt)
-{
- switch (fmt)
- {
- case AFMT_QUERY:
- break;
- case AFMT_U8:
- case AFMT_S8:
- case AFMT_S16_LE:
- vidc_audio_format = fmt;
- vidc_update_filler(vidc_audio_format, vidc_audio_channels);
- break;
- default:
- vidc_audio_format = AFMT_S16_LE;
- vidc_update_filler(vidc_audio_format, vidc_audio_channels);
- break;
- }
- return vidc_audio_format;
-}
-
-static int vidc_audio_set_rate(int rate)
-{
- if (rate)
- {
- int newsize, new2size;
-
- vidc_audio_rate = ((500000 / rate) + 1) >> 1;
- if (vidc_audio_rate < 3)
- vidc_audio_rate = 3;
- if (vidc_audio_rate > 255)
- vidc_audio_rate = 255;
- outl((vidc_audio_rate - 2) | 0xb0000000, IO_VIDC_BASE);
- outl(0xb1000003, IO_VIDC_BASE);
- newsize = (10000 / vidc_audio_rate) & ~3;
- if (newsize < 208)
- newsize = 208;
- if (newsize > 4096)
- newsize = 4096;
- for (new2size = 128; new2size < newsize; new2size <<= 1);
- if (new2size - newsize > newsize - (new2size >> 1))
- new2size >>= 1;
- dma_bufsize = new2size;
- }
- return 250000 / vidc_audio_rate;
-}
-
-static int vidc_audio_set_channels(int channels)
-{
- switch (channels)
- {
- case 0:
- break;
- case 1:
- case 2:
- vidc_audio_channels = channels;
- vidc_update_filler(vidc_audio_format, vidc_audio_channels);
- break;
- default:
- vidc_audio_channels = 2;
- vidc_update_filler(vidc_audio_format, vidc_audio_channels);
- break;
- }
- return vidc_audio_channels;
-}
-
-/*
- * Open the device
- *
- * dev - device
- * mode - mode to open device (logical OR of OPEN_READ and OPEN_WRITE)
- *
- * Called when opening the DMAbuf (dmabuf.c:259)
- */
-static int vidc_audio_open(int dev, int mode)
-{
- if (vidc_busy)
- return -EBUSY;
-
- if ((mode & OPEN_READ) && (!mode & OPEN_WRITE))
- {
- /* This audio device doesn't have recording capability */
- return -EIO;
- }
- vidc_busy = 1;
- return 0;
-}
-
-/*
- * Close the device
- *
- * dev - device
- *
- * Called when closing the DMAbuf (dmabuf.c:477)
- * after halt_xfer
- */
-static void vidc_audio_close(int dev)
-{
- vidc_busy = 0;
-}
-
-static int vidc_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
- int ret;
-
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (get_user(ret, (int *) arg))
- return -EFAULT;
- ret = vidc_audio_set_rate(ret);
- break;
-
- case SOUND_PCM_READ_RATE:
- ret = vidc_audio_set_rate(0);
- break;
-
- case SNDCTL_DSP_STEREO:
- if (get_user(ret, (int *) arg))
- return -EFAULT;
- ret = vidc_audio_set_channels(ret + 1) - 1;
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (get_user(ret, (int *) arg))
- return -EFAULT;
- ret = vidc_audio_set_channels(ret);
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- ret = vidc_audio_set_channels(0);
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(ret, (int *) arg))
- return -EFAULT;
- ret = vidc_audio_set_bits(ret);
- break;
-
- case SOUND_PCM_READ_BITS:
- ret = vidc_audio_set_bits(0);
- break;
-
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- default:
- return -EINVAL;
- }
- return put_user(ret, (int *) arg);
-}
-
-/*
- * Output a block via DMA to sound device
- *
- * dev - device number
- * buf - physical address of buffer
- * total_count - total byte count in buffer
- * intrflag - set if this has been called from an interrupt (via DMAbuf_outputintr)
- * restart_dma - set if DMA needs to be re-initialised
- *
- * Called when:
- * 1. Starting output (dmabuf.c:1327)
- * 2. (dmabuf.c:1504)
- * 3. A new buffer needs to be sent to the device (dmabuf.c:1579)
- */
-static void vidc_audio_output_block(int dev, unsigned long buf, int total_count,
- int intrflag)
-{
- struct audio_operations *adev = audio_devs[dev];
- struct dma_buffparms *dmap = adev->dmap_out;
-
- dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf;
- dma_count = total_count;
-
- if (!(adev->flags & DMA_ACTIVE))
- {
- unsigned long flags;
- save_flags_cli(flags);
-
- vidc_sound_dma_irq(0, NULL, NULL);
- outb(DMA_CR_E | 0x10, IOMD_SD0CR);
-
- restore_flags(flags);
- }
-}
-
-static void vidc_audio_start_input(int dev, unsigned long buf, int count,
- int intrflag)
-{
-}
-
-static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount)
-{
- return -EINVAL;
-}
-
-static void vidc_audio_dma_interrupt(void)
-{
- DMAbuf_outputintr(vidc_adev, 1);
-}
-
-/*
- * Prepare for outputting samples to `dev'
- *
- * Each buffer that will be passed will be `bsize' bytes long,
- * with a total of `bcount' buffers.
- *
- * Called when:
- * 1. A trigger enables audio output (dmabuf.c:978)
- * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152)
- * 3. We restart a transfer (dmabuf.c:1324)
- */
-static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount)
-{
- audio_devs[dev]->dmap_out->flags |= DMA_NODMA;
- dma_interrupt = vidc_audio_dma_interrupt;
- return 0;
-}
-
-/*
- * Stop our current operation.
- */
-static void vidc_audio_reset(int dev)
-{
- /* stop interrupts. Our real interrupt routine
- * will close DMA down for us
- */
- dma_interrupt = NULL;
-}
-
-static int vidc_audio_local_qlen(int dev)
-{
- return /*dma_count !=*/ 0;
-}
-
-static struct audio_driver vidc_audio_driver =
-{
- vidc_audio_open, /* open */
- vidc_audio_close, /* close */
- vidc_audio_output_block, /* output_block */
- vidc_audio_start_input, /* start_input */
- vidc_audio_ioctl, /* ioctl */
- vidc_audio_prepare_for_input, /* prepare_for_input */
- vidc_audio_prepare_for_output, /* prepare_for_output */
- vidc_audio_reset, /* reset */
- vidc_audio_local_qlen, /*+local_qlen */
- NULL, /*+copy_from_user */
- NULL, /*+halt_input */
- NULL, /* halt_output */
- NULL, /*+trigger */
- NULL, /*+set_speed */
- NULL, /*+set_bits */
- NULL, /*+set_channels */
-};
-
-void vidc_audio_init(struct address_info *hw_config)
-{
- vidc_audio_volume = 100 | (100 << 8);
-
- if ((vidc_adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- "VIDCsound", &vidc_audio_driver,
- sizeof(struct audio_driver),
- DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE,
- NULL, hw_config->dma, hw_config->dma2)) >= 0)
- {
- audio_devs[vidc_adev]->min_fragment = 10; /* 1024 bytes => 64 buffers */
- audio_devs[vidc_adev]->mixer_dev = num_mixers;
- }
- else printk(KERN_ERR "VIDCsound: Too many PCM devices available\n");
-}
diff --git a/drivers/sound/vidc_fill.S b/drivers/sound/vidc_fill.S
index 53fc2ed01..c198b72c6 100644
--- a/drivers/sound/vidc_fill.S
+++ b/drivers/sound/vidc_fill.S
@@ -191,24 +191,24 @@ ENTRY(vidc_sound_dma_irq)
.data
.globl SYMBOL_NAME(dma_interrupt)
SYMBOL_NAME(dma_interrupt):
- .long 0
+ .long 0 @ r3
.globl SYMBOL_NAME(dma_pbuf)
SYMBOL_NAME(dma_pbuf):
- .long 0
- .long 0
+ .long 0 @ r4
+ .long 0 @ r5
.globl SYMBOL_NAME(dma_start)
SYMBOL_NAME(dma_start):
- .long 0
+ .long 0 @ r0
.globl SYMBOL_NAME(dma_count)
SYMBOL_NAME(dma_count):
- .long 0
+ .long 0 @ r1
.globl SYMBOL_NAME(dma_buf)
SYMBOL_NAME(dma_buf):
- .long 0
- .long 0
+ .long 0 @ r2
+ .long 0 @ r3
.globl SYMBOL_NAME(vidc_filler)
SYMBOL_NAME(vidc_filler):
- .long SYMBOL_NAME(vidc_fill_noaudio)
+ .long SYMBOL_NAME(vidc_fill_noaudio) @ r4
.globl SYMBOL_NAME(dma_bufsize)
SYMBOL_NAME(dma_bufsize):
- .long 0x1000
+ .long 0x1000 @ r5
diff --git a/drivers/sound/vidc_mixer.c b/drivers/sound/vidc_mixer.c
deleted file mode 100644
index 01be4925c..000000000
--- a/drivers/sound/vidc_mixer.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * drivers/sound/vidc_mixer.c
- *
- * Mixer routines for VIDC
- *
- * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
- */
-
-#include "sound_config.h"
-#include "vidc.h"
-
-int vidc_volume;
-
-static int vidc_get_volume(void)
-{
- return vidc_volume;
-}
-
-static int vidc_set_volume(int newvol)
-{
- vidc_volume = newvol;
-/* printk ("vidc_set_volume: %X\n", newvol); */
- return newvol;
-}
-
-static int vidc_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
- int ret;
-
- switch (cmd)
- {
- case SOUND_MIXER_READ_VOLUME:
- ret = vidc_get_volume();
- break;
-
- case SOUND_MIXER_WRITE_VOLUME:
- if (get_user(ret, (int *) arg))
- return -EINVAL;
- ret = vidc_set_volume(ret);
- break;
-
- case SOUND_MIXER_READ_BASS:
- case SOUND_MIXER_WRITE_BASS:
- case SOUND_MIXER_READ_TREBLE:
- case SOUND_MIXER_WRITE_TREBLE:
- ret = 50;
- break;
-
- case SOUND_MIXER_READ_SYNTH:
-// ret = vidc_synth_get_volume();
- ret = 0;
- break;
-
- case SOUND_MIXER_WRITE_SYNTH:
- if (get_user(ret, (int *) arg))
- return -EINVAL;
-// ret = vidc_synth_set_volume(ret);
- ret = 0;
- break;
-
- case SOUND_MIXER_READ_PCM:
- ret = vidc_audio_get_volume();
- break;
-
- case SOUND_MIXER_WRITE_PCM:
- if (get_user(ret, (int *) arg))
- return -EINVAL;
- ret = vidc_audio_set_volume(ret);
- break;
-
- case SOUND_MIXER_READ_SPEAKER:
- ret = 100;
- break;
-
- case SOUND_MIXER_WRITE_SPEAKER:
- ret = 100;
- break;
-
- case SOUND_MIXER_READ_LINE:
- case SOUND_MIXER_WRITE_LINE:
- case SOUND_MIXER_READ_MIC:
- case SOUND_MIXER_WRITE_MIC:
- ret = 0;
- break;
-
- case SOUND_MIXER_READ_CD:
- case SOUND_MIXER_WRITE_CD:
- ret = 100 | (100 << 8);
- break;
-
- case SOUND_MIXER_READ_IMIX:
- case SOUND_MIXER_WRITE_IMIX:
- case SOUND_MIXER_READ_ALTPCM:
- case SOUND_MIXER_WRITE_ALTPCM:
- case SOUND_MIXER_READ_LINE1:
- case SOUND_MIXER_WRITE_LINE1:
- case SOUND_MIXER_READ_LINE2:
- case SOUND_MIXER_WRITE_LINE2:
- case SOUND_MIXER_READ_LINE3:
- case SOUND_MIXER_WRITE_LINE3:
- ret = 0;
- break;
-
- case SOUND_MIXER_READ_RECSRC:
- ret = 0;
- break;
-
- case SOUND_MIXER_WRITE_RECSRC:
- return -EINVAL;
- break;
-
- case SOUND_MIXER_READ_DEVMASK:
- ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
- break;
-
- case SOUND_MIXER_READ_RECMASK:
- ret = 0;
- break;
-
- case SOUND_MIXER_READ_STEREODEVS:
- ret = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
- break;
-
- case SOUND_MIXER_READ_CAPS:
- ret = 0;
- break;
-
- case SOUND_MIXER_READ_MUTE:
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- break;
- }
- return put_user(ret, (int *) arg);
-}
-
-static struct mixer_operations vidc_mixer_operations = {
- "VIDC",
- "VIDCsound",
- vidc_default_mixer_ioctl /* ioctl */
-};
-
-void vidc_mixer_init(struct address_info *hw_config)
-{
- int vidc_mixer = sound_alloc_mixerdev();
- vidc_volume = 100 | (100 << 8);
- if (num_mixers < MAX_MIXER_DEV)
- mixer_devs[vidc_mixer] = &vidc_mixer_operations;
-}
diff --git a/drivers/sound/vidc_synth.c b/drivers/sound/vidc_synth.c
deleted file mode 100644
index ba94f0bc6..000000000
--- a/drivers/sound/vidc_synth.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * drivers/sound/vidc_synth.c
- *
- * Synthesizer routines for the VIDC
- *
- * Copyright (C) 1997 Russell King <rmk@arm.uk.linux.org>
- */
-
-#include "sound_config.h"
-#include "vidc.h"
-#if 0
-static struct synth_info vidc_info =
-{
- "VIDCsound", /* name */
- 0, /* device */
- SYNTH_TYPE_SAMPLE, /* synth_type */
- 0, /* synth_subtype */
- 0, /* perc_mode */
- 16, /* nr_voices */
- 0, /* nr_drums */
- 0, /* instr_bank_size */
- 0, /* capabilities */
-};
-
-int vidc_sdev;
-int vidc_synth_volume;
-
-static int vidc_synth_open(int dev, int mode)
-{
- if (vidc_busy)
- return -EBUSY;
-
- vidc_busy = 1;
- return 0;
-}
-
-static void vidc_synth_close(int dev)
-{
- vidc_busy = 0;
-}
-
-
-static struct synth_operations vidc_synth_operations =
-{
- "VIDC Synth", /* name */
- &vidc_info, /* info */
- 0, /* midi_dev */
- SYNTH_TYPE_SAMPLE, /* synth_type */
- /*SAMPLE_TYPE_XXX */ 0, /* synth_subtype */
- vidc_synth_open, /* open */
- vidc_synth_close, /* close */
- NULL, /* ioctl */
- NULL, /* kill_note */
- NULL, /* start_note */
- NULL, /* set_instr */
- NULL, /* reset */
- NULL, /* hw_control */
- NULL, /* load_patch */
- NULL, /* aftertouch */
- NULL, /* controller */
- NULL, /* panning */
- NULL, /* volume_method */
- NULL, /* bender */
- NULL, /* alloc_voice */
- NULL, /* setup_voice */
- NULL, /* send_sysex */
- /* alloc */
- /* chn_info[16] */
- /* syex_buf */
- /* syex_ptr */
-};
-
-int vidc_synth_get_volume(void)
-{
- return vidc_synth_volume;
-}
-
-int vidc_synth_set_volume(int newvol)
-{
- return vidc_synth_volume = newvol;
-}
-
-void vidc_synth_init(struct address_info *hw_config)
-{
- vidc_synth_volume = 100 | (100 << 8);
- if ((vidc_sdev=sound_alloc_synthdev())!=-1)
- synth_devs[vidc_sdev] = &vidc_synth_operations;
- else
- printk(KERN_ERR "VIDCsound: Too many synthesizers\n");
-}
-#endif
diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c
index 143512ea4..905b9cff6 100644
--- a/drivers/sound/waveartist.c
+++ b/drivers/sound/waveartist.c
@@ -838,7 +838,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs)
else
printk(KERN_WARNING "waveartist: unexpected interrupt\n");
-#ifdef CONFIG_AUDIO
if (irqstatus & 0x01) {
int temp = 1;
@@ -855,7 +854,6 @@ waveartist_intr(int irq, void *dev_id, struct pt_regs *regs)
if (temp) //default:
printk(KERN_WARNING "waveartist: Unknown interrupt\n");
}
-#endif
if (irqstatus & 0x2)
// We do not use SB mode natively...
printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n");
diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c
index d7df1790b..2967fdf18 100644
--- a/drivers/sound/wavfront.c
+++ b/drivers/sound/wavfront.c
@@ -86,7 +86,7 @@
*/
#if defined(__alpha__)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#define LOOPS_PER_SEC cpu_data[smp_processor_id()].loops_per_sec
#else
#define LOOPS_PER_SEC loops_per_sec
@@ -1686,13 +1686,11 @@ wavefront_load_gus_patch (int devno, int format, const char *addr,
master otherwise.
*/
-#ifdef CONFIG_MIDI
if (dev.mididev > 0) {
midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
((guspatch.panning << 4) > 127) ?
127 : (guspatch.panning << 4));
}
-#endif CONFIG_MIDI
return(0);
}
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index cc03acb09..d93391340 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -643,16 +643,10 @@ static struct tty_driver acm_tty_driver = {
};
/*
- * Init / cleanup.
+ * Init / exit.
*/
-static void __exit usb_acm_cleanup(void)
-{
- usb_deregister(&acm_driver);
- tty_unregister_driver(&acm_tty_driver);
-}
-
-static int __init usb_acm_init(void)
+static int __init acm_init(void)
{
acm_tty_driver.init_termios = tty_std_termios;
acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -668,5 +662,11 @@ static int __init usb_acm_init(void)
return 0;
}
-module_init(usb_acm_init);
-module_exit(usb_acm_cleanup);
+static void __exit acm_exit(void)
+{
+ usb_deregister(&acm_driver);
+ tty_unregister_driver(&acm_tty_driver);
+}
+
+module_init(acm_init);
+module_exit(acm_exit);
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 82a55ec8e..c4ae62d4c 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -1002,7 +1002,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
return mask;
}
-static struct file_operations usbdevfs_device_file_operations = {
+struct file_operations usbdevfs_device_file_operations = {
llseek: usbdev_lseek,
read: usbdev_read,
poll: usbdev_poll,
@@ -1010,7 +1010,3 @@ static struct file_operations usbdevfs_device_file_operations = {
open: usbdev_open,
release: usbdev_release,
};
-
-struct inode_operations usbdevfs_device_inode_operations = {
- &usbdevfs_device_file_operations, /* file-ops */
-};
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 44d7cfec4..9cca9fdf6 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -256,20 +256,16 @@ static struct input_handler evdev_handler = {
disconnect: evdev_disconnect,
};
-#ifdef MODULE
-int init_module(void)
-#else
-int __init evdev_init(void)
-#endif
+static int __init evdev_init(void)
{
input_register_handler(&evdev_handler);
-
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit evdev_exit(void)
{
input_unregister_handler(&evdev_handler);
}
-#endif
+
+module_init(evdev_init);
+module_exit(evdev_exit);
diff --git a/drivers/usb/ftdi_sio.h b/drivers/usb/ftdi_sio.h
new file mode 100644
index 000000000..36fa7bb3e
--- /dev/null
+++ b/drivers/usb/ftdi_sio.h
@@ -0,0 +1,380 @@
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* The device is based on the FTDI FT8U100AX chip, DB25 on one side, USB on the other */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/* http://www.ftdi.co.uk */
+
+/* The implementation of the device I have is called a USC-1000 */
+/* which is available from http://www.dse.co.nz - cat no XH4214 */
+/* It looks similar to this: http://www.dansdata.com/usbser.htm but I can't be sure */
+/* There are other USC-1000s which don't look like my device though so beware */
+
+/* Definitions for the FTDI USB Single Port Serial Converter */
+/* known as FTDI_SIO (Serial Input/Output application of the chipset) */
+
+#define FTDI_VID 0x0403 /* Vendor Id */
+#define FTDI_SIO_PID 0x8372 /* Product Id */
+
+/* Vendor Request Interface */
+#define FTDI_SIO_RESET 0 /* Reset the port */
+#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
+#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
+#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
+#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */
+#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modern status register */
+#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */
+#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */
+
+/* Port Identifier Table */
+#define PIT_DEFAULT 0 /* SIOA */
+#define PIT_SIOA 1 /* SIOA */
+/* The device this is tested with one has one port */
+#define PIT_SIOB 2 /* SIOB */
+#define PIT_PARALLEL 3 /* Parallel */
+
+/* FTDI_SIO_RESET */
+#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
+#define FTDI_SIO_RESET_REQUEST_TYPE 0x40
+#define FTDI_SIO_RESET_SIO 0
+#define FTDI_SIO_RESET_PURGE_RX 1
+#define FTDI_SIO_RESET_PURGE_TX 2
+/*
+ BmRequestType: 0100 0000B
+ bRequest: FTDI_SIO_RESET
+ wValue: Control Value
+ 0 = Reset SIO
+ 1 = Purge RX buffer
+ 2 = Purge TX buffer
+ wIndex: Port
+ wLength: 0
+ Data: None
+
+ */
+
+/* FTDI_SIO_SET_BAUDRATE */
+#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
+
+/*
+ BmRequestType: 0100 0000B
+ bRequest: FTDI_SIO_SET_BAUDRATE
+ wValue: BaudRate value - see below
+ wIndex: Port
+ wLength: 0
+ Data: None
+*/
+
+typedef enum {
+ ftdi_sio_b300 = 0,
+ ftdi_sio_b600 = 1,
+ ftdi_sio_b1200 = 2,
+ ftdi_sio_b2400 = 3,
+ ftdi_sio_b4800 = 4,
+ ftdi_sio_b9600 = 5,
+ ftdi_sio_b19200 = 6,
+ ftdi_sio_b38400 = 7,
+ ftdi_sio_b57600 = 8,
+ ftdi_sio_b115200 = 9
+} FTDI_SIO_baudrate_t ;
+
+#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
+#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 )
+
+/* FTDI_SIO_SET_DATA */
+
+/* BmRequestType: 0100 0000B */
+/* bRequest: FTDI_SIO_SET_DATA */
+/* wValue: Data characteristics (see below) */
+/* wIndex: Port */
+/* wLength: 0 */
+/* Data: None */
+/*
+ Data characteristics
+
+B0..7 Number of data bits
+B8..10 Parity
+ 0 = None
+ 1 = Odd
+ 2 = Even
+ 3 = Mark
+ 4 = Space
+ B11..13 Stop Bits
+ 0 = 1
+ 1 = 1.5
+ 2 = 2
+ B14..15 Reserved
+*/
+
+
+
+/* FTDI_SIO_MODEM_CTRL */
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
+
+/*
+ BmRequestType: 0100 0000B
+ bRequest: FTDI_SIO_MODEM_CTRL
+ wValue: ControlValue (see below)
+ wIndex: Port
+ wLength: 0
+ Data: None
+
+ NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ command will be IGNORED without an error being returned
+*/
+
+#define FTDI_SIO_SET_DTR_MASK 0x1
+#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK << 8))
+#define FTDI_SIO_SET_DTR_LOW ( 0 | ( FTDI_SIO_SET_DTR_MASK << 8))
+#define FTDI_SIO_SET_RTS_MASK 0x2
+#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
+#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
+
+/* ControlValue
+ B0 DTR state
+ 0 = reset
+ 1 = set
+ B1 RTS state
+ 0 = reset
+ 1 = set
+ B2..7 Reserved
+ B8 DTR state enable
+ 0 = ignore
+ 1 = use DTR state
+ B9 RTS state enable
+ 0 = ignore
+ 1 = use RTS state
+ B10..15 Reserved
+*/
+
+/* FTDI_SIO_SET_FLOW_CTRL */
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
+#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0
+#define FTDI_SIO_RTS_CTS_HS 0x1
+#define FTDI_SIO_DTR_DSR_HS 0x2
+#define FTDI_SIO_XON_XOFF_HS 0x4
+/*
+ BmRequestType: 0100 0000b
+ bRequest: FTDI_SIO_SET_FLOW_CTRL
+ wValue: Xoff/Xon
+ wIndex: Protocol/Port - hIndex is protocl / lIndex is port
+ wLength: 0
+ Data: None
+
+hIndex - protocol has
+ B0 Output handshaking using RTS/CTS
+ 0 = disabled
+ 1 = enabled
+ B1 Output handshaking using DTR/DSR
+ 0 = disabled
+ 1 = enabled
+ B2 Xon/Xoff handshaking
+ 0 = disabled
+ 1 = enabled
+
+A value of zero in the hIndex field selects no handshaking
+
+If Xon/Xoff handshaking is specified, the hValue field contains the Xoff character
+and the lValue field contains the Xon character.
+
+*/
+
+/* FTDI_SIO_SET_EVENT_CHAR */
+/* Set the special event character for the specified communications port */
+/* If the device sees this character it will immediately return the */
+/* data read so far - rather than wait 40ms or until 62 bytes is read */
+#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
+#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
+
+
+/*
+ BmRequestType: 0100 0000b
+ bRequest: FTDI_SIO_SET_EVENT_CHAR
+ wValue: EventChar
+ wIndex: Port
+ wLength: 0
+ Data: None
+
+wValue:
+ B0..7 Event Character
+ B8 Event Character Processing
+ 0 = disabled
+ 1 = enabled
+ B9..15 Reserved
+
+*/
+
+/* FTDI_SIO_SET_ERROR_CHAR */
+/* Set the parity error replacement character for the specified communications port */
+
+/*
+ BmRequestType: 0100 0000b
+ bRequest: FTDI_SIO_SET_EVENT_CHAR
+ wValue: Error Char
+ wIndex: Port
+ wLength: 0
+ Data: None
+
+Error Char
+ B0..7 Error Character
+ B8 Error Character Processing
+ 0 = disabled
+ 1 = enabled
+ B9..15 Reserved
+
+*/
+
+/* FTDI_SIO_GET_MODEM_STATUS */
+/* Retreive the current value of the modem status register */
+
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS
+#define FTDI_SIO_CTS_MASK 0x10
+#define FTDI_SIO_DSR_MASK 0x20
+#define FTDI_SIO_RI_MASK 0x40
+#define FTDI_SIO_RLSD_MASK 0x80
+/*
+ BmRequestType: 1100 0000b
+ bRequest: FTDI_SIO_GET_MODEM_STATUS
+ wValue: zero
+ wIndex: Port
+ wLength: 1
+ Data: Status
+
+One byte of data is returned
+B0..3 0
+B4 CTS
+ 0 = inactive
+ 1 = active
+B5 DSR
+ 0 = inactive
+ 1 = active
+B6 Ring Indicator (RI)
+ 0 = inactive
+ 1 = active
+B7 Receive Line Signal Detect (RLSD)
+ 0 = inactive
+ 1 = active
+*/
+
+
+
+/* Descriptors returned by the device
+
+ Device Descriptor
+
+Offset Field Size Value Description
+0 bLength 1 0x12 Size of descriptor in bytes
+1 bDescriptorType 1 0x01 DEVICE Descriptor Type
+2 bcdUSB 2 0x0110 USB Spec Release Number
+4 bDeviceClass 1 0x00 Class Code
+5 bDeviceSubClass 1 0x00 SubClass Code
+6 bDeviceProtocol 1 0x00 Protocol Code
+7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0
+8 idVendor 2 0x0403 Vendor ID
+10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID)
+12 bcdDevice 2 0x0001 Device release number
+14 iManufacturer 1 0x01 Index of man. string desc
+15 iProduct 1 0x02 Index of prod string desc
+16 iSerialNumber 1 0x02 Index of serial nmr string desc
+17 bNumConfigurations 1 0x01 Number of possible configurations
+
+Configuration Descriptor
+
+Offset Field Size Value
+0 bLength 1 0x09 Size of descriptor in bytes
+1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type
+2 wTotalLength 2 0x0020 Total length of data
+4 bNumInterfaces 1 0x01 Number of interfaces supported
+5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req
+6 iConfiguration 1 0x02 Index of config string descriptor
+7 bmAttributes 1 0x20 Config characteristics Remote Wakeup
+8 MaxPower 1 0x1E Max power consumption
+
+Interface Descriptor
+
+Offset Field Size Value
+0 bLength 1 0x09 Size of descriptor in bytes
+1 bDescriptorType 1 0x04 INTERFACE Descriptor Type
+2 bInterfaceNumber 1 0x00 Number of interface
+3 bAlternateSetting 1 0x00 Value used to select alternate
+4 bNumEndpoints 1 0x02 Number of endpoints
+5 bInterfaceClass 1 0xFF Class Code
+6 bInterfaceSubClass 1 0xFF Subclass Code
+7 bInterfaceProtocol 1 0xFF Protocol Code
+8 iInterface 1 0x02 Index of interface string description
+
+IN Endpoint Descriptor
+
+Offset Field Size Value
+0 bLength 1 0x07 Size of descriptor in bytes
+1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+2 bEndpointAddress 1 0x82 Address of endpoint
+3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+4 bNumEndpoints 2 0x0040 maximum packet size
+5 bInterval 1 0x00 Interval for polling endpoint
+
+OUT Endpoint Descriptor
+
+Offset Field Size Value
+0 bLength 1 0x07 Size of descriptor in bytes
+1 bDescriptorType 1 0x05 ENDPOINT descriptor type
+2 bEndpointAddress 1 0x02 Address of endpoint
+3 bmAttributes 1 0x02 Endpoint attributes - Bulk
+4 bNumEndpoints 2 0x0040 maximum packet size
+5 bInterval 1 0x00 Interval for polling endpoint
+
+DATA FORMAT
+
+IN Endpoint
+
+The device reserves the first two bytes of data on this endpoint to contain the current
+values of the modem and line status registers. In the absence of data, the device
+generates a message consisting of these two status bytes every 40 ms
+
+Byte 0: Modem Status
+
+Offset Description
+B0 Reserved - must be 1
+B1 Reserved - must be 0
+B2 Reserved - must be 0
+B3 Reserved - must be 0
+B4 Clear to Send (CTS)
+B5 Data Set Ready (DSR)
+B6 Ring Indicator (RI)
+B7 Receive Line Signal Detect (RLSD)
+
+Byte 1: Line Status
+
+Offset Description
+B0 Data Ready (DR)
+B1 Overrun Error (OE)
+B2 Parity Error (PE)
+B3 Framing Error (FE)
+B4 Break Interrupt (BI)
+B5 Transmitter Holding Register (THRE)
+B6 Transmitter Empty (TEMT)
+B7 Error in RCVR FIFO
+
+OUT Endpoint
+
+This device reserves the first bytes of data on this endpoint contain the length
+and port identifier of the message. For the FTDI USB Serial converter the port
+identifier is always 1.
+
+Byte 0: Line Status
+
+Offset Description
+B0 Reserved - must be 1
+B1 Reserved - must be 0
+B2..7 Length of message - (not including Byte 0)
+
+*/
diff --git a/drivers/usb/graphire.c b/drivers/usb/graphire.c
index 8921c7db8..3537c8607 100644
--- a/drivers/usb/graphire.c
+++ b/drivers/usb/graphire.c
@@ -37,6 +37,7 @@
#include <linux/malloc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/init.h>
#include "usb.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -179,17 +180,16 @@ static struct usb_driver graphire_driver = {
disconnect: graphire_disconnect,
};
-#ifdef MODULE
-void cleanup_module(void)
+static int __init graphire_init(void)
{
- usb_deregister(&graphire_driver);
+ usb_register(&graphire_driver);
+ return 0;
}
-int init_module(void)
-#else
-int graphire_init(void)
-#endif
+static void __exit graphire_exit(void)
{
- usb_register(&graphire_driver);
- return 0;
+ usb_deregister(&graphire_driver);
}
+
+module_init(graphire_init);
+module_exit(graphire_exit);
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index 85b44010c..778bb3532 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -40,6 +40,8 @@
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+
#undef DEBUG
#undef DEBUG_DATA
@@ -573,14 +575,14 @@ static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
case 2:
if ((end - start) >= 2) {
- item->data.u16 = le16_to_cpu( *((__u16*)start)++);
+ item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
return start;
}
case 3:
item->size++;
if ((end - start) >= 4) {
- item->data.u32 = le32_to_cpu( *((__u32*)start)++);
+ item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
return start;
}
}
@@ -706,7 +708,7 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
{
report += (offset >> 5) << 2; offset &= 31;
- return (le64_to_cpu(*(__u64*)report) >> offset) & ((1 << n) - 1);
+ return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1);
}
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
@@ -1408,19 +1410,16 @@ static struct usb_driver hid_driver = {
disconnect: hid_disconnect
};
-#ifdef MODULE
-void cleanup_module(void)
+static int __init hid_init(void)
{
- usb_deregister(&hid_driver);
+ usb_register(&hid_driver);
+ return 0;
}
-int init_module(void)
-#else
-int hid_init(void)
-#endif
+static void __exit hid_exit(void)
{
- usb_register(&hid_driver);
- return 0;
+ usb_deregister(&hid_driver);
}
-__initcall(hid_init);
+module_init(hid_init);
+module_exit(hid_exit);
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 3c80bb8be..2306615f0 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -46,24 +46,17 @@
static LIST_HEAD(superlist);
extern struct inode_operations usbdevfs_bus_inode_operations;
-
-static struct inode_operations devices_inode_operations = {
- &usbdevfs_devices_fops
-};
-
-static struct inode_operations drivers_inode_operations = {
- &usbdevfs_drivers_fops
-};
+extern struct file_operations usbdevfs_bus_file_operations;
struct special {
const char *name;
- struct inode_operations *iops;
+ struct file_operations *fops;
struct list_head inodes;
};
static struct special special[] = {
- { "devices", &devices_inode_operations, },
- { "drivers", &drivers_inode_operations, }
+ { "devices", &usbdevfs_devices_fops, },
+ { "drivers", &usbdevfs_drivers_fops, }
};
#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
@@ -110,7 +103,7 @@ static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
inode->i_uid = sb->u.usbdevfs_sb.devuid;
inode->i_gid = sb->u.usbdevfs_sb.devgid;
inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
- inode->i_op = &usbdevfs_device_inode_operations;
+ inode->i_fop = &usbdevfs_device_file_operations;
inode->i_size = sizeof(struct usb_device_descriptor);
inode->u.usbdev_i.p.dev = dev;
list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
@@ -148,6 +141,7 @@ static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
inode->i_gid = sb->u.usbdevfs_sb.busgid;
inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
inode->i_op = &usbdevfs_bus_inode_operations;
+ inode->i_fop = &usbdevfs_bus_file_operations;
inode->u.usbdev_i.p.bus = bus;
list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
@@ -159,7 +153,6 @@ static void free_inode(struct inode *inode)
inode->u.usbdev_i.p.dev = NULL;
inode->i_mode &= ~S_IRWXUGO;
inode->i_uid = inode->i_gid = 0;
- inode->i_op = NULL;
inode->i_size = 0;
list_del(&inode->u.usbdev_i.slist);
INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
@@ -405,7 +398,6 @@ static struct file_operations usbdevfs_root_file_operations = {
};
static struct inode_operations usbdevfs_root_inode_operations = {
- default_file_ops: &usbdevfs_root_file_operations,
lookup: usbdevfs_root_lookup,
};
@@ -414,7 +406,6 @@ static struct file_operations usbdevfs_bus_file_operations = {
};
static struct inode_operations usbdevfs_bus_inode_operations = {
- default_file_ops: &usbdevfs_bus_file_operations,
lookup: usbdevfs_bus_lookup,
};
@@ -433,13 +424,14 @@ static void usbdevfs_read_inode(struct inode *inode)
case ISPECIAL:
if (inode->i_ino == IROOT) {
inode->i_op = &usbdevfs_root_inode_operations;
+ inode->i_fop = &usbdevfs_root_file_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
return;
}
if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
return;
spec = &special[inode->i_ino-(IROOT+1)];
- inode->i_op = spec->iops;
+ inode->i_fop = spec->fops;
return;
case IDEVICE:
@@ -453,10 +445,6 @@ static void usbdevfs_read_inode(struct inode *inode)
}
}
-static void usbdevfs_put_inode(struct inode *inode)
-{
-}
-
static void usbdevfs_put_super(struct super_block *sb)
{
list_del(&sb->u.usbdevfs_sb.slist);
@@ -482,15 +470,9 @@ static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsi
}
static struct super_operations usbdevfs_sops = {
- usbdevfs_read_inode,
- NULL,
- usbdevfs_put_inode,
- NULL,
- NULL,
- usbdevfs_put_super,
- NULL,
- usbdevfs_statfs,
- NULL
+ read_inode: usbdevfs_read_inode,
+ put_super: usbdevfs_put_super,
+ statfs: usbdevfs_statfs,
};
struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index d613976f5..e370927b3 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -31,7 +31,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/random.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -303,35 +302,3 @@ void input_close_device(struct input_handle *handle)
handleptr = &((*handleptr)->hnext);
*handleptr = (*handleptr)->hnext;
}
-
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init input_init(void)
-#endif
-{
-#ifndef MODULE
-#ifdef CONFIG_INPUT_KEYBDEV
- keybdev_init();
-#endif
-#ifdef CONFIG_INPUT_MOUSEDEV
- mousedev_init();
-#endif
-#ifdef CONFIG_INPUT_JOYDEV
- joydev_init();
-#endif
-#ifdef CONFIG_INPUT_EVDEV
- evdev_init();
-#endif
-#endif
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-}
-#endif
-
-__initcall(input_init);
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 9f1c94fc0..e2e1d2961 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -82,7 +82,7 @@ static struct joydev *joydev_base[BITS_PER_LONG];
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_SUPPORTED_DEVICE("js");
-static int js_correct(int value, struct js_corr *corr)
+static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
case JS_CORR_NONE:
@@ -102,7 +102,7 @@ static int js_correct(int value, struct js_corr *corr)
return value;
}
-static void js_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct joydev *joydev = handle->private;
struct joydev_list *list = joydev->list;
@@ -120,7 +120,7 @@ static void js_event(struct input_handle *handle, unsigned int type, unsigned in
case EV_ABS:
event.type = JS_EVENT_AXIS;
event.number = joydev->absmap[code];
- event.value = js_correct(value, &joydev->corr[event.number]);
+ event.value = joydev_correct(value, &joydev->corr[event.number]);
break;
default:
@@ -226,8 +226,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 |
(joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0;
- data.x = ((js_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
- data.y = ((js_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
+ data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
+ data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
return -EFAULT;
@@ -276,7 +276,7 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
event.number = list->startup;
} else {
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.value = js_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]],
+ event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]],
&joydev->corr[list->startup - joydev->nkey]);
event.number = list->startup - joydev->nkey;
}
@@ -459,29 +459,27 @@ static void joydev_disconnect(struct input_handle *handle)
}
static struct input_handler joydev_handler = {
- event: js_event,
+ event: joydev_event,
connect: joydev_connect,
disconnect: joydev_disconnect,
};
-#ifdef MODULE
-void cleanup_module(void)
-{
- input_unregister_handler(&joydev_handler);
- if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: can't unregister device\n");
-}
-
-int init_module(void)
-#else
-int __init joydev_init(void)
-#endif
+static int joydev_init(void)
{
if (register_chrdev(JOYDEV_MAJOR, "js", &joydev_fops)) {
printk(KERN_ERR "joydev: unable to get major %d for joystick\n", JOYDEV_MAJOR);
return -EBUSY;
}
input_register_handler(&joydev_handler);
-
return 0;
}
+
+static void joydev_exit(void)
+{
+ input_unregister_handler(&joydev_handler);
+ if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
+ printk(KERN_ERR "js: can't unregister device\n");
+}
+
+module_init(joydev_init);
+module_exit(joydev_exit);
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
index 1e00b7e49..2aef212cb 100644
--- a/drivers/usb/keybdev.c
+++ b/drivers/usb/keybdev.c
@@ -158,18 +158,18 @@ struct input_handler keybdev_handler = {
disconnect: keybdev_disconnect,
};
-#ifdef MODULE
-void cleanup_module(void)
-{
- kbd_ledfunc = NULL;
- input_unregister_handler(&keybdev_handler);
-}
-int init_module(void)
-#else
-int __init keybdev_init(void)
-#endif
+static int __init keybdev_init(void)
{
input_register_handler(&keybdev_handler);
kbd_ledfunc = keybdev_ledfunc;
return 0;
}
+
+static void __exit keybdev_exit(void)
+{
+ kbd_ledfunc = NULL;
+ input_unregister_handler(&keybdev_handler);
+}
+
+module_init(keybdev_init);
+module_exit(keybdev_exit);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 95623c986..0984e48fd 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -447,12 +447,7 @@ static struct input_handler mousedev_handler = {
disconnect: mousedev_disconnect,
};
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init mousedev_init(void)
-#endif
+static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
@@ -472,13 +467,13 @@ int __init mousedev_init(void)
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit mousedev_exit(void)
{
#ifdef CONFIG_INPUT_MOUSEDEV_MIX
misc_deregister(&mousedev_single.misc);
#endif
-
input_unregister_handler(&mousedev_handler);
}
-#endif
+
+module_init(mousedev_init);
+module_exit(mousedev_exit);
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 07220ad9b..182915a19 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -432,18 +432,17 @@ static struct usb_driver usblp_driver = {
minor: USBLP_MINOR_BASE
};
-static void __exit usb_printer_cleanup(void)
-{
- usb_deregister(&usblp_driver);
-}
-
-static int __init usb_printer_init(void)
+static int __init usblp_init(void)
{
if (usb_register(&usblp_driver))
return -1;
-
return 0;
}
-module_init(usb_printer_init);
-module_exit(usb_printer_cleanup);
+static void __exit usblp_exit(void)
+{
+ usb_deregister(&usblp_driver);
+}
+
+module_init(usblp_init);
+module_exit(usblp_exit);
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index d55e54206..aa0531a89 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -817,15 +817,12 @@ usb_driver scanner_driver = {
SCN_BASE_MNR
};
-#ifdef MODULE
-void cleanup_module(void)
+void __exit usb_scanner_exit(void)
{
usb_deregister(&scanner_driver);
}
-int init_module(void)
-#else
-int usb_scanner_init(void)
-#endif
+
+int __init usb_scanner_init(void)
{
if (usb_register(&scanner_driver) < 0)
return -1;
@@ -834,4 +831,5 @@ int usb_scanner_init(void)
return 0;
}
-__initcall(usb_scanner_init);
+module_init(usb_scanner_init);
+module_exit(usb_scanner_exit);
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 60b411761..0d6457965 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -33,12 +33,8 @@ int usb_audio_init(void);
int usb_cpia_init(void);
int usb_ibmcam_init(void);
int usb_ov511_init(void);
-int usb_stor_init(void);
int dabusb_init(void);
int plusb_init(void);
-int usb_mouse_init(void);
-int usb_kbd_init(void);
-int graphire_init(void);
/*
* HCI drivers
@@ -86,24 +82,12 @@ int usb_init(void)
#ifdef CONFIG_USB_OV511
usb_ov511_init();
#endif
-#ifdef CONFIG_USB_STORAGE
- usb_stor_init();
-#endif
#ifdef CONFIG_USB_DABUSB
dabusb_init();
#endif
#ifdef CONFIG_USB_PLUSB
plusb_init();
#endif
-#ifdef CONFIG_USB_MOUSE
- usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
- usb_kbd_init();
-#endif
-#ifdef CONFIG_USB_GRAPHIRE
- graphire_init();
-#endif
#ifdef CONFIG_USB_UHCI
uhci_init();
#endif
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 7ca3b5b59..bb017e60c 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -45,6 +45,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
+#include <asm/unaligned.h>
#undef DEBUG
#define OHCI_USE_NPS
@@ -62,7 +63,7 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
-spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
/*-------------------------------------------------------------------------*
* URB support functions
@@ -319,6 +320,7 @@ static int sohci_submit_urb (urb_t * urb)
if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
urb_rm_priv(urb);
usb_dec_dev_use (urb->dev);
+ spin_unlock_irqrestore(&usb_ed_lock, flags);
return -EINVAL;
}
@@ -1261,7 +1263,7 @@ static int rh_submit_urb (urb_t * urb)
int len = 0;
int status = TD_CC_NOERROR;
- __u8 datab[16];
+ __u32 datab[4];
__u8 * data_buf = datab;
__u16 bmRType_bReq;
@@ -1371,7 +1373,8 @@ static int rh_submit_urb (urb_t * urb)
case RH_GET_DESCRIPTOR | RH_CLASS:
*(__u8 *) (data_buf+1) = 0x29;
- *(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a));
+ put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)),
+ (__u32 *) (data_buf + 2));
*(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
len = min (leni, min(*(__u8 *) data_buf, wLength));
@@ -1380,7 +1383,8 @@ static int rh_submit_urb (urb_t * urb)
*(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff;
*(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16;
} else {
- *(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b));
+ put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)),
+ (__u32 *) (data_buf + 7));
}
OK (len);
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c
index f87600e83..6b9615e72 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/usb-serial.c
@@ -14,6 +14,17 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (02/21/2000) gkh
+ * Made it so that any serial devices only have to specify which functions
+ * they want to overload from the generic function calls (great,
+ * inheritance in C, in a driver, just what I wanted...)
+ * Added support for set_termios and ioctl function calls. No drivers take
+ * advantage of this yet.
+ * Removed the #ifdef MODULE, now there is no module specific code.
+ * Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ * to Miles Lott).
+ * Small fix to get_free_serial.
+ *
* (02/14/2000) gkh
* Removed the Belkin and Peracom functionality from the driver due to
* the lack of support from the vendor, and me not wanting people to
@@ -169,6 +180,19 @@
#include "usb-serial.h"
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/* local function prototypes */
+static int serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int serial_write_room (struct tty_struct *tty);
+static int serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
@@ -224,7 +248,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
continue;
good_spot = 1;
- for (j = 0; j < num_ports-1; ++j)
+ for (j = 1; j <= num_ports-1; ++j)
if (serial_table[i+j])
good_spot = 0;
if (good_spot == 0)
@@ -328,12 +352,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
tty->driver_data = serial;
serial->tty = tty;
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->open) {
return (serial->type->open(tty, filp));
+ } else {
+ return (generic_serial_open(tty, filp));
}
-
- return (0);
}
@@ -363,9 +387,11 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
return;
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->close) {
serial->type->close(tty, filp);
+ } else {
+ generic_serial_close(tty, filp);
}
}
@@ -391,13 +417,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->write) {
return (serial->type->write(tty, from_user, buf, count));
+ } else {
+ return (generic_serial_write(tty, from_user, buf, count));
}
-
- /* no specific driver, so return that we didn't write anything */
- return (0);
}
@@ -422,12 +447,12 @@ static int serial_write_room (struct tty_struct *tty)
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->write_room) {
return (serial->type->write_room(tty));
+ } else {
+ return (generic_write_room(tty));
}
-
- return (0);
}
@@ -452,12 +477,12 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
return (-EINVAL);
}
- /* pass on to the driver specific version of this function */
+ /* pass on to the driver specific version of this function if it is available */
if (serial->type->chars_in_buffer) {
return (serial->type->chars_in_buffer(tty));
+ } else {
+ return (generic_chars_in_buffer(tty));
}
-
- return (0);
}
@@ -485,6 +510,8 @@ static void serial_throttle (struct tty_struct * tty)
/* pass on to the driver specific version of this function */
if (serial->type->throttle) {
serial->type->throttle(tty);
+ } else {
+ generic_throttle(tty);
}
return;
@@ -515,12 +542,86 @@ static void serial_unthrottle (struct tty_struct * tty)
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle) {
serial->type->unthrottle(tty);
+ } else {
+ generic_unthrottle(tty);
}
return;
}
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port;
+
+ dbg("serial_ioctl");
+
+ if (!serial) {
+ dbg("serial == NULL!");
+ return -ENODEV;
+ }
+
+ port = MINOR(tty->device) - serial->minor;
+
+ dbg("serial_ioctl port %d", port);
+
+ /* do some sanity checking that we really have a device present */
+ if (!serial->type) {
+ dbg("serial->type == NULL!");
+ return -ENODEV;
+ }
+ if (!serial->active[port]) {
+ dbg ("device not open");
+ return -ENODEV;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->ioctl) {
+ return (serial->type->ioctl(tty, file, cmd, arg));
+ } else {
+ return (generic_ioctl (tty, file, cmd, arg));
+ }
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port;
+
+ dbg("serial_set_termios");
+
+ if (!serial) {
+ dbg("serial == NULL!");
+ return;
+ }
+
+ port = MINOR(tty->device) - serial->minor;
+
+ dbg("serial_set_termios port %d", port);
+
+ /* do some sanity checking that we really have a device present */
+ if (!serial->type) {
+ dbg("serial->type == NULL!");
+ return;
+ }
+ if (!serial->active[port]) {
+ dbg ("device not open");
+ return;
+ }
+
+ /* pass on to the driver specific version of this function if it is available */
+ if (serial->type->set_termios) {
+ serial->type->set_termios(tty, old);
+ } else {
+ generic_set_termios (tty, old);
+ }
+
+ return;
+}
+
+
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
/*****************************************************************************
* Connect Tech's White Heat specific driver functions
@@ -566,6 +667,29 @@ static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp)
}
+static void whiteheat_set_termios (struct tty_struct *tty, struct termios *old_termios)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ unsigned int cflag = tty->termios->c_cflag;
+
+ dbg("whiteheat_set_termios port %d", port);
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("nothing to change...");
+ return;
+ }
+ }
+
+ /* do the parsing of the cflag to see what to set the line to */
+ /* FIXME!! */
+
+ return;
+}
+
static void whiteheat_throttle (struct tty_struct * tty)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
@@ -813,25 +937,96 @@ static int visor_startup (struct usb_serial *serial)
/******************************************************************************
* FTDI SIO Serial Converter specific driver functions
******************************************************************************/
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/* to talk to the device */
+
+#include "ftdi_sio.h"
+
static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ char buf[1]; /* Needed for the usb_control_msg I think */
int port = MINOR(tty->device) - serial->minor;
- dbg("ftdi_serial_open port %d", port);
+ dbg("ftdi_sio_serial_open port %d", port);
if (serial->active[port]) {
dbg ("device already open");
return -EINVAL;
}
serial->active[port] = 1;
-
+
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
+ 0, buf, 0, HZ * 5);
+
+ /* FIXME - Should I really purge the buffers? */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_PURGE_RX,
+ 0, buf, 0, HZ * 5);
+
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_PURGE_TX,
+ 0, buf, 0, HZ * 5);
+
+
+ /* As per usb_serial_init s/be CS8, B9600, 1 STOP BIT */
+ if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ ftdi_sio_b9600, 0,
+ buf, 0, HZ * 5) < 0){
+ dbg("Error from baudrate urb");
+ return(-EINVAL);
+ }
+
+ if ( usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ 8 | FTDI_SIO_SET_DATA_PARITY_NONE |
+ FTDI_SIO_SET_DATA_STOP_BITS_1, 0,
+ buf, 0, HZ * 5) < 0){
+ dbg("Error from cs8/noparity/1 stopbit urb");
+ return(-EINVAL);
+ }
+
+ /* Disable flow control */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+ 0, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("error from flowcontrol urb");
+ return(-EINVAL);
+ }
+
+ /* Turn on RTS and DTR since we are not flow controlling*/
+ /* FIXME - check for correct behaviour clocal vs non clocal */
+ /* FIXME - might be able to do both simultaneously */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_HIGH, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from DTR HIGH urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_HIGH, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from RTS HIGH urb");
+ }
+
/*Start reading from the device*/
if (usb_submit_urb(&serial->read_urb[port]))
dbg("usb_submit_urb(read bulk) failed");
- /* Need to do device specific setup here (control lines, baud rate, etc.) */
- /* FIXME!!! */
return (0);
}
@@ -840,13 +1035,29 @@ static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp)
static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
{
struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ char buf[1];
int port = MINOR(tty->device) - serial->minor;
- dbg("ftdi_serial_close port %d", port);
-
- /* Need to change the control lines here */
- /* FIXME */
+ dbg("ftdi_sio_serial_close port %d", port);
+ /* FIXME - might be able to do both simultaneously */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_DTR_LOW, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from DTR LOW urb");
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ (unsigned)FTDI_SIO_SET_RTS_LOW, 0,
+ buf, 0, HZ * 5) < 0) {
+ dbg("Error from RTS LOW urb");
+ }
+
+ /* FIXME Should I flush the device here? - not doing it for now */
+
/* shutdown our bulk reads and writes */
usb_unlink_urb (&serial->write_urb[port]);
usb_unlink_urb (&serial->read_urb[port]);
@@ -854,6 +1065,290 @@ static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp)
}
+
+/* The ftdi_sio requires the first byte to have:
+ B0 1
+ B1 0
+ B2..7 length of message excluding byte 0
+*/
+static int ftdi_sio_serial_write (struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ const int data_offset = 1;
+
+ dbg("ftdi_sio_serial_write port %d, %d bytes", port, count);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (serial->num_bulk_out) {
+ unsigned char *first_byte = serial->write_urb[port].transfer_buffer;
+
+ if (serial->write_urb[port].status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count += data_offset;
+ count = (count > serial->bulk_out_size[port]) ?
+ serial->bulk_out_size[port] : count;
+
+
+ /* Copy in the data to send */
+ if (from_user) {
+ copy_from_user(serial->write_urb[port].transfer_buffer + data_offset ,
+ buf, count - data_offset );
+ }
+ else {
+ memcpy(serial->write_urb[port].transfer_buffer + data_offset,
+ buf, count - data_offset );
+ }
+
+ /* Write the control byte at the front of the packet*/
+ first_byte = serial->write_urb[port].transfer_buffer;
+ *first_byte = 1 | ((count-data_offset) << 2) ;
+
+#ifdef DEBUG
+ dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+ if (count) {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ("0x%02x ", first_byte[i]);
+ if (first_byte[i] > ' ' && first_byte[i] < '~') {
+ printk("%c ", first_byte[i]);
+ } else {
+ printk(" ");
+ }
+ }
+
+
+ printk ("\n");
+ }
+
+#endif
+
+
+ /* send the data out the bulk port */
+ serial->write_urb[port].transfer_buffer_length = count;
+
+ if (usb_submit_urb(&serial->write_urb[port]))
+ dbg("usb_submit_urb(write bulk) failed");
+
+ dbg("write returning: %d",count - data_offset);
+ return (count - data_offset);
+ }
+
+ /* no bulk out, so return 0 bytes written */
+ return (0);
+}
+
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+ struct usb_serial *serial = (struct usb_serial *)urb->context;
+ struct tty_struct *tty = serial->tty;
+ unsigned char *data = urb->transfer_buffer;
+ const int data_offset = 2;
+ int i;
+
+ dbg("ftdi_sio_read_bulk_callback");
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if (urb->actual_length > 2) {
+ printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i) {
+ printk ("0x%.2x ", data[i]);
+ if (data[i] > ' ' && data[i] < '~') {
+ printk("%c ", data[i]);
+ } else {
+ printk(" ");
+ }
+ }
+ printk ("\n");
+ }
+#endif
+
+
+ if (urb->actual_length > data_offset) {
+ for (i = data_offset ; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios *old_termios)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ unsigned int cflag = tty->termios->c_cflag;
+ __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);
+
+ /* FIXME - we should keep the old termios really */
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless */
+
+ /* Set number of data bits, parity, stop bits */
+
+ urb_value = 0;
+ urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+ FTDI_SIO_SET_DATA_STOP_BITS_1);
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ FTDI_SIO_SET_DATA_PARITY_EVEN) :
+ FTDI_SIO_SET_DATA_PARITY_NONE);
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+ case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+ case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+ case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+ default:
+ dbg("CSIZE was set but not CS5-CS8");
+ }
+ }
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, 100) < 0) {
+ dbg("FAILED to set databits/stopbits/parity");
+ }
+
+ /* Now do the baudrate */
+ /* FIXME - should drop lines on B0 */
+ /* FIXME Should also handle CLOCAL here */
+
+ switch(cflag & CBAUD){
+ case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+ case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+ case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+ case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+ case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+ case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+ case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+ case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+ case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+ case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+ default: dbg("FTDI_SIO does not support the baudrate requested");
+ /* FIXME - how to return an error for this? */ break;
+ }
+ /* Send the URB */
+ if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_BAUDRATE_REQUEST,
+ FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+ urb_value, 0,
+ buf, 0, 100) < 0) {
+ dbg("urb failed to set baurdrate");
+ }
+ return;
+}
+
+/*FIXME - the beginnings of this implementation - not even hooked into the driver yet */
+static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = (struct usb_serial *) tty->driver_data;
+ int port = MINOR(tty->device) - serial->minor;
+ __u16 urb_value=0; /* Will hold the new flags */
+ char buf[1];
+ int ret, mask;
+ dbg("ftdi_sio_ioctl port %d", port);
+
+ /* Based on code from acm.c */
+ switch (cmd) {
+
+ case TIOCMGET:
+ /* Request the status from the device */
+ if ((ret = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+ 0, 0,
+ buf, 1, HZ * 5)) < 0 ) {
+ dbg("Get not get modem status of device");
+ return(ret);
+ }
+
+ return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+ (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+ (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
+ (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0),
+ (unsigned long *) arg);
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+ /* FIXME Need to remember if we have set DTR or RTS since we
+ can't ask the device */
+ /* FIXME - also need to find the meaning of TIOCMBIS/BIC/SET */
+ if (mask & TIOCM_DTR) {
+ switch(cmd) {
+ case TIOCMSET:
+ urb_value = FTDI_SIO_SET_DTR_HIGH | FTDI_SIO_SET_RTS_LOW;
+ break;
+
+ case TIOCMBIS:
+ /* Will leave RTS alone and set DTR */
+ urb_value = FTDI_SIO_SET_DTR_HIGH;
+ break;
+
+ case TIOCMBIC:
+ urb_value = FTDI_SIO_SET_DTR_LOW;
+ break;
+ }
+ }
+
+ if (mask & TIOCM_RTS) {
+ switch(cmd) {
+ case TIOCMSET:
+ urb_value = FTDI_SIO_SET_DTR_LOW | FTDI_SIO_SET_RTS_HIGH;
+ break;
+
+ case TIOCMBIS:
+ /* Will leave DTR and set RTS */
+ urb_value = FTDI_SIO_SET_RTS_HIGH;
+ break;
+
+ case TIOCMBIC:
+ /* Will unset RTS */
+ urb_value = FTDI_SIO_SET_RTS_LOW;
+ break;
+ }
+ }
+
+
+ return(usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+ urb_value , 0,
+ buf, 0, HZ * 5));
+ }
+}
+
#endif /* CONFIG_USB_SERIAL_FTDI_SIO */
@@ -1041,6 +1536,34 @@ static int generic_chars_in_buffer (struct tty_struct *tty)
}
+static void generic_throttle (struct tty_struct *tty)
+{
+ /* do nothing for the generic device */
+ return;
+}
+
+
+static void generic_unthrottle (struct tty_struct *tty)
+{
+ /* do nothing for the generic device */
+ return;
+}
+
+
+static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ /* generic driver doesn't support any ioctls yet */
+ return -ENOIOCTLCMD;
+}
+
+
+static void generic_set_termios (struct tty_struct *tty, struct termios * old)
+{
+ /* generic driver doesn't really care about setting any line settings */
+ return;
+}
+
+
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial *serial = (struct usb_serial *)urb->context;
@@ -1059,7 +1582,7 @@ static void generic_read_bulk_callback (struct urb *urb)
if (urb->actual_length) {
printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
- printk ("0x%.2x ", data[i]);
+ printk ("%.2x ", data[i]);
}
printk ("\n");
}
@@ -1352,8 +1875,8 @@ static struct tty_driver serial_tty_driver = {
put_char: NULL,
flush_chars: NULL,
write_room: serial_write_room,
- ioctl: NULL,
- set_termios: NULL,
+ ioctl: serial_ioctl,
+ set_termios: serial_set_termios,
set_ldisc: NULL,
throttle: serial_throttle,
unthrottle: serial_unthrottle,
@@ -1397,19 +1920,14 @@ int usb_serial_init(void)
}
-#ifdef MODULE
-int init_module(void)
-{
- return usb_serial_init();
-}
-
-void cleanup_module(void)
+void usb_serial_exit(void)
{
tty_unregister_driver(&serial_tty_driver);
usb_deregister(&usb_serial_driver);
}
-#else
-__initcall(usb_serial_init);
-#endif
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+
diff --git a/drivers/usb/usb-serial.h b/drivers/usb/usb-serial.h
index 6d8e978b5..c62bae569 100644
--- a/drivers/usb/usb-serial.h
+++ b/drivers/usb/usb-serial.h
@@ -87,15 +87,6 @@ struct usb_serial {
#define NUM_DONT_CARE (-1)
-/* local function prototypes */
-static int serial_open (struct tty_struct *tty, struct file * filp);
-static void serial_close (struct tty_struct *tty, struct file * filp);
-static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
-static int serial_write_room (struct tty_struct *tty);
-static int serial_chars_in_buffer (struct tty_struct *tty);
-static void serial_throttle (struct tty_struct * tty);
-static void serial_unthrottle (struct tty_struct * tty);
-
/* This structure defines the individual serial converter. */
struct usb_serial_device_type {
@@ -110,6 +101,8 @@ struct usb_serial_device_type {
char num_bulk_out;
char num_ports; /* number of serial ports this device has */
+ void *private; /* data private to the specific driver */
+
/* function call to make before accepting driver */
int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
@@ -118,21 +111,30 @@ struct usb_serial_device_type {
void (*close)(struct tty_struct * tty, struct file * filp);
int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);
int (*write_room)(struct tty_struct *tty);
+ int (*ioctl)(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+ void (*set_termios)(struct tty_struct *tty, struct termios * old);
int (*chars_in_buffer)(struct tty_struct *tty);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
+
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
+
};
/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
/* need to always compile these in, as some of the other devices use these functions as their own. */
+/* if a driver does not provide a function pointer, the generic function will be called. */
static int generic_serial_open (struct tty_struct *tty, struct file *filp);
static void generic_serial_close (struct tty_struct *tty, struct file *filp);
static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
static int generic_write_room (struct tty_struct *tty);
+static int generic_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void generic_set_termios (struct tty_struct *tty, struct termios * old);
static int generic_chars_in_buffer (struct tty_struct *tty);
+static void generic_throttle (struct tty_struct *tty);
+static void generic_unthrottle (struct tty_struct *tty);
static void generic_read_bulk_callback (struct urb *urb);
static void generic_write_bulk_callback (struct urb *urb);
@@ -150,13 +152,6 @@ static struct usb_serial_device_type generic_device = {
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
num_ports: 1,
- open: generic_serial_open,
- close: generic_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
- read_bulk_callback: generic_read_bulk_callback,
- write_bulk_callback: generic_write_bulk_callback
};
#endif
@@ -165,6 +160,7 @@ static struct usb_serial_device_type generic_device = {
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp);
static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp);
+static void whiteheat_set_termios (struct tty_struct *tty, struct termios * old);
static void whiteheat_throttle (struct tty_struct *tty);
static void whiteheat_unthrottle (struct tty_struct *tty);
static int whiteheat_startup (struct usb_serial *serial);
@@ -198,11 +194,9 @@ static struct usb_serial_device_type whiteheat_device = {
num_ports: 4,
open: whiteheat_serial_open,
close: whiteheat_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
throttle: whiteheat_throttle,
- unthrottle: whiteheat_unthrottle
+ unthrottle: whiteheat_unthrottle,
+ set_termios: whiteheat_set_termios,
};
#endif
@@ -283,14 +277,9 @@ static struct usb_serial_device_type handspring_device = {
num_ports: 2,
open: visor_serial_open,
close: visor_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
- read_bulk_callback: generic_read_bulk_callback,
- write_bulk_callback: generic_write_bulk_callback
};
#endif
@@ -299,8 +288,12 @@ static struct usb_serial_device_type handspring_device = {
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_serial_open (struct tty_struct *tty, struct file *filp);
static void ftdi_sio_serial_close (struct tty_struct *tty, struct file *filp);
+static int ftdi_sio_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static void ftdi_sio_read_bulk_callback (struct urb *urb);
+static void ftdi_sio_set_termios (struct tty_struct *tty, struct termios * old);
+static int ftdi_sio_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
-/* All of the device info needed for the Handspring Visor */
+/* All of the device info needed for the FTDI SIO serial converter */
static __u16 ftdi_vendor_id = FTDI_VENDOR_ID;
static __u16 ftdi_sio_product_id = FTDI_SIO_SERIAL_CONVERTER_ID;
static struct usb_serial_device_type ftdi_sio_device = {
@@ -316,11 +309,9 @@ static struct usb_serial_device_type ftdi_sio_device = {
num_ports: 1,
open: ftdi_sio_serial_open,
close: ftdi_sio_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
- read_bulk_callback: generic_read_bulk_callback,
- write_bulk_callback: generic_write_bulk_callback
+ write: ftdi_sio_serial_write,
+ read_bulk_callback: ftdi_sio_read_bulk_callback,
+ set_termios: ftdi_sio_set_termios
};
#endif
@@ -331,7 +322,7 @@ static int keyspan_pda_serial_open (struct tty_struct *tty, struct file *filp);
static void keyspan_pda_serial_close (struct tty_struct *tty, struct file *filp);
static int keyspan_pda_startup (struct usb_serial *serial);
-/* All of the device info needed for the Handspring Visor */
+/* 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;
@@ -360,17 +351,12 @@ static struct usb_serial_device_type keyspan_pda_device = {
num_ports: 1,
open: keyspan_pda_serial_open,
close: keyspan_pda_serial_close,
- write: generic_serial_write,
- write_room: generic_write_room,
- chars_in_buffer: generic_chars_in_buffer,
- read_bulk_callback: generic_read_bulk_callback,
- write_bulk_callback: generic_write_bulk_callback
};
#endif
/* To add support for another serial converter, create a usb_serial_device_type
- structure for that device, and add it to this list, making sure that the last
- entry is NULL. */
+ structure for that device, and add it to this list, making sure that the
+ last entry is NULL. */
static struct usb_serial_device_type *usb_serial_devices[] = {
#ifdef CONFIG_USB_SERIAL_GENERIC
&generic_device,
diff --git a/drivers/usb/usb-storage-debug.h b/drivers/usb/usb-storage-debug.h
index 8994c06ba..1c5fcc0e2 100644
--- a/drivers/usb/usb-storage-debug.h
+++ b/drivers/usb/usb-storage-debug.h
@@ -1,3 +1,4 @@
+#include <linux/config.h>
#ifdef CONFIG_USB_STORAGE_DEBUG
/* Debug output for Driver for USB mass storage (scsi-like) devices
diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
index f3358ddfe..00fecea9d 100644
--- a/drivers/usb/usbkbd.c
+++ b/drivers/usb/usbkbd.c
@@ -32,6 +32,7 @@
#include <linux/malloc.h>
#include <linux/module.h>
#include <linux/input.h>
+#include <linux/init.h>
#include "usb.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -202,17 +203,16 @@ static struct usb_driver usb_kbd_driver = {
disconnect: usb_kbd_disconnect
};
-#ifdef MODULE
-void cleanup_module(void)
+static int __init usb_kbd_init(void)
{
- usb_deregister(&usb_kbd_driver);
+ usb_register(&usb_kbd_driver);
+ return 0;
}
-int init_module(void)
-#else
-int usb_kbd_init(void)
-#endif
+static void __exit usb_kbd_exit(void)
{
- usb_register(&usb_kbd_driver);
- return 0;
+ usb_deregister(&usb_kbd_driver);
}
+
+module_init(usb_kbd_init);
+module_exit(usb_kbd_exit);
diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c
index 7276ca670..75e834649 100644
--- a/drivers/usb/usbmouse.c
+++ b/drivers/usb/usbmouse.c
@@ -32,6 +32,7 @@
#include <linux/malloc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/init.h>
#include "usb.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -132,18 +133,16 @@ static struct usb_driver usb_mouse_driver = {
disconnect: usb_mouse_disconnect,
};
-#ifdef MODULE
-void cleanup_module(void)
+static int __init usb_mouse_init(void)
{
- usb_deregister(&usb_mouse_driver);
+ usb_register(&usb_mouse_driver);
+ return 0;
}
-int init_module(void)
-#else
-int usb_mouse_init(void)
-#endif
+static void __exit usb_mouse_exit(void)
{
- usb_register(&usb_mouse_driver);
- return 0;
+ usb_deregister(&usb_mouse_driver);
}
+module_init(usb_mouse_init);
+module_exit(usb_mouse_exit);
diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c
index fa2d1b465..06ddeb5b2 100644
--- a/drivers/usb/wmforce.c
+++ b/drivers/usb/wmforce.c
@@ -32,6 +32,7 @@
#include <linux/malloc.h>
#include <linux/input.h>
#include <linux/module.h>
+#include <linux/init.h>
#include "usb.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -149,17 +150,16 @@ static struct usb_driver wmforce_driver = {
disconnect: wmforce_disconnect,
};
-#ifdef MODULE
-void cleanup_module(void)
+static int __init wmforce_init(void)
{
- usb_deregister(&wmforce_driver);
+ usb_register(&wmforce_driver);
+ return 0;
}
-int init_module(void)
-#else
-int wmforce_init(void)
-#endif
+static void __exit wmforce_exit(void)
{
- usb_register(&wmforce_driver);
- return 0;
+ usb_deregister(&wmforce_driver);
}
+
+module_init(wmforce_init);
+module_exit(wmforce_exit);
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index b7a855b77..9d12bf42a 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -105,6 +105,10 @@ if [ "$CONFIG_FB" = "y" ]; then
bool ' Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
bool ' Mystique support' CONFIG_FB_MATROX_MYSTIQUE
bool ' G100/G200/G400 support' CONFIG_FB_MATROX_G100
+ dep_tristate ' Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
+ if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
+ dep_tristate ' G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
+ fi
bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
fi
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e52eee833..75896bbf8 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -3,9 +3,9 @@
# Rewritten to use lists instead of if-statements.
SUB_DIRS :=
-MOD_SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
MOD_IN_SUB_DIRS :=
-ALL_SUB_DIRS :=
+ALL_SUB_DIRS := $(SUB_DIRS) matrox
O_TARGET := video.o
O_OBJS :=
@@ -16,7 +16,11 @@ M_OBJS :=
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o fbcon-vga.o
+export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o fbcon-vga.o \
+ fbcon-iplan2p2.o fbcon-iplan2p4.o fbcon-iplan2p8.o fbcon-vga-planes.o \
+ fbcon-cfb16.o fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o fbcon-cfb8.o \
+ fbcon-mac.o fbcon-mfb.o fbcon-vga8-planes.o \
+ matrox/matroxfb.o
# Object file lists.
obj-y :=
@@ -81,11 +85,20 @@ 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_MATROX) += matroxfb.o
obj-$(CONFIG_FB_SUN3) += sun3fb.o
obj-$(CONFIG_FB_BWTWO) += bwtwofb.o
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+ifeq ($(CONFIG_FB_MATROX),y)
+SUB_DIRS += matrox
+obj-y += matrox/matrox.o
+MOD_SUB_DIRS += matrox
+else
+ ifeq ($(CONFIG_FB_MATROX),m)
+ MOD_SUB_DIRS += matrox
+ endif
+endif
+
# Generic Low Level Drivers
obj-$(CONFIG_FBCON_AFB) += fbcon-afb.o
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
index da084b045..388b0e1d2 100644
--- a/drivers/video/aty128fb.c
+++ b/drivers/video/aty128fb.c
@@ -118,20 +118,19 @@ static struct fb_videomode defaultmode __initdata = {
/* chip description information */
struct aty128_chip_info {
const char *name;
- unsigned short vendor;
unsigned short device;
};
/* supported Rage128 chipsets */
-static const struct aty128_chip_info aty128_pci_probe_list[] =
-{
- {"PCI_DEVICE_ID_ATI_RAGE128_RE", PCI_VENDOR_ID_ATI, 0x5245},
- {"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246},
- {"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b},
- {"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c},
- {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046},
- {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052},
- {NULL, 0, 0}
+static const struct aty128_chip_info aty128_pci_probe_list[] __initdata =
+{
+ {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE},
+ {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF},
+ {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK},
+ {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL},
+ {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF},
+ {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR},
+ {NULL, 0}
};
/* packed BIOS settings */
@@ -186,7 +185,8 @@ static int currcon = 0;
static char *aty128fb_name = "ATY Rage128";
static char fontname[40] __initdata = { 0 };
-static char noaccel __initdata = 0;
+static char noaccel __initdata = 1;
+static unsigned int initdepth __initdata = 8;
#ifndef MODULE
static const char *mode_option __initdata = NULL;
@@ -253,7 +253,9 @@ struct fb_info_aty128 {
void *regbase;
const struct aty128_meminfo *mem; /* onboard mem info */
u32 vram_size; /* onboard video ram */
- void *BIOS_SEG; /* BIOS segment */
+#ifndef CONFIG_PPC
+ void *bios_seg; /* video BIOS segment */
+#endif
unsigned short card_revision; /* video card revision */
struct aty128fb_par default_par, current_par;
struct display disp;
@@ -362,12 +364,27 @@ static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
#endif
#ifdef FBCON_HAS_CFB16
static struct display_switch fbcon_aty128_16;
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p,
+ int c, int yy, int xx);
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count,
+ int yy, int xx);
#endif
#ifdef FBCON_HAS_CFB24
static struct display_switch fbcon_aty128_24;
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p,
+ int c, int yy, int xx);
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count,
+ int yy, int xx);
#endif
#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_aty128_32;
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p,
+ int c, int yy, int xx);
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count,
+ int yy, int xx);
#endif
static struct fb_ops aty128fb_ops = {
@@ -651,7 +668,7 @@ aty128_init_engine(const struct aty128fb_par *par,
GMC_SRC_CLIP_DEFAULT |
GMC_DST_CLIP_DEFAULT |
GMC_BRUSH_SOLIDCOLOR |
- (bpp_to_depth(par->crtc.bpp) << 8) |
+ (bpp_to_depth(par->crtc.bpp << 8)) |
GMC_SRC_DSTCOLOR |
GMC_BYTE_ORDER_MSB_TO_LSB |
GMC_DP_CONVERSION_TEMP_6500 |
@@ -911,6 +928,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
u32 pix_width;
+ /* fun with masking */
h_total = crtc->h_total & 0x1ff;
h_disp = (crtc->h_total>>16) & 0xff;
h_sync_strt = (crtc->h_sync_strt_wid>>3) & 0x1ff;
@@ -1094,7 +1112,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
x;
#ifdef DEBUG
- printk(KERN_DEBUG "x %x\n", x);
+ printk(KERN_DEBUG "aty128fb: x %x\n", x);
#endif
b = 0;
while (x) {
@@ -1109,13 +1127,13 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
x = round_div(n, d);
roff = x * (fifo_depth - 4);
if ((ron + m->Rloop) >= roff) {
- printk(KERN_ERR "Mode out of range\n");
+ printk(KERN_ERR "aty128fb: Mode out of range!\n");
return -EINVAL;
}
#ifdef DEBUG
- printk(KERN_DEBUG "p: %x rloop: %x x: %x ron: %x roff: %x\n", p,
- m->Rloop, x, ron, roff);
+ printk(KERN_DEBUG "aty128fb: p: %x rloop: %x x: %x ron: %x roff: %x\n",
+ p, m->Rloop, x, ron, roff);
#endif
dsp->dda_config = p << 16 | m->Rloop << 20 | x;
dsp->dda_on_off = ron << 16 | roff;
@@ -1203,10 +1221,10 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par,
{
int err;
- if ((err = aty128_var_to_crtc(var, &(par->crtc), info)))
+ if ((err = aty128_var_to_crtc(var, &par->crtc, info)))
return err;
- if ((err = aty128_var_to_pll(var->pixclock, &(par->pll), info)))
+ if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info)))
return err;
if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info)))
@@ -1587,7 +1605,25 @@ aty128fb_setup(char *options)
fontname[i] = 0;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
- }
+ } else if (!strncmp(this_opt, "depth:", 6)) {
+ unsigned int depth = simple_strtoul(this_opt+6, NULL, 0);
+ switch (depth) {
+ case 0 ... 8:
+ initdepth = 8;
+ break;
+ case 9 ... 16:
+ initdepth = 16;
+ break;
+ case 17 ... 24:
+ initdepth = 24;
+ break;
+ case 25 ... 32:
+ initdepth = 32;
+ break;
+ default:
+ initdepth = 8;
+ }
+ }
#ifdef CONFIG_MTRR
else if(!strncmp(this_opt, "nomtrr", 6)) {
mtrr = 0;
@@ -1636,9 +1672,11 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
u32 dac;
int j, k;
u8 chip_rev;
+ const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
+ char *video_card = NULL;
if (!register_test(info)) {
- printk(KERN_ERR "Can't write to video registers\n");
+ printk(KERN_ERR "aty128fb: Can't write to video registers\n");
return 0;
}
@@ -1647,14 +1685,17 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
- /* TODO: be more verbose */
- printk(KERN_INFO "aty128fb: Rage128 [chip rev 0x%x] [card rev %x] ",
- chip_rev, info->card_revision);
+ /* put a name with the face */
+ while (info->pdev->device != aci->device) { aci++; }
+ video_card = (char *)aci->name;
+
+ printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] [card rev %x] ",
+ video_card, chip_rev, info->card_revision);
if (info->vram_size % (1024 * 1024) == 0)
- printk("%dM \n", info->vram_size / (1024*1024));
+ printk("%dM\n", info->vram_size / (1024*1024));
else
- printk("%dk \n", info->vram_size / 1024);
+ printk("%dk\n", info->vram_size / 1024);
/* fill in info */
strcpy(info->fb_info.modename, aty128fb_name);
@@ -1678,7 +1719,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
- &defaultmode, 8))
+ &defaultmode, initdepth))
var = default_var;
#endif
@@ -1767,13 +1808,13 @@ aty128pci_probe(void)
struct pci_dev *pdev = NULL;
const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
- while(aci->name != NULL) {
- pdev = pci_find_device(aci->vendor, aci->device, NULL);
- while(pdev != NULL) {
- if(aty128_pci_register(pdev, aci) > 0)
+ while (aci->name != NULL) {
+ pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
+ while (pdev != NULL) {
+ if (aty128_pci_register(pdev, aci) == 0)
return;
- pdev = pci_find_device(aci->vendor, aci->device, pdev);
- }
+ pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
+ }
aci++;
}
@@ -1797,16 +1838,16 @@ aty128_pci_register(struct pci_dev *pdev,
fb_addr = rp->start;
fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
- request_mem_region (rp->start, rp->end - rp->start + 1, "aty128fb");
+ request_mem_region(rp->start, rp->end - rp->start + 1, "aty128fb");
rp = &pdev->resource[2];
reg_addr = rp->start;
reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
if (!reg_addr) {
- release_mem_region (pdev->resource[0].start,
- pdev->resource[0].end -
- pdev->resource[0].start + 1);
+ release_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
return -1;
}
#else
@@ -1874,13 +1915,13 @@ aty128_pci_register(struct pci_dev *pdev,
return 0;
err_out:
- kfree (info);
+ kfree(info);
unmap_out:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,1)
- release_mem_region (pdev->resource[0].start,
+ release_mem_region(pdev->resource[0].start,
pdev->resource[0].end -
pdev->resource[0].start + 1);
- release_mem_region (pdev->resource[2].start,
+ release_mem_region(pdev->resource[2].start,
pdev->resource[2].end -
pdev->resource[2].start + 1);
#endif
@@ -1949,7 +1990,7 @@ aty128find_ROM(struct fb_info_aty128 *info)
printk(KERN_INFO "aty128fb: Rage128 BIOS located at segment %4.4X\n",
(u32)rom_base);
- info->BIOS_SEG = rom_base;
+ info->bios_seg = rom_base;
flag = 1;
break;
}
@@ -1965,16 +2006,16 @@ aty128_get_pllinfo(struct fb_info_aty128 *info)
u16 bios_header_offset, pll_info_offset;
PLL_BLOCK pll;
- bios_header = info->BIOS_SEG + 0x48L;
+ bios_header = info->bios_seg + 0x48L;
header_ptr = bios_header;
bios_header_offset = readw(header_ptr);
- bios_header = info->BIOS_SEG + bios_header_offset;
+ bios_header = info->bios_seg + bios_header_offset;
bios_header += 0x30;
header_ptr = bios_header;
pll_info_offset = readw(header_ptr);
- header_ptr = info->BIOS_SEG + pll_info_offset;
+ header_ptr = info->bios_seg + pll_info_offset;
memcpy_fromio(&pll, header_ptr, 50);
@@ -2013,8 +2054,8 @@ aty128_get_pllinfo(struct fb_info_aty128 *info)
}
/* free up to-be unused resources */
- if (info->BIOS_SEG)
- iounmap(info->BIOS_SEG);
+ if (info->bios_seg)
+ iounmap(info->bios_seg);
return;
}
@@ -2346,7 +2387,6 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
}
-/* TODO: Fix accel and add to these structs */
#ifdef FBCON_HAS_CFB8
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index 57ae6e15e..5b78c939c 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/* $Id: atyfb.c,v 1.139 2000/02/12 22:47:04 davem Exp $
+/* $Id: atyfb.c,v 1.140 2000/02/25 05:46:27 davem Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
@@ -63,11 +63,13 @@
#ifdef __powerpc__
#include <linux/adb.h>
-#include <linux/pmu.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
#endif
+#ifdef CONFIG_ADB_PMU
+#include <linux/pmu.h>
+#endif
#ifdef CONFIG_NVRAM
#include <linux/nvram.h>
#endif
@@ -121,10 +123,6 @@
#define GUI_RESERVE (1 * PAGE_SIZE)
-#ifndef __powerpc__
-#define eieio() /* Enforce In-order Execution of I/O */
-#endif
-
/* FIXME: remove the FAIL definition */
#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
@@ -3205,25 +3203,18 @@ static void atyfb_save_palette(struct fb_info *fb, int enter)
tmp |= 0x2;
aty_st_8(DAC_CNTL, tmp, info);
aty_st_8(DAC_MASK, 0xff, info);
- eieio();
+
scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
(info->current_par.crtc.bpp == 16)) ? 3 : 0;
- info->aty_cmap_regs->rindex = i << scale;
- eieio();
- atyfb_save.r[enter][i] = info->aty_cmap_regs->lut;
- eieio();
- atyfb_save.g[enter][i] = info->aty_cmap_regs->lut;
- eieio();
- atyfb_save.b[enter][i] = info->aty_cmap_regs->lut;
- eieio();
- info->aty_cmap_regs->windex = i << scale;
- eieio();
- info->aty_cmap_regs->lut = atyfb_save.r[1-enter][i];
- eieio();
- info->aty_cmap_regs->lut = atyfb_save.g[1-enter][i];
- eieio();
- info->aty_cmap_regs->lut = atyfb_save.b[1-enter][i];
- eieio();
+ writeb(i << scale, &info->aty_cmap_regs->rindex);
+
+ atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut);
+ atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut);
+ atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut);
+ writeb(i << scale, &info->aty_cmap_regs->windex);
+ writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut);
+ writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut);
+ writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut);
}
}
@@ -3276,9 +3267,6 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
u8 pll_ref_div;
info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
-#ifdef __sparc_v9__
- info->aty_cmap_regs = __va(info->aty_cmap_regs);
-#endif
chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
Gx = chip_id & CFG_CHIP_TYPE;
Rev = (chip_id & CFG_CHIP_REV)>>24;
@@ -3519,6 +3507,9 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
info->total_vram -= GUI_RESERVE;
}
+ /* Clear the video memory */
+ memset_io(info->frame_buffer, 0, info->total_vram);
+
disp = &info->disp;
strcpy(info->fb_info.modename, atyfb_name);
@@ -3692,7 +3683,7 @@ int __init atyfb_init(void)
/*
* Map in big-endian aperture.
*/
- info->frame_buffer = (unsigned long) __va(addr + 0x800000UL);
+ info->frame_buffer = (unsigned long) addr + 0x800000UL;
info->frame_buffer_phys = addr + 0x800000UL;
/*
@@ -3937,7 +3928,7 @@ int __init atyfb_init(void)
* Add /dev/fb mmap values.
*/
info->mmap_map[0].voff = 0x8000000000000000UL;
- info->mmap_map[0].poff = __pa(info->frame_buffer & PAGE_MASK);
+ info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK;
info->mmap_map[0].size = info->total_vram;
info->mmap_map[0].prot_mask = _PAGE_CACHE;
info->mmap_map[0].prot_flag = _PAGE_E;
@@ -4186,7 +4177,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
struct fb_info_aty *info = (struct fb_info_aty *)fb;
u8 gen_cntl;
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ADB_PMU
if ((_machine == _MACH_Pmac) && blank)
pmu_enable_backlight(0);
#endif
@@ -4211,7 +4202,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
gen_cntl &= ~(0x4c);
aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
-#ifdef CONFIG_PPC
+#ifdef CONFIG_ADB_PMU
if ((_machine == _MACH_Pmac) && !blank)
pmu_enable_backlight(1);
#endif
@@ -4268,14 +4259,10 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
aty_st_8(DAC_MASK, 0xff, info);
scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
(info->current_par.crtc.bpp == 16)) ? 3 : 0;
- info->aty_cmap_regs->windex = regno << scale;
- eieio();
- info->aty_cmap_regs->lut = red;
- eieio();
- info->aty_cmap_regs->lut = green;
- eieio();
- info->aty_cmap_regs->lut = blue;
- eieio();
+ writeb(regno << scale, &info->aty_cmap_regs->windex);
+ writeb(red, &info->aty_cmap_regs->lut);
+ writeb(green, &info->aty_cmap_regs->lut);
+ writeb(blue, &info->aty_cmap_regs->lut);
if (regno < 16)
switch (info->current_par.crtc.bpp) {
#ifdef FBCON_HAS_CFB16
diff --git a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile
new file mode 100644
index 000000000..6de9be372
--- /dev/null
+++ b/drivers/video/matrox/Makefile
@@ -0,0 +1,60 @@
+# Makefile for the Linux video drivers.
+# 5 Aug 1999, James Simmons, <mailto:jsimmons@edgeglobal.com>
+# Rewritten to use lists instead of if-statements.
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_IN_SUB_DIRS :=
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := matrox.o
+O_OBJS :=
+M_OBJS :=
+# This is a nice idea but needs depmod altering
+# MOD_LIST_NAME := VIDEO_MODULES
+
+# All of the (potential) objects that export symbols.
+# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
+
+export-objs := matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o
+
+# Object file lists.
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_FB_MATROX) += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o
+obj-$(CONFIG_FB_MATROX_I2C) += i2c-matroxfb.o
+obj-$(CONFIG_FB_MATROX_MAVEN) += matroxfb_maven.o matroxfb_crtc2.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+# Take multi-part drivers out of obj-y and put components in.
+
+obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
+clean:
+ rm -f core *.o *.a *.s
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
new file mode 100644
index 000000000..bbb695223
--- /dev/null
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -0,0 +1,348 @@
+#include "matroxfb_base.h"
+#include "matroxfb_maven.h"
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+/* MGA-TVO I2C for G200, G400 */
+#define MAT_CLK 0x20
+#define MAT_DATA 0x10
+/* primary head DDC for Mystique(?), G100, G200, G400 */
+#define DDC1_CLK 0x08
+#define DDC1_DATA 0x02
+/* primary head DDC for Millennium, Millennium II */
+#define DDC1B_CLK 0x10
+#define DDC1B_DATA 0x04
+/* secondary head DDC for G400 */
+#define DDC2_CLK 0x04
+#define DDC2_DATA 0x01
+
+/******************************************************/
+
+static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
+ unsigned long flags;
+ int v;
+
+ matroxfb_DAC_lock_irqsave(flags);
+ v = matroxfb_DAC_in(PMINFO DAC_XGENIODATA);
+ matroxfb_DAC_unlock_irqrestore(flags);
+ return v;
+}
+
+static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+ unsigned long flags;
+ int v;
+
+ matroxfb_DAC_lock_irqsave(flags);
+ v = (matroxfb_DAC_in(PMINFO DAC_XGENIOCTRL) & mask) | val;
+ matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, v);
+ /* We must reset GENIODATA very often... XFree plays with this register */
+ matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00);
+ matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+/* software I2C functions */
+static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+ if (state)
+ state = 0;
+ else
+ state = mask;
+ matroxfb_set_gpio(minfo, ~mask, state);
+}
+
+static void matroxfb_maven_setsda(void* data, int state) {
+ matroxfb_i2c_set(data, MAT_DATA, state);
+}
+
+static void matroxfb_maven_setscl(void* data, int state) {
+ matroxfb_i2c_set(data, MAT_CLK, state);
+}
+
+static int matroxfb_maven_getsda(void* data) {
+ return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0;
+}
+
+static int matroxfb_maven_getscl(void* data) {
+ return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0;
+}
+
+static void matroxfb_ddc1_setsda(void* data, int state) {
+ matroxfb_i2c_set(data, DDC1_DATA, state);
+}
+
+static void matroxfb_ddc1_setscl(void* data, int state) {
+ matroxfb_i2c_set(data, DDC1_CLK, state);
+}
+
+static int matroxfb_ddc1_getsda(void* data) {
+ return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0;
+}
+
+static int matroxfb_ddc1_getscl(void* data) {
+ return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0;
+}
+
+static void matroxfb_ddc1b_setsda(void* data, int state) {
+ matroxfb_i2c_set(data, DDC1B_DATA, state);
+}
+
+static void matroxfb_ddc1b_setscl(void* data, int state) {
+ matroxfb_i2c_set(data, DDC1B_CLK, state);
+}
+
+static int matroxfb_ddc1b_getsda(void* data) {
+ return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0;
+}
+
+static int matroxfb_ddc1b_getscl(void* data) {
+ return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0;
+}
+
+static void matroxfb_ddc2_setsda(void* data, int state) {
+ matroxfb_i2c_set(data, DDC2_DATA, state);
+}
+
+static void matroxfb_ddc2_setscl(void* data, int state) {
+ matroxfb_i2c_set(data, DDC2_CLK, state);
+}
+
+static int matroxfb_ddc2_getsda(void* data) {
+ return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0;
+}
+
+static int matroxfb_ddc2_getscl(void* data) {
+ return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
+}
+
+static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
+ MOD_INC_USE_COUNT;
+}
+
+static void matroxfb_dh_dec_use(struct i2c_adapter* dummy) {
+ MOD_DEC_USE_COUNT;
+}
+
+static struct i2c_adapter matroxmaven_i2c_adapter_template =
+{
+ "",
+ I2C_HW_B_G400,
+
+ NULL,
+ NULL,
+
+ matroxfb_dh_inc_use,
+ matroxfb_dh_dec_use,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static struct i2c_algo_bit_data matroxmaven_i2c_algo_template =
+{
+ NULL,
+ matroxfb_maven_setsda,
+ matroxfb_maven_setscl,
+ matroxfb_maven_getsda,
+ matroxfb_maven_getscl,
+ 10, 10, 100,
+};
+
+static struct i2c_adapter matrox_ddc1_adapter_template =
+{
+ "",
+ I2C_HW_B_G400, /* DDC */
+
+ NULL,
+ NULL,
+
+ matroxfb_dh_inc_use,
+ matroxfb_dh_dec_use,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static struct i2c_algo_bit_data matrox_ddc1_algo_template =
+{
+ NULL,
+ matroxfb_ddc1_setsda,
+ matroxfb_ddc1_setscl,
+ matroxfb_ddc1_getsda,
+ matroxfb_ddc1_getscl,
+ 10, 10, 100,
+};
+
+static struct i2c_algo_bit_data matrox_ddc1b_algo_template =
+{
+ NULL,
+ matroxfb_ddc1b_setsda,
+ matroxfb_ddc1b_setscl,
+ matroxfb_ddc1b_getsda,
+ matroxfb_ddc1b_getscl,
+ 10, 10, 100,
+};
+
+static struct i2c_adapter matrox_ddc2_adapter_template =
+{
+ "",
+ I2C_HW_B_G400, /* DDC */
+
+ NULL,
+ NULL,
+
+ matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */
+ matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */
+ NULL,
+ NULL,
+ NULL,
+};
+
+static struct i2c_algo_bit_data matrox_ddc2_algo_template =
+{
+ NULL,
+ matroxfb_ddc2_setsda,
+ matroxfb_ddc2_setscl,
+ matroxfb_ddc2_getsda,
+ matroxfb_ddc2_getscl,
+ 10, 10, 100,
+};
+
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) {
+ int err;
+
+ b->adapter.data = minfo;
+ b->adapter.algo_data = &b->bac;
+ b->bac.data = minfo;
+ err = i2c_bit_add_bus(&b->adapter);
+ b->initialized = !err;
+ return err;
+}
+
+static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
+ if (b->initialized) {
+ i2c_bit_del_bus(&b->adapter);
+ b->initialized = 0;
+ }
+}
+
+static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) {
+ struct i2c_bit_adapter *b = &minfo2->maven;
+
+ b->adapter = matroxmaven_i2c_adapter_template;
+ b->bac = matroxmaven_i2c_algo_template;
+ sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
+ return i2c_bus_reg(b, minfo2->primary_dev);
+}
+
+static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
+ i2c_bit_bus_del(&minfo2->maven);
+}
+
+static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) {
+ struct i2c_bit_adapter *b = &minfo2->ddc1;
+
+ b->adapter = matrox_ddc1_adapter_template;
+ b->bac = matrox_ddc1_algo_template;
+ sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
+ return i2c_bus_reg(b, minfo2->primary_dev);
+}
+
+static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) {
+ struct i2c_bit_adapter *b = &minfo2->ddc1;
+
+ b->adapter = matrox_ddc1_adapter_template;
+ b->bac = matrox_ddc1b_algo_template;
+ sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
+ return i2c_bus_reg(b, minfo2->primary_dev);
+}
+
+static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
+ i2c_bit_bus_del(&minfo2->ddc1);
+}
+
+static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
+ struct i2c_bit_adapter *b = &minfo2->ddc2;
+
+ b->adapter = matrox_ddc2_adapter_template;
+ b->bac = matrox_ddc2_algo_template;
+ sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
+ return i2c_bus_reg(b, minfo2->primary_dev);
+}
+
+static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
+ i2c_bit_bus_del(&minfo2->ddc2);
+}
+
+static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
+ int err;
+ unsigned long flags;
+ struct matroxfb_dh_maven_info* m2info;
+
+ m2info = (struct matroxfb_dh_maven_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+ if (!m2info)
+ return NULL;
+
+ matroxfb_DAC_lock_irqsave(flags);
+ matroxfb_DAC_out(PMINFO DAC_XGENIODATA, 0x00);
+ matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0xFF);
+ matroxfb_DAC_unlock_irqrestore(flags);
+
+ memset(m2info, 0, sizeof(*m2info));
+ m2info->primary_dev = minfo;
+
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W ||
+ ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP)
+ err = i2c_ddc1b_init(m2info);
+ else
+ err = i2c_ddc1_init(m2info);
+ if (err)
+ goto fail_ddc1;
+ if (ACCESS_FBINFO(devflags.maven_capable)) {
+ err = i2c_ddc2_init(m2info);
+ if (err)
+ printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
+ err = i2c_maven_init(m2info);
+ if (err)
+ printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
+ }
+ return m2info;
+fail_ddc1:;
+ kfree(m2info);
+ printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
+ return NULL;
+}
+
+static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
+ struct matroxfb_dh_maven_info* m2info = data;
+
+ i2c_maven_done(m2info);
+ i2c_ddc2_done(m2info);
+ i2c_ddc1_done(m2info);
+ kfree(m2info);
+}
+
+static struct matroxfb_driver i2c_matroxfb = {
+ LIST_HEAD_INIT(i2c_matroxfb.node),
+ "i2c-matroxfb",
+ i2c_matroxfb_probe,
+ i2c_matroxfb_remove,
+};
+
+static int __init i2c_matroxfb_init(void) {
+ if (matroxfb_register_driver(&i2c_matroxfb)) {
+ printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static void __exit i2c_matroxfb_exit(void) {
+ matroxfb_unregister_driver(&i2c_matroxfb);
+}
+
+MODULE_AUTHOR("(c) 1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
+
+module_init(i2c_matroxfb_init);
+module_exit(i2c_matroxfb_exit);
+/* no __setup required */
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
new file mode 100644
index 000000000..db84a3000
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -0,0 +1,924 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.21 1999/01/09
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <trini@kernel.crashing.org>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ * "Bibek Sahu" <scorpio@dodds.net>
+ * Access device through readb|w|l and write b|w|l
+ * Extensive debugging stuff
+ *
+ * "Daniel Haun" <haund@usa.net>
+ * Testing, hardware cursor fixes
+ *
+ * "Scott Wood" <sawst46+@pitt.edu>
+ * Fixes
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * PPC betatesting, PPC support, backward compatibility
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * "Thomas Pornin" <pornin@bolet.ens.fr>
+ * Alpha betatesting
+ *
+ * "Pieter van Leuven" <pvl@iae.nl>
+ * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ * G100 testing
+ *
+ * "H. Peter Arvin" <hpa@transmeta.com>
+ * Ideas
+ *
+ * "Cort Dougan" <cort@cs.nmt.edu>
+ * CHRP fixes and PReP cleanup
+ *
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not walk through include tree :-( */
+#include <linux/config.h>
+
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
+
+#ifdef NEED_DAC1064
+#define outDAC1064 matroxfb_DAC_out
+#define inDAC1064 matroxfb_DAC_in
+
+#define DAC1064_OPT_SCLK_PCI 0x00
+#define DAC1064_OPT_SCLK_PLL 0x01
+#define DAC1064_OPT_SCLK_EXT 0x02
+#define DAC1064_OPT_SCLK_MASK 0x03
+#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3 0x00
+#define DAC1064_OPT_MDIV1 0x08
+#define DAC1064_OPT_MDIV2 0x00
+#define DAC1064_OPT_RESERVED 0x10
+
+static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
+#define minfo ((struct matrox_fb_info*)ptr)
+ matroxfb_DAC_lock();
+ outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
+ ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
+ add_timer(&ACCESS_FBINFO(cursor.timer));
+ matroxfb_DAC_unlock();
+#undef minfo
+}
+
+static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) {
+ vaddr_t cursorbase;
+ u_int32_t xline;
+ unsigned int i;
+ unsigned int h, to;
+ CRITFLAGS
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ matroxfb_createcursorshape(PMINFO p, p->var.vmode);
+
+ xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
+ cursorbase = ACCESS_FBINFO(video.vbase);
+ h = ACCESS_FBINFO(features.DAC1064.cursorimage);
+
+ CRITBEGIN
+
+#ifdef __BIG_ENDIAN
+ WaitTillIdle();
+ mga_outl(M_OPMODE, M_OPMODE_32BPP);
+#endif
+ to = ACCESS_FBINFO(cursor.u);
+ for (i = 0; i < to; i++) {
+ mga_writel(cursorbase, h, 0);
+ mga_writel(cursorbase, h+4, 0);
+ mga_writel(cursorbase, h+8, ~0);
+ mga_writel(cursorbase, h+12, ~0);
+ h += 16;
+ }
+ to = ACCESS_FBINFO(cursor.d);
+ for (; i < to; i++) {
+ mga_writel(cursorbase, h, 0);
+ mga_writel(cursorbase, h+4, xline);
+ mga_writel(cursorbase, h+8, ~0);
+ mga_writel(cursorbase, h+12, ~0);
+ h += 16;
+ }
+ for (; i < 64; i++) {
+ mga_writel(cursorbase, h, 0);
+ mga_writel(cursorbase, h+4, 0);
+ mga_writel(cursorbase, h+8, ~0);
+ mga_writel(cursorbase, h+12, ~0);
+ h += 16;
+ }
+#ifdef __BIG_ENDIAN
+ mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+#endif
+
+ CRITEND
+}
+
+static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
+ unsigned long flags;
+ MINFO_FROM_DISP(p);
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ if (mode == CM_ERASE) {
+ if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+ matroxfb_DAC_lock_irqsave(flags);
+ ACCESS_FBINFO(cursor.state) = CM_ERASE;
+ del_timer(&ACCESS_FBINFO(cursor.timer));
+ outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
+ matroxfb_DAC_unlock_irqrestore(flags);
+ }
+ return;
+ }
+ if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
+ matroxfb_DAC1064_createcursor(PMINFO p);
+ x *= fontwidth(p);
+ y *= fontheight(p);
+ y -= p->var.yoffset;
+ if (p->var.vmode & FB_VMODE_DOUBLE)
+ y *= 2;
+ matroxfb_DAC_lock_irqsave(flags);
+ if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
+ ACCESS_FBINFO(cursor.redraw) = 0;
+ ACCESS_FBINFO(cursor.x) = x;
+ ACCESS_FBINFO(cursor.y) = y;
+ x += 64;
+ y += 64;
+ outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
+ mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x);
+ mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8);
+ mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y);
+ mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8);
+ }
+ ACCESS_FBINFO(cursor.state) = CM_DRAW;
+ if (ACCESS_FBINFO(devflags.blink))
+ mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
+ outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA);
+ matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) {
+ if (p && p->conp)
+ matroxfb_DAC1064_createcursor(PMXINFO(p) p);
+ return 0;
+}
+
+static int DAC1064_selhwcursor(WPMINFO struct display* p) {
+ ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor;
+ ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont;
+ return 0;
+}
+
+static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
+ unsigned int fvco;
+ unsigned int p;
+
+ DBG("DAC1064_calcclock")
+
+ fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
+ p = (1 << p) - 1;
+ if (fvco <= 100000)
+ ;
+ else if (fvco <= 140000)
+ p |= 0x08;
+ else if (fvco <= 180000)
+ p |= 0x10;
+ else
+ p |= 0x18;
+ *post = p;
+}
+
+/* they must be in POS order */
+static const unsigned char MGA1064_DAC_regs[] = {
+ M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+ M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+ M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+ M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
+ DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
+ M1064_XMISCCTRL,
+ M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
+ M1064_XCRCBITSEL,
+ M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+static const unsigned char MGA1064_DAC[] = {
+ 0x00, 0x00, M1064_XCURCTRL_DIS,
+ 0x00, 0x00, 0x00, /* black */
+ 0xFF, 0xFF, 0xFF, /* white */
+ 0xFF, 0x00, 0x00, /* red */
+ 0x00, 0,
+ M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
+ M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
+ M1064_XMISCCTRL_DAC_8BIT,
+ 0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
+ 0x00,
+ 0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
+ unsigned int m, n, p;
+
+ DBG("DAC1064_setpclk")
+
+ DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ hw->DACclk[0] = m;
+ hw->DACclk[1] = n;
+ hw->DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
+ u_int32_t mx;
+
+ DBG("DAC1064_setmclk")
+
+ if (ACCESS_FBINFO(devflags.noinit)) {
+ /* read MCLK and give up... */
+ hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
+ hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
+ hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
+ return;
+ }
+ mx = hw->MXoptionReg | 0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x000000BB;
+ if (oscinfo & DAC1064_OPT_GDIV1)
+ mx |= 0x00000008;
+ if (oscinfo & DAC1064_OPT_MDIV1)
+ mx |= 0x00000010;
+ if (oscinfo & DAC1064_OPT_RESERVED)
+ mx |= 0x00000080;
+ if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+ /* select PCI clock until we have setup oscilator... */
+ int clk;
+ unsigned int m, n, p;
+
+ /* powerup system PLL, select PCI clock */
+ mx |= 0x00000020;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+
+ /* !!! you must not access device if MCLK is not running !!!
+ Doing so cause immediate PCI lockup :-( Maybe they should
+ generate ABORT or I/O (parity...) error and Linux should
+ recover from this... (kill driver/process). But world is not
+ perfect... */
+ /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+ select PLL... because of PLL can be stopped at this time) */
+ DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+ outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+ outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+ for (clk = 65536; clk; --clk) {
+ if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
+ break;
+ }
+ if (!clk)
+ printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+ /* select PLL */
+ mx |= 0x00000005;
+ } else {
+ /* select specified system clock source */
+ mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+ }
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ mx &= ~0x00000004;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
+ hw->MXoptionReg = mx;
+}
+
+void DAC1064_global_init(CPMINFO struct matrox_hw_state* hw) {
+ hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
+ hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
+ hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
+#if defined(CONFIG_FB_MATROX_MAVEN) || defined(CONFIG_FB_MATROX_MAVEN_MODULE)
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
+ hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
+ } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY)
+ hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+ else
+ hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_DIS;
+ if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
+ hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+#else
+ hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_EN;
+#endif
+}
+
+void DAC1064_global_restore(CPMINFO const struct matrox_hw_state* hw) {
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+ outDAC1064(PMINFO M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) {
+ outDAC1064(PMINFO 0x20, 0x04);
+ outDAC1064(PMINFO 0x1F, 0x00);
+ }
+}
+
+static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) {
+ DBG("DAC1064_init_1")
+
+ memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+ if (p->type == FB_TYPE_TEXT) {
+ hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT;
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
+ | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ } else {
+ switch (p->var.bits_per_pixel) {
+ /* case 4: not supported by MGA1064 DAC */
+ case 8:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 16:
+ if (p->var.green.length == 5)
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ else
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 24:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ case 32:
+ hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+ break;
+ default:
+ return 1; /* unsupported depth */
+ }
+ }
+
+ DAC1064_global_init(PMINFO hw);
+ hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
+ hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+ hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+ hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
+ hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
+ return 0;
+}
+
+static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
+
+ DBG("DAC1064_init_2")
+
+ if (p->var.bits_per_pixel > 16) { /* 256 entries */
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ hw->DACpal[i * 3 + 0] = i;
+ hw->DACpal[i * 3 + 1] = i;
+ hw->DACpal[i * 3 + 2] = i;
+ }
+ } else if (p->var.bits_per_pixel > 8) {
+ if (p->var.green.length == 5) { /* 0..31, 128..159 */
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ /* with p15 == 0 */
+ hw->DACpal[i * 3 + 0] = i << 3;
+ hw->DACpal[i * 3 + 1] = i << 3;
+ hw->DACpal[i * 3 + 2] = i << 3;
+ /* with p15 == 1 */
+ hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+ hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+ hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+ }
+ } else {
+ int i;
+
+ for (i = 0; i < 64; i++) { /* 0..63 */
+ hw->DACpal[i * 3 + 0] = i << 3;
+ hw->DACpal[i * 3 + 1] = i << 2;
+ hw->DACpal[i * 3 + 2] = i << 3;
+ }
+ }
+ } else {
+ memset(hw->DACpal, 0, 768);
+ }
+ return 0;
+}
+
+static void DAC1064_restore_1(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
+ CRITFLAGS
+
+ DBG("DAC1064_restore_1")
+
+ CRITBEGIN
+
+ outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
+ outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
+ outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
+ if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
+ unsigned int i;
+
+ for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+ if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
+ outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
+ }
+ }
+
+ DAC1064_global_restore(PMINFO hw);
+
+ CRITEND
+};
+
+static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
+#ifdef DEBUG
+ unsigned int i;
+#endif
+
+ DBG("DAC1064_restore_2")
+
+ matrox_init_putc(PMINFO p, matroxfb_DAC1064_createcursor);
+#ifdef DEBUG
+ dprintk(KERN_DEBUG "DAC1064regs ");
+ for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+ dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
+ if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+ }
+ dprintk("\n" KERN_DEBUG "DAC1064clk ");
+ for (i = 0; i < 6; i++)
+ dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+ dprintk("\n");
+#endif
+}
+
+static int m1064_compute(void* outdev, struct my_timming* m, struct matrox_hw_state* hw) {
+#define minfo ((struct matrox_fb_info*)outdev)
+ DAC1064_setpclk(PMINFO hw, m->pixclock);
+#undef minfo
+ return 0;
+}
+
+static int m1064_program(void* outdev, const struct matrox_hw_state* hw) {
+#define minfo ((struct matrox_fb_info*)outdev)
+ int i;
+ int tmout;
+ CRITFLAGS
+
+ CRITBEGIN
+
+ for (i = 0; i < 3; i++)
+ outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
+ for (tmout = 500000; tmout; tmout--) {
+ if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+ break;
+ udelay(10);
+ };
+
+ CRITEND
+
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+
+#undef minfo
+ return 0;
+}
+
+static int m1064_start(void* outdev) {
+ /* nothing */
+ return 0;
+}
+
+static void m1064_incuse(void* outdev) {
+ /* nothing yet; MODULE_INC_USE in future... */
+}
+
+static void m1064_decuse(void* outdev) {
+ /* nothing yet; MODULE_DEC_USE in future... */
+}
+
+static int m1064_setmode(void* outdev, u_int32_t mode) {
+ if (mode != MATROXFB_OUTPUT_MODE_MONITOR)
+ return -EINVAL;
+ return 0;
+}
+
+static struct matrox_altout m1064 = {
+ m1064_compute,
+ m1064_program,
+ m1064_start,
+ m1064_incuse,
+ m1064_decuse,
+ m1064_setmode
+};
+
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
+
+ DBG("MGA1064_init")
+
+ if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
+ if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1;
+
+ hw->MiscOutReg = 0xCB;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->MiscOutReg &= ~0x40;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->MiscOutReg &= ~0x80;
+ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+ hw->CRTCEXT[3] |= 0x40;
+
+ if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
+
+ DBG("MGAG100_init")
+
+ if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
+ hw->MXoptionReg &= ~0x2000;
+ if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1;
+
+ hw->MiscOutReg = 0xEF;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->MiscOutReg &= ~0x40;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->MiscOutReg &= ~0x80;
+ if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+ hw->CRTCEXT[3] |= 0x40;
+
+ if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
+ return 0;
+}
+#endif /* G100 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
+
+ DBG("MGA1064_ramdac_init");
+
+ /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 14318;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 100;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+ ACCESS_FBINFO(features.pll.in_div_min) = 1;
+ ACCESS_FBINFO(features.pll.in_div_max) = 31;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
+ /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+ DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+/* BIOS environ */
+static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
+ /* G100 wants 0x10, G200 SGRAM does not care... */
+#if 0
+static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
+ int reg;
+ int selClk;
+ int clk;
+
+ DBG("MGAG100_progPixClock")
+
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
+ M1064_XPIXCLKCTRL_PLL_UP);
+ switch (flags & 3) {
+ case 0: reg = M1064_XPIXPLLAM; break;
+ case 1: reg = M1064_XPIXPLLBM; break;
+ default: reg = M1064_XPIXPLLCM; break;
+ }
+ outDAC1064(PMINFO reg++, m);
+ outDAC1064(PMINFO reg++, n);
+ outDAC1064(PMINFO reg, p);
+ selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+ /* there should be flags & 0x03 & case 0/1/else */
+ /* and we should first select source and after that we should wait for PLL */
+ /* and we are waiting for PLL with oscilator disabled... Is it right? */
+ switch (flags & 0x03) {
+ case 0x00: break;
+ case 0x01: selClk |= 4; break;
+ default: selClk |= 0x0C; break;
+ }
+ mga_outb(M_MISC_REG, selClk);
+ for (clk = 500000; clk; clk--) {
+ if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
+ break;
+ udelay(10);
+ };
+ if (!clk)
+ printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+ selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+ switch (flags & 0x0C) {
+ case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+ case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+ default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+ }
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
+ outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+static void MGAG100_setPixClock(CPMINFO int flags, int freq){
+ unsigned int m, n, p;
+
+ DBG("MGAG100_setPixClock")
+
+ DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
+ MGAG100_progPixClock(PMINFO flags, m, n, p);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
+ static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+ DBG("MGA1064_preinit")
+
+ /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+ ACCESS_FBINFO(capable.text) = 1;
+ ACCESS_FBINFO(capable.vxres) = vxres_mystique;
+ ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+ ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
+
+ ACCESS_FBINFO(primout) = &m1064;
+
+ if (ACCESS_FBINFO(devflags.noinit))
+ return 0; /* do not modify settings */
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x00094E20;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+ mga_outl(M_CTLWTST, 0x00000000);
+ udelay(200);
+ mga_outl(M_MACCESS, 0x00008000);
+ udelay(100);
+ mga_outl(M_MACCESS, 0x0000C000);
+ return 0;
+}
+
+static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
+
+ DBG("MGA1064_reset");
+
+ ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
+ if (ACCESS_FBINFO(devflags.hwcursor))
+ ACCESS_FBINFO(video.len_usable) -= 1024;
+ matroxfb_fastfont_init(MINFO);
+ MGA1064_ramdac_init(PMINFO hw);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
+ static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+ u_int32_t reg50;
+#if 0
+ u_int32_t q;
+#endif
+
+ DBG("MGAG100_preinit")
+
+ /* there are some instabilities if in_div > 19 && vco < 61000 */
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 27000;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 7;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 127;
+ ACCESS_FBINFO(features.pll.in_div_min) = 1;
+ ACCESS_FBINFO(features.pll.in_div_max) = 31;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
+ /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
+ ACCESS_FBINFO(capable.text) = 1;
+ ACCESS_FBINFO(capable.vxres) = vxres_g100;
+ ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
+ ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
+ ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
+
+ ACCESS_FBINFO(primout) = &m1064;
+
+ if (ACCESS_FBINFO(devflags.noinit))
+ return 0;
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x00078020;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, &reg50);
+ reg50 &= ~0x3000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
+
+ DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
+
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) {
+ hw->MXoptionReg |= 0x1080;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ mga_outl(M_CTLWTST, 0x00000300);
+ /* mga_outl(M_CTLWTST, 0x03258A31); */
+ udelay(100);
+ mga_outb(0x1C05, 0x00);
+ mga_outb(0x1C05, 0x80);
+ udelay(100);
+ mga_outb(0x1C05, 0x40);
+ mga_outb(0x1C05, 0xC0);
+ udelay(100);
+ reg50 &= ~0xFF;
+ reg50 |= 0x07;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
+ /* it should help with G100 */
+ mga_outb(M_GRAPHICS_INDEX, 6);
+ mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+ mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+ mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+ mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA);
+ mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55);
+ mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55);
+#if 0
+ if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) {
+ hw->MXoptionReg &= ~0x1000;
+ }
+#endif
+ } else {
+ hw->MXoptionReg |= 0x00000C00;
+ if (ACCESS_FBINFO(devflags.sgram))
+ hw->MXoptionReg |= 0x4000;
+ mga_outl(M_CTLWTST, 0x042450A1);
+ mga_outb(0x1E47, 0x00);
+ mga_outb(0x1E46, 0x00);
+ udelay(10);
+ mga_outb(0x1C05, 0x00);
+ mga_outb(0x1C05, 0x80);
+ udelay(100);
+ mga_outw(0x1E44, 0x0108);
+ }
+ hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ return 0;
+}
+
+static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
+ u_int8_t b;
+
+ DBG("MGAG100_reset")
+
+ ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
+ if (ACCESS_FBINFO(devflags.hwcursor))
+ ACCESS_FBINFO(video.len_usable) -= 1024;
+ matroxfb_fastfont_init(MINFO);
+
+ {
+#ifdef G100_BROKEN_IBM_82351
+ u_int32_t d;
+
+ find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+ pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+ if (b == ACCESS_FBINFO(pcidev)->bus->number) {
+ pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
+ pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
+ pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
+ pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
+ }
+#endif
+ if (!ACCESS_FBINFO(devflags.noinit)) {
+ if (x7AF4 & 8) {
+ hw->MXoptionReg |= 0x40;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ }
+ mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
+ }
+ }
+ DAC1064_setmclk(PMINFO hw, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
+ if (ACCESS_FBINFO(devflags.noinit))
+ return;
+ MGAG100_setPixClock(PMINFO 4, 25175);
+ MGAG100_setPixClock(PMINFO 5, 28322);
+ if (x7AF4 & 0x10) {
+ b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
+ outDAC1064(PMINFO M1064_XGENIODATA, b);
+ b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
+ outDAC1064(PMINFO M1064_XGENIOCTRL, b);
+ }
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+ CRITFLAGS
+
+ DBG("MGA1064_restore")
+
+ CRITBEGIN
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ mga_outb(M_IEN, 0x00);
+ mga_outb(M_CACHEFLUSH, 0x00);
+
+ CRITEND
+
+ DAC1064_restore_1(PMINFO hw, oldhw);
+ matroxfb_vgaHWrestore(PMINFO hw, oldhw);
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+ DAC1064_restore_2(PMINFO hw, oldhw, p);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+ CRITFLAGS
+
+ DBG("MGAG100_restore")
+
+ CRITBEGIN
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+ CRITEND
+
+ DAC1064_restore_1(PMINFO hw, oldhw);
+ matroxfb_vgaHWrestore(PMINFO hw, oldhw);
+#ifdef CONFIG_FB_MATROX_32MB
+ if (ACCESS_FBINFO(devflags.support32MB))
+ mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+ DAC1064_restore_2(PMINFO hw, oldhw, p);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+struct matrox_switch matrox_mystique = {
+ MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, DAC1064_selhwcursor
+};
+EXPORT_SYMBOL(matrox_mystique);
+#endif
+
+#ifdef CONFIG_FB_MATROX_G100
+struct matrox_switch matrox_G100 = {
+ MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, DAC1064_selhwcursor
+};
+EXPORT_SYMBOL(matrox_G100);
+#endif
+
+#ifdef NEED_DAC1064
+EXPORT_SYMBOL(DAC1064_global_init);
+EXPORT_SYMBOL(DAC1064_global_restore);
+#endif
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
new file mode 100644
index 000000000..4a8fdb801
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -0,0 +1,147 @@
+#ifndef __MATROXFB_DAC1064_H__
+#define __MATROXFB_DAC1064_H__
+
+/* make checkconfig does not walk through include tree */
+#include <linux/config.h>
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+extern struct matrox_switch matrox_mystique;
+#endif
+#ifdef CONFIG_FB_MATROX_G100
+extern struct matrox_switch matrox_G100;
+#endif
+#ifdef NEED_DAC1064
+void DAC1064_global_init(CPMINFO struct matrox_hw_state*);
+void DAC1064_global_restore(CPMINFO const struct matrox_hw_state*);
+#endif
+
+#define M1064_INDEX 0x00
+#define M1064_PALWRADD 0x00
+#define M1064_PALDATA 0x01
+#define M1064_PIXRDMSK 0x02
+#define M1064_PALRDADD 0x03
+#define M1064_X_DATAREG 0x0A
+#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */
+#define M1064_CURPOSXH 0x0D
+#define M1064_CURPOSYL 0x0E
+#define M1064_CURPOSYH 0x0F
+
+#define M1064_XCURADDL 0x04
+#define M1064_XCURADDH 0x05
+#define M1064_XCURCTRL 0x06
+#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
+#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
+#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
+#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
+#define M1064_XCURCOL0RED 0x08
+#define M1064_XCURCOL0GREEN 0x09
+#define M1064_XCURCOL0BLUE 0x0A
+#define M1064_XCURCOL1RED 0x0C
+#define M1064_XCURCOL1GREEN 0x0D
+#define M1064_XCURCOL1BLUE 0x0E
+#define M1064_XCURCOL2RED 0x10
+#define M1064_XCURCOL2GREEN 0x11
+#define M1064_XCURCOL2BLUE 0x12
+#define DAC1064_XVREFCTRL 0x18
+#define DAC1064_XVREFCTRL_INTERNAL 0x3F
+#define DAC1064_XVREFCTRL_EXTERNAL 0x00
+#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03
+#define M1064_XMULCTRL 0x19
+#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */
+#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */
+#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */
+#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */
+#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */
+#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */
+#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
+#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08
+#define M1064_XPIXCLKCTRL 0x1A
+#define M1064_XPIXCLKCTRL_SRC_PCI 0x00
+#define M1064_XPIXCLKCTRL_SRC_PLL 0x01
+#define M1064_XPIXCLKCTRL_SRC_EXT 0x02
+#define M1064_XPIXCLKCTRL_SRC_MASK 0x03
+#define M1064_XPIXCLKCTRL_EN 0x00
+#define M1064_XPIXCLKCTRL_DIS 0x04
+#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00
+#define M1064_XPIXCLKCTRL_PLL_UP 0x08
+#define M1064_XGENCTRL 0x1D
+#define M1064_XGENCTRL_VS_0 0x00
+#define M1064_XGENCTRL_VS_1 0x01
+#define M1064_XGENCTRL_ALPHA_DIS 0x00
+#define M1064_XGENCTRL_ALPHA_EN 0x02
+#define M1064_XGENCTRL_BLACK_0IRE 0x00
+#define M1064_XGENCTRL_BLACK_75IRE 0x10
+#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00
+#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20
+#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
+#define M1064_XMISCCTRL 0x1E
+#define M1064_XMISCCTRL_DAC_DIS 0x00
+#define M1064_XMISCCTRL_DAC_EN 0x01
+#define M1064_XMISCCTRL_MFC_VGA 0x00
+#define M1064_XMISCCTRL_MFC_MAFC 0x02
+#define M1064_XMISCCTRL_MFC_DIS 0x06
+#define G400_XMISCCTRL_MFC_MAFC 0x02
+#define G400_XMISCCTRL_MFC_PANELLINK 0x04
+#define G400_XMISCCTRL_MFC_DIS 0x06
+#define G400_XMISCCTRL_MFC_MASK 0x06
+#define M1064_XMISCCTRL_DAC_6BIT 0x00
+#define M1064_XMISCCTRL_DAC_8BIT 0x08
+#define M1064_XMISCCTRL_DAC_WIDTHMASK 0x08
+#define M1064_XMISCCTRL_LUT_DIS 0x00
+#define M1064_XMISCCTRL_LUT_EN 0x10
+#define G400_XMISCCTRL_VDO_MAFC12 0x00
+#define G400_XMISCCTRL_VDO_BYPASS656 0x40
+#define G400_XMISCCTRL_VDO_C2_MAFC12 0x80
+#define G400_XMISCCTRL_VDO_C2_BYPASS656 0xC0
+#define G400_XMISCCTRL_VDO_MASK 0xE0
+#define M1064_XGENIOCTRL 0x2A
+#define M1064_XGENIODATA 0x2B
+#define DAC1064_XSYSPLLM 0x2C
+#define DAC1064_XSYSPLLN 0x2D
+#define DAC1064_XSYSPLLP 0x2E
+#define DAC1064_XSYSPLLSTAT 0x2F
+#define M1064_XZOOMCTRL 0x38
+#define M1064_XZOOMCTRL_1 0x00
+#define M1064_XZOOMCTRL_2 0x01
+#define M1064_XZOOMCTRL_4 0x03
+#define M1064_XSENSETEST 0x3A
+#define M1064_XSENSETEST_BCOMP 0x01
+#define M1064_XSENSETEST_GCOMP 0x02
+#define M1064_XSENSETEST_RCOMP 0x04
+#define M1064_XSENSETEST_PDOWN 0x00
+#define M1064_XSENSETEST_PUP 0x80
+#define M1064_XCRCREML 0x3C
+#define M1064_XCRCREMH 0x3D
+#define M1064_XCRCBITSEL 0x3E
+#define M1064_XCOLKEYMASKL 0x40
+#define M1064_XCOLKEYMASKH 0x41
+#define M1064_XCOLKEYL 0x42
+#define M1064_XCOLKEYH 0x43
+#define M1064_XPIXPLLAM 0x44
+#define M1064_XPIXPLLAN 0x45
+#define M1064_XPIXPLLAP 0x46
+#define M1064_XPIXPLLBM 0x48
+#define M1064_XPIXPLLBN 0x49
+#define M1064_XPIXPLLBP 0x4A
+#define M1064_XPIXPLLCM 0x4C
+#define M1064_XPIXPLLCN 0x4D
+#define M1064_XPIXPLLCP 0x4E
+#define M1064_XPIXPLLSTAT 0x4F
+
+enum POS1064 {
+ POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
+ POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
+ POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE,
+ POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE,
+ POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL,
+ POS1064_XMISCCTRL,
+ POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
+ POS1064_XCRCBITSEL,
+ POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH };
+
+
+#endif /* __MATROXFB_DAC1064_H__ */
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
new file mode 100644
index 000000000..6bc3cea64
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -0,0 +1,862 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.21 2000/01/09
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <trini@kernel.crashing.org>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ * "Bibek Sahu" <scorpio@dodds.net>
+ * Access device through readb|w|l and write b|w|l
+ * Extensive debugging stuff
+ *
+ * "Daniel Haun" <haund@usa.net>
+ * Testing, hardware cursor fixes
+ *
+ * "Scott Wood" <sawst46+@pitt.edu>
+ * Fixes
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * PPC betatesting, PPC support, backward compatibility
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * "Thomas Pornin" <pornin@bolet.ens.fr>
+ * Alpha betatesting
+ *
+ * "Pieter van Leuven" <pvl@iae.nl>
+ * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ * G100 testing
+ *
+ * "H. Peter Arvin" <hpa@transmeta.com>
+ * Ideas
+ *
+ * "Cort Dougan" <cort@cs.nmt.edu>
+ * CHRP fixes and PReP cleanup
+ *
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not verify included files... */
+#include <linux/config.h>
+
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define outTi3026 matroxfb_DAC_out
+#define inTi3026 matroxfb_DAC_in
+
+#define TVP3026_INDEX 0x00
+#define TVP3026_PALWRADD 0x00
+#define TVP3026_PALDATA 0x01
+#define TVP3026_PIXRDMSK 0x02
+#define TVP3026_PALRDADD 0x03
+#define TVP3026_CURCOLWRADD 0x04
+#define TVP3026_CLOVERSCAN 0x00
+#define TVP3026_CLCOLOR0 0x01
+#define TVP3026_CLCOLOR1 0x02
+#define TVP3026_CLCOLOR2 0x03
+#define TVP3026_CURCOLDATA 0x05
+#define TVP3026_CURCOLRDADD 0x07
+#define TVP3026_CURCTRL 0x09
+#define TVP3026_X_DATAREG 0x0A
+#define TVP3026_CURRAMDATA 0x0B
+#define TVP3026_CURPOSXL 0x0C
+#define TVP3026_CURPOSXH 0x0D
+#define TVP3026_CURPOSYL 0x0E
+#define TVP3026_CURPOSYH 0x0F
+
+#define TVP3026_XSILICONREV 0x01
+#define TVP3026_XCURCTRL 0x06
+#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
+#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
+#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
+#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
+#define TVP3026_XCURCTRL_BLANK2048 0x00
+#define TVP3026_XCURCTRL_BLANK4096 0x10
+#define TVP3026_XCURCTRL_INTERLACED 0x20
+#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */
+#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */
+#define TVP3026_XCURCTRL_INDIRECT 0x00
+#define TVP3026_XCURCTRL_DIRECT 0x80
+#define TVP3026_XLATCHCTRL 0x0F
+#define TVP3026_XLATCHCTRL_1_1 0x06
+#define TVP3026_XLATCHCTRL_2_1 0x07
+#define TVP3026_XLATCHCTRL_4_1 0x06
+#define TVP3026_XLATCHCTRL_8_1 0x06
+#define TVP3026_XLATCHCTRL_16_1 0x06
+#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */
+#define TVP3026A_XLATCHCTRL_8_3 0x07
+#define TVP3026B_XLATCHCTRL_4_3 0x08
+#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */
+#define TVP3026_XTRUECOLORCTRL 0x18
+#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00
+#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20
+#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80
+#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */
+#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00
+#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17
+#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06
+#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07
+#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05
+#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04
+#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03
+#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01
+#define TVP3026_XMUXCTRL 0x19
+#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */
+#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */
+#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */
+#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */
+#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */
+#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */
+#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48
+#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50
+#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58
+#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL 0x1A
+#define TVP3026_XCLKCTRL_DIV1 0x00
+#define TVP3026_XCLKCTRL_DIV2 0x10
+#define TVP3026_XCLKCTRL_DIV4 0x20
+#define TVP3026_XCLKCTRL_DIV8 0x30
+#define TVP3026_XCLKCTRL_DIV16 0x40
+#define TVP3026_XCLKCTRL_DIV32 0x50
+#define TVP3026_XCLKCTRL_DIV64 0x60
+#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70
+#define TVP3026_XCLKCTRL_SRC_CLK0 0x00
+#define TVP3026_XCLKCTRL_SRC_CLK1 0x01
+#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/
+#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */
+#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */
+#define TVP3026_XCLKCTRL_SRC_PLL 0x05
+#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */
+#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE 0x1C
+#define TVP3026_XGENCTRL 0x1D
+#define TVP3026_XGENCTRL_HSYNC_POS 0x00
+#define TVP3026_XGENCTRL_HSYNC_NEG 0x01
+#define TVP3026_XGENCTRL_VSYNC_POS 0x00
+#define TVP3026_XGENCTRL_VSYNC_NEG 0x02
+#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08
+#define TVP3026_XGENCTRL_BLACK_0IRE 0x00
+#define TVP3026_XGENCTRL_BLACK_75IRE 0x10
+#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00
+#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20
+#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00
+#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40
+#define TVP3026_XMISCCTRL 0x1E
+#define TVP3026_XMISCCTRL_DAC_PUP 0x00
+#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01
+#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */
+#define TVP3026_XMISCCTRL_DAC_6BIT 0x04
+#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C
+#define TVP3026_XMISCCTRL_PSEL_DIS 0x00
+#define TVP3026_XMISCCTRL_PSEL_EN 0x10
+#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
+#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL 0x2A
+#define TVP3026_XGENIODATA 0x2B
+#define TVP3026_XPLLADDR 0x2C
+#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define TVP3026_XPLLDATA_N 0x00
+#define TVP3026_XPLLDATA_M 0x01
+#define TVP3026_XPLLDATA_P 0x02
+#define TVP3026_XPLLDATA_STAT 0x03
+#define TVP3026_XPIXPLLDATA 0x2D
+#define TVP3026_XMEMPLLDATA 0x2E
+#define TVP3026_XLOOPPLLDATA 0x2F
+#define TVP3026_XCOLKEYOVRMIN 0x30
+#define TVP3026_XCOLKEYOVRMAX 0x31
+#define TVP3026_XCOLKEYREDMIN 0x32
+#define TVP3026_XCOLKEYREDMAX 0x33
+#define TVP3026_XCOLKEYGREENMIN 0x34
+#define TVP3026_XCOLKEYGREENMAX 0x35
+#define TVP3026_XCOLKEYBLUEMIN 0x36
+#define TVP3026_XCOLKEYBLUEMAX 0x37
+#define TVP3026_XCOLKEYCTRL 0x38
+#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01
+#define TVP3026_XCOLKEYCTRL_RED_EN 0x02
+#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08
+#define TVP3026_XCOLKEYCTRL_NEGATE 0x10
+#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00
+#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20
+#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40
+#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60
+#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80
+#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
+#define TVP3026_XMEMPLLCTRL 0x39
+#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08
+#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */
+#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */
+#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00
+#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20
+#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST 0x3A
+#define TVP3026_XTESTMODEDATA 0x3B
+#define TVP3026_XCRCREML 0x3C
+#define TVP3026_XCRCREMH 0x3D
+#define TVP3026_XCRCBITSEL 0x3E
+#define TVP3026_XID 0x3F
+
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
+ TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
+ TVP3026_XPALETTEPAGE,
+ TVP3026_XGENCTRL,
+ TVP3026_XMISCCTRL,
+ TVP3026_XGENIOCTRL,
+ TVP3026_XGENIODATA,
+ TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+ TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+ TVP3026_XCOLKEYCTRL,
+ TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL 0
+#define POS3026_XTRUECOLORCTRL 1
+#define POS3026_XMUXCTRL 2
+#define POS3026_XCLKCTRL 3
+#define POS3026_XGENCTRL 5
+#define POS3026_XMISCCTRL 6
+#define POS3026_XMEMPLLCTRL 18
+#define POS3026_XCURCTRL 20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+ 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
+ 0x00,
+ TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
+ TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
+ 0x00,
+ 0x1E,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ TVP3026_XCOLKEYCTRL_ZOOM1,
+ 0x00, 0x00, TVP3026_XCURCTRL_DIS };
+
+static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
+#define minfo ((struct matrox_fb_info*)ptr)
+ matroxfb_DAC_lock();
+ outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
+ ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
+ add_timer(&ACCESS_FBINFO(cursor.timer));
+ matroxfb_DAC_unlock();
+#undef minfo
+}
+
+static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) {
+ unsigned long flags;
+ u_int32_t xline;
+ unsigned int i;
+ unsigned int to;
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ DBG("matroxfb_ti3026_createcursor");
+
+ matroxfb_createcursorshape(PMINFO p, p->var.vmode);
+
+ xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
+ matroxfb_DAC_lock_irqsave(flags);
+ mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
+ to = ACCESS_FBINFO(cursor.u);
+ for (i = 0; i < to; i++) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ }
+ to = ACCESS_FBINFO(cursor.d);
+ for (; i < to; i++) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ }
+ for (; i < 64; i++) {
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
+ }
+ for (i = 0; i < 512; i++)
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
+ matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
+ unsigned long flags;
+ MINFO_FROM_DISP(p);
+
+ DBG("matroxfb_ti3026_cursor")
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ if (mode == CM_ERASE) {
+ if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+ matroxfb_DAC_lock_irqsave(flags);
+ ACCESS_FBINFO(cursor.state) = CM_ERASE;
+ del_timer(&ACCESS_FBINFO(cursor.timer));
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
+ matroxfb_DAC_unlock_irqrestore(flags);
+ }
+ return;
+ }
+ if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
+ matroxfb_ti3026_createcursor(PMINFO p);
+ x *= fontwidth(p);
+ y *= fontheight(p);
+ y -= p->var.yoffset;
+ if (p->var.vmode & FB_VMODE_DOUBLE)
+ y *= 2;
+ matroxfb_DAC_lock_irqsave(flags);
+ if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
+ ACCESS_FBINFO(cursor.redraw) = 0;
+ ACCESS_FBINFO(cursor.x) = x;
+ ACCESS_FBINFO(cursor.y) = y;
+ x += 64;
+ y += 64;
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
+ mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
+ }
+ ACCESS_FBINFO(cursor.state) = CM_DRAW;
+ if (ACCESS_FBINFO(devflags.blink))
+ mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
+ outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA);
+ matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
+
+ DBG("matrox_ti3026_setfont");
+
+ if (p && p->conp)
+ matroxfb_ti3026_createcursor(PMXINFO(p) p);
+ return 0;
+}
+
+static int matroxfb_ti3026_selhwcursor(WPMINFO struct display* p) {
+ ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
+ ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
+ return 0;
+}
+
+static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
+ unsigned int fvco;
+ unsigned int lin, lfeed, lpost;
+
+ DBG("Ti3026_calcclock")
+
+ fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
+ fvco >>= (*post = lpost);
+ *in = 64 - lin;
+ *feed = 64 - lfeed;
+ return fvco;
+}
+
+static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, struct display* p) {
+ unsigned int f_pll;
+ unsigned int pixfeed, pixin, pixpost;
+
+ DBG("Ti3026_setpclk")
+
+ f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
+
+ hw->DACclk[0] = pixin | 0xC0;
+ hw->DACclk[1] = pixfeed;
+ hw->DACclk[2] = pixpost | 0xB0;
+
+ if (p->type == FB_TYPE_TEXT) {
+ hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL;
+ hw->DACclk[3] = 0xFD;
+ hw->DACclk[4] = 0x3D;
+ hw->DACclk[5] = 0x70;
+ } else {
+ unsigned int loopfeed, loopin, looppost, loopdiv, z;
+ unsigned int Bpp;
+
+ Bpp = ACCESS_FBINFO(curr.final_bppShift);
+
+ if (p->var.bits_per_pixel == 24) {
+ loopfeed = 3; /* set lm to any possible value */
+ loopin = 3 * 32 / Bpp;
+ } else {
+ loopfeed = 4;
+ loopin = 4 * 32 / Bpp;
+ }
+ z = (110000 * loopin) / (f_pll * loopfeed);
+ loopdiv = 0; /* div 2 */
+ if (z < 2)
+ looppost = 0;
+ else if (z < 4)
+ looppost = 1;
+ else if (z < 8)
+ looppost = 2;
+ else {
+ looppost = 3;
+ loopdiv = z/16;
+ }
+ if (p->var.bits_per_pixel == 24) {
+ hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+ hw->DACclk[4] = (65 - loopfeed) | 0x80;
+ if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
+ if (isInterleave(MINFO))
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+ else {
+ hw->DACclk[4] &= ~0xC0;
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+ }
+ } else {
+ if (isInterleave(MINFO))
+ ; /* default... */
+ else {
+ hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
+ }
+ }
+ hw->DACclk[5] = looppost | 0xF8;
+ if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
+ hw->DACclk[5] ^= 0x40;
+ } else {
+ hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+ hw->DACclk[4] = 65 - loopfeed;
+ hw->DACclk[5] = looppost | 0xF0;
+ }
+ hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+ }
+ return 0;
+}
+
+static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
+ u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+
+ DBG("Ti3026_init")
+
+ memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
+ if (p->type == FB_TYPE_TEXT) {
+ hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+ hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL |
+ TVP3026_XCLKCTRL_DIV4;
+ hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+ } else {
+ switch (p->var.bits_per_pixel) {
+ case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+ hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+ break;
+ case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+ hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+ break;
+ case 16:
+ /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+ break;
+ case 24:
+ /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+ hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+ break;
+ case 32:
+ /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
+ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+ break;
+ default:
+ return 1; /* TODO: failed */
+ }
+ }
+ if (matroxfb_vgaHWinit(PMINFO hw, m, p)) return 1;
+
+ /* set SYNC */
+ hw->MiscOutReg = 0xCB;
+ if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+ if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+ if (m->sync & FB_SYNC_ON_GREEN)
+ hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+ /* set DELAY */
+ if (ACCESS_FBINFO(video.len) < 0x400000)
+ hw->CRTCEXT[3] |= 0x08;
+ else if (ACCESS_FBINFO(video.len) > 0x400000)
+ hw->CRTCEXT[3] |= 0x10;
+
+ /* set HWCURSOR */
+ if (m->interlaced) {
+ hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+ }
+ if (m->HTotal >= 1536)
+ hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
+
+ /* set interleaving */
+ hw->MXoptionReg &= ~0x00001000;
+ if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
+
+ /* set DAC */
+ Ti3026_setpclk(PMINFO hw, m->pixclock, p);
+ return 0;
+}
+
+static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
+ unsigned int f_pll;
+ unsigned int pclk_m, pclk_n, pclk_p;
+ unsigned int mclk_m, mclk_n, mclk_p;
+ unsigned int rfhcnt, mclk_ctl;
+ int tmout;
+
+ DBG("ti3026_setMCLK")
+
+ f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
+
+ /* save pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
+ pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+
+ /* stop pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ /* set pclk to new mclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ };
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+ /* output pclk on mclk pin */
+ mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+ /* stop MCLK */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
+
+ /* set mclk to new freq */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
+ outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+ f_pll = f_pll * 333 / (10000 << mclk_p);
+ if (isMilleniumII(MINFO)) {
+ rfhcnt = (f_pll - 128) / 256;
+ if (rfhcnt > 15)
+ rfhcnt = 15;
+ } else {
+ rfhcnt = (f_pll - 64) / 128;
+ if (rfhcnt > 15)
+ rfhcnt = 0;
+ }
+ hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ /* output MCLK to MCLK pin */
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+ /* stop PCLK */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ /* restore pclk */
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
+
+ /* wait for PLL to lock */
+ for (tmout = 500000; tmout; tmout--) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
+
+ DBG("ti3026_ramdac_init")
+
+ ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
+ ACCESS_FBINFO(features.pll.ref_freq) = 114545;
+ ACCESS_FBINFO(features.pll.feed_div_min) = 2;
+ ACCESS_FBINFO(features.pll.feed_div_max) = 24;
+ ACCESS_FBINFO(features.pll.in_div_min) = 2;
+ ACCESS_FBINFO(features.pll.in_div_max) = 63;
+ ACCESS_FBINFO(features.pll.post_shift_max) = 3;
+ if (ACCESS_FBINFO(devflags.noinit))
+ return;
+ ti3026_setMCLK(PMINFO hw, 60000);
+}
+
+static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
+ int i;
+ CRITFLAGS
+
+ DBG("Ti3026_restore")
+
+#ifdef DEBUG
+ dprintk(KERN_INFO "EXTVGA regs: ");
+ for (i = 0; i < 6; i++)
+ dprintk("%02X:", hw->CRTCEXT[i]);
+ dprintk("\n");
+#endif
+
+ CRITBEGIN
+
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ CRITEND
+
+ matroxfb_vgaHWrestore(PMINFO hw, oldhw);
+
+ CRITBEGIN
+
+ for (i = 0; i < 6; i++)
+ mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+ for (i = 0; i < 21; i++) {
+ outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
+ }
+ if (oldhw) {
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+ oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
+ oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+ oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
+ oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
+ }
+ CRITEND
+ if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
+ /* agrhh... setting up PLL is very slow on Millennium... */
+ /* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
+ /* Maybe even we should call schedule() ? */
+
+ CRITBEGIN
+ outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
+
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+ for (i = 0; i < 3; i++)
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+ /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
+ if (hw->MiscOutReg & 0x08) {
+ int tmout;
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+ for (tmout = 500000; tmout; --tmout) {
+ if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+
+ CRITEND
+
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+ else
+ dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+ CRITBEGIN
+ }
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
+ for (i = 3; i < 6; i++)
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+ CRITEND
+ if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
+ int tmout;
+
+ CRITBEGIN
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
+ for (tmout = 500000; tmout; --tmout) {
+ if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
+ break;
+ udelay(10);
+ }
+ CRITEND
+ if (!tmout)
+ printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+ else
+ dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+ }
+ }
+ matrox_init_putc(PMINFO p, matroxfb_ti3026_createcursor);
+
+#ifdef DEBUG
+ dprintk(KERN_DEBUG "3026DACregs ");
+ for (i = 0; i < 21; i++) {
+ dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+ if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
+ }
+ dprintk("\n" KERN_DEBUG "DACclk ");
+ for (i = 0; i < 6; i++)
+ dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+ dprintk("\n");
+#endif
+}
+
+static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
+
+ DBG("Ti3026_reset")
+
+ matroxfb_fastfont_init(MINFO);
+
+ ti3026_ramdac_init(PMINFO hw);
+}
+
+static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
+ static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
+ 1024, 1152, 1280, 1600, 1664, 1920,
+ 2048, 0};
+ static const int vxres_mill1[] = { 640, 768, 800, 960,
+ 1024, 1152, 1280, 1600, 1920,
+ 2048, 0};
+
+ DBG("Ti3026_preinit")
+
+ ACCESS_FBINFO(millenium) = 1;
+ ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
+ ACCESS_FBINFO(capable.cfb4) = 1;
+ ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
+ ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
+ ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
+
+ if (ACCESS_FBINFO(devflags.noinit))
+ return 0;
+ /* preserve VGA I/O, BIOS and PPC */
+ hw->MXoptionReg &= 0xC0000100;
+ hw->MXoptionReg |= 0x002C0000;
+ if (ACCESS_FBINFO(devflags.novga))
+ hw->MXoptionReg &= ~0x00000100;
+ if (ACCESS_FBINFO(devflags.nobios))
+ hw->MXoptionReg &= ~0x40000000;
+ if (ACCESS_FBINFO(devflags.nopciretry))
+ hw->MXoptionReg |= 0x20000000;
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+
+ ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
+
+ outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+ outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+ outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+
+ outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
+ outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
+ outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
+
+ mga_outb(M_MISC_REG, 0x67);
+
+ outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+ mga_outl(M_RESET, 1);
+ udelay(250);
+ mga_outl(M_RESET, 0);
+ udelay(250);
+ mga_outl(M_MACCESS, 0x00008000);
+ udelay(10);
+ return 0;
+}
+
+struct matrox_switch matrox_millennium = {
+ Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore, matroxfb_ti3026_selhwcursor
+};
+EXPORT_SYMBOL(matrox_millennium);
+#endif
diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h
new file mode 100644
index 000000000..541933d7e
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_Ti3026.h
@@ -0,0 +1,13 @@
+#ifndef __MATROXFB_TI3026_H__
+#define __MATROXFB_TI3026_H__
+
+/* make checkconfig does not walk through whole include tree */
+#include <linux/config.h>
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+extern struct matrox_switch matrox_millennium;
+#endif
+
+#endif /* __MATROXFB_TI3026_H__ */
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
new file mode 100644
index 000000000..2eb2cfd85
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -0,0 +1,1212 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.21 2000/01/09
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <trini@kernel.crashing.org>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ * "Bibek Sahu" <scorpio@dodds.net>
+ * Access device through readb|w|l and write b|w|l
+ * Extensive debugging stuff
+ *
+ * "Daniel Haun" <haund@usa.net>
+ * Testing, hardware cursor fixes
+ *
+ * "Scott Wood" <sawst46+@pitt.edu>
+ * Fixes
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * PPC betatesting, PPC support, backward compatibility
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * "Thomas Pornin" <pornin@bolet.ens.fr>
+ * Alpha betatesting
+ *
+ * "Pieter van Leuven" <pvl@iae.nl>
+ * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ * G100 testing
+ *
+ * "H. Peter Arvin" <hpa@transmeta.com>
+ * Ideas
+ *
+ * "Cort Dougan" <cort@cs.nmt.edu>
+ * CHRP fixes and PReP cleanup
+ *
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+
+#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
+void matrox_cfbX_init(WPMINFO struct display* p) {
+ u_int32_t maccess;
+ u_int32_t mpitch;
+ u_int32_t mopmode;
+
+ DBG("matrox_cfbX_init")
+
+ mpitch = p->var.xres_virtual;
+
+ if (p->type == FB_TYPE_TEXT) {
+ maccess = 0x00000000;
+ mpitch = (mpitch >> 4) | 0x8000; /* set something */
+ mopmode = M_OPMODE_8BPP;
+ } else {
+ switch (p->var.bits_per_pixel) {
+ case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
+ mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+ mopmode = M_OPMODE_4BPP;
+ break;
+ case 8: maccess = 0x00000000;
+ mopmode = M_OPMODE_8BPP;
+ break;
+ case 16: if (p->var.green.length == 5)
+ maccess = 0xC0000001;
+ else
+ maccess = 0x40000001;
+ mopmode = M_OPMODE_16BPP;
+ break;
+ case 24: maccess = 0x00000003;
+ mopmode = M_OPMODE_24BPP;
+ break;
+ case 32: maccess = 0x00000002;
+ mopmode = M_OPMODE_32BPP;
+ break;
+ default: maccess = 0x00000000;
+ mopmode = 0x00000000;
+ break; /* turn off acceleration!!! */
+ }
+ }
+ mga_fifo(8);
+ mga_outl(M_PITCH, mpitch);
+ mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
+ if (ACCESS_FBINFO(capable.plnwt))
+ mga_outl(M_PLNWT, -1);
+ mga_outl(M_OPMODE, mopmode);
+ mga_outl(M_CXBNDRY, 0xFFFF0000);
+ mga_outl(M_YTOP, 0);
+ mga_outl(M_YBOT, 0x01FFFFFF);
+ mga_outl(M_MACCESS, maccess);
+ ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+ if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
+ ACCESS_FBINFO(accel.m_opmode) = mopmode;
+}
+
+static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+ int pixx = p->var.xres_virtual, start, end;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG("matrox_cfbX_bmove")
+
+ CRITBEGIN
+
+ sx *= fontwidth(p);
+ dx *= fontwidth(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+ mga_fifo(2);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+ M_DWG_BFCOL | M_DWG_REPLACE);
+ mga_outl(M_AR5, pixx);
+ width--;
+ start = sy*pixx+sx+curr_ydstorg(MINFO);
+ end = start+width;
+ } else {
+ mga_fifo(3);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+ mga_outl(M_SGN, 5);
+ mga_outl(M_AR5, -pixx);
+ width--;
+ end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+ start = end+width;
+ dy += height-1;
+ }
+ mga_fifo(4);
+ mga_outl(M_AR0, end);
+ mga_outl(M_AR3, start);
+ mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+ mga_ydstlen(dy, height);
+ WaitTillIdle();
+
+ CRITEND
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
+ int pixx, start, end;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+ /* both (sx or dx or width) and fontwidth() are odd, so their multiply is
+ also odd, that means that we cannot use acceleration */
+
+ DBG("matrox_cfb4_bmove")
+
+ CRITBEGIN
+
+ if ((sx | dx | width) & fontwidth(p) & 1) {
+ fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
+ return;
+ }
+ sx *= fontwidth(p);
+ dx *= fontwidth(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+ sy *= fontheight(p);
+ dy *= fontheight(p);
+ pixx = p->var.xres_virtual >> 1;
+ sx >>= 1;
+ dx >>= 1;
+ width >>= 1;
+ if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+ mga_fifo(2);
+ mga_outl(M_AR5, pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+ M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ start = sy*pixx+sx+curr_ydstorg(MINFO);
+ end = start+width;
+ } else {
+ mga_fifo(3);
+ mga_outl(M_SGN, 5);
+ mga_outl(M_AR5, -pixx);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+ width--;
+ end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
+ start = end+width;
+ dy += height-1;
+ }
+ mga_fifo(5);
+ mga_outl(M_AR0, end);
+ mga_outl(M_AR3, start);
+ mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+ mga_outl(M_YDST, dy*pixx >> 5);
+ mga_outl(M_LEN | M_EXEC, height);
+ WaitTillIdle();
+
+ CRITEND
+}
+#endif
+
+static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height,
+ int width) {
+ CRITFLAGS
+
+ DBG("matroxfb_accel_clear")
+
+ CRITBEGIN
+
+ mga_fifo(5);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
+ mga_outl(M_FCOL, color);
+ mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+ mga_ydstlen(sy, height);
+ WaitTillIdle();
+
+ CRITEND
+}
+
+static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
+
+ DBG("matrox_cfbX_clear")
+
+ matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
+ height * fontheight(p), width * fontwidth(p));
+}
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+ int whattodo;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG("matrox_cfb4_clear")
+
+ CRITBEGIN
+
+ whattodo = 0;
+ bgx = attr_bgcol_ec(p, conp);
+ bgx |= bgx << 4;
+ bgx |= bgx << 8;
+ bgx |= bgx << 16;
+ sy *= fontheight(p);
+ sx *= fontwidth(p);
+ height *= fontheight(p);
+ width *= fontwidth(p);
+ if (sx & 1) {
+ sx ++;
+ if (!width) return;
+ width --;
+ whattodo = 1;
+ }
+ if (width & 1) {
+ whattodo |= 2;
+ }
+ width >>= 1;
+ sx >>= 1;
+ if (width) {
+ mga_fifo(5);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
+ mga_outl(M_FCOL, bgx);
+ mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+ mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
+ mga_outl(M_LEN | M_EXEC, height);
+ WaitTillIdle();
+ }
+ if (whattodo) {
+ u_int32_t step = p->var.xres_virtual >> 1;
+ vaddr_t vbase = ACCESS_FBINFO(video.vbase);
+ if (whattodo & 1) {
+ unsigned int uaddr = sy * step + sx - 1;
+ u_int32_t loop;
+ u_int8_t bgx2 = bgx & 0xF0;
+ for (loop = height; loop > 0; loop --) {
+ mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
+ uaddr += step;
+ }
+ }
+ if (whattodo & 2) {
+ unsigned int uaddr = sy * step + sx + width;
+ u_int32_t loop;
+ u_int8_t bgx2 = bgx & 0x0F;
+ for (loop = height; loop > 0; loop --) {
+ mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
+ uaddr += step;
+ }
+ }
+ }
+
+ CRITEND
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ DBG("matrox_cfb8_clear")
+
+ bgx = attr_bgcol_ec(p, conp);
+ bgx |= bgx << 8;
+ bgx |= bgx << 16;
+ matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ DBG("matrox_cfb16_clear")
+
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
+ u_int32_t bgx;
+
+ DBG("matrox_cfb32_clear")
+
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ matrox_cfbX_clear(bgx, p, sy, sx, height, width);
+}
+#endif
+
+static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
+ unsigned int charcell;
+ unsigned int ar3;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ charcell = fontwidth(p) * fontheight(p);
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ CRITBEGIN
+
+ mga_fifo(8);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
+ ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
+ mga_outl(M_AR3, ar3);
+ mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
+ mga_ydstlen(yy, fontheight(p));
+ WaitTillIdle();
+
+ CRITEND
+}
+
+static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
+ u_int32_t ar0;
+ u_int32_t step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matrox_cfbX_putc");
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ CRITBEGIN
+
+#ifdef __BIG_ENDIAN
+ WaitTillIdle();
+ mga_outl(M_OPMODE, M_OPMODE_8BPP);
+#else
+ mga_fifo(7);
+#endif
+ ar0 = fontwidth(p) - 1;
+ mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
+ if (fontwidth(p) <= 8)
+ step = 1;
+ else if (fontwidth(p) <= 16)
+ step = 2;
+ else
+ step = 4;
+ if (fontwidth(p) == step << 3) {
+ size_t charcell = fontheight(p)*step;
+ /* TODO: Align charcell to 4B for BE */
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
+ mga_ydstlen(yy, fontheight(p));
+ mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
+ } else {
+ u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
+ int i;
+
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ mga_outl(M_AR5, 0);
+ mga_outl(M_AR3, 0);
+ mga_outl(M_AR0, ar0);
+ mga_ydstlen(yy, fontheight(p));
+
+ switch (step) {
+ case 1:
+ for (i = fontheight(p); i > 0; i--) {
+#ifdef __LITTLE_ENDIAN
+ mga_outl(0, *chardata++);
+#else
+ mga_outl(0, (*chardata++) << 24);
+#endif
+ }
+ break;
+ case 2:
+ for (i = fontheight(p); i > 0; i--) {
+#ifdef __LITTLE_ENDIAN
+ mga_outl(0, *(u_int16_t*)chardata);
+#else
+ mga_outl(0, (*(u_int16_t*)chardata) << 16);
+#endif
+ chardata += 2;
+ }
+ break;
+ case 4:
+ mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4);
+ break;
+ }
+ }
+ WaitTillIdle();
+#ifdef __BIG_ENDIAN
+ mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+#endif
+ CRITEND
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb8_putc");
+
+ fgx = attr_fgcol(p, c);
+ bgx = attr_bgcol(p, c);
+ fgx |= (fgx << 8);
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+ ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb16_putc");
+
+ fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 16);
+ ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb32_putc");
+
+ fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
+ ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
+}
+#endif
+
+static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ unsigned int charcell;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ charcell = fontwidth(p) * fontheight(p);
+
+ CRITBEGIN
+
+ mga_fifo(3);
+ mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ while (count--) {
+ u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell;
+
+ mga_fifo(4);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
+ mga_outl(M_AR3, ar3);
+ mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
+ mga_ydstlen(yy, fontheight(p));
+ xx += fontwidth(p);
+ }
+ WaitTillIdle();
+
+ CRITEND
+}
+
+static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t step;
+ u_int32_t ydstlen;
+ u_int32_t xlen;
+ u_int32_t ar0;
+ u_int32_t charcell;
+ u_int32_t fxbndry;
+ vaddr_t mmio;
+ int easy;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfbX_putcs");
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ if (fontwidth(p) <= 8)
+ step = 1;
+ else if (fontwidth(p) <= 16)
+ step = 2;
+ else
+ step = 4;
+ charcell = fontheight(p)*step;
+ xlen = (charcell + 3) & ~3;
+ ydstlen = (yy << 16) | fontheight(p);
+ if (fontwidth(p) == step << 3) {
+ ar0 = fontheight(p)*fontwidth(p) - 1;
+ easy = 1;
+ } else {
+ ar0 = fontwidth(p) - 1;
+ easy = 0;
+ }
+
+ CRITBEGIN
+
+#ifdef __BIG_ENDIAN
+ WaitTillIdle();
+ mga_outl(M_OPMODE, M_OPMODE_8BPP);
+#else
+ mga_fifo(3);
+#endif
+ if (easy)
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+ else
+ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
+ mga_outl(M_FCOL, fgx);
+ mga_outl(M_BCOL, bgx);
+ fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
+ mmio = ACCESS_FBINFO(mmio.vbase);
+ while (count--) {
+ u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
+
+ mga_fifo(6);
+ mga_writel(mmio, M_FXBNDRY, fxbndry);
+ mga_writel(mmio, M_AR0, ar0);
+ mga_writel(mmio, M_AR3, 0);
+ if (easy) {
+ mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+ mga_memcpy_toio(mmio, 0, chardata, xlen);
+ } else {
+ mga_writel(mmio, M_AR5, 0);
+ mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+ switch (step) {
+ case 1: {
+ u_int8_t* charend = chardata + charcell;
+ for (; chardata != charend; chardata++) {
+#ifdef __LITTLE_ENDIAN
+ mga_writel(mmio, 0, *chardata);
+#else
+ mga_writel(mmio, 0, (*chardata) << 24);
+#endif
+ }
+ }
+ break;
+ case 2: {
+ u_int8_t* charend = chardata + charcell;
+ for (; chardata != charend; chardata += 2) {
+#ifdef __LITTLE_ENDIAN
+ mga_writel(mmio, 0, *(u_int16_t*)chardata);
+#else
+ mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16);
+#endif
+ }
+ }
+ break;
+ default:
+ mga_memcpy_toio(mmio, 0, chardata, charcell);
+ break;
+ }
+ }
+ fxbndry += fontwidth(p) + (fontwidth(p) << 16);
+ }
+ WaitTillIdle();
+#ifdef __BIG_ENDIAN
+ mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+#endif
+ CRITEND
+}
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb8_putcs");
+
+ fgx = attr_fgcol(p, scr_readw(s));
+ bgx = attr_bgcol(p, scr_readw(s));
+ fgx |= (fgx << 8);
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 8);
+ bgx |= (bgx << 16);
+ ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb16_putcs");
+
+ fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+ fgx |= (fgx << 16);
+ bgx |= (bgx << 16);
+ ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
+static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
+ u_int32_t fgx, bgx;
+ MINFO_FROM_DISP(p);
+
+ DBG_HEAVY("matroxfb_cfb32_putcs");
+
+ fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
+ ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
+}
+#endif
+
+#ifdef FBCON_HAS_CFB4
+static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG_LOOP("matroxfb_cfb4_revc");
+
+ if (fontwidth(p) & 1) {
+ fbcon_cfb4_revc(p, xx, yy);
+ return;
+ }
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+ xx |= (xx + fontwidth(p)) << 16;
+ xx >>= 1;
+
+ CRITBEGIN
+
+ mga_fifo(5);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0xFFFFFFFF);
+ mga_outl(M_FXBNDRY, xx);
+ mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
+ mga_outl(M_LEN | M_EXEC, fontheight(p));
+ WaitTillIdle();
+
+ CRITEND
+}
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG_LOOP("matrox_cfb8_revc")
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ CRITBEGIN
+
+ mga_fifo(4);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0x0F0F0F0F);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+ mga_ydstlen(yy, fontheight(p));
+ WaitTillIdle();
+
+ CRITEND
+}
+#endif
+
+static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ DBG_LOOP("matrox_cfbX_revc")
+
+ yy *= fontheight(p);
+ xx *= fontwidth(p);
+
+ CRITBEGIN
+
+ mga_fifo(4);
+ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
+ mga_outl(M_FCOL, 0xFFFFFFFF);
+ mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
+ mga_ydstlen(yy, fontheight(p));
+ WaitTillIdle();
+
+ CRITEND
+}
+
+static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
+ unsigned int bottom_height, right_width;
+ unsigned int bottom_start, right_start;
+ unsigned int cell_h, cell_w;
+
+ DBG("matrox_cfbX_clear_margins")
+
+ cell_w = fontwidth(p);
+ if (!cell_w) return; /* PARANOID */
+ right_width = p->var.xres % cell_w;
+ right_start = p->var.xres - right_width;
+ if (!bottom_only && right_width) {
+ /* clear whole right margin, not only visible portion */
+ matroxfb_accel_clear( PMXINFO(p)
+ /* color */ 0x00000000,
+ /* y */ 0,
+ /* x */ p->var.xoffset + right_start,
+ /* height */ p->var.yres_virtual,
+ /* width */ right_width);
+ }
+ cell_h = fontheight(p);
+ if (!cell_h) return; /* PARANOID */
+ bottom_height = p->var.yres % cell_h;
+ if (bottom_height) {
+ bottom_start = p->var.yres - bottom_height;
+ matroxfb_accel_clear( PMXINFO(p)
+ /* color */ 0x00000000,
+ /* y */ p->var.yoffset + bottom_start,
+ /* x */ p->var.xoffset,
+ /* height */ bottom_height,
+ /* width */ right_start);
+ }
+}
+
+static void matrox_text_setup(struct display* p) {
+ MINFO_FROM_DISP(p);
+
+ p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
+ p->next_plane = 0;
+}
+
+static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx,
+ int height, int width) {
+ unsigned int srcoff;
+ unsigned int dstoff;
+ unsigned int step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ CRITBEGIN
+
+ step = ACCESS_FBINFO(devflags.textstep);
+ srcoff = (sy * p->next_line) + (sx * step);
+ dstoff = (dy * p->next_line) + (dx * step);
+ if (dstoff < srcoff) {
+ while (height > 0) {
+ int i;
+ for (i = width; i > 0; dstoff += step, srcoff += step, i--)
+ mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
+ height--;
+ dstoff += p->next_line - width * step;
+ srcoff += p->next_line - width * step;
+ }
+ } else {
+ unsigned int off;
+
+ off = (height - 1) * p->next_line + (width - 1) * step;
+ srcoff += off;
+ dstoff += off;
+ while (height > 0) {
+ int i;
+ for (i = width; i > 0; dstoff -= step, srcoff -= step, i--)
+ mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
+ dstoff -= p->next_line - width * step;
+ srcoff -= p->next_line - width * step;
+ height--;
+ }
+ }
+ CRITEND
+}
+
+static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
+ int height, int width) {
+ unsigned int offs;
+ unsigned int val;
+ unsigned int step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ step = ACCESS_FBINFO(devflags.textstep);
+ offs = sy * p->next_line + sx * step;
+ val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
+
+ CRITBEGIN
+
+ while (height > 0) {
+ int i;
+ for (i = width; i > 0; offs += step, i--)
+ mga_writew(ACCESS_FBINFO(video.vbase), offs, val);
+ offs += p->next_line - width * step;
+ height--;
+ }
+ CRITEND
+}
+
+static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
+ unsigned int offs;
+ unsigned int chr;
+ unsigned int step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ step = ACCESS_FBINFO(devflags.textstep);
+ offs = yy * p->next_line + xx * step;
+ chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
+ if (chr & 0x10000) chr |= 0x08;
+
+ CRITBEGIN
+
+ mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
+
+ CRITEND
+}
+
+static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
+ int count, int yy, int xx) {
+ unsigned int offs;
+ unsigned int attr;
+ unsigned int step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ step = ACCESS_FBINFO(devflags.textstep);
+ offs = yy * p->next_line + xx * step;
+ attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+
+ CRITBEGIN
+
+ while (count-- > 0) {
+ unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
+ if (chr & 0x10000) chr ^= 0x10008;
+ mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
+ offs += step;
+ }
+
+ CRITEND
+}
+
+static void matrox_text_revc(struct display* p, int xx, int yy) {
+ unsigned int offs;
+ unsigned int step;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ step = ACCESS_FBINFO(devflags.textstep);
+ offs = yy * p->next_line + xx * step + 1;
+
+ CRITBEGIN
+
+ mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
+
+ CRITEND
+}
+
+void matrox_text_createcursor(WPMINFO struct display* p) {
+ CRITFLAGS
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ matroxfb_createcursorshape(PMINFO p, 0);
+
+ CRITBEGIN
+
+ mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+ mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
+
+ CRITEND
+}
+
+static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
+ unsigned int pos;
+ CRITFLAGS
+ MINFO_FROM_DISP(p);
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+
+ if (mode == CM_ERASE) {
+ if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+
+ CRITBEGIN
+
+ mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
+
+ CRITEND
+
+ ACCESS_FBINFO(cursor.state) = CM_ERASE;
+ }
+ return;
+ }
+ if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
+ matrox_text_createcursor(PMINFO p);
+
+ /* DO NOT CHECK cursor.x != x because of matroxfb_vgaHWinit moves cursor to 0,0 */
+ ACCESS_FBINFO(cursor.x) = x;
+ ACCESS_FBINFO(cursor.y) = y;
+ pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
+
+ CRITBEGIN
+
+ mga_setr(M_CRTC_INDEX, 0x0F, pos);
+ mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
+
+ mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+
+ CRITEND
+
+ ACCESS_FBINFO(cursor.state) = CM_DRAW;
+}
+
+void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) {
+ unsigned hf;
+ unsigned vf;
+ unsigned vxres;
+ unsigned ych;
+
+ hf = fontwidth(p);
+ if (!hf) hf = 8;
+ /* do not touch xres */
+ vxres = (var->xres_virtual + hf - 1) / hf;
+ if (vxres >= 256)
+ vxres = 255;
+ if (vxres < 16)
+ vxres = 16;
+ vxres = (vxres + 1) & ~1; /* must be even */
+ vf = fontheight(p);
+ if (!vf) vf = 16;
+ if (var->yres < var->yres_virtual) {
+ ych = ACCESS_FBINFO(devflags.textvram) / vxres;
+ var->yres_virtual = ych * vf;
+ } else
+ ych = var->yres_virtual / vf;
+ if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) {
+ ych = ACCESS_FBINFO(devflags.textvram) / vxres;
+ var->yres_virtual = ych * vf;
+ }
+ var->xres_virtual = vxres * hf;
+}
+
+static int matrox_text_setfont(struct display* p, int width, int height) {
+ DBG("matrox_text_setfont");
+
+ if (p) {
+ MINFO_FROM_DISP(p);
+
+ matrox_text_round(PMINFO &p->var, p);
+ p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
+
+ if (p->conp)
+ matrox_text_createcursor(PMINFO p);
+ }
+ return 0;
+}
+
+#define matrox_cfb16_revc matrox_cfbX_revc
+#define matrox_cfb24_revc matrox_cfbX_revc
+#define matrox_cfb32_revc matrox_cfbX_revc
+
+#define matrox_cfb24_clear matrox_cfb32_clear
+#define matrox_cfb24_putc matrox_cfb32_putc
+#define matrox_cfb24_putcs matrox_cfb32_putcs
+
+#ifdef FBCON_HAS_VGATEXT
+static struct display_switch matroxfb_text = {
+ matrox_text_setup, matrox_text_bmove, matrox_text_clear,
+ matrox_text_putc, matrox_text_putcs, matrox_text_revc,
+ matrox_text_cursor, matrox_text_setfont, NULL,
+ FONTWIDTH(8)|FONTWIDTH(9)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB4
+static struct display_switch matroxfb_cfb4 = {
+ fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear,
+ fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc,
+ NULL, NULL, NULL,
+ /* cursor... */ /* set_font... */
+ FONTWIDTH(8) /* fix, fix, fix it */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch matroxfb_cfb8 = {
+ fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear,
+ matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB16
+static struct display_switch matroxfb_cfb16 = {
+ fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear,
+ matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static struct display_switch matroxfb_cfb24 = {
+ fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear,
+ matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static struct display_switch matroxfb_cfb32 = {
+ fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear,
+ matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc,
+ NULL, NULL, matrox_cfbX_clear_margins,
+ ~1 /* FONTWIDTHS */
+};
+#endif
+
+void initMatrox(WPMINFO struct display* p) {
+ struct display_switch *swtmp;
+
+ DBG("initMatrox")
+
+ if (ACCESS_FBINFO(currcon_display) != p)
+ return;
+ if (p->dispsw && p->conp)
+ fb_con.con_cursor(p->conp, CM_ERASE);
+ p->dispsw_data = NULL;
+ if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
+ if (p->type == FB_TYPE_TEXT) {
+ swtmp = &matroxfb_text;
+ } else {
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ swtmp = &fbcon_cfb4;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ swtmp = &fbcon_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+ swtmp = &fbcon_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+ swtmp = &fbcon_cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+ swtmp = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ p->dispsw = &fbcon_dummy;
+ return;
+ }
+ }
+ dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
+ } else if (p->type == FB_TYPE_TEXT) {
+ swtmp = &matroxfb_text;
+ } else {
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ swtmp = &matroxfb_cfb4;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ swtmp = &matroxfb_cfb8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
+ swtmp = &matroxfb_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
+ swtmp = &matroxfb_cfb24;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
+ swtmp = &matroxfb_cfb32;
+ break;
+#endif
+ default:
+ p->dispsw = &fbcon_dummy;
+ return;
+ }
+ }
+ memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
+ p->dispsw = &ACCESS_FBINFO(dispsw);
+ if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
+ ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO p);
+ }
+}
+
+void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) {
+ int i;
+
+ if (p && p->conp) {
+ if (p->type == FB_TYPE_TEXT) {
+ matrox_text_createcursor(PMINFO p);
+ matrox_text_loadfont(PMINFO p);
+ i = 0;
+ } else {
+ dac_createcursor(PMINFO p);
+ i = matroxfb_fastfont_tryset(PMINFO p);
+ }
+ } else
+ i = 0;
+ if (i) {
+ ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc;
+ ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs;
+ } else {
+ ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc;
+ ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
+ }
+}
diff --git a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h
new file mode 100644
index 000000000..a3165a0a2
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_accel.h
@@ -0,0 +1,12 @@
+#ifndef __MATROXFB_ACCEL_H__
+#define __MATROXFB_ACCEL_H__
+
+#include "matroxfb_base.h"
+
+void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
+void matrox_cfbX_init(WPMINFO struct display* p);
+void matrox_text_createcursor(WPMINFO struct display* p);
+void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
+void initMatrox(WPMINFO struct display* p);
+
+#endif
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
new file mode 100644
index 000000000..a8af1c68c
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -0,0 +1,2544 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.21 1999/01/09
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <trini@kernel.crashing.org>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ * "Bibek Sahu" <scorpio@dodds.net>
+ * Access device through readb|w|l and write b|w|l
+ * Extensive debugging stuff
+ *
+ * "Daniel Haun" <haund@usa.net>
+ * Testing, hardware cursor fixes
+ *
+ * "Scott Wood" <sawst46+@pitt.edu>
+ * Fixes
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * PPC betatesting, PPC support, backward compatibility
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * "Thomas Pornin" <pornin@bolet.ens.fr>
+ * Alpha betatesting
+ *
+ * "Pieter van Leuven" <pvl@iae.nl>
+ * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ * G100 testing
+ *
+ * "H. Peter Arvin" <hpa@transmeta.com>
+ * Ideas
+ *
+ * "Cort Dougan" <cort@cs.nmt.edu>
+ * CHRP fixes and PReP cleanup
+ *
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
+ * "Samuel Hocevar" <sam@via.ecp.fr>
+ * Fixes
+ *
+ * "Anton Altaparmakov" <AntonA@bigfoot.com>
+ * G400 MAX/non-MAX distinction
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not check included files... */
+#include <linux/config.h>
+
+#include "matroxfb_base.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_maven.h"
+#include "matroxfb_crtc2.h"
+#include <linux/matroxfb.h>
+#include <asm/uaccess.h>
+
+#if defined(CONFIG_FB_OF)
+unsigned char nvram_read_byte(int);
+int matrox_of_init(struct device_node *dp);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined = {
+ 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
+ 0,0, /* virtual -> visible no offset */
+ 8, /* depth -> load bits_per_pixel */
+ 0, /* greyscale ? */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* transparency */
+ 0, /* standard pixel format */
+ FB_ACTIVATE_NOW,
+ -1,-1,
+ FB_ACCELF_TEXT, /* accel flags */
+ 39721L,48L,16L,33L,10L,
+ 96L,2L,~0, /* No sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
+ unsigned int pos;
+ unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+ unsigned int p3;
+#endif
+ struct display *disp;
+ CRITFLAGS
+
+ DBG("matrox_pan_var")
+
+ if (ACCESS_FBINFO(dead))
+ return;
+
+ disp = ACCESS_FBINFO(currcon_display);
+ if (disp->type == FB_TYPE_TEXT) {
+ pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8);
+ } else {
+ pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+ pos += ACCESS_FBINFO(curr.ydstorg.chunks);
+ }
+ p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
+ p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+ p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+ p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
+#endif
+
+ CRITBEGIN
+
+ mga_setr(M_CRTC_INDEX, 0x0D, p0);
+ mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+ if (ACCESS_FBINFO(devflags.support32MB))
+ mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
+ mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+
+ CRITEND
+}
+
+static void matroxfb_remove(WPMINFO int dummy) {
+ /* Currently we are holding big kernel lock on all dead & usecount updates.
+ * Destroy everything after all users release it. Especially do not unregister
+ * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check
+ * for device unplugged when in use.
+ * In future we should point mmio.vbase & video.vbase somewhere where we can
+ * write data without causing too much damage...
+ */
+
+ ACCESS_FBINFO(dead) = 1;
+ if (ACCESS_FBINFO(usecount)) {
+ /* destroy it later */
+ return;
+ }
+ matroxfb_unregister_device(MINFO);
+ unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+ del_timer(&ACCESS_FBINFO(cursor.timer));
+#ifdef CONFIG_MTRR
+ if (ACCESS_FBINFO(mtrr.vram_valid))
+ mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
+#endif
+ mga_iounmap(ACCESS_FBINFO(mmio.vbase));
+ mga_iounmap(ACCESS_FBINFO(video.vbase));
+ release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum));
+ release_mem_region(ACCESS_FBINFO(mmio.base), 16384);
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
+ kfree_s(minfo, sizeof(struct matrox_fb_info));
+#endif
+}
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ DBG_LOOP("matroxfb_open")
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+ MOD_INC_USE_COUNT;
+ ACCESS_FBINFO(usecount)++;
+#undef minfo
+ return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ DBG_LOOP("matroxfb_release")
+
+ if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
+ matroxfb_remove(PMINFO 0);
+ }
+ MOD_DEC_USE_COUNT;
+#undef minfo
+ return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
+ struct fb_info* info) {
+#define minfo ((struct matrox_fb_info*)info)
+
+ DBG("matroxfb_pan_display")
+
+ if (var->vmode & FB_VMODE_YWRAP) {
+ if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+ return -EINVAL;
+ } else {
+ if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+ var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ return -EINVAL;
+ }
+ if (con == ACCESS_FBINFO(currcon))
+ matrox_pan_var(PMINFO var);
+ fb_display[con].var.xoffset = var->xoffset;
+ fb_display[con].var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+ else
+ fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_updatevar(int con, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ DBG("matroxfb_updatevar");
+
+ matrox_pan_var(PMINFO &fb_display[con].var);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
+ int bppshft2;
+
+ DBG("matroxfb_get_final_bppShift")
+
+ bppshft2 = bpp;
+ if (!bppshft2) {
+ return 8;
+ }
+ if (isInterleave(MINFO))
+ bppshft2 >>= 1;
+ if (ACCESS_FBINFO(devflags.video64bits))
+ bppshft2 >>= 1;
+ return bppshft2;
+}
+
+static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
+ int over;
+ int rounding;
+
+ DBG("matroxfb_test_and_set_rounding")
+
+ switch (bpp) {
+ case 0: return xres;
+ case 4: rounding = 128;
+ break;
+ case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
+ break;
+ case 16: rounding = 32;
+ break;
+ case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
+ break;
+ default: rounding = 16;
+ /* on G400, 16 really does not work */
+ if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+ rounding = 32;
+ break;
+ }
+ if (isInterleave(MINFO)) {
+ rounding *= 2;
+ }
+ over = xres % rounding;
+ if (over)
+ xres += rounding-over;
+ return xres;
+}
+
+static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
+ const int* width;
+ int xres_new;
+
+ DBG("matroxfb_pitch_adjust")
+
+ if (!bpp) return xres;
+
+ width = ACCESS_FBINFO(capable.vxres);
+
+ if (ACCESS_FBINFO(devflags.precise_width)) {
+ while (*width) {
+ if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
+ break;
+ }
+ width++;
+ }
+ xres_new = *width;
+ } else {
+ xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
+ }
+ if (!xres_new) return 0;
+ if (xres != xres_new) {
+ printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
+ }
+ return xres_new;
+}
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+
+ DBG("matroxfb_get_cmap_len")
+
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_VGATEXT
+ case 0:
+ return 16; /* pseudocolor... 16 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ return 16; /* pseudocolor... 16 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ return 256; /* pseudocolor... 256 entries HW palette */
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ return 16; /* directcolor... 16 entries SW palette */
+ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+ }
+ return 16; /* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
+ unsigned int vramlen;
+ unsigned int memlen;
+
+ DBG("matroxfb_decode_var")
+
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_VGATEXT
+ case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB4
+ case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8: break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16: break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24: break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32: break;
+#endif
+ default: return -EINVAL;
+ }
+ *ydstorg = 0;
+ vramlen = ACCESS_FBINFO(video.len_usable);
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->bits_per_pixel) {
+ var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
+ memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+ if (memlen > vramlen) {
+ var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+ memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+ }
+ /* There is hardware bug that no line can cross 4MB boundary */
+ /* give up for CFB24, it is impossible to easy workaround it */
+ /* for other try to do something */
+ if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
+ if (var->bits_per_pixel == 24) {
+ /* sorry */
+ } else {
+ unsigned int linelen;
+ unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
+ unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
+ unsigned int max_yres;
+
+ while (m1) {
+ int t;
+
+ while (m2 >= m1) m2 -= m1;
+ t = m1;
+ m1 = m2;
+ m2 = t;
+ }
+ m2 = linelen * PAGE_SIZE / m2;
+ *ydstorg = m2 = 0x400000 % m2;
+ max_yres = (vramlen - m2) / linelen;
+ if (var->yres_virtual > max_yres)
+ var->yres_virtual = max_yres;
+ }
+ }
+ } else {
+ matrox_text_round(PMINFO var, p);
+#if 0
+/* we must limit pixclock by mclk...
+ Millennium I: 66 MHz = 15000
+ Millennium II: 61 MHz = 16300
+ Millennium G200: 83 MHz = 12000 */
+ if (var->pixclock < 15000)
+ var->pixclock = 15000; /* limit for "normal" gclk & mclk */
+#endif
+ }
+ /* YDSTLEN contains only signed 16bit value */
+ if (var->yres_virtual > 32767)
+ var->yres_virtual = 32767;
+ /* we must round yres/xres down, we already rounded y/xres_virtual up
+ if it was possible. We should return -EINVAL, but I disagree */
+ if (var->yres_virtual < var->yres)
+ var->yres = var->yres_virtual;
+ if (var->xres_virtual < var->xres)
+ var->xres = var->xres_virtual;
+ if (var->xoffset + var->xres > var->xres_virtual)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yoffset + var->yres > var->yres_virtual)
+ var->yoffset = var->yres_virtual - var->yres;
+
+ if (var->bits_per_pixel == 0) {
+ var->red.offset = 0;
+ var->red.length = 6;
+ var->green.offset = 0;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 6;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ *visual = MX_VISUAL_PSEUDOCOLOR;
+ } else if (var->bits_per_pixel == 4) {
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ *visual = MX_VISUAL_PSEUDOCOLOR;
+ } else if (var->bits_per_pixel <= 8) {
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ *visual = MX_VISUAL_PSEUDOCOLOR;
+ } else {
+ if (var->bits_per_pixel <= 16) {
+ if (var->green.length == 5) {
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ } else {
+ 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;
+ }
+ } else if (var->bits_per_pixel <= 24) {
+ 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;
+ } else {
+ 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;
+ }
+ dprintk("matroxfb: truecolor: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ var->transp.length,
+ var->red.length,
+ var->green.length,
+ var->blue.length,
+ var->transp.offset,
+ var->red.offset,
+ var->green.offset,
+ var->blue.offset);
+ *visual = MX_VISUAL_DIRECTCOLOR;
+ }
+ *video_cmap_len = matroxfb_get_cmap_len(var);
+ dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual);
+ return 0;
+}
+
+static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info)
+{
+ struct display* p;
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+#endif
+
+ DBG("matrox_setcolreg")
+
+ /*
+ * 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.
+ */
+
+ if (regno >= ACCESS_FBINFO(curr.cmap_len))
+ return 1;
+
+ ACCESS_FBINFO(palette[regno].red) = red;
+ ACCESS_FBINFO(palette[regno].green) = green;
+ ACCESS_FBINFO(palette[regno].blue) = blue;
+ ACCESS_FBINFO(palette[regno].transp) = transp;
+
+ p = ACCESS_FBINFO(currcon_display);
+ if (p->var.grayscale) {
+ /* gray = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ red = CNVT_TOHW(red, p->var.red.length);
+ green = CNVT_TOHW(green, p->var.green.length);
+ blue = CNVT_TOHW(blue, p->var.blue.length);
+ transp = CNVT_TOHW(transp, p->var.transp.length);
+
+ switch (p->var.bits_per_pixel) {
+#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT)
+#ifdef FBCON_HAS_VGATEXT
+ case 0:
+#endif
+#ifdef FBCON_HAS_CFB4
+ case 4:
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+#endif
+ mga_outb(M_DAC_REG, regno);
+ mga_outb(M_DAC_VAL, red);
+ mga_outb(M_DAC_VAL, green);
+ mga_outb(M_DAC_VAL, blue);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ ACCESS_FBINFO(cmap.cfb16[regno]) =
+ (red << p->var.red.offset) |
+ (green << p->var.green.offset) |
+ (blue << p->var.blue.offset) |
+ (transp << p->var.transp.offset); /* for 1:5:5:5 */
+ break;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ ACCESS_FBINFO(cmap.cfb24[regno]) =
+ (red << p->var.red.offset) |
+ (green << p->var.green.offset) |
+ (blue << p->var.blue.offset);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ ACCESS_FBINFO(cmap.cfb32[regno]) =
+ (red << p->var.red.offset) |
+ (green << p->var.green.offset) |
+ (blue << p->var.blue.offset) |
+ (transp << p->var.transp.offset); /* 8:8:8:8 */
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void do_install_cmap(WPMINFO struct display* dsp)
+{
+ DBG("do_install_cmap")
+
+ if (dsp->cmap.len)
+ fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+ else
+ fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
+ 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+}
+
+static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ struct display* p;
+ DBG("matroxfb_get_fix")
+
+#define minfo ((struct matrox_fb_info*)info)
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+
+ if (con >= 0)
+ p = fb_display + con;
+ else
+ p = ACCESS_FBINFO(fbcon.disp);
+
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id,"MATROX");
+
+ fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
+ fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
+ fix->type = p->type;
+ fix->type_aux = p->type_aux;
+ fix->visual = p->visual;
+ fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = p->line_length;
+ fix->mmio_start = ACCESS_FBINFO(mmio.base);
+ fix->mmio_len = ACCESS_FBINFO(mmio.len);
+ fix->accel = ACCESS_FBINFO(devflags.accelerator);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ DBG("matroxfb_get_var")
+
+ if(con < 0)
+ *var=ACCESS_FBINFO(fbcon.disp)->var;
+ else
+ *var=fb_display[con].var;
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ int err;
+ int visual;
+ int cmap_len;
+ unsigned int ydstorg;
+ struct display* display;
+ int chgvar;
+
+ DBG("matroxfb_set_var")
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+
+ if (con >= 0)
+ display = fb_display + con;
+ else
+ display = ACCESS_FBINFO(fbcon.disp);
+ if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0)
+ return err;
+ switch (var->activate & FB_ACTIVATE_MASK) {
+ case FB_ACTIVATE_TEST: return 0;
+ case FB_ACTIVATE_NXTOPEN: /* ?? */
+ case FB_ACTIVATE_NOW: break; /* continue */
+ default: return -EINVAL; /* unknown */
+ }
+ if (con >= 0) {
+ chgvar = ((display->var.xres != var->xres) ||
+ (display->var.yres != var->yres) ||
+ (display->var.xres_virtual != var->xres_virtual) ||
+ (display->var.yres_virtual != var->yres_virtual) ||
+ (display->var.bits_per_pixel != var->bits_per_pixel) ||
+ memcmp(&display->var.red, &var->red, sizeof(var->red)) ||
+ memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
+ memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
+ } else {
+ chgvar = 0;
+ }
+ display->var = *var;
+ /* cmap */
+ display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
+ display->visual = visual;
+ display->ypanstep = 1;
+ display->ywrapstep = 0;
+ if (var->bits_per_pixel) {
+ display->type = FB_TYPE_PACKED_PIXELS;
+ display->type_aux = 0;
+ display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+ } else {
+ display->type = FB_TYPE_TEXT;
+ display->type_aux = ACCESS_FBINFO(devflags.text_type_aux);
+ display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
+ }
+ display->can_soft_blank = 1;
+ display->inverse = ACCESS_FBINFO(devflags.inverse);
+ /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
+ /* next_plane, fontdata, _font*, userfont */
+ initMatrox(PMINFO display); /* dispsw */
+ /* dispsw, scrollmode, yscroll */
+ /* fgshift, bgshift, charmask */
+ if (chgvar && info && info->changevar)
+ info->changevar(con);
+ if (con == ACCESS_FBINFO(currcon)) {
+ unsigned int pos;
+
+ ACCESS_FBINFO(curr.cmap_len) = cmap_len;
+ if (display->type == FB_TYPE_TEXT) {
+ /* textmode must be in first megabyte, so no ydstorg allowed */
+ ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
+ ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
+ ACCESS_FBINFO(curr.ydstorg.pixels) = 0;
+ } else {
+ ydstorg += ACCESS_FBINFO(devflags.ydstorg);
+ ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg;
+ ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2);
+ if (var->bits_per_pixel == 4)
+ ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg;
+ else
+ ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel;
+ }
+ ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
+ if (visual == MX_VISUAL_PSEUDOCOLOR) {
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ int j;
+
+ j = color_table[i];
+ ACCESS_FBINFO(palette[i].red) = default_red[j];
+ ACCESS_FBINFO(palette[i].green) = default_grn[j];
+ ACCESS_FBINFO(palette[i].blue) = default_blu[j];
+ }
+ }
+
+ { struct my_timming mt;
+ struct matrox_hw_state* hw;
+ struct matrox_hw_state* ohw;
+
+ matroxfb_var2my(var, &mt);
+ /* CRTC1 delays */
+ switch (var->bits_per_pixel) {
+ case 0: mt.delay = 31 + 0; break;
+ case 16: mt.delay = 21 + 8; break;
+ case 24: mt.delay = 17 + 8; break;
+ case 32: mt.delay = 16 + 8; break;
+ default: mt.delay = 31 + 8; break;
+ }
+
+ hw = ACCESS_FBINFO(newhw);
+ ohw = ACCESS_FBINFO(currenthw);
+
+ /* copy last setting... */
+ memcpy(hw, ohw, sizeof(*hw));
+
+ del_timer(&ACCESS_FBINFO(cursor.timer));
+ ACCESS_FBINFO(cursor.state) = CM_ERASE;
+
+ ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display));
+ if (display->type == FB_TYPE_TEXT) {
+ if (fontheight(display))
+ pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
+ else
+ pos = 0;
+ } else {
+ pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
+ pos += ACCESS_FBINFO(curr.ydstorg.chunks);
+ }
+
+ hw->CRTC[0x0D] = pos & 0xFF;
+ hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+ hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+ hw->CRTCEXT[8] = pos >> 21;
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw);
+ }
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->program(MINFO, hw);
+ }
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ ACCESS_FBINFO(cursor.redraw) = 1;
+ ACCESS_FBINFO(currenthw) = hw;
+ ACCESS_FBINFO(newhw) = ohw;
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->start(MINFO);
+ }
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ matrox_cfbX_init(PMINFO display);
+ do_install_cmap(PMINFO display);
+#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
+ if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
+ int vmode, cmode;
+
+ display_info.width = var->xres;
+ display_info.height = var->yres;
+ display_info.depth = var->bits_per_pixel;
+ display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8;
+ if (mac_var_to_vmode(var, &vmode, &cmode))
+ display_info.mode = 0;
+ else
+ display_info.mode = vmode;
+ strcpy(display_info.name, ACCESS_FBINFO(matrox_name));
+ display_info.fb_address = ACCESS_FBINFO(video.base);
+ display_info.cmap_adr_address = 0;
+ display_info.cmap_data_address = 0;
+ display_info.disp_reg_address = ACCESS_FBINFO(mmio.base);
+ }
+#endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */
+ }
+ }
+ return 0;
+#undef minfo
+}
+
+static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *info)
+{
+
+ DBG("matrox_getcolreg")
+
+#define minfo ((struct matrox_fb_info*)info)
+ /*
+ * Read a single color register and split it into colors/transparent.
+ * Return != 0 for invalid regno.
+ */
+
+ if (regno >= ACCESS_FBINFO(curr.cmap_len))
+ return 1;
+
+ *red = ACCESS_FBINFO(palette[regno].red);
+ *green = ACCESS_FBINFO(palette[regno].green);
+ *blue = ACCESS_FBINFO(palette[regno].blue);
+ *transp = ACCESS_FBINFO(palette[regno].transp);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
+ : fb_display + con;
+
+ DBG("matroxfb_get_cmap")
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+
+ if (con == ACCESS_FBINFO(currcon)) /* current console? */
+ return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
+ else if (dsp->cmap.len) /* non default colormap? */
+ fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
+ cmap, kspc ? 0 : 2);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
+{
+ unsigned int cmap_len;
+ struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
+#define minfo ((struct matrox_fb_info*)info)
+
+ DBG("matroxfb_set_cmap")
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+
+ cmap_len = matroxfb_get_cmap_len(&dsp->var);
+ if (dsp->cmap.len != cmap_len) {
+ int err;
+
+ err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
+ if (err)
+ return err;
+ }
+ if (con == ACCESS_FBINFO(currcon)) { /* current console? */
+ return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+ } else
+ fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
+ return 0;
+#undef minfo
+}
+
+static int matroxfb_switch(int con, struct fb_info *info);
+
+static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank)
+{
+ unsigned int sts1;
+
+ memset(vblank, 0, sizeof(*vblank));
+ vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
+ FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
+ sts1 = mga_inb(M_INSTS1);
+ vblank->vcount = mga_inl(M_VCOUNT);
+ /* BTW, on my PIII/450 with G400, reading M_INSTS1
+ byte makes this call about 12% slower (1.70 vs. 2.05 us
+ per ioctl()) */
+ if (sts1 & 1)
+ vblank->flags |= FB_VBLANK_HBLANKING;
+ if (sts1 & 8)
+ vblank->flags |= FB_VBLANK_VSYNCING;
+ if (vblank->count >= ACCESS_FBINFO(currcon_display)->var.yres)
+ vblank->flags |= FB_VBLANK_VBLANKING;
+ vblank->hcount = 0;
+ vblank->count = 0;
+ return 0;
+}
+
+static int matroxfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ DBG("matroxfb_ioctl")
+
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+
+ switch (cmd) {
+ case FBIOGET_VBLANK:
+ {
+ struct fb_vblank vblank;
+ int err;
+
+ err = matroxfb_get_vblank(PMINFO &vblank);
+ if (err)
+ return err;
+ copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT);
+ return 0;
+ }
+ case MATROXFB_SET_OUTPUT_MODE:
+ {
+ struct matroxioc_output_mode mom;
+ int val;
+
+ copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT);
+ if (mom.output >= sizeof(u_int32_t))
+ return -EINVAL;
+ switch (mom.output) {
+ case MATROXFB_OUTPUT_PRIMARY:
+ if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR)
+ return -EINVAL;
+ /* mode did not change... */
+ return 0;
+ case MATROXFB_OUTPUT_SECONDARY:
+ val = -EINVAL;
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
+ val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ if (val != 1)
+ return val;
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+ matroxfb_switch(ACCESS_FBINFO(currcon), info);
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ struct matroxfb_dh_fb_info* crtc2;
+
+ down_read(&ACCESS_FBINFO(crtc2.lock));
+ crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info));
+ if (crtc2)
+ crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon);
+ up_read(&ACCESS_FBINFO(crtc2.lock));
+ }
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+ case MATROXFB_GET_OUTPUT_MODE:
+ {
+ struct matroxioc_output_mode mom;
+ int val;
+
+ copy_from_user_ret(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom), -EFAULT);
+ if (mom.output >= sizeof(u_int32_t))
+ return -EINVAL;
+ switch (mom.output) {
+ case MATROXFB_OUTPUT_PRIMARY:
+ mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
+ break;
+ case MATROXFB_OUTPUT_SECONDARY:
+ val = -EINVAL;
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
+ val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ if (val)
+ return val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ copy_to_user_ret((struct matroxioc_output_mode*)arg, &mom, sizeof(mom), -EFAULT);
+ return 0;
+ }
+ case MATROXFB_SET_OUTPUT_CONNECTION:
+ {
+ u_int32_t tmp;
+
+ copy_from_user_ret(&tmp, (u_int32_t*)arg, sizeof(tmp), -EFAULT);
+ if (tmp & ~ACCESS_FBINFO(output.all))
+ return -EINVAL;
+ if (tmp & ACCESS_FBINFO(output.sh))
+ return -EINVAL;
+ if (tmp == ACCESS_FBINFO(output.ph))
+ return 0;
+ ACCESS_FBINFO(output.ph) = tmp;
+ matroxfb_switch(ACCESS_FBINFO(currcon), info);
+ return 0;
+ }
+ case MATROXFB_GET_OUTPUT_CONNECTION:
+ {
+ put_user_ret(ACCESS_FBINFO(output.ph), (u_int32_t*)arg, -EFAULT);
+ return 0;
+ }
+ case MATROXFB_GET_AVAILABLE_OUTPUTS:
+ {
+ u_int32_t tmp;
+
+ tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
+ put_user_ret(tmp, (u_int32_t*)arg, -EFAULT);
+ return 0;
+ }
+ case MATROXFB_GET_ALL_OUTPUTS:
+ {
+ put_user_ret(ACCESS_FBINFO(output.all), (u_int32_t*)arg, -EFAULT);
+ return 0;
+ }
+ }
+ return -EINVAL;
+#undef minfo
+}
+
+static struct fb_ops matroxfb_ops = {
+ matroxfb_open,
+ matroxfb_release,
+ matroxfb_get_fix,
+ matroxfb_get_var,
+ matroxfb_set_var,
+ matroxfb_get_cmap,
+ matroxfb_set_cmap,
+ matroxfb_pan_display,
+ matroxfb_ioctl,
+ NULL, /* mmap */
+ NULL, /* rasterimg */
+};
+
+static int matroxfb_switch(int con, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ struct fb_cmap* cmap;
+ struct display *p;
+
+ DBG("matroxfb_switch");
+
+ if (ACCESS_FBINFO(currcon) >= 0) {
+ /* Do we have to save the colormap? */
+ cmap = &(ACCESS_FBINFO(currcon_display)->cmap);
+ dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(currcon), cmap->len);
+
+ if (cmap->len) {
+ dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ fb_get_cmap(cmap, 1, matrox_getcolreg, info);
+#ifdef DEBUG
+ if (cmap->red) {
+ dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
+ }
+#endif
+ }
+ }
+ ACCESS_FBINFO(currcon) = con;
+ if (con < 0)
+ p = ACCESS_FBINFO(fbcon.disp);
+ else
+ p = fb_display + con;
+ ACCESS_FBINFO(currcon_display) = p;
+ p->var.activate = FB_ACTIVATE_NOW;
+#ifdef DEBUG
+ cmap = &p->cmap;
+ dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
+ dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ if (p->cmap.red) {
+ dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
+ }
+#endif
+ matroxfb_set_var(&p->var, con, info);
+#ifdef DEBUG
+ dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
+ dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
+ if (p->cmap.red) {
+ dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
+ }
+#endif
+ return 0;
+#undef minfo
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static void matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo ((struct matrox_fb_info*)info)
+ int seq;
+ int crtc;
+ CRITFLAGS
+
+ DBG("matroxfb_blank")
+
+ if (ACCESS_FBINFO(dead))
+ return;
+
+ switch (blank) {
+ case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */
+ case 2: seq = 0x20; crtc = 0x10; break;
+ case 3: seq = 0x20; crtc = 0x20; break;
+ case 4: seq = 0x20; crtc = 0x30; break;
+ default: seq = 0x00; crtc = 0x00; break;
+ }
+
+ CRITBEGIN
+
+ mga_outb(M_SEQ_INDEX, 1);
+ mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+ mga_outb(M_EXTVGA_INDEX, 1);
+ mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+ CRITEND
+
+#undef minfo
+}
+
+#define RSDepth(X) (((X) >> 8) & 0x0F)
+#define RS8bpp 0x1
+#define RS15bpp 0x2
+#define RS16bpp 0x3
+#define RS32bpp 0x4
+#define RS4bpp 0x5
+#define RS24bpp 0x6
+#define RSText 0x7
+#define RSText8 0x8
+/* 9-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = {
+ { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
+ { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+ { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
+ { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+ { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
+ { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
+ { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
+ { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
+};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */
+static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24 = 0; /* "matrox:inv24" */
+static int cross4MB = -1; /* "matrox:cross4MB" */
+static int disabled = 0; /* "matrox:disabled" */
+static int noaccel = 0; /* "matrox:noaccel" */
+static int nopan = 0; /* "matrox:nopan" */
+static int no_pci_retry = 0; /* "matrox:nopciretry" */
+static int novga = 0; /* "matrox:novga" */
+static int nobios = 0; /* "matrox:nobios" */
+static int noinit = 1; /* "matrox:init" */
+static int inverse = 0; /* "matrox:inverse" */
+static int hwcursor = 1; /* "matrox:nohwcursor" */
+static int blink = 1; /* "matrox:noblink" */
+static int sgram = 0; /* "matrox:sgram" */
+#ifdef CONFIG_MTRR
+static int mtrr = 1; /* "matrox:nomtrr" */
+#endif
+static int grayscale = 0; /* "matrox:grayscale" */
+static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */
+static int dev = -1; /* "matrox:dev:xxxxx" */
+static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
+static int depth = -1; /* "matrox:depth:xxxxx" */
+static unsigned int xres = 0; /* "matrox:xres:xxxxx" */
+static unsigned int yres = 0; /* "matrox:yres:xxxxx" */
+static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
+static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */
+static unsigned int left = ~0; /* "matrox:left:xxxxx" */
+static unsigned int right = ~0; /* "matrox:right:xxxxx" */
+static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */
+static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */
+static int sync = -1; /* "matrox:sync:xxxxx" */
+static unsigned int fv = 0; /* "matrox:fv:xxxxx" */
+static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */
+static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */
+static char fontname[64]; /* "matrox:font:xxxxx" */
+
+#ifndef MODULE
+static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */
+#endif
+
+static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSize){
+ vaddr_t vm;
+ unsigned int offs;
+ unsigned int offs2;
+ unsigned char store;
+ unsigned char bytes[32];
+ unsigned char* tmp;
+
+ DBG("matroxfb_getmemory")
+
+ vm = ACCESS_FBINFO(video.vbase);
+ maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
+ /* at least 2MB */
+ if (maxSize < 0x0200000) return 0;
+ if (maxSize > 0x2000000) maxSize = 0x2000000;
+
+ mga_outb(M_EXTVGA_INDEX, 0x03);
+ mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
+
+ store = mga_readb(vm, 0x1234);
+ tmp = bytes;
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+ *tmp++ = mga_readb(vm, offs);
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+ mga_writeb(vm, offs, 0x02);
+ if (ACCESS_FBINFO(features.accel.has_cacheflush))
+ mga_outb(M_CACHEFLUSH, 0x00);
+ else
+ mga_writeb(vm, 0x1234, 0x99);
+ for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+ if (mga_readb(vm, offs) != 0x02)
+ break;
+ mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
+ if (mga_readb(vm, offs))
+ break;
+ }
+ tmp = bytes;
+ for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+ mga_writeb(vm, offs2, *tmp++);
+ mga_writeb(vm, 0x1234, store);
+
+ mga_outb(M_EXTVGA_INDEX, 0x03);
+ mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
+
+ *realSize = offs - 0x100000;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || ((offs - 0x100000) & 0x3FFFFF));
+#endif
+ return 1;
+}
+
+struct video_board {
+ int maxvram;
+ int maxdisplayable;
+ int accelID;
+ struct matrox_switch* lowlevel;
+ };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillennium = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millennium};
+static struct video_board vbMillennium2 = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millennium};
+static struct video_board vbMillennium2A = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millennium};
+#endif /* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
+#endif /* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G100
+static struct video_board vbG100 = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
+static struct video_board vbG200 = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+ whole 32MB */
+static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
+#else
+static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
+#endif
+#endif
+
+#define DEVF_VIDEO64BIT 0x0001
+#define DEVF_SWAPS 0x0002
+#define DEVF_MILLENNIUM 0x0004
+#define DEVF_MILLENNIUM2 0x0008
+#define DEVF_CROSS4MB 0x0010
+#define DEVF_TEXT4B 0x0020
+#define DEVF_DDC_8_2 0x0040
+#define DEVF_DMA 0x0080
+#define DEVF_SUPPORT32MB 0x0100
+#define DEVF_ANY_VXRES 0x0200
+#define DEVF_TEXT16B 0x0400
+#define DEVF_CRTC2 0x0800
+#define DEVF_MAVEN_CAPABLE 0x1000
+
+#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
+#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
+#define DEVF_G200 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE)
+#define DEVF_G400 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
+
+static struct board {
+ unsigned short vendor, device, rev, svid, sid;
+ unsigned int flags;
+ unsigned int maxclk;
+ struct video_board* base;
+ const char* name;
+ } dev_list[] = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF,
+ 0, 0,
+ DEVF_MILLENNIUM | DEVF_TEXT4B,
+ 230000,
+ &vbMillennium,
+ "Millennium (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF,
+ 0, 0,
+ DEVF_MILLENNIUM | DEVF_MILLENNIUM2 | DEVF_SWAPS,
+ 220000,
+ &vbMillennium2,
+ "Millennium II (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
+ 0, 0,
+ DEVF_MILLENNIUM | DEVF_MILLENNIUM2 | DEVF_SWAPS,
+ 250000,
+ &vbMillennium2A,
+ "Millennium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02,
+ 0, 0,
+ DEVF_VIDEO64BIT,
+ 180000,
+ &vbMystique,
+ "Mystique (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF,
+ 0, 0,
+ DEVF_VIDEO64BIT | DEVF_SWAPS,
+ 220000,
+ &vbMystique,
+ "Mystique 220 (PCI)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G100
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "MGA-G100 (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
+ 0, 0,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "unknown G100 (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "Productiva G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
+ 0, 0,
+ DEVF_G100,
+ 230000,
+ &vbG100,
+ "unknown G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
+ 0, 0,
+ DEVF_G200,
+ 250000,
+ &vbG200,
+ "unknown G200 (PCI)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
+ DEVF_G200,
+ 220000,
+ &vbG200,
+ "MGA-G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+ DEVF_G200,
+ 230000,
+ &vbG200,
+ "Mystique G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+ DEVF_G200,
+ 250000,
+ &vbG200,
+ "Millennium G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+ DEVF_G200,
+ 230000,
+ &vbG200,
+ "Marvel G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+ DEVF_G200,
+ 230000,
+ &vbG200,
+ "MGA-G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
+ 0, 0,
+ DEVF_G200,
+ 230000,
+ &vbG200,
+ "unknown G200 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
+ PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
+ DEVF_G400,
+ 360000,
+ &vbG400,
+ "Millennium G400 MAX (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
+ 0, 0,
+ DEVF_G400,
+ 300000,
+ &vbG400,
+ "unknown G400 (AGP)"},
+#endif
+ {0, 0, 0xFF,
+ 0, 0,
+ 0,
+ 0,
+ NULL,
+ NULL}};
+
+#ifndef MODULE
+static struct fb_videomode defaultmode = {
+ /* 640x480 @ 60Hz, 31.5 kHz */
+ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
+#endif /* !MODULE */
+
+static int hotplug = 0;
+
+static int initMatrox2(WPMINFO struct display* d, struct board* b){
+ unsigned long ctrlptr_phys = 0;
+ unsigned long video_base_phys = 0;
+ unsigned int memsize;
+ struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
+ int err;
+
+ DBG("initMatrox2")
+
+ /* set default values... */
+ vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+ ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
+ ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
+ ACCESS_FBINFO(max_pixel_clock) = b->maxclk;
+
+ printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+ ACCESS_FBINFO(capable.plnwt) = 1;
+ ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
+ if (b->flags & DEVF_TEXT4B) {
+ ACCESS_FBINFO(devflags.vgastep) = 4;
+ ACCESS_FBINFO(devflags.textmode) = 4;
+ ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
+ } else if (b->flags & DEVF_TEXT16B) {
+ ACCESS_FBINFO(devflags.vgastep) = 16;
+ ACCESS_FBINFO(devflags.textmode) = 1;
+ ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
+ } else {
+ ACCESS_FBINFO(devflags.vgastep) = 8;
+ ACCESS_FBINFO(devflags.textmode) = 1;
+ ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
+ }
+#ifdef CONFIG_FB_MATROX_32MB
+ ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+#endif
+ ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
+ ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
+ ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
+ ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
+ ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
+
+ if (ACCESS_FBINFO(capable.cross4MB) < 0)
+ ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
+ if (b->flags & DEVF_SWAPS) {
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
+ video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
+ } else {
+ ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
+ video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
+ }
+ err = -EINVAL;
+ if (!ctrlptr_phys) {
+ printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+ goto fail;
+ }
+ if (!video_base_phys) {
+ printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+ goto fail;
+ }
+ memsize = b->base->maxvram;
+ if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) {
+ goto fail;
+ }
+ if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) {
+ goto failCtrlMR;
+ }
+ ACCESS_FBINFO(video.len_maximum) = memsize;
+ /* convert mem (autodetect k, M) */
+ if (mem < 1024) mem *= 1024;
+ if (mem < 0x00100000) mem *= 1024;
+
+ if (mem && (mem < memsize))
+ memsize = mem;
+ err = -ENOMEM;
+ if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+ goto failVideoMR;
+ }
+ ACCESS_FBINFO(mmio.base) = ctrlptr_phys;
+ ACCESS_FBINFO(mmio.len) = 16384;
+ ACCESS_FBINFO(video.base) = video_base_phys;
+ if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+ video_base_phys, memsize);
+ goto failCtrlIO;
+ }
+ {
+ u_int32_t cmd;
+ u_int32_t mga_option;
+
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
+ pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
+ mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+ mga_option |= MX_OPTION_BSWAP;
+ /* disable palette snooping */
+ cmd &= ~PCI_COMMAND_VGA_PALETTE;
+ if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
+ if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
+ printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+ }
+ mga_option |= 0x20000000;
+ ACCESS_FBINFO(devflags.nopciretry) = 1;
+ }
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
+ hw->MXoptionReg = mga_option;
+
+ /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+ /* maybe preinit() candidate, but it is same... for all devices... at this time... */
+ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
+ }
+
+ err = -ENXIO;
+ if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
+ goto failVideoIO;
+ }
+
+ err = -ENOMEM;
+ if (!matroxfb_getmemory(PMINFO memsize, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) {
+ printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+ goto failVideoIO;
+ }
+ ACCESS_FBINFO(devflags.ydstorg) = 0;
+
+ ACCESS_FBINFO(currcon) = -1;
+ ACCESS_FBINFO(currcon_display) = d;
+ mga_iounmap(ACCESS_FBINFO(video.vbase));
+ ACCESS_FBINFO(video.base) = video_base_phys;
+ if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
+ printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+ video_base_phys, ACCESS_FBINFO(video.len));
+ goto failCtrlIO;
+ }
+ ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
+ if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+ ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
+ ACCESS_FBINFO(mtrr.vram_valid) = 1;
+ printk(KERN_INFO "matroxfb: MTRR's turned on\n");
+ }
+#endif /* CONFIG_MTRR */
+
+ if (!ACCESS_FBINFO(devflags.novga))
+ request_region(0x3C0, 32, "matrox");
+ ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
+ ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
+ ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
+ ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
+ ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
+ ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
+
+ /* static settings */
+ if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
+ strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
+ }
+ vesafb_defined.red = colors[depth-1].red;
+ vesafb_defined.green = colors[depth-1].green;
+ vesafb_defined.blue = colors[depth-1].blue;
+ vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+ vesafb_defined.grayscale = grayscale;
+ vesafb_defined.vmode = 0;
+ if (noaccel)
+ vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+ strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
+ ACCESS_FBINFO(fbcon.changevar) = NULL;
+ ACCESS_FBINFO(fbcon.node) = -1;
+ ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
+ ACCESS_FBINFO(fbcon.disp) = d;
+ ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
+ ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
+ ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+ /* after __init time we are like module... no logo */
+ ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT;
+ ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+
+#ifndef MODULE
+ /* mode database is marked __init!!! */
+ if (!hotplug) {
+ fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+ NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
+ }
+#endif /* !MODULE */
+
+ /* mode modifiers */
+ if (hslen)
+ vesafb_defined.hsync_len = hslen;
+ if (vslen)
+ vesafb_defined.vsync_len = vslen;
+ if (left != ~0)
+ vesafb_defined.left_margin = left;
+ if (right != ~0)
+ vesafb_defined.right_margin = right;
+ if (upper != ~0)
+ vesafb_defined.upper_margin = upper;
+ if (lower != ~0)
+ vesafb_defined.lower_margin = lower;
+ if (xres)
+ vesafb_defined.xres = xres;
+ if (yres)
+ vesafb_defined.yres = yres;
+ if (sync != -1)
+ vesafb_defined.sync = sync;
+ else if (vesafb_defined.sync == ~0) {
+ vesafb_defined.sync = 0;
+ if (yres < 400)
+ vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
+ else if (yres < 480)
+ vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+
+ /* fv, fh, maxclk limits was specified */
+ {
+ unsigned int tmp;
+
+ if (fv) {
+ tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
+ + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+ if ((tmp < fh) || (fh == 0)) fh = tmp;
+ }
+ if (fh) {
+ tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
+ + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+ if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+ }
+ maxclk = (maxclk + 499) / 500;
+ if (maxclk) {
+ tmp = (2000000000 + maxclk) / maxclk;
+ if (tmp > pixclock) pixclock = tmp;
+ }
+ }
+ if (pixclock) {
+ if (pixclock < 2000) /* > 500MHz */
+ pixclock = 4000; /* 250MHz */
+ if (pixclock > 1000000)
+ pixclock = 1000000; /* 1MHz */
+ vesafb_defined.pixclock = pixclock;
+ }
+
+ /* FIXME: Where to move this?! */
+#if defined(CONFIG_FB_OF)
+#if defined(CONFIG_FB_COMPAT_XPMAC)
+ strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */
+ strncat(ACCESS_FBINFO(matrox_name), b->name, 26);
+ if (!console_fb_info)
+ console_fb_info = &ACCESS_FBINFO(fbcon);
+#endif
+ if ((xres <= 640) && (yres <= 480)) {
+ struct fb_var_screeninfo var;
+ if (default_vmode == VMODE_NVRAM) {
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_CHOOSE;
+ }
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_640_480_60;
+ if (default_cmode == CMODE_NVRAM)
+ default_cmode = nvram_read_byte(NV_CMODE);
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+ default_cmode = CMODE_8;
+ if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
+ var.accel_flags = vesafb_defined.accel_flags;
+ var.xoffset = var.yoffset = 0;
+ vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
+ }
+ }
+#endif
+ vesafb_defined.xres_virtual = vesafb_defined.xres;
+ if (nopan) {
+ vesafb_defined.yres_virtual = vesafb_defined.yres;
+ } else {
+ vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+ to yres_virtual * xres_virtual < 2^32 */
+ }
+ err = -EINVAL;
+ if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
+ printk(KERN_ERR "matroxfb: cannot set required parameters\n");
+ goto failVideoIO;
+ }
+
+ printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+ vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+ vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+ printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+ ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len));
+
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+ if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
+ goto failVideoIO;
+ }
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
+ if (ACCESS_FBINFO(currcon) < 0) {
+ /* there is no console on this fb... but we have to initialize hardware
+ * until someone tells me what is proper thing to do */
+ printk(KERN_INFO "fb%d: initializing hardware\n",
+ GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
+ matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
+ }
+ return 0;
+failVideoIO:;
+ mga_iounmap(ACCESS_FBINFO(video.vbase));
+failCtrlIO:;
+ mga_iounmap(ACCESS_FBINFO(mmio.vbase));
+failVideoMR:;
+ release_mem_region(video_base_phys, ACCESS_FBINFO(video.len_maximum));
+failCtrlMR:;
+ release_mem_region(ctrlptr_phys, 16384);
+fail:;
+ return err;
+}
+
+LIST_HEAD(matroxfb_list);
+LIST_HEAD(matroxfb_driver_list);
+
+#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb)
+#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node)
+int matroxfb_register_driver(struct matroxfb_driver* drv) {
+ struct matrox_fb_info* minfo;
+
+ list_add(&drv->node, &matroxfb_driver_list);
+ for (minfo = matroxfb_l(matroxfb_list.next);
+ minfo != matroxfb_l(&matroxfb_list);
+ minfo = matroxfb_l(minfo->next_fb.next)) {
+ void* p;
+
+ if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS)
+ continue;
+ p = drv->probe(minfo);
+ if (p) {
+ minfo->drivers_data[minfo->drivers_count] = p;
+ minfo->drivers[minfo->drivers_count++] = drv;
+ }
+ }
+ return 0;
+}
+
+void matroxfb_unregister_driver(struct matroxfb_driver* drv) {
+ struct matrox_fb_info* minfo;
+
+ list_del(&drv->node);
+ for (minfo = matroxfb_l(matroxfb_list.next);
+ minfo != matroxfb_l(&matroxfb_list);
+ minfo = matroxfb_l(minfo->next_fb.next)) {
+ int i;
+
+ for (i = 0; i < minfo->drivers_count; ) {
+ if (minfo->drivers[i] == drv) {
+ if (drv && drv->remove)
+ drv->remove(minfo, minfo->drivers_data[i]);
+ minfo->drivers[i] = minfo->drivers[--minfo->drivers_count];
+ minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count];
+ } else
+ i++;
+ }
+ }
+}
+
+static void matroxfb_register_device(struct matrox_fb_info* minfo) {
+ struct matroxfb_driver* drv;
+ int i = 0;
+ list_add(&ACCESS_FBINFO(next_fb), &matroxfb_list);
+ for (drv = matroxfb_driver_l(matroxfb_driver_list.next);
+ drv != matroxfb_driver_l(&matroxfb_driver_list);
+ drv = matroxfb_driver_l(drv->node.next)) {
+ if (drv && drv->probe) {
+ void *p = drv->probe(minfo);
+ if (p) {
+ minfo->drivers_data[i] = p;
+ minfo->drivers[i++] = drv;
+ if (i == MATROXFB_MAX_FB_DRIVERS)
+ break;
+ }
+ }
+ }
+ minfo->drivers_count = i;
+}
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
+ int i;
+
+ list_del(&ACCESS_FBINFO(next_fb));
+ for (i = 0; i < minfo->drivers_count; i++) {
+ struct matroxfb_driver* drv = minfo->drivers[i];
+
+ if (drv && drv->remove)
+ drv->remove(minfo, minfo->drivers_data[i]);
+ }
+}
+
+static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
+ struct board* b;
+ u_int8_t rev;
+ u_int16_t svid;
+ u_int16_t sid;
+ struct matrox_fb_info* minfo;
+ struct display* d;
+ int err;
+#ifndef CONFIG_FB_MATROX_MULTIHEAD
+ static int registered = 0;
+#endif
+ DBG("matroxfb_probe")
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ svid = pdev->subsystem_vendor;
+ sid = pdev->subsystem_device;
+ for (b = dev_list; b->vendor; b++) {
+ if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+ if (b->svid)
+ if ((b->svid != svid) || (b->sid != sid)) continue;
+ break;
+ }
+ /* not match... */
+ if (!b->vendor)
+ return -1;
+ if (dev > 0) {
+ /* not requested one... */
+ dev--;
+ return -1;
+ }
+ if (pci_enable_device(pdev)) {
+ return -1;
+ }
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
+ if (!minfo)
+ return -1;
+ d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
+ if (!d) {
+ kfree(minfo);
+ return -1;
+ }
+#else
+ if (registered) /* singlehead driver... */
+ return -1;
+ minfo = &matroxfb_global_mxinfo;
+ d = &global_disp;
+#endif
+ memset(MINFO, 0, sizeof(*MINFO));
+ memset(d, 0, sizeof(*d));
+
+ ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
+ ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
+ ACCESS_FBINFO(pcidev) = pdev;
+ ACCESS_FBINFO(dead) = 0;
+ ACCESS_FBINFO(usecount) = 0;
+ pdev->driver_data = MINFO;
+ /* CMDLINE */
+ memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
+ /* DEVFLAGS */
+ ACCESS_FBINFO(devflags.inverse) = inverse;
+ ACCESS_FBINFO(devflags.novga) = novga;
+ ACCESS_FBINFO(devflags.nobios) = nobios;
+ ACCESS_FBINFO(devflags.noinit) = noinit;
+ ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
+ ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
+ ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
+ ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
+ ACCESS_FBINFO(devflags.blink) = blink;
+ ACCESS_FBINFO(devflags.sgram) = sgram;
+ ACCESS_FBINFO(capable.cross4MB) = cross4MB;
+
+ ACCESS_FBINFO(fastfont.size) = fastfont;
+
+ ACCESS_FBINFO(cursor.state) = CM_ERASE;
+ ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL;
+ ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO;
+ spin_lock_init(&ACCESS_FBINFO(lock.DAC));
+ spin_lock_init(&ACCESS_FBINFO(lock.accel));
+ init_rwsem(&ACCESS_FBINFO(crtc2.lock));
+ init_rwsem(&ACCESS_FBINFO(altout.lock));
+
+ ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
+ ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
+ ACCESS_FBINFO(output.sh) = 0;
+
+ /* subsequent heads always needs initialization and must not enable BIOS */
+ noinit = 0;
+ nobios = 1;
+ novga = 1;
+
+ err = initMatrox2(PMINFO d, b);
+ if (!err) {
+ matroxfb_register_device(MINFO);
+ return 0;
+ }
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+ kfree(d);
+ kfree(minfo);
+#endif
+ return -1;
+}
+
+static void pci_remove_matrox(struct pci_dev* pdev) {
+ struct matrox_fb_info* minfo;
+
+ minfo = pdev->driver_data;
+ matroxfb_remove(PMINFO 1);
+}
+
+static struct pci_driver matroxfb_driver = {
+ name: "matroxfb",
+ probe: matroxfb_probe,
+ remove: pci_remove_matrox,
+};
+
+/* **************************** init-time only **************************** */
+
+#define RSResolution(X) ((X) & 0x0F)
+#define RS640x400 1
+#define RS640x480 2
+#define RS800x600 3
+#define RS1024x768 4
+#define RS1280x1024 5
+#define RS1600x1200 6
+#define RS768x576 7
+#define RS960x720 8
+#define RS1152x864 9
+#define RS1408x1056 10
+#define RS640x350 11
+#define RS1056x344 12 /* 132 x 43 text */
+#define RS1056x400 13 /* 132 x 50 text */
+#define RS1056x480 14 /* 132 x 60 text */
+#define RSNoxNo 15
+/* 10-FF */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+ { 640, 400, 48, 16, 39, 8, 96, 2, 70 },
+ { 640, 480, 48, 16, 33, 10, 96, 2, 60 },
+ { 800, 600, 144, 24, 28, 8, 112, 6, 60 },
+ { 1024, 768, 160, 32, 30, 4, 128, 4, 60 },
+ { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 },
+ { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 },
+ { 768, 576, 144, 16, 28, 6, 112, 4, 60 },
+ { 960, 720, 144, 24, 28, 8, 112, 4, 60 },
+ { 1152, 864, 192, 32, 30, 4, 128, 4, 60 },
+ { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 },
+ { 640, 350, 48, 16, 39, 8, 96, 2, 70 },
+ { 1056, 344, 96, 24, 59, 44, 160, 2, 70 },
+ { 1056, 400, 96, 24, 39, 8, 160, 2, 70 },
+ { 1056, 480, 96, 24, 36, 12, 160, 3, 60 },
+ { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 }
+};
+
+#define RSCreate(X,Y) ((X) | ((Y) << 8))
+static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+#ifdef FBCON_HAS_CFB8
+ { ~0, RSCreate(RSNoxNo, RS8bpp ) },
+ { 0x101, RSCreate(RS640x480, RS8bpp ) },
+ { 0x100, RSCreate(RS640x400, RS8bpp ) },
+ { 0x180, RSCreate(RS768x576, RS8bpp ) },
+ { 0x103, RSCreate(RS800x600, RS8bpp ) },
+ { 0x188, RSCreate(RS960x720, RS8bpp ) },
+ { 0x105, RSCreate(RS1024x768, RS8bpp ) },
+ { 0x190, RSCreate(RS1152x864, RS8bpp ) },
+ { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+ { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+ { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+#endif
+#ifdef FBCON_HAS_CFB16
+ { ~0, RSCreate(RSNoxNo, RS15bpp) },
+ { 0x110, RSCreate(RS640x480, RS15bpp) },
+ { 0x181, RSCreate(RS768x576, RS15bpp) },
+ { 0x113, RSCreate(RS800x600, RS15bpp) },
+ { 0x189, RSCreate(RS960x720, RS15bpp) },
+ { 0x116, RSCreate(RS1024x768, RS15bpp) },
+ { 0x191, RSCreate(RS1152x864, RS15bpp) },
+ { 0x119, RSCreate(RS1280x1024, RS15bpp) },
+ { 0x199, RSCreate(RS1408x1056, RS15bpp) },
+ { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+ { 0x111, RSCreate(RS640x480, RS16bpp) },
+ { 0x182, RSCreate(RS768x576, RS16bpp) },
+ { 0x114, RSCreate(RS800x600, RS16bpp) },
+ { 0x18A, RSCreate(RS960x720, RS16bpp) },
+ { 0x117, RSCreate(RS1024x768, RS16bpp) },
+ { 0x192, RSCreate(RS1152x864, RS16bpp) },
+ { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+ { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+ { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+#endif
+#ifdef FBCON_HAS_CFB24
+ { ~0, RSCreate(RSNoxNo, RS24bpp) },
+ { 0x1B2, RSCreate(RS640x480, RS24bpp) },
+ { 0x184, RSCreate(RS768x576, RS24bpp) },
+ { 0x1B5, RSCreate(RS800x600, RS24bpp) },
+ { 0x18C, RSCreate(RS960x720, RS24bpp) },
+ { 0x1B8, RSCreate(RS1024x768, RS24bpp) },
+ { 0x194, RSCreate(RS1152x864, RS24bpp) },
+ { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+ { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+ { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+#endif
+#ifdef FBCON_HAS_CFB32
+ { ~0, RSCreate(RSNoxNo, RS32bpp) },
+ { 0x112, RSCreate(RS640x480, RS32bpp) },
+ { 0x183, RSCreate(RS768x576, RS32bpp) },
+ { 0x115, RSCreate(RS800x600, RS32bpp) },
+ { 0x18B, RSCreate(RS960x720, RS32bpp) },
+ { 0x118, RSCreate(RS1024x768, RS32bpp) },
+ { 0x193, RSCreate(RS1152x864, RS32bpp) },
+ { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+ { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+ { 0x11F, RSCreate(RS1600x1200, RS32bpp) },
+#endif
+#ifdef FBCON_HAS_VGATEXT
+ { ~0, RSCreate(RSNoxNo, RSText ) },
+ { 0x002, RSCreate(RS640x400, RSText ) }, /* 80x25 */
+ { 0x003, RSCreate(RS640x400, RSText ) }, /* 80x25 */
+ { 0x007, RSCreate(RS640x400, RSText ) }, /* 80x25 */
+ { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */
+ { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */
+ { 0x109, RSCreate(RS1056x400, RSText ) }, /* 132x25 */
+ { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */
+ { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */
+ { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */
+#endif
+#ifdef FBCON_HAS_CFB4
+ { ~0, RSCreate(RSNoxNo, RS4bpp ) },
+ { 0x010, RSCreate(RS640x350, RS4bpp ) },
+ { 0x012, RSCreate(RS640x480, RS4bpp ) },
+ { 0x102, RSCreate(RS800x600, RS4bpp ) },
+ { 0x104, RSCreate(RS1024x768, RS4bpp ) },
+ { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+#endif
+ { 0, 0 }};
+
+static void __init matroxfb_init_params(void) {
+ /* fh from kHz to Hz */
+ if (fh < 1000)
+ fh *= 1000; /* 1kHz minimum */
+ /* maxclk */
+ if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
+ if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
+ /* fix VESA number */
+ if (vesa != ~0)
+ vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
+
+ /* static settings */
+ for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+ if (RSptr->vesa == vesa) break;
+ }
+ if (!RSptr->vesa) {
+ printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+ RSptr = vesamap;
+ }
+ {
+ int res = RSResolution(RSptr->info)-1;
+ if (left == ~0)
+ left = timmings[res].left;
+ if (!xres)
+ xres = timmings[res].xres;
+ if (right == ~0)
+ right = timmings[res].right;
+ if (!hslen)
+ hslen = timmings[res].hslen;
+ if (upper == ~0)
+ upper = timmings[res].upper;
+ if (!yres)
+ yres = timmings[res].yres;
+ if (lower == ~0)
+ lower = timmings[res].lower;
+ if (!vslen)
+ vslen = timmings[res].vslen;
+ if (!(fv||fh||maxclk||pixclock))
+ fv = timmings[res].vfreq;
+ if (depth == -1)
+ depth = RSDepth(RSptr->info);
+ }
+}
+
+static void __init matrox_init(void) {
+ matroxfb_init_params();
+ pci_register_driver(&matroxfb_driver);
+ dev = -1; /* accept all new devices... */
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit matrox_done(void) {
+ pci_unregister_driver(&matroxfb_driver);
+}
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init matroxfb_setup(char *options) {
+ char *this_opt;
+
+ DBG("matroxfb_setup")
+
+ fontname[0] = '\0';
+
+ if (!options || !*options)
+ return 0;
+
+ for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ if (!*this_opt) continue;
+
+ dprintk("matroxfb_setup: option %s\n", this_opt);
+
+ if (!strncmp(this_opt, "dev:", 4))
+ dev = simple_strtoul(this_opt+4, NULL, 0);
+ else if (!strncmp(this_opt, "depth:", 6)) {
+ switch (simple_strtoul(this_opt+6, NULL, 0)) {
+ case 0: depth = RSText; break;
+ case 4: depth = RS4bpp; break;
+ case 8: depth = RS8bpp; break;
+ case 15:depth = RS15bpp; break;
+ case 16:depth = RS16bpp; break;
+ case 24:depth = RS24bpp; break;
+ case 32:depth = RS32bpp; break;
+ default:
+ printk(KERN_ERR "matroxfb: unsupported color depth\n");
+ }
+ } else if (!strncmp(this_opt, "xres:", 5))
+ xres = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "yres:", 5))
+ yres = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "vslen:", 6))
+ vslen = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "hslen:", 6))
+ hslen = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "left:", 5))
+ left = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "right:", 6))
+ right = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "upper:", 6))
+ upper = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "lower:", 6))
+ lower = simple_strtoul(this_opt+6, NULL, 0);
+ else if (!strncmp(this_opt, "pixclock:", 9))
+ pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ else if (!strncmp(this_opt, "sync:", 5))
+ sync = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "vesa:", 5))
+ vesa = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "font:", 5))
+ strncpy(fontname, this_opt+5, sizeof(fontname)-1);
+ else if (!strncmp(this_opt, "maxclk:", 7))
+ maxclk = simple_strtoul(this_opt+7, NULL, 0);
+ else if (!strncmp(this_opt, "fh:", 3))
+ fh = simple_strtoul(this_opt+3, NULL, 0);
+ else if (!strncmp(this_opt, "fv:", 3))
+ fv = simple_strtoul(this_opt+3, NULL, 0);
+ else if (!strncmp(this_opt, "mem:", 4))
+ mem = simple_strtoul(this_opt+4, NULL, 0);
+ else if (!strncmp(this_opt, "mode:", 5))
+ strncpy(videomode, this_opt+5, sizeof(videomode)-1);
+#ifdef CONFIG_FB_OF
+ else if (!strncmp(this_opt, "vmode:", 6)) {
+ unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+ if (vmode > 0 && vmode <= VMODE_MAX)
+ default_vmode = vmode;
+ } else if (!strncmp(this_opt, "cmode:", 6)) {
+ unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+ switch (cmode) {
+ case 0:
+ case 8:
+ default_cmode = CMODE_8;
+ break;
+ case 15:
+ case 16:
+ default_cmode = CMODE_16;
+ break;
+ case 24:
+ case 32:
+ default_cmode = CMODE_32;
+ break;
+ }
+ }
+#endif
+ else if (!strncmp(this_opt, "fastfont:", 9))
+ fastfont = simple_strtoul(this_opt+9, NULL, 0);
+ else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */
+ fastfont = 0;
+ else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */
+ disabled = 1;
+ else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */
+ disabled = 0;
+ else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */
+ sgram = 1;
+ else if (!strcmp(this_opt, "sdram"))
+ sgram = 0;
+ else {
+ int value = 1;
+
+ if (!strncmp(this_opt, "no", 2)) {
+ value = 0;
+ this_opt += 2;
+ }
+ if (! strcmp(this_opt, "inverse"))
+ inverse = value;
+ else if (!strcmp(this_opt, "accel"))
+ noaccel = !value;
+ else if (!strcmp(this_opt, "pan"))
+ nopan = !value;
+ else if (!strcmp(this_opt, "pciretry"))
+ no_pci_retry = !value;
+ else if (!strcmp(this_opt, "vga"))
+ novga = !value;
+ else if (!strcmp(this_opt, "bios"))
+ nobios = !value;
+ else if (!strcmp(this_opt, "init"))
+ noinit = !value;
+#ifdef CONFIG_MTRR
+ else if (!strcmp(this_opt, "mtrr"))
+ mtrr = value;
+#endif
+ else if (!strcmp(this_opt, "inv24"))
+ inv24 = value;
+ else if (!strcmp(this_opt, "cross4MB"))
+ cross4MB = value;
+ else if (!strcmp(this_opt, "hwcursor"))
+ hwcursor = value;
+ else if (!strcmp(this_opt, "blink"))
+ blink = value;
+ else if (!strcmp(this_opt, "grayscale"))
+ grayscale = value;
+ else {
+ strncpy(videomode, this_opt, sizeof(videomode)-1);
+ }
+ }
+ }
+ return 0;
+}
+
+static int __init initialized = 0;
+
+int __init matroxfb_init(void)
+{
+ DBG("matroxfb_init")
+
+ if (disabled)
+ return -ENXIO;
+ if (!initialized) {
+ initialized = 1;
+ matrox_init();
+ }
+ /* never return failure, user can hotplug matrox later... */
+ return 0;
+}
+
+#if defined(CONFIG_FB_OF)
+int __init matrox_of_init(struct device_node *dp){
+ DBG("matrox_of_init");
+
+ if (disabled)
+ return -ENXIO;
+ if (!initialized) {
+ initialized = 1;
+ matrox_init();
+ }
+ /* failure? */
+ return 0;
+}
+#endif /* CONFIG_FB_OF */
+
+#else
+
+/* *************************** init module code **************************** */
+
+MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
+MODULE_PARM(mem, "i");
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+MODULE_PARM(nopan, "i");
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+MODULE_PARM(no_pci_retry, "i");
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(novga, "i");
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+MODULE_PARM(nobios, "i");
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
+MODULE_PARM(noinit, "i");
+MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
+MODULE_PARM(mtrr, "i");
+MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
+MODULE_PARM(sgram, "i");
+MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM(inv24, "i");
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+#else
+MODULE_PARM(dev, "i");
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
+#endif
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+MODULE_PARM(upper, "i");
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+MODULE_PARM(lower, "i");
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(vslen, "i");
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+MODULE_PARM(left, "i");
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+MODULE_PARM(right, "i");
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+MODULE_PARM(hslen, "i");
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+MODULE_PARM(pixclock, "i");
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+MODULE_PARM(depth, "i");
+MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
+MODULE_PARM(maxclk, "i");
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+MODULE_PARM(fh, "i");
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+MODULE_PARM(fv, "i");
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
+MODULE_PARM(hwcursor, "i");
+MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)");
+MODULE_PARM(blink, "i");
+MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)");
+MODULE_PARM(fastfont, "i");
+MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)");
+MODULE_PARM(grayscale, "i");
+MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
+MODULE_PARM(cross4MB, "i");
+MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+#ifdef CONFIG_FB_OF
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
+
+int __init init_module(void){
+
+ DBG("init_module")
+
+ if (disabled)
+ return -ENXIO;
+
+ if (depth == 0)
+ depth = RSText;
+ else if (depth == 4)
+ depth = RS4bpp;
+ else if (depth == 8)
+ depth = RS8bpp;
+ else if (depth == 15)
+ depth = RS15bpp;
+ else if (depth == 16)
+ depth = RS16bpp;
+ else if (depth == 24)
+ depth = RS24bpp;
+ else if (depth == 32)
+ depth = RS32bpp;
+ else if (depth != -1) {
+ printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+ depth = -1;
+ }
+ matrox_init();
+ /* never return failure; user can hotplug matrox later... */
+ return 0;
+}
+#endif /* MODULE */
+
+module_exit(matrox_done);
+EXPORT_SYMBOL(matroxfb_register_driver);
+EXPORT_SYMBOL(matroxfb_unregister_driver);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
new file mode 100644
index 000000000..0cb21b0f9
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -0,0 +1,825 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ */
+#ifndef __MATROXFB_H__
+#define __MATROXFB_H__
+
+/* general, but fairly heavy, debugging */
+#undef MATROXFB_DEBUG
+
+/* heavy debugging: */
+/* -- logs putc[s], so everytime a char is displayed, it's logged */
+#undef MATROXFB_DEBUG_HEAVY
+
+/* This one _could_ cause infinite loops */
+/* It _does_ cause lots and lots of messages during idle loops */
+#undef MATROXFB_DEBUG_LOOP
+
+/* Debug register calls, too? */
+#undef MATROXFB_DEBUG_REG
+
+/* Guard accelerator accesses with spin_lock_irqsave... */
+#undef MATROXFB_USE_SPINLOCKS
+
+#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/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb4.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#if defined(CONFIG_FB_OF)
+#if defined(CONFIG_FB_COMPAT_XPMAC)
+#include <asm/vc_ioctl.h>
+#endif
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <video/macmodes.h>
+#endif
+
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
+#define FBCON_HAS_VGATEXT
+
+#ifdef MATROXFB_DEBUG
+
+#define DEBUG
+#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x));
+
+#ifdef MATROXFB_DEBUG_HEAVY
+#define DBG_HEAVY(x) DBG(x)
+#else /* MATROXFB_DEBUG_HEAVY */
+#define DBG_HEAVY(x) /* DBG_HEAVY */
+#endif /* MATROXFB_DEBUG_HEAVY */
+
+#ifdef MATROXFB_DEBUG_LOOP
+#define DBG_LOOP(x) DBG(x)
+#else /* MATROXFB_DEBUG_LOOP */
+#define DBG_LOOP(x) /* DBG_LOOP */
+#endif /* MATROXFB_DEBUG_LOOP */
+
+#ifdef MATROXFB_DEBUG_REG
+#define DBG_REG(x) DBG(x)
+#else /* MATROXFB_DEBUG_REG */
+#define DBG_REG(x) /* DBG_REG */
+#endif /* MATROXFB_DEBUG_REG */
+
+#else /* MATROXFB_DEBUG */
+
+#define DBG(x) /* DBG */
+#define DBG_HEAVY(x) /* DBG_HEAVY */
+#define DBG_REG(x) /* DBG_REG */
+#define DBG_LOOP(x) /* DBG_LOOP */
+
+#endif /* MATROXFB_DEBUG */
+
+#ifndef __i386__
+#ifndef ioremap_nocache
+#define ioremap_nocache(X,Y) ioremap(X,Y)
+#endif
+#endif
+
+#if defined(__alpha__) || defined(__m68k__)
+#define READx_WORKS
+#define MEMCPYTOIO_WORKS
+#else
+#define READx_FAILS
+/* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */
+/* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */
+/* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */
+/* much of PCI bandwidth is used during transfers... */
+#if defined(__i386__)
+#define MEMCPYTOIO_MEMCPY
+#else
+#define MEMCPYTOIO_WRITEL
+#endif
+#endif
+
+#ifdef __sparc__
+#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..."
+#endif
+
+#if defined(__m68k__)
+#define MAP_BUSTOVIRT
+#else
+#define MAP_IOREMAP
+#endif
+
+#ifdef DEBUG
+#define dprintk(X...) printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G200_PCI
+#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G200_AGP
+#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100
+#define PCI_DEVICE_ID_MATROX_G100 0x1000
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
+#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
+#endif
+#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
+#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_GENERIC 0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001
+#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP 0x2179
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G100, G200 and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
+#define NEED_DAC1064 1
+#endif
+
+typedef struct {
+ u_int8_t* vaddr;
+} vaddr_t;
+
+#ifdef READx_WORKS
+static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
+ return readb(va.vaddr + offs);
+}
+
+static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
+ return readw(va.vaddr + offs);
+}
+
+static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
+ return readl(va.vaddr + offs);
+}
+
+static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
+ writeb(value, va.vaddr + offs);
+}
+
+static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
+ writew(value, va.vaddr + offs);
+}
+
+static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
+ writel(value, va.vaddr + offs);
+}
+#else
+static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
+ return *(volatile u_int8_t*)(va.vaddr + offs);
+}
+
+static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
+ return *(volatile u_int16_t*)(va.vaddr + offs);
+}
+
+static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
+ return *(volatile u_int32_t*)(va.vaddr + offs);
+}
+
+static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
+ *(volatile u_int8_t*)(va.vaddr + offs) = value;
+}
+
+static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
+ *(volatile u_int16_t*)(va.vaddr + offs) = value;
+}
+
+static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
+ *(volatile u_int32_t*)(va.vaddr + offs) = value;
+}
+#endif
+
+static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) {
+#ifdef MEMCPYTOIO_WORKS
+ memcpy_toio(va.vaddr + offs, src, len);
+#elif defined(MEMCPYTOIO_WRITEL)
+#define srcd ((const u_int32_t*)src)
+ if (offs & 3) {
+ while (len >= 4) {
+ mga_writel(va, offs, get_unaligned(srcd++));
+ offs += 4;
+ len -= 4;
+ }
+ } else {
+ while (len >= 4) {
+ mga_writel(va, offs, *srcd++);
+ offs += 4;
+ len -= 4;
+ }
+ }
+#undef srcd
+ if (len) {
+ u_int32_t tmp;
+
+ memcpy(&tmp, src, len);
+ mga_writel(va, offs, tmp);
+ }
+#elif defined(MEMCPYTOIO_MEMCPY)
+ memcpy(va.vaddr + offs, src, len);
+#else
+#error "Sorry, do not know how to write block of data to device"
+#endif
+}
+
+static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
+ va->vaddr += offs;
+}
+
+static inline void* vaddr_va(vaddr_t va) {
+ return va.vaddr;
+}
+
+#define MGA_IOREMAP_NORMAL 0
+#define MGA_IOREMAP_NOCACHE 1
+
+#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE
+#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE
+static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) {
+#ifdef MAP_IOREMAP
+ if (flags & MGA_IOREMAP_NOCACHE)
+ virt->vaddr = ioremap_nocache(phys, size);
+ else
+ virt->vaddr = ioremap(phys, size);
+#else
+#ifdef MAP_BUSTOVIRT
+ virt->vaddr = bus_to_virt(phys);
+#else
+#error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up"
+#endif
+#endif
+ return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
+}
+
+static inline void mga_iounmap(vaddr_t va) {
+#ifdef MAP_IOREMAP
+ iounmap(va.vaddr);
+#endif
+}
+
+struct my_timming {
+ unsigned int pixclock;
+ unsigned int HDisplay;
+ unsigned int HSyncStart;
+ unsigned int HSyncEnd;
+ unsigned int HTotal;
+ unsigned int VDisplay;
+ unsigned int VSyncStart;
+ unsigned int VSyncEnd;
+ unsigned int VTotal;
+ unsigned int sync;
+ int dblscan;
+ int interlaced;
+ unsigned int delay; /* CRTC delay */
+};
+
+struct matrox_pll_features {
+ unsigned int vco_freq_min;
+ unsigned int ref_freq;
+ unsigned int feed_div_min;
+ unsigned int feed_div_max;
+ unsigned int in_div_min;
+ unsigned int in_div_max;
+ unsigned int post_shift_max;
+};
+
+struct matroxfb_par
+{
+ unsigned int final_bppShift;
+ unsigned int cmap_len;
+ struct {
+ unsigned int bytes;
+ unsigned int pixels;
+ unsigned int chunks;
+ } ydstorg;
+ void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int);
+ void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int);
+};
+
+struct matrox_fb_info;
+
+struct matrox_DAC1064_features {
+ u_int8_t xvrefctrl;
+ u_int8_t xmiscctrl;
+ unsigned int cursorimage;
+};
+
+struct matrox_accel_features {
+ int has_cacheflush;
+};
+
+/* current hardware status */
+struct mavenregs {
+ u_int8_t regs[256];
+ int mode;
+ int vlines;
+ int xtal;
+ int fv;
+
+ u_int16_t htotal;
+ u_int16_t hcorr;
+};
+
+struct matrox_hw_state {
+ u_int32_t MXoptionReg;
+ unsigned char DACclk[6];
+ unsigned char DACreg[64];
+ unsigned char MiscOutReg;
+ unsigned char DACpal[768];
+ unsigned char CRTC[25];
+ unsigned char CRTCEXT[9];
+ unsigned char SEQ[5];
+ /* unused for MGA mode, but who knows... */
+ unsigned char GCTL[9];
+ /* unused for MGA mode, but who knows... */
+ unsigned char ATTR[21];
+
+ /* TVOut only */
+ struct mavenregs maven;
+
+ /* CRTC2 only */
+ /* u_int32_t TBD */
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+ unsigned char ramdac_rev;
+#endif
+ u_int32_t m_dwg_rect;
+ u_int32_t m_opmode;
+};
+
+struct matrox_altout {
+ int (*compute)(void* altout_dev, struct my_timming* input, struct matrox_hw_state* state);
+ int (*program)(void* altout_dev, const struct matrox_hw_state* state);
+ int (*start)(void* altout_dev);
+ void (*incuse)(void* altout_dev);
+ void (*decuse)(void* altout_dev);
+ int (*setmode)(void* altout_dev, u_int32_t mode);
+ int (*getmode)(void* altout_dev, u_int32_t* mode);
+};
+
+struct matrox_switch;
+struct matroxfb_driver;
+
+struct matrox_fb_info {
+ /* fb_info must be first */
+ struct fb_info fbcon;
+
+ struct list_head next_fb;
+
+ int dead;
+ unsigned int usecount;
+
+ struct matroxfb_par curr;
+ struct matrox_hw_state hw1;
+ struct matrox_hw_state hw2;
+ struct matrox_hw_state* newhw;
+ struct matrox_hw_state* currenthw;
+
+ struct matrox_accel_data accel;
+
+ struct pci_dev* pcidev;
+
+ struct {
+ u_int32_t all;
+ u_int32_t ph;
+ u_int32_t sh;
+ } output;
+ struct matrox_altout* primout;
+ struct {
+ struct fb_info* info;
+ struct rw_semaphore lock;
+ } crtc2;
+ struct {
+ struct matrox_altout* output;
+ void* device;
+ struct rw_semaphore lock;
+ } altout;
+
+#define MATROXFB_MAX_FB_DRIVERS 5
+ struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
+ void* (drivers_data[MATROXFB_MAX_FB_DRIVERS]);
+ unsigned int drivers_count;
+
+ struct {
+ unsigned long base; /* physical */
+ vaddr_t vbase; /* CPU view */
+ unsigned int len;
+ unsigned int len_usable;
+ unsigned int len_maximum;
+ } video;
+
+ struct {
+ unsigned long base; /* physical */
+ vaddr_t vbase; /* CPU view */
+ unsigned int len;
+ } mmio;
+
+ unsigned int max_pixel_clock;
+
+ struct matrox_switch* hw_switch;
+ int currcon;
+ struct display* currcon_display;
+
+ struct {
+ struct matrox_pll_features pll;
+ struct matrox_DAC1064_features DAC1064;
+ struct matrox_accel_features accel;
+ } features;
+ struct {
+ spinlock_t DAC;
+ spinlock_t accel;
+ } lock;
+
+ int interleave;
+ int millenium;
+ int milleniumII;
+ struct {
+ int cfb4;
+ const int* vxres;
+ int cross4MB;
+ int text;
+ int plnwt;
+ } capable;
+ struct {
+ unsigned int size;
+ unsigned int mgabase;
+ vaddr_t vbase;
+ } fastfont;
+#ifdef CONFIG_MTRR
+ struct {
+ int vram;
+ int vram_valid;
+ } mtrr;
+#endif
+ struct {
+ int precise_width;
+ int mga_24bpp_fix;
+ int novga;
+ int nobios;
+ int nopciretry;
+ int noinit;
+ int inverse;
+ int hwcursor;
+ int blink;
+ int sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+ int support32MB;
+#endif
+
+ int accelerator;
+ int text_type_aux;
+ int video64bits;
+ int crtc2;
+ int maven_capable;
+ unsigned int vgastep;
+ unsigned int textmode;
+ unsigned int textstep;
+ unsigned int textvram; /* character cells */
+ unsigned int ydstorg; /* offset in bytes from video start to usable memory */
+ /* 0 except for 6MB Millenium */
+ } devflags;
+ struct display_switch dispsw;
+ struct {
+ int x;
+ int y;
+ unsigned int w;
+ unsigned int u;
+ unsigned int d;
+ unsigned int type;
+ int state;
+ int redraw;
+ struct timer_list timer;
+ } cursor;
+ struct { unsigned red, green, blue, transp; } palette[256];
+#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
+ char matrox_name[32];
+#endif
+/* These ifdefs must be last! They differ for module & non-module compiles */
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
+ union {
+#ifdef FBCON_HAS_CFB16
+ u_int16_t cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+ u_int32_t cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u_int32_t cfb32[16];
+#endif
+ } cmap;
+#endif
+};
+
+#ifdef CONFIG_FB_MATROX_MULTIHEAD
+#define ACCESS_FBINFO2(info, x) (info->x)
+#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
+
+#define MINFO minfo
+
+#define WPMINFO2 struct matrox_fb_info* minfo
+#define WPMINFO WPMINFO2 ,
+#define CPMINFO2 const struct matrox_fb_info* minfo
+#define CPMINFO CPMINFO2 ,
+#define PMINFO2 minfo
+#define PMINFO PMINFO2 ,
+
+static inline struct matrox_fb_info* mxinfo(const struct display* p) {
+ return (struct matrox_fb_info*)p->fb_info;
+}
+
+#define PMXINFO(p) mxinfo(p),
+#define MINFO_FROM(x) struct matrox_fb_info* minfo = x
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
+
+#else
+
+extern struct matrox_fb_info matroxfb_global_mxinfo;
+struct display global_disp;
+
+#define ACCESS_FBINFO(x) (matroxfb_global_mxinfo.x)
+#define ACCESS_FBINFO2(info, x) (matroxfb_global_mxinfo.x)
+
+#define MINFO (&matroxfb_global_mxinfo)
+
+#define WPMINFO2 void
+#define WPMINFO
+#define CPMINFO2 void
+#define CPMINFO
+#define PMINFO2
+#define PMINFO
+
+#if 0
+static inline struct matrox_fb_info* mxinfo(const struct display* p) {
+ return &matroxfb_global_mxinfo;
+}
+#endif
+
+#define PMXINFO(p)
+#define MINFO_FROM(x)
+#define MINFO_FROM_DISP(x)
+
+#endif
+
+struct matrox_switch {
+ int (*preinit)(WPMINFO struct matrox_hw_state*);
+ void (*reset)(WPMINFO struct matrox_hw_state*);
+ int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*, struct display*);
+ void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
+ int (*selhwcursor)(WPMINFO struct display*);
+};
+
+struct matroxfb_driver {
+ struct list_head node;
+ char* name;
+ void* (*probe)(struct matrox_fb_info* info);
+ void (*remove)(struct matrox_fb_info* info, void* data);
+};
+
+int matroxfb_register_driver(struct matroxfb_driver* drv);
+void matroxfb_unregister_driver(struct matroxfb_driver* drv);
+
+#define PCI_OPTION_REG 0x40
+#define PCI_MGA_INDEX 0x44
+#define PCI_MGA_DATA 0x48
+
+#define M_DWGCTL 0x1C00
+#define M_MACCESS 0x1C04
+#define M_CTLWTST 0x1C08
+
+#define M_PLNWT 0x1C1C
+
+#define M_BCOL 0x1C20
+#define M_FCOL 0x1C24
+
+#define M_SGN 0x1C58
+#define M_LEN 0x1C5C
+#define M_AR0 0x1C60
+#define M_AR1 0x1C64
+#define M_AR2 0x1C68
+#define M_AR3 0x1C6C
+#define M_AR4 0x1C70
+#define M_AR5 0x1C74
+#define M_AR6 0x1C78
+
+#define M_CXBNDRY 0x1C80
+#define M_FXBNDRY 0x1C84
+#define M_YDSTLEN 0x1C88
+#define M_PITCH 0x1C8C
+#define M_YDST 0x1C90
+#define M_YDSTORG 0x1C94
+#define M_YTOP 0x1C98
+#define M_YBOT 0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH 0x1FFF
+
+#define M_EXEC 0x0100
+
+#define M_DWG_TRAP 0x04
+#define M_DWG_BITBLT 0x08
+#define M_DWG_ILOAD 0x09
+
+#define M_DWG_LINEAR 0x0080
+#define M_DWG_SOLID 0x0800
+#define M_DWG_ARZERO 0x1000
+#define M_DWG_SGNZERO 0x2000
+#define M_DWG_SHIFTZERO 0x4000
+
+#define M_DWG_REPLACE 0x000C0000
+#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR 0x00060010
+
+#define M_DWG_BFCOL 0x04000000
+#define M_DWG_BMONOWF 0x08000000
+
+#define M_DWG_TRANSC 0x40000000
+
+#define M_FIFOSTATUS 0x1E10
+#define M_STATUS 0x1E14
+
+#define M_IEN 0x1E1C
+
+#define M_VCOUNT 0x1E20
+
+#define M_RESET 0x1E40
+
+#define M_AGP2PLL 0x1E4C
+
+#define M_OPMODE 0x1E54
+#define M_OPMODE_DMA_GEN_WRITE 0x00
+#define M_OPMODE_DMA_BLIT 0x04
+#define M_OPMODE_DMA_VECTOR_WRITE 0x08
+#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */
+#define M_OPMODE_DMA_BE_8BPP 0x0000
+#define M_OPMODE_DMA_BE_16BPP 0x0100
+#define M_OPMODE_DMA_BE_32BPP 0x0200
+#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */
+#define M_OPMODE_DIR_BE_8BPP 0x000000
+#define M_OPMODE_DIR_BE_16BPP 0x010000
+#define M_OPMODE_DIR_BE_32BPP 0x020000
+
+#define M_ATTR_INDEX 0x1FC0
+#define M_ATTR_DATA 0x1FC1
+
+#define M_MISC_REG 0x1FC2
+#define M_3C2_RD 0x1FC2
+
+#define M_SEQ_INDEX 0x1FC4
+#define M_SEQ_DATA 0x1FC5
+
+#define M_MISC_REG_READ 0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA 0x1FCF
+
+#define M_CRTC_INDEX 0x1FD4
+
+#define M_ATTR_RESET 0x1FDA
+#define M_3DA_WR 0x1FDA
+#define M_INSTS1 0x1FDA
+
+#define M_EXTVGA_INDEX 0x1FDE
+#define M_EXTVGA_DATA 0x1FDF
+
+/* G200 only */
+#define M_SRCORG 0x2CB4
+
+#define M_RAMDAC_BASE 0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG (M_RAMDAC_BASE+0)
+#define M_DAC_VAL (M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK (M_RAMDAC_BASE+2)
+
+#define M_X_INDEX 0x00
+#define M_X_DATAREG 0x0A
+
+#define DAC_XGENIOCTRL 0x2A
+#define DAC_XGENIODATA 0x2B
+
+#ifdef __LITTLE_ENDIAN
+#define MX_OPTION_BSWAP 0x00000000
+
+#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define MX_OPTION_BSWAP 0x80000000
+
+#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
+#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */
+#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr))
+#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr))
+#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val))
+#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
+#ifdef __LITTLE_ENDIAN
+#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port))
+#else
+#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n))
+#else
+#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+#endif
+
+#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x) (x->interleave)
+#define isMillenium(x) (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x) (0)
+#define isMillenium(x) (0)
+#define isMilleniumII(x) (0)
+#endif
+
+#define matroxfb_DAC_lock() spin_lock(&ACCESS_FBINFO(lock.DAC))
+#define matroxfb_DAC_unlock() spin_unlock(&ACCESS_FBINFO(lock.DAC))
+#define matroxfb_DAC_lock_irqsave(flags) spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC),flags)
+#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC),flags)
+extern void matroxfb_DAC_out(CPMINFO int reg, int val);
+extern int matroxfb_DAC_in(CPMINFO int reg);
+extern struct list_head matroxfb_list;
+extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
+
+#ifdef MATROXFB_USE_SPINLOCKS
+#define CRITBEGIN spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags);
+#define CRITEND spin_unlock_irqrestore(&ACCESS_FBINFO(lock.accel), critflags);
+#define CRITFLAGS unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+#endif /* __MATROXFB_H__ */
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
new file mode 100644
index 000000000..46fdb5fad
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -0,0 +1,788 @@
+#include "matroxfb_maven.h"
+#include "matroxfb_crtc2.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include <linux/matroxfb.h>
+#include <asm/uaccess.h>
+
+/* **************************************************** */
+
+static int mem = 8192;
+
+MODULE_PARM(mem, "i");
+MODULE_PARM_DESC(mem, "Memory size reserved for dualhead (default=8MB)");
+
+/* **************************************************** */
+
+static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp, struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ if (regno > 16)
+ return 1;
+ *red = m2info->palette[regno].red;
+ *blue = m2info->palette[regno].blue;
+ *green = m2info->palette[regno].green;
+ *transp = m2info->palette[regno].transp;
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct display* p;
+
+ if (regno > 16)
+ return 1;
+ m2info->palette[regno].red = red;
+ m2info->palette[regno].blue = blue;
+ m2info->palette[regno].green = green;
+ m2info->palette[regno].transp = transp;
+ p = m2info->currcon_display;
+ if (p->var.grayscale) {
+ /* gray = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+ red = CNVT_TOHW(red, p->var.red.length);
+ green = CNVT_TOHW(green, p->var.green.length);
+ blue = CNVT_TOHW(blue, p->var.blue.length);
+ transp = CNVT_TOHW(transp, p->var.transp.length);
+
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ m2info->cmap.cfb16[regno] =
+ (red << p->var.red.offset) |
+ (green << p->var.green.offset) |
+ (blue << p->var.blue.offset) |
+ (transp << p->var.transp.offset);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ m2info->cmap.cfb32[regno] =
+ (red << p->var.red.offset) |
+ (green << p->var.green.offset) |
+ (blue << p->var.blue.offset) |
+ (transp << p->var.transp.offset);
+ break;
+#endif
+ }
+ return 0;
+#undef m2info
+}
+
+static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
+ if (p->cmap.len)
+ fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
+ else
+ fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
+}
+
+static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
+ struct my_timming* mt,
+ struct display* p,
+ int mode,
+ unsigned int pos) {
+ u_int32_t tmp;
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ switch (mode) {
+ case 15:
+ tmp = 0x00200000;
+ break;
+ case 16:
+ tmp = 0x00400000;
+ break;
+/* case 32: */
+ default:
+ tmp = 0x00800000;
+ break;
+ }
+
+ if (ACCESS_FBINFO(output.sh)) {
+ tmp |= 0x00000001; /* enable CRTC2 */
+
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ tmp |= 0x00000002; /* source from VDOCLK */
+ tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
+ /* MGA TVO is our clock source */
+ } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ tmp |= 0x00000004; /* source from pixclock */
+ /* PIXPLL is our clock source */
+ }
+
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
+ tmp |= 0x00100000; /* connect CRTC2 to DAC */
+ }
+ mga_outl(0x3C10, tmp | 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */
+ mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
+ mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
+ mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
+ mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
+ mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart)); /* preload */
+ mga_outl(0x3C28, pos); /* vmemory start */
+ mga_outl(0x3C40, p->var.xres_virtual * (p->var.bits_per_pixel >> 3));
+ tmp = 0x0FFF0000; /* line compare */
+ if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
+ tmp |= 0x00000100;
+ if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
+ tmp |= 0x00000200;
+ mga_outl(0x3C44, tmp);
+ mga_outl(0x3C4C, 0); /* data control */
+}
+
+static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
+ struct display* p) {
+ /* no acceleration for secondary head... */
+}
+
+static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
+ struct fb_var_screeninfo* var) {
+ unsigned int pos;
+
+#define minfo (m2info->primary_dev)
+ pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
+ pos += m2info->video.offbase;
+ mga_outl(0x3C28, pos);
+#undef minfo
+}
+
+static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
+ struct display* p,
+ struct fb_var_screeninfo* var,
+ int *visual,
+ int *video_cmap_len,
+ int *mode) {
+ unsigned int mask;
+ unsigned int memlen;
+ unsigned int vramlen;
+
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+ case 16: mask = 0x1F;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32: mask = 0x0F;
+ break;
+#endif
+ default: return -EINVAL;
+ }
+ vramlen = m2info->video.len_usable;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ var->xres_virtual = (var->xres_virtual + mask) & ~mask;
+ if (var->yres_virtual > 32767)
+ return -EINVAL;
+ memlen = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel >> 3);
+ if (memlen > vramlen)
+ return -EINVAL;
+ if (var->xoffset + var->xres > var->xres_virtual)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yoffset + var->yres > var->yres_virtual)
+ var->yoffset = var->yres_virtual - var->yres;
+
+ var->xres &= ~7;
+ var->left_margin &= ~7;
+ var->right_margin &= ~7;
+ var->hsync_len &= ~7;
+
+ *mode = var->bits_per_pixel;
+ if (var->bits_per_pixel == 16) {
+ if (var->green.length == 5) {
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ *mode = 15;
+ } else {
+ 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;
+ }
+ } else {
+ 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;
+ }
+ *visual = FB_VISUAL_TRUECOLOR;
+ *video_cmap_len = 16;
+ return 0;
+}
+
+static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) {
+ switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ p->dispsw_data = m2info->cmap.cfb16;
+ p->dispsw = &fbcon_cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ p->dispsw_data = m2info->cmap.cfb32;
+ p->dispsw = &fbcon_cfb32;
+ break;
+#endif
+ default:
+ p->dispsw_data = NULL;
+ p->dispsw = &fbcon_dummy;
+ break;
+ }
+}
+
+static int matroxfb_dh_open(struct fb_info* info, int user) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+ MOD_INC_USE_COUNT;
+
+ if (minfo) {
+ if (ACCESS_FBINFO(dead)) {
+ return -ENXIO;
+ }
+ }
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_release(struct fb_info* info, int user) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ if (minfo) {
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct display* p;
+
+ if (con >= 0)
+ p = fb_display + con;
+ else
+ p = m2info->fbcon.disp;
+
+ memset(fix, 0, sizeof(*fix));
+ strcpy(fix->id, "MATROX DH");
+
+ fix->smem_start = m2info->video.base;
+ fix->smem_len = m2info->video.len_usable;
+ fix->type = p->type;
+ fix->type_aux = p->type_aux;
+ fix->visual = p->visual;
+ fix->xpanstep = 8; /* TBD */
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = p->line_length;
+ fix->mmio_start = m2info->mmio.base;
+ fix->mmio_len = m2info->mmio.len;
+ fix->accel = 0; /* no accel... */
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ if (con < 0)
+ *var = m2info->fbcon.disp->var;
+ else
+ *var = fb_display[con].var;
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct display* p;
+ int chgvar;
+ int visual;
+ int cmap_len;
+ int mode;
+ int err;
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ if (con < 0)
+ p = m2info->fbcon.disp;
+ else
+ p = fb_display + con;
+ if ((err = matroxfb_dh_decode_var(m2info, p, var, &visual, &cmap_len, &mode)) != 0)
+ return err;
+ switch (var->activate & FB_ACTIVATE_MASK) {
+ case FB_ACTIVATE_TEST: return 0;
+ case FB_ACTIVATE_NXTOPEN:
+ case FB_ACTIVATE_NOW: break;
+ default: return -EINVAL;
+ }
+ if (con >= 0) {
+ chgvar = (p->var.xres != var->xres) ||
+ (p->var.yres != var->yres) ||
+ (p->var.xres_virtual != var->xres_virtual) ||
+ (p->var.yres_virtual != var->yres_virtual) ||
+ (p->var.bits_per_pixel != var->bits_per_pixel) ||
+ memcmp(&p->var.red, &var->red, sizeof(var->red)) ||
+ memcmp(&p->var.green, &var->green, sizeof(var->green)) ||
+ memcmp(&p->var.blue, &var->blue, sizeof(var->blue));
+ } else
+ chgvar = 0;
+ p->var = *var;
+ /* cmap */
+ p->screen_base = vaddr_va(m2info->video.vbase);
+ p->visual = visual;
+ p->ypanstep = 1;
+ p->ywrapstep = 0;
+ p->type = FB_TYPE_PACKED_PIXELS;
+ p->type_aux = 0;
+ p->next_line = p->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+ p->can_soft_blank = 0;
+ p->inverse = 0; /* TBD */
+ initMatroxDH(m2info, p);
+ if (chgvar && info && info->changevar)
+ info->changevar(con);
+ if (con == m2info->currcon) {
+ struct my_timming mt;
+ struct matrox_hw_state* hw;
+ struct matrox_hw_state* ohw;
+ unsigned int pos;
+
+ matroxfb_var2my(var, &mt);
+ /* CRTC2 delay */
+ mt.delay = 34;
+
+ hw = ACCESS_FBINFO(newhw);
+ ohw = ACCESS_FBINFO(currenthw);
+
+ /* copy last setting... */
+ memcpy(hw, ohw, sizeof(*hw));
+
+ pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
+ pos += m2info->video.offbase;
+ DAC1064_global_init(PMINFO hw);
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw);
+ }
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt, hw);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+ DAC1064_global_restore(PMINFO hw);
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->program(MINFO, hw);
+ }
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device), hw);
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(primout))
+ ACCESS_FBINFO(primout)->start(MINFO);
+ }
+ if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ down_read(&ACCESS_FBINFO(altout.lock));
+ if (ACCESS_FBINFO(altout.output))
+ ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
+ up_read(&ACCESS_FBINFO(altout.lock));
+ }
+ matroxfb_dh_cfbX_init(m2info, p);
+ do_install_cmap(m2info, p);
+ }
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct display* dsp;
+
+ if (con < 0)
+ dsp = m2info->fbcon.disp;
+ else
+ dsp = fb_display + con;
+ if (con == m2info->currcon)
+ return fb_get_cmap(cmap, kspc, matroxfb_dh_getcolreg, info);
+ else if (dsp->cmap.len)
+ fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
+ else
+ fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct display* dsp;
+
+ if (con < 0)
+ dsp = m2info->fbcon.disp;
+ else
+ dsp = fb_display + con;
+ if (dsp->cmap.len != 16) {
+ int err;
+
+ err = fb_alloc_cmap(&dsp->cmap, 16, 0);
+ if (err)
+ return err;
+ }
+ if (con == m2info->currcon)
+ return fb_set_cmap(cmap, kspc, matroxfb_dh_setcolreg, info);
+ else
+ fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+ var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+ return -EINVAL;
+ if (con == m2info->currcon)
+ matroxfb_dh_pan_var(m2info, var);
+ fb_display[con].var.xoffset = var->xoffset;
+ fb_display[con].var.yoffset = var->yoffset;
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_switch(int con, struct fb_info* info);
+
+static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) {
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ memset(vblank, 0, sizeof(*vblank));
+ vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK;
+ /* mask out reserved bits + field number (odd/even) */
+ vblank->vcount = mga_inl(0x3C48) & 0x000007FF;
+ /* compatibility stuff */
+ if (vblank->vcount >= m2info->currcon_display->var.yres)
+ vblank->flags |= FB_VBLANK_VBLANKING;
+ return 0;
+}
+
+static int matroxfb_dh_ioctl(struct inode* inode,
+ struct file* file,
+ unsigned int cmd,
+ unsigned long arg,
+ int con,
+ struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ DBG("matroxfb_crtc2_ioctl")
+
+ switch (cmd) {
+ case FBIOGET_VBLANK:
+ {
+ struct fb_vblank vblank;
+ int err;
+
+ err = matroxfb_dh_get_vblank(m2info, &vblank);
+ if (err)
+ return err;
+ copy_to_user_ret((struct fb_vblank*)arg, &vblank, sizeof(vblank), -EFAULT);
+ return 0;
+ }
+ case MATROXFB_SET_OUTPUT_MODE:
+ case MATROXFB_GET_OUTPUT_MODE:
+ case MATROXFB_GET_ALL_OUTPUTS:
+ {
+ return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, con, &minfo->fbcon);
+ }
+ case MATROXFB_SET_OUTPUT_CONNECTION:
+ {
+ u_int32_t tmp;
+
+ get_user_ret(tmp, (u_int32_t*)arg, -EFAULT);
+ if (tmp & ~ACCESS_FBINFO(output.all))
+ return -EINVAL;
+ if (tmp & ACCESS_FBINFO(output.ph))
+ return -EINVAL;
+ if (tmp == ACCESS_FBINFO(output.sh))
+ return 0;
+ ACCESS_FBINFO(output.sh) = tmp;
+ matroxfb_dh_switch(m2info->currcon, info);
+ return 0;
+ }
+ case MATROXFB_GET_OUTPUT_CONNECTION:
+ {
+ put_user_ret(ACCESS_FBINFO(output.sh), (u_int32_t*)arg, -EFAULT);
+ return 0;
+ }
+ case MATROXFB_GET_AVAILABLE_OUTPUTS:
+ {
+ u_int32_t tmp;
+
+ tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph);
+ put_user_ret(tmp, (u_int32_t*)arg, -EFAULT);
+ return 0;
+ }
+ }
+ return -EINVAL;
+#undef m2info
+}
+
+static struct fb_ops matroxfb_dh_ops = {
+ matroxfb_dh_open,
+ matroxfb_dh_release,
+ matroxfb_dh_get_fix,
+ matroxfb_dh_get_var,
+ matroxfb_dh_set_var,
+ matroxfb_dh_get_cmap,
+ matroxfb_dh_set_cmap,
+ matroxfb_dh_pan_display,
+ matroxfb_dh_ioctl,
+ NULL /* mmap */
+};
+
+static int matroxfb_dh_switch(int con, struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ struct fb_cmap* cmap;
+ struct display* p;
+
+ if (m2info->currcon >= 0) {
+ cmap = &m2info->currcon_display->cmap;
+ if (cmap->len) {
+ fb_get_cmap(cmap, 1, matroxfb_dh_getcolreg, info);
+ }
+ }
+ m2info->currcon = con;
+ if (con < 0)
+ p = m2info->fbcon.disp;
+ else
+ p = fb_display + con;
+ m2info->currcon_display = p;
+ p->var.activate = FB_ACTIVATE_NOW;
+ matroxfb_dh_set_var(&p->var, con, info);
+ return 0;
+#undef m2info
+}
+
+static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ matroxfb_dh_pan_var(m2info, &fb_display[con].var);
+ return 0;
+#undef m2info
+}
+
+static void matroxfb_dh_blank(int blank, struct fb_info* info) {
+#define m2info ((struct matroxfb_dh_fb_info*)info)
+ switch (blank) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ default:;
+ }
+ /* do something... */
+#undef m2info
+}
+
+static struct fb_var_screeninfo matroxfb_dh_defined = {
+ 640,480,640,480,/* W,H, virtual W,H */
+ 0,0, /* offset */
+ 32, /* depth */
+ 0, /* gray */
+ {0,0,0}, /* R */
+ {0,0,0}, /* G */
+ {0,0,0}, /* B */
+ {0,0,0}, /* alpha */
+ 0, /* nonstd */
+ FB_ACTIVATE_NOW,
+ -1,-1, /* display size */
+ 0, /* accel flags */
+ 39721L,48L,16L,33L,10L,
+ 96L,2,0, /* no sync info */
+ FB_VMODE_NONINTERLACED,
+ {0,0,0,0,0,0}
+};
+
+static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+ struct display* d;
+ void* oldcrtc2;
+
+ d = kmalloc(sizeof(*d), GFP_KERNEL);
+
+ memset(d, 0, sizeof(*d));
+
+ strcpy(m2info->fbcon.modename, "MATROX CRTC2");
+ m2info->fbcon.changevar = NULL;
+ m2info->fbcon.node = -1;
+ m2info->fbcon.fbops = &matroxfb_dh_ops;
+ m2info->fbcon.disp = d;
+ m2info->fbcon.switch_con = &matroxfb_dh_switch;
+ m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
+ m2info->fbcon.blank = &matroxfb_dh_blank;
+ m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
+ m2info->currcon = -1;
+ m2info->currcon_display = d;
+
+ if (mem < 64)
+ mem *= 1024;
+ if (mem < 64*1024)
+ mem *= 1024;
+ mem &= ~0x00000FFF; /* PAGE_MASK? */
+ if (minfo->video.len_usable + mem <= minfo->video.len)
+ m2info->video.offbase = minfo->video.len - mem;
+ else if (minfo->video.len < mem) {
+ kfree(d);
+ return -ENOMEM;
+ } else { /* check yres on first head... */
+ m2info->video.borrowed = mem;
+ minfo->video.len_usable -= mem;
+ m2info->video.offbase = minfo->video.len_usable;
+ }
+ m2info->video.base = ACCESS_FBINFO(video.base) + m2info->video.offbase;
+ m2info->video.len = m2info->video.len_usable = m2info->video.len_maximum = mem;
+ m2info->video.vbase.vaddr = vaddr_va(ACCESS_FBINFO(video.vbase)) + m2info->video.offbase;
+ m2info->mmio.base = ACCESS_FBINFO(mmio.base);
+ m2info->mmio.vbase = ACCESS_FBINFO(mmio.vbase);
+ m2info->mmio.len = ACCESS_FBINFO(mmio.len);
+
+ /*
+ * If we have two outputs, connect CRTC2 to it...
+ */
+ if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
+ ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ }
+
+ matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
+ if (register_framebuffer(&m2info->fbcon)) {
+ kfree(d);
+ return -ENXIO;
+ }
+ if (m2info->currcon < 0) {
+ matroxfb_dh_set_var(&matroxfb_dh_defined, -1, &m2info->fbcon);
+ }
+ down_write(&ACCESS_FBINFO(crtc2.lock));
+ oldcrtc2 = minfo->crtc2.info;
+ minfo->crtc2.info = &m2info->fbcon;
+ up_write(&ACCESS_FBINFO(crtc2.lock));
+ if (oldcrtc2) {
+ printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
+ oldcrtc2);
+ }
+ return 0;
+#undef minfo
+}
+
+/* ************************** */
+
+static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+ if (matroxfb_dh_regit(PMINFO m2info)) {
+ printk(KERN_ERR "matroxfb_crtc2: secondary head failed to register\n");
+ return -1;
+ }
+ printk(KERN_INFO "matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n",
+ GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), GET_FB_IDX(m2info->fbcon.node));
+ m2info->fbcon_registered = 1;
+ return 0;
+#undef minfo
+}
+
+static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info* m2info) {
+#define minfo (m2info->primary_dev)
+ if (m2info->fbcon_registered) {
+ int id;
+ struct fb_info* crtc2;
+
+ down_write(&ACCESS_FBINFO(crtc2.lock));
+ crtc2 = minfo->crtc2.info;
+ if (crtc2 == &m2info->fbcon)
+ minfo->crtc2.info = NULL;
+ up_write(&ACCESS_FBINFO(crtc2.lock));
+ if (crtc2 != &m2info->fbcon) {
+ printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
+ crtc2, &m2info->fbcon);
+ printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
+ return;
+ }
+ id = GET_FB_IDX(m2info->fbcon.node);
+ unregister_framebuffer(&m2info->fbcon);
+ kfree(m2info->fbcon.disp);
+ /* return memory back to primary head */
+ ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed;
+ printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id);
+ m2info->fbcon_registered = 0;
+ }
+#undef minfo
+}
+
+static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
+ struct matroxfb_dh_fb_info* m2info;
+
+ /* hardware is CRTC2 incapable... */
+ if (!minfo->devflags.crtc2)
+ return NULL;
+ m2info = (struct matroxfb_dh_fb_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
+ if (!m2info) {
+ printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
+ return NULL;
+ }
+ memset(m2info, 0, sizeof(*m2info));
+ m2info->primary_dev = minfo;
+ if (matroxfb_dh_registerfb(m2info)) {
+ kfree(m2info);
+ printk(KERN_ERR "matroxfb_crtc2: CRTC2 framebuffer failed to register\n");
+ return NULL;
+ }
+ return m2info;
+}
+
+static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
+ matroxfb_dh_deregisterfb(crtc2);
+}
+
+static struct matroxfb_driver crtc2 = {
+ name: "Matrox G400 CRTC2",
+ probe: matroxfb_crtc2_probe,
+ remove: matroxfb_crtc2_remove };
+
+static int matroxfb_crtc2_init(void) {
+ matroxfb_register_driver(&crtc2);
+ return 0;
+}
+
+static void matroxfb_crtc2_exit(void) {
+ matroxfb_unregister_driver(&crtc2);
+}
+
+MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
+module_init(matroxfb_crtc2_init);
+module_exit(matroxfb_crtc2_exit);
+/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h
new file mode 100644
index 000000000..e625053bc
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_crtc2.h
@@ -0,0 +1,44 @@
+#ifndef __MATROXFB_CRTC2_H__
+#define __MATROXFB_CRTC2_H__
+
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "matroxfb_base.h"
+
+struct matroxfb_dh_fb_info {
+ struct fb_info fbcon;
+ int fbcon_registered;
+
+ struct matrox_fb_info* primary_dev;
+
+ struct {
+ unsigned long base; /* physical */
+ vaddr_t vbase; /* virtual */
+ unsigned int len;
+ unsigned int len_usable;
+ unsigned int len_maximum;
+ unsigned int offbase;
+ unsigned int borrowed;
+ } video;
+ struct {
+ unsigned long base;
+ vaddr_t vbase;
+ unsigned int len;
+ } mmio;
+
+ int currcon;
+ struct display* currcon_display;
+
+ union {
+#ifdef FBCON_HAS_CFB16
+ u_int16_t cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u_int32_t cfb32[16];
+#endif
+ } cmap;
+ struct { unsigned red, green, blue, transp; } palette[16];
+};
+
+#endif /* __MATROXFB_CRTC2_H__ */
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
new file mode 100644
index 000000000..978dba156
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -0,0 +1,1040 @@
+#include "matroxfb_maven.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include <linux/i2c.h>
+#include <linux/matroxfb.h>
+#include <asm/div64.h>
+#include <asm/uaccess.h>
+
+#define MAVEN_I2CID (0x1B)
+
+#define MODE_PAL MATROXFB_OUTPUT_MODE_PAL
+#define MODE_NTSC MATROXFB_OUTPUT_MODE_NTSC
+#define MODE_TV(x) (((x) == MODE_PAL) || ((x) == MODE_NTSC))
+#define MODE_MONITOR MATROXFB_OUTPUT_MODE_MONITOR
+
+struct maven_data {
+ struct matrox_fb_info* primary_head;
+ struct i2c_client* client;
+ int mode;
+};
+
+static int maven_get_reg(struct i2c_client* c, char reg) {
+ char dst;
+ struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
+ { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
+ s32 err;
+
+ err = i2c_transfer(c->adapter, msgs, 2);
+ if (err < 0)
+ printk(KERN_INFO "ReadReg(%d) failed\n", reg);
+ return dst & 0xFF;
+}
+
+static int maven_set_reg(struct i2c_client* c, int reg, int val) {
+ s32 err;
+
+ err = i2c_smbus_write_byte_data(c, reg, val);
+ if (err)
+ printk(KERN_INFO "WriteReg(%d) failed\n", reg);
+ return err;
+}
+
+static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
+ s32 err;
+
+ err = i2c_smbus_write_word_data(c, reg, val);
+ if (err)
+ printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
+ return err;
+}
+
+static const struct matrox_pll_features maven_pll = {
+ 50000,
+ 27000,
+ 4, 127,
+ 2, 31,
+ 3
+};
+
+struct matrox_pll_features2 {
+ unsigned int vco_freq_min;
+ unsigned int vco_freq_max;
+ unsigned int feed_div_min;
+ unsigned int feed_div_max;
+ unsigned int in_div_min;
+ unsigned int in_div_max;
+ unsigned int post_shift_max;
+};
+
+struct matrox_pll_ctl {
+ unsigned int ref_freq;
+ unsigned int den;
+};
+
+static const struct matrox_pll_features2 maven1000_pll = {
+ 50000000,
+ 300000000,
+ 5, 128,
+ 3, 32,
+ 3
+};
+
+static const struct matrox_pll_ctl maven_PAL = {
+ 540000,
+ 50
+};
+
+static const struct matrox_pll_ctl maven_NTSC = {
+ 450450, /* 27027000/60 == 27000000/59.94005994 */
+ 60
+};
+
+static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
+ const struct matrox_pll_ctl* ctl,
+ unsigned int htotal, unsigned int vtotal,
+ unsigned int* in, unsigned int* feed, unsigned int* post,
+ unsigned int* h2) {
+ unsigned int besth2 = 0;
+ unsigned int fxtal = ctl->ref_freq;
+ unsigned int fmin = pll->vco_freq_min / ctl->den;
+ unsigned int fwant;
+ unsigned int p;
+ unsigned int scrlen;
+ unsigned int fmax;
+
+ DBG("PLL_calcclock")
+
+ scrlen = htotal * (vtotal - 1);
+ fwant = htotal * vtotal;
+ fmax = pll->vco_freq_max / ctl->den;
+
+ printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
+ fwant, fxtal, htotal, vtotal, fmax);
+ for (p = 1; p <= pll->post_shift_max; p++) {
+ if (fwant * 2 > fmax)
+ break;
+ fwant *= 2;
+ }
+ if (fwant > fmax)
+ return 0;
+ for (; p-- > 0; fwant >>= 1) {
+ unsigned int m;
+
+ if (fwant < fmin) break;
+ for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
+ unsigned int n;
+ unsigned int dvd;
+ unsigned int ln;
+
+ n = (fwant * m) / fxtal;
+ if (n < pll->feed_div_min)
+ continue;
+ if (n > pll->feed_div_max)
+ break;
+
+ ln = fxtal * n;
+ dvd = m << p;
+
+ if (ln % dvd)
+ continue;
+ ln = ln / dvd;
+
+ if (ln < scrlen + 2)
+ continue;
+ ln = ln - scrlen;
+ if (ln > htotal)
+ continue;
+ printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
+ if (ln > besth2) {
+ printk(KERN_DEBUG "Better...\n");
+ *h2 = besth2 = ln;
+ *post = p;
+ *in = m;
+ *feed = n;
+ }
+ }
+ }
+ if (besth2 < 2)
+ return 0;
+ dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
+ return fxtal * (*feed) / (*in) * ctl->den;
+}
+
+static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
+ unsigned int htotal, unsigned int vtotal,
+ unsigned int* in, unsigned int* feed, unsigned int* post,
+ unsigned int* htotal2) {
+ unsigned int fvco;
+ unsigned int p;
+
+ fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
+ if (!fvco)
+ return -EINVAL;
+ p = (1 << p) - 1;
+ if (fvco <= 100000000)
+ ;
+ else if (fvco <= 140000000)
+ p |= 0x08;
+ else if (fvco <= 180000000)
+ p |= 0x10;
+ else
+ p |= 0x18;
+ *post = p;
+ return 0;
+}
+
+static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
+ unsigned int* in, unsigned int* feed, unsigned int* post) {
+ unsigned int fvco;
+ unsigned int p;
+
+ fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
+ p = (1 << p) - 1;
+ if (fvco <= 100000)
+ ;
+ else if (fvco <= 140000)
+ p |= 0x08;
+ else if (fvco <= 180000)
+ p |= 0x10;
+ else
+ p |= 0x18;
+ *post = p;
+ return;
+}
+
+static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
+ static struct mavenregs palregs = { {
+ 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
+ 0x00,
+ 0x00, /* ? not written */
+ 0x00, /* modified by code (F9 written...) */
+ 0x00, /* ? not written */
+ 0x7E, /* 08 */
+ 0x44, /* 09 */
+ 0x9C, /* 0A */
+ 0x2E, /* 0B */
+ 0x21, /* 0C */
+ 0x00, /* ? not written */
+ 0x3F, 0x03, /* 0E-0F */
+ 0x3F, 0x03, /* 10-11 */
+ 0x1A, /* 12 */
+ 0x2A, /* 13 */
+ 0x1C, 0x3D, 0x14, /* 14-16 */
+ 0x9C, 0x01, /* 17-18 */
+ 0x00, /* 19 */
+ 0xFE, /* 1A */
+ 0x7E, /* 1B */
+ 0x60, /* 1C */
+ 0x05, /* 1D */
+ 0x89, 0x03, /* 1E-1F */
+ 0x72, /* 20 */
+ 0x07, /* 21 */
+ 0x72, /* 22 */
+ 0x00, /* 23 */
+ 0x00, /* 24 */
+ 0x00, /* 25 */
+ 0x08, /* 26 */
+ 0x04, /* 27 */
+ 0x00, /* 28 */
+ 0x1A, /* 29 */
+ 0x55, 0x01, /* 2A-2B */
+ 0x26, /* 2C */
+ 0x07, 0x7E, /* 2D-2E */
+ 0x02, 0x54, /* 2F-30 */
+ 0xB0, 0x00, /* 31-32 */
+ 0x14, /* 33 */
+ 0x49, /* 34 */
+ 0x00, /* 35 written multiple times */
+ 0x00, /* 36 not written */
+ 0xA3, /* 37 */
+ 0xC8, /* 38 */
+ 0x22, /* 39 */
+ 0x02, /* 3A */
+ 0x22, /* 3B */
+ 0x3F, 0x03, /* 3C-3D */
+ 0x00, /* 3E written multiple times */
+ 0x00, /* 3F not written */
+ }, MODE_PAL, 625, 50 };
+ static struct mavenregs ntscregs = { {
+ 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
+ 0x00,
+ 0x00, /* ? not written */
+ 0x00, /* modified by code (F9 written...) */
+ 0x00, /* ? not written */
+ 0x7E, /* 08 */
+ 0x43, /* 09 */
+ 0x7E, /* 0A */
+ 0x3D, /* 0B */
+ 0x00, /* 0C */
+ 0x00, /* ? not written */
+ 0x41, 0x00, /* 0E-0F */
+ 0x3C, 0x00, /* 10-11 */
+ 0x17, /* 12 */
+ 0x21, /* 13 */
+ 0x1B, 0x1B, 0x24, /* 14-16 */
+ 0x83, 0x01, /* 17-18 */
+ 0x00, /* 19 */
+ 0x0F, /* 1A */
+ 0x0F, /* 1B */
+ 0x60, /* 1C */
+ 0x05, /* 1D */
+ 0x89, 0x02, /* 1E-1F */
+ 0x5F, /* 20 */
+ 0x04, /* 21 */
+ 0x5F, /* 22 */
+ 0x01, /* 23 */
+ 0x02, /* 24 */
+ 0x00, /* 25 */
+ 0x0A, /* 26 */
+ 0x05, /* 27 */
+ 0x00, /* 28 */
+ 0x10, /* 29 */
+ 0xFF, 0x03, /* 2A-2B */
+ 0x24, /* 2C */
+ 0x0F, 0x78, /* 2D-2E */
+ 0x00, 0x00, /* 2F-30 */
+ 0xB2, 0x04, /* 31-32 */
+ 0x14, /* 33 */
+ 0x02, /* 34 */
+ 0x00, /* 35 written multiple times */
+ 0x00, /* 36 not written */
+ 0xA3, /* 37 */
+ 0xC8, /* 38 */
+ 0x15, /* 39 */
+ 0x05, /* 3A */
+ 0x3B, /* 3B */
+ 0x3C, 0x00, /* 3C-3D */
+ 0x00, /* 3E written multiple times */
+ 0x00, /* never written */
+ }, MODE_NTSC, 525, 60 };
+
+ if (md->mode & MODE_PAL)
+ *data = palregs;
+ else
+ *data = ntscregs;
+
+ data->regs[0x93] = 0xA2;
+
+ /* gamma correction registers */
+ data->regs[0x83] = 0x00;
+ data->regs[0x84] = 0x00;
+ data->regs[0x85] = 0x00;
+ data->regs[0x86] = 0x1F;
+ data->regs[0x87] = 0x10;
+ data->regs[0x88] = 0x10;
+ data->regs[0x89] = 0x10;
+ data->regs[0x8A] = 0x64; /* 100 */
+ data->regs[0x8B] = 0xC8; /* 200 */
+
+ return;
+}
+
+#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
+#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
+static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
+ int val;
+
+
+ maven_set_reg(c, 0x3E, 0x01);
+ maven_get_reg(c, 0x82); /* fetch oscillator state? */
+ maven_set_reg(c, 0x8C, 0x00);
+ maven_get_reg(c, 0x94); /* get 0x82 */
+ maven_set_reg(c, 0x94, 0xA2);
+ /* xmiscctrl */
+
+ maven_set_reg_pair(c, 0x8E, 0x1EFF);
+ maven_set_reg(c, 0xC6, 0x01);
+
+ /* removed code... */
+
+ maven_get_reg(c, 0x06);
+ maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */
+
+ /* removed code here... */
+
+ /* real code begins here? */
+ /* chroma subcarrier */
+ LR(0x00); LR(0x01); LR(0x02); LR(0x03);
+
+ LR(0x04);
+
+ LR(0x2C);
+ LR(0x08);
+ LR(0x0A);
+ LR(0x09);
+ LR(0x29);
+ LRP(0x31);
+ LRP(0x17);
+ LR(0x0B);
+ LR(0x0C);
+ if (m->mode & MODE_PAL) {
+ maven_set_reg(c, 0x35, 0x10); /* ... */
+ } else {
+ maven_set_reg(c, 0x35, 0x0F); /* ... */
+ }
+
+ LRP(0x10);
+
+ LRP(0x0E);
+ LRP(0x1E);
+
+ LR(0x20); /* saturation #1 */
+ LR(0x22); /* saturation #2 */
+ LR(0x25); /* hue */
+ LR(0x34);
+ LR(0x33);
+ LR(0x19);
+ LR(0x12);
+ LR(0x3B);
+ LR(0x13);
+ LR(0x39);
+ LR(0x1D);
+ LR(0x3A);
+ LR(0x24);
+ LR(0x14);
+ LR(0x15);
+ LR(0x16);
+ LRP(0x2D);
+ LRP(0x2F);
+ LR(0x1A);
+ LR(0x1B);
+ LR(0x1C);
+ LR(0x23);
+ LR(0x26);
+ LR(0x28);
+ LR(0x27);
+ LR(0x21);
+ LRP(0x2A);
+ if (m->mode & MODE_PAL)
+ maven_set_reg(c, 0x35, 0x1D); /* ... */
+ else
+ maven_set_reg(c, 0x35, 0x1C);
+
+ LRP(0x3C);
+ LR(0x37);
+ LR(0x38);
+ maven_set_reg(c, 0xB3, 0x01);
+
+ maven_get_reg(c, 0xB0); /* read 0x80 */
+ maven_set_reg(c, 0xB0, 0x08); /* ugh... */
+ maven_get_reg(c, 0xB9); /* read 0x7C */
+ maven_set_reg(c, 0xB9, 0x78);
+ maven_get_reg(c, 0xBF); /* read 0x00 */
+ maven_set_reg(c, 0xBF, 0x02);
+ maven_get_reg(c, 0x94); /* read 0x82 */
+ maven_set_reg(c, 0x94, 0xB3);
+
+ LR(0x80); /* 04 1A 91 or 05 21 91 */
+ LR(0x81);
+ LR(0x82);
+
+ maven_set_reg(c, 0x8C, 0x20);
+ maven_get_reg(c, 0x8D);
+ maven_set_reg(c, 0x8D, 0x10);
+
+ LR(0x90); /* 4D 50 52 or 4E 05 45 */
+ LR(0x91);
+ LR(0x92);
+
+ LRP(0x9A); /* 0049 or 004F */
+ LRP(0x9C); /* 0004 or 0004 */
+ LRP(0x9E); /* 0458 or 045E */
+ LRP(0xA0); /* 05DA or 051B */
+ LRP(0xA2); /* 00CC or 00CF */
+ LRP(0xA4); /* 007D or 007F */
+ LRP(0xA6); /* 007C or 007E */
+ LRP(0xA8); /* 03CB or 03CE */
+ LRP(0x98); /* 0000 or 0000 */
+ LRP(0xAE); /* 0044 or 003A */
+ LRP(0x96); /* 05DA or 051B */
+ LRP(0xAA); /* 04BC or 046A */
+ LRP(0xAC); /* 004D or 004E */
+
+ LR(0xBE);
+ LR(0xC2);
+
+ maven_get_reg(c, 0x8D);
+ maven_set_reg(c, 0x8D, 0x00);
+
+ LR(0x20); /* saturation #1 */
+ LR(0x22); /* saturation #2 */
+ LR(0x93); /* whoops */
+ LR(0x20); /* oh, saturation #1 again */
+ LR(0x22); /* oh, saturation #2 again */
+ LR(0x25); /* hue */
+ LRP(0x0E);
+ LRP(0x1E);
+ LRP(0x0E); /* problems with memory? */
+ LRP(0x1E); /* yes, matrox must have problems in memory area... */
+
+ /* load gamma correction stuff */
+ LR(0x83);
+ LR(0x84);
+ LR(0x85);
+ LR(0x86);
+ LR(0x87);
+ LR(0x88);
+ LR(0x89);
+ LR(0x8A);
+ LR(0x8B);
+
+ val = maven_get_reg(c, 0x8D);
+ val &= 0x10; /* 0x10 or anything ored with it */
+ maven_set_reg(c, 0x8D, val);
+
+ LR(0x33);
+ LR(0x19);
+ LR(0x12);
+ LR(0x3B);
+ LR(0x13);
+ LR(0x39);
+ LR(0x1D);
+ LR(0x3A);
+ LR(0x24);
+ LR(0x14);
+ LR(0x15);
+ LR(0x16);
+ LRP(0x2D);
+ LRP(0x2F);
+ LR(0x1A);
+ LR(0x1B);
+ LR(0x1C);
+ LR(0x23);
+ LR(0x26);
+ LR(0x28);
+ LR(0x27);
+ LR(0x21);
+ LRP(0x2A);
+ if (m->mode & MODE_PAL)
+ maven_set_reg(c, 0x35, 0x1D);
+ else
+ maven_set_reg(c, 0x35, 0x1C);
+ LRP(0x3C);
+ LR(0x37);
+ LR(0x38);
+
+ maven_get_reg(c, 0xB0);
+ LR(0xB0); /* output mode */
+ LR(0x90);
+ LR(0xBE);
+ LR(0xC2);
+
+ LRP(0x9A);
+ LRP(0xA2);
+ LRP(0x9E);
+ LRP(0xA6);
+ LRP(0xAA);
+ LRP(0xAC);
+ maven_set_reg(c, 0x3E, 0x00);
+ maven_set_reg(c, 0x95, 0x20);
+}
+
+static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
+ struct mavenregs* m) {
+ unsigned int x;
+ unsigned int err = ~0;
+
+ /* 1:1 */
+ m->regs[0x80] = 0x0F;
+ m->regs[0x81] = 0x07;
+ m->regs[0x82] = 0x81;
+
+ for (x = 0; x < 8; x++) {
+ unsigned int a, b, c, h2;
+ unsigned int h = ht + 2 + x;
+
+ if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
+ unsigned int diff = h - h2;
+
+ if (diff < err) {
+ err = diff;
+ m->regs[0x80] = a - 1;
+ m->regs[0x81] = b - 1;
+ m->regs[0x82] = c | 0x80;
+ m->hcorr = h2 - 2;
+ m->htotal = h - 2;
+ }
+ }
+ }
+ return err != ~0U;
+}
+
+static inline int maven_compute_timming(struct maven_data* md,
+ struct my_timming* mt,
+ struct mavenregs* m) {
+ unsigned int tmpi;
+ unsigned int a, bv, c;
+
+ m->mode = md->mode;
+ if (MODE_TV(md->mode)) {
+ unsigned int lmargin;
+ unsigned int umargin;
+ unsigned int vslen;
+ unsigned int hcrt;
+ unsigned int slen;
+
+ maven_init_TVdata(md, m);
+
+ if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
+ return -EINVAL;
+
+ lmargin = mt->HTotal - mt->HSyncEnd;
+ slen = mt->HSyncEnd - mt->HSyncStart;
+ hcrt = mt->HTotal - slen - mt->delay;
+ umargin = mt->VTotal - mt->VSyncEnd;
+ vslen = mt->VSyncEnd - mt->VSyncStart;
+
+ if (m->hcorr < mt->HTotal)
+ hcrt += m->hcorr;
+ if (hcrt > mt->HTotal)
+ hcrt -= mt->HTotal;
+ if (hcrt + 2 > mt->HTotal)
+ hcrt = 0; /* or issue warning? */
+
+ /* last (first? middle?) line in picture can have different length */
+ /* hlen - 2 */
+ m->regs[0x96] = m->hcorr;
+ m->regs[0x97] = m->hcorr >> 8;
+ /* ... */
+ m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
+ /* hblanking end */
+ m->regs[0x9A] = lmargin; /* 100% */
+ m->regs[0x9B] = lmargin >> 8; /* 100% */
+ /* who knows */
+ m->regs[0x9C] = 0x04;
+ m->regs[0x9D] = 0x00;
+ /* htotal - 2 */
+ m->regs[0xA0] = m->htotal;
+ m->regs[0xA1] = m->htotal >> 8;
+ /* vblanking end */
+ m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
+ m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
+ /* something end... [A6]+1..[A8] */
+ m->regs[0xA4] = 0x01;
+ m->regs[0xA5] = 0x00;
+ /* something start... 0..[A4]-1 */
+ m->regs[0xA6] = 0x00;
+ m->regs[0xA7] = 0x00;
+ /* vertical line count - 1 */
+ m->regs[0xA8] = mt->VTotal - 1;
+ m->regs[0xA9] = (mt->VTotal - 1) >> 8;
+ /* horizontal vidrst pos */
+ m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
+ m->regs[0xAB] = hcrt >> 8;
+ /* vertical vidrst pos */
+ m->regs[0xAC] = mt->VTotal - 2;
+ m->regs[0xAD] = (mt->VTotal - 2) >> 8;
+ /* moves picture up/down and so on... */
+ m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
+ m->regs[0xAF] = 0x00;
+ {
+ int hdec;
+ int hlen;
+ unsigned int ibmin = 4 + lmargin + mt->HDisplay;
+ unsigned int ib;
+ int i;
+
+ /* Verify! */
+ /* Where 94208 came from? */
+ if (mt->HTotal)
+ hdec = 94208 / (mt->HTotal);
+ else
+ hdec = 0x81;
+ if (hdec > 0x81)
+ hdec = 0x81;
+ if (hdec < 0x41)
+ hdec = 0x41;
+ hdec--;
+ hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
+ if (hlen < 0)
+ hlen = 0;
+ hlen = hlen >> 8;
+ if (hlen > 0xFF)
+ hlen = 0xFF;
+ /* Now we have to compute input buffer length.
+ If you want any picture, it must be between
+ 4 + lmargin + xres
+ and
+ 94208 / hdec
+ If you want perfect picture even on the top
+ of screen, it must be also
+ 0x3C0000 * i / hdec + Q - R / hdec
+ where
+ R Qmin Qmax
+ 0x07000 0x5AE 0x5BF
+ 0x08000 0x5CF 0x5FF
+ 0x0C000 0x653 0x67F
+ 0x10000 0x6F8 0x6FF
+ */
+ i = 1;
+ do {
+ ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
+ i++;
+ } while (ib < ibmin);
+ if (ib >= m->htotal + 2) {
+ ib = ibmin;
+ }
+
+ m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
+ m->regs[0xC2] = hlen;
+ /* 'valid' input line length */
+ m->regs[0x9E] = ib;
+ m->regs[0x9F] = ib >> 8;
+ }
+ {
+ int vdec;
+ int vlen;
+
+#define MATROX_USE64BIT_DIVIDE
+ if (mt->VTotal) {
+#ifdef MATROX_USE64BIT_DIVIDE
+ u64 f1;
+ u32 a;
+ u32 b;
+
+ a = m->vlines * (m->htotal + 2);
+ b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
+
+ f1 = ((u64)a) << 15; /* *32768 */
+ do_div(f1, b);
+ vdec = f1;
+#else
+ vdec = m->vlines * 32768 / mt->VTotal;
+#endif
+ } else
+ vdec = 0x8000;
+ if (vdec > 0x8000)
+ vdec = 0x8000;
+ vlen = (vslen + umargin + mt->VDisplay) * vdec;
+ vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
+ if (vlen < 0)
+ vlen = 0;
+ if (vlen > 0xFF)
+ vlen = 0xFF;
+ vdec--;
+ m->regs[0x91] = vdec;
+ m->regs[0x92] = vdec >> 8;
+ m->regs[0xBE] = vlen;
+ }
+ m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
+ return 0;
+ }
+
+ DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
+ m->regs[0x80] = a;
+ m->regs[0x81] = bv;
+ m->regs[0x82] = c | 0x80;
+
+ m->regs[0xB3] = 0x01;
+ m->regs[0x94] = 0xB2;
+
+ /* htotal... */
+ m->regs[0x96] = mt->HTotal;
+ m->regs[0x97] = mt->HTotal >> 8;
+ /* ?? */
+ m->regs[0x98] = 0x00;
+ m->regs[0x99] = 0x00;
+ /* hsync len */
+ tmpi = mt->HSyncEnd - mt->HSyncStart;
+ m->regs[0x9A] = tmpi;
+ m->regs[0x9B] = tmpi >> 8;
+ /* hblank end */
+ tmpi = mt->HTotal - mt->HSyncStart;
+ m->regs[0x9C] = tmpi;
+ m->regs[0x9D] = tmpi >> 8;
+ /* hblank start */
+ tmpi += mt->HDisplay;
+ m->regs[0x9E] = tmpi;
+ m->regs[0x9F] = tmpi >> 8;
+ /* htotal + 1 */
+ tmpi = mt->HTotal + 1;
+ m->regs[0xA0] = tmpi;
+ m->regs[0xA1] = tmpi >> 8;
+ /* vsync?! */
+ tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
+ m->regs[0xA2] = tmpi;
+ m->regs[0xA3] = tmpi >> 8;
+ /* ignored? */
+ tmpi = mt->VTotal - mt->VSyncStart;
+ m->regs[0xA4] = tmpi;
+ m->regs[0xA5] = tmpi >> 8;
+ /* ignored? */
+ tmpi = mt->VTotal - 1;
+ m->regs[0xA6] = tmpi;
+ m->regs[0xA7] = tmpi >> 8;
+ /* vtotal - 1 */
+ m->regs[0xA8] = tmpi;
+ m->regs[0xA9] = tmpi >> 8;
+ /* hor vidrst */
+ tmpi = mt->HTotal - mt->delay;
+ m->regs[0xAA] = tmpi;
+ m->regs[0xAB] = tmpi >> 8;
+ /* vert vidrst */
+ tmpi = mt->VTotal - 2;
+ m->regs[0xAC] = tmpi;
+ m->regs[0xAD] = tmpi >> 8;
+ /* ignored? */
+ m->regs[0xAE] = 0x00;
+ m->regs[0xAF] = 0x00;
+
+ m->regs[0xB0] = 0x03; /* output: monitor */
+ m->regs[0xB1] = 0xA0; /* ??? */
+ m->regs[0x8C] = 0x20; /* must be set... */
+ m->regs[0x8D] = 0x00; /* defaults to 0x10: test signal */
+ m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
+ m->regs[0xBF] = 0x22; /* makes picture stable */
+
+ return 0;
+}
+
+static inline int maven_program_timming(struct maven_data* md,
+ const struct mavenregs* m) {
+ struct i2c_client* c = md->client;
+
+ if (m->mode & MODE_MONITOR) {
+ LR(0x80);
+ LR(0x81);
+ LR(0x82);
+
+ LR(0xB3);
+ LR(0x94);
+
+ LRP(0x96);
+ LRP(0x98);
+ LRP(0x9A);
+ LRP(0x9C);
+ LRP(0x9E);
+ LRP(0xA0);
+ LRP(0xA2);
+ LRP(0xA4);
+ LRP(0xA6);
+ LRP(0xA8);
+ LRP(0xAA);
+ LRP(0xAC);
+ LRP(0xAE);
+
+ LR(0xB0); /* output: monitor */
+ LR(0xB1); /* ??? */
+ LR(0x8C); /* must be set... */
+ LR(0x8D); /* defaults to 0x10: test signal */
+ LR(0xB9); /* defaults to 0x2C: too bright */
+ LR(0xBF); /* makes picture stable */
+ } else {
+ maven_init_TV(c, m);
+ }
+ return 0;
+}
+
+static inline int maven_resync(struct maven_data* md) {
+ struct i2c_client* c = md->client;
+ maven_set_reg(c, 0x95, 0x20); /* start whole thing */
+ return 0;
+}
+
+static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) {
+ switch (arg) {
+ case MATROXFB_OUTPUT_MODE_PAL:
+ case MATROXFB_OUTPUT_MODE_NTSC:
+ case MATROXFB_OUTPUT_MODE_MONITOR:
+ md->mode = arg;
+ return 1;
+ }
+ return -EINVAL;
+}
+
+static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
+ *arg = md->mode;
+ return 0;
+}
+
+/******************************************************/
+
+static int maven_out_compute(void* md, struct my_timming* mt, struct matrox_hw_state* mr) {
+ return maven_compute_timming(md, mt, &mr->maven);
+}
+
+static int maven_out_program(void* md, const struct matrox_hw_state* mr) {
+ return maven_program_timming(md, &mr->maven);
+}
+
+static int maven_out_start(void* md) {
+ return maven_resync(md);
+}
+
+static void maven_out_incuse(void* md) {
+ if (md)
+ i2c_inc_use_client(((struct maven_data*)md)->client);
+}
+
+static void maven_out_decuse(void* md) {
+ if (md)
+ i2c_dec_use_client(((struct maven_data*)md)->client);
+}
+
+static int maven_out_set_mode(void* md, u_int32_t arg) {
+ return maven_set_output_mode(md, arg);
+}
+
+static int maven_out_get_mode(void* md, u_int32_t* arg) {
+ return maven_get_output_mode(md, arg);
+}
+
+static struct matrox_altout maven_altout = {
+ maven_out_compute,
+ maven_out_program,
+ maven_out_start,
+ maven_out_incuse,
+ maven_out_decuse,
+ maven_out_set_mode,
+ maven_out_get_mode
+};
+
+static int maven_init_client(struct i2c_client* clnt) {
+ struct i2c_adapter* a = clnt->adapter;
+ /* data are set to primary head... maybe I should change it */
+ struct matroxfb_dh_maven_info* m2info =
+ (struct matroxfb_dh_maven_info*)(((u_int8_t*)a) - offsetof(struct matroxfb_dh_maven_info, maven.adapter));
+ struct maven_data* md = clnt->data;
+ /* add some checks that m2info is matroxfb_dh_fb_info here... */
+ struct matrox_fb_info* minfo = m2info->primary_dev;
+
+ md->mode = MODE_MONITOR;
+ md->primary_head = MINFO;
+ md->client = clnt;
+ down_write(&ACCESS_FBINFO(altout.lock));
+ ACCESS_FBINFO(altout.device) = md;
+ ACCESS_FBINFO(altout.output) = &maven_altout;
+ up_write(&ACCESS_FBINFO(altout.lock));
+ ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
+ return 0;
+}
+
+static int maven_shutdown_client(struct i2c_client* clnt) {
+ struct maven_data* md = clnt->data;
+
+ if (md->primary_head) {
+ md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ down_write(&md->primary_head->altout.lock);
+ md->primary_head->altout.device = NULL;
+ md->primary_head->altout.output = NULL;
+ up_write(&md->primary_head->altout.lock);
+ md->primary_head = NULL;
+ }
+ return 0;
+}
+
+static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
+
+static void maven_inc_use(struct i2c_client* clnt) {
+ MOD_INC_USE_COUNT;
+}
+
+static void maven_dec_use(struct i2c_client* clnt) {
+ MOD_DEC_USE_COUNT;
+}
+
+static struct i2c_driver maven_driver;
+
+static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigned short flags,
+ int kind) {
+ int err = 0;
+ struct i2c_client* new_client;
+ struct maven_data* data;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_PROTOCOL_MANGLING))
+ goto ERROR0;
+ if (!(new_client = (struct i2c_client*)kmalloc(sizeof(struct i2c_client) + sizeof(struct maven_data),
+ GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto ERROR0;
+ }
+ data = (struct maven_data*)(new_client + 1);
+ new_client->data = data;
+ new_client->addr = address;
+ new_client->adapter = adapter;
+ new_client->driver = &maven_driver;
+ new_client->flags = 0;
+ if (kind < 0) {
+ ;
+ }
+ strcpy(new_client->name, "maven client");
+ if ((err = i2c_attach_client(new_client)))
+ goto ERROR3;
+ err = maven_init_client(new_client);
+ if (err)
+ goto ERROR4;
+ return 0;
+ERROR4:;
+ i2c_detach_client(new_client);
+ERROR3:;
+ kfree(new_client);
+ERROR0:;
+ return err;
+}
+
+static int maven_attach_adapter(struct i2c_adapter* adapter) {
+ if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400))
+ return i2c_probe(adapter, &addr_data, &maven_detect_client);
+ return 0;
+}
+
+static int maven_detach_client(struct i2c_client* client) {
+ int err;
+
+ if ((err = i2c_detach_client(client))) {
+ printk(KERN_ERR "maven: Cannot deregister client\n");
+ return err;
+ }
+ maven_shutdown_client(client);
+ kfree(client);
+ return 0;
+}
+
+static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) {
+ return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */
+}
+
+static int maven_driver_registered = 0;
+
+static struct i2c_driver maven_driver={
+ "maven",
+ I2C_DRIVERID_MGATVO,
+ I2C_DF_NOTIFY,
+ maven_attach_adapter,
+ maven_detach_client,
+ maven_command,
+ maven_inc_use,
+ maven_dec_use
+};
+
+/* ************************** */
+
+static int matroxfb_maven_init(void) {
+ int err;
+
+ err = i2c_add_driver(&maven_driver);
+ if (err) {
+ printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err);
+ return err;
+ }
+ maven_driver_registered = 1;
+ return 0;
+}
+
+static void matroxfb_maven_exit(void) {
+ if (maven_driver_registered)
+ i2c_del_driver(&maven_driver);
+}
+
+MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
+module_init(matroxfb_maven_init);
+module_exit(matroxfb_maven_exit);
+/* we do not have __setup() yet */
diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h
new file mode 100644
index 000000000..cbf340e0a
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_maven.h
@@ -0,0 +1,23 @@
+#ifndef __MATROXFB_MAVEN_H__
+#define __MATROXFB_MAVEN_H__
+
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "matroxfb_base.h"
+
+struct i2c_bit_adapter {
+ struct i2c_adapter adapter;
+ int initialized;
+ struct i2c_algo_bit_data bac;
+};
+
+struct matroxfb_dh_maven_info {
+ struct matrox_fb_info* primary_dev;
+
+ struct i2c_bit_adapter maven;
+ struct i2c_bit_adapter ddc1;
+ struct i2c_bit_adapter ddc2;
+};
+
+#endif /* __MATROXFB_MAVEN_H__ */
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
new file mode 100644
index 000000000..126ab9b66
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -0,0 +1,660 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.21 2000/01/09
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ * Betatesting, fixes, ideas
+ *
+ * "Kurt Garloff" <garloff@kg1.ping.de>
+ * Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ * "Tom Rini" <trini@kernel.crashing.org>
+ * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ * "Bibek Sahu" <scorpio@dodds.net>
+ * Access device through readb|w|l and write b|w|l
+ * Extensive debugging stuff
+ *
+ * "Daniel Haun" <haund@usa.net>
+ * Testing, hardware cursor fixes
+ *
+ * "Scott Wood" <sawst46+@pitt.edu>
+ * Fixes
+ *
+ * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ * Betatesting
+ *
+ * "Kelly French" <targon@hazmat.com>
+ * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ * Betatesting, bug reporting
+ *
+ * "Pablo Bianucci" <pbian@pccp.com.ar>
+ * Fixes, ideas, betatesting
+ *
+ * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ * Fixes, enhandcements, ideas, betatesting
+ *
+ * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ * PPC betatesting, PPC support, backward compatibility
+ *
+ * "Paul Womar" <Paul@pwomar.demon.co.uk>
+ * "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ * PPC betatesting
+ *
+ * "Thomas Pornin" <pornin@bolet.ens.fr>
+ * Alpha betatesting
+ *
+ * "Pieter van Leuven" <pvl@iae.nl>
+ * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ * G100 testing
+ *
+ * "H. Peter Arvin" <hpa@transmeta.com>
+ * Ideas
+ *
+ * "Cort Dougan" <cort@cs.nmt.edu>
+ * CHRP fixes and PReP cleanup
+ *
+ * "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ * G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ * is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ * were used when writting this driver)
+ *
+ * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+/* make checkconfig does not check includes for this... */
+#include <linux/config.h>
+
+#include "matroxfb_misc.h"
+#include <linux/interrupt.h>
+#include <linux/matroxfb.h>
+
+void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) {
+ unsigned int h;
+ unsigned int cu, cd;
+
+ h = fontheight(p);
+
+ if (vmode & FB_VMODE_DOUBLE)
+ h *= 2;
+ cd = h;
+ if (cd >= 10)
+ cd--;
+ switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) {
+ case CUR_NONE:
+ cu = cd;
+ break;
+ case CUR_UNDERLINE:
+ cu = cd - 2;
+ break;
+ case CUR_LOWER_THIRD:
+ cu = (h * 2) / 3;
+ break;
+ case CUR_LOWER_HALF:
+ cu = h / 2;
+ break;
+ case CUR_TWO_THIRDS:
+ cu = h / 3;
+ break;
+ case CUR_BLOCK:
+ default:
+ cu = 0;
+ cd = h;
+ break;
+ }
+ ACCESS_FBINFO(cursor.w) = fontwidth(p);
+ ACCESS_FBINFO(cursor.u) = cu;
+ ACCESS_FBINFO(cursor.d) = cd;
+}
+
+void matroxfb_DAC_out(CPMINFO int reg, int val) {
+ DBG_REG("outDAC");
+ mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+ mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
+}
+
+int matroxfb_DAC_in(CPMINFO int reg) {
+ DBG_REG("inDAC");
+ mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+ return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
+}
+
+void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+ unsigned int pixclock = var->pixclock;
+
+ DBG("var2my")
+
+ if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
+ mt->pixclock = 1000000000 / pixclock;
+ if (mt->pixclock < 1) mt->pixclock = 1;
+ mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+ mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+ mt->HDisplay = var->xres;
+ mt->HSyncStart = mt->HDisplay + var->right_margin;
+ mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+ mt->HTotal = mt->HSyncEnd + var->left_margin;
+ mt->VDisplay = var->yres;
+ mt->VSyncStart = mt->VDisplay + var->lower_margin;
+ mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+ mt->VTotal = mt->VSyncEnd + var->upper_margin;
+ mt->sync = var->sync;
+}
+
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+ unsigned int* in, unsigned int* feed, unsigned int* post) {
+ unsigned int bestdiff = ~0;
+ unsigned int bestvco = 0;
+ unsigned int fxtal = pll->ref_freq;
+ unsigned int fwant;
+ unsigned int p;
+
+ DBG("PLL_calcclock")
+
+ fwant = freq;
+
+#ifdef DEBUG
+ printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max);
+ printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq);
+ printk(KERN_ERR "freq: %d\n", freq);
+ printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min);
+ printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min);
+ printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max);
+ printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min);
+ printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max);
+ printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+ for (p = 1; p <= pll->post_shift_max; p++) {
+ if (fwant * 2 > fmax)
+ break;
+ fwant *= 2;
+ }
+ if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min;
+ if (fwant > fmax) fwant = fmax;
+ for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
+ unsigned int m;
+
+ if (fwant < pll->vco_freq_min) break;
+ for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
+ unsigned int diff, fvco;
+ unsigned int n;
+
+ n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+ if (n > pll->feed_div_max)
+ break;
+ if (n < pll->feed_div_min)
+ n = pll->feed_div_min;
+ fvco = (fxtal * (n + 1)) / (m + 1);
+ if (fvco < fwant)
+ diff = fwant - fvco;
+ else
+ diff = fvco - fwant;
+ if (diff < bestdiff) {
+ bestdiff = diff;
+ *post = p;
+ *in = m;
+ *feed = n;
+ bestvco = fvco;
+ }
+ }
+ }
+ dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+ return bestvco;
+}
+
+int matroxfb_vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
+ unsigned int hd, hs, he, hbe, ht;
+ unsigned int vd, vs, ve, vt;
+ unsigned int wd;
+ unsigned int divider;
+ int i;
+ int text = p->type == FB_TYPE_TEXT;
+ int fwidth;
+
+ if (text) {
+ fwidth = fontwidth(p);
+ if (!fwidth) fwidth = 8;
+ } else
+ fwidth = 8;
+
+ DBG("vgaHWinit")
+
+ hw->SEQ[0] = 0x00;
+ if (fwidth == 9)
+ hw->SEQ[1] = 0x00;
+ else
+ hw->SEQ[1] = 0x01; /* or 0x09 */
+ hw->SEQ[2] = 0x0F; /* bitplanes */
+ hw->SEQ[3] = 0x00;
+ if (text)
+ hw->SEQ[4] = 0x02;
+ else
+ hw->SEQ[4] = 0x0E;
+ /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */
+ if (m->dblscan) {
+ m->VTotal <<= 1;
+ m->VDisplay <<= 1;
+ m->VSyncStart <<= 1;
+ m->VSyncEnd <<= 1;
+ }
+ if (m->interlaced) {
+ m->VTotal >>= 1;
+ m->VDisplay >>= 1;
+ m->VSyncStart >>= 1;
+ m->VSyncEnd >>= 1;
+ }
+
+ /* GCTL is ignored when not using 0xA0000 aperture */
+ hw->GCTL[0] = 0x00;
+ hw->GCTL[1] = 0x00;
+ hw->GCTL[2] = 0x00;
+ hw->GCTL[3] = 0x00;
+ hw->GCTL[4] = 0x00;
+ if (text) {
+ hw->GCTL[5] = 0x10;
+ hw->GCTL[6] = 0x02;
+ } else {
+ hw->GCTL[5] = 0x40;
+ hw->GCTL[6] = 0x05;
+ }
+ hw->GCTL[7] = 0x0F;
+ hw->GCTL[8] = 0xFF;
+
+ /* Whole ATTR is ignored in PowerGraphics mode */
+ for (i = 0; i < 16; i++)
+ hw->ATTR[i] = i;
+ if (text) {
+ hw->ATTR[16] = 0x04;
+ } else {
+ hw->ATTR[16] = 0x41;
+ }
+ hw->ATTR[17] = 0xFF;
+ hw->ATTR[18] = 0x0F;
+ if (fwidth == 9)
+ hw->ATTR[19] = 0x08;
+ else
+ hw->ATTR[19] = 0x00;
+ hw->ATTR[20] = 0x00;
+
+ if (text) {
+ hd = m->HDisplay / fwidth;
+ hs = m->HSyncStart / fwidth;
+ he = m->HSyncEnd / fwidth;
+ ht = m->HTotal / fwidth;
+ divider = 8;
+ } else {
+ hd = m->HDisplay >> 3;
+ hs = m->HSyncStart >> 3;
+ he = m->HSyncEnd >> 3;
+ ht = m->HTotal >> 3;
+ /* standard timmings are in 8pixels, but for interleaved we cannot */
+ /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+ /* using 16 or more pixels per unit can save us */
+ divider = ACCESS_FBINFO(curr.final_bppShift);
+ }
+ while (divider & 3) {
+ hd >>= 1;
+ hs >>= 1;
+ he >>= 1;
+ ht >>= 1;
+ divider <<= 1;
+ }
+ divider = divider / 4;
+ /* divider can be from 1 to 8 */
+ while (divider > 8) {
+ hd <<= 1;
+ hs <<= 1;
+ he <<= 1;
+ ht <<= 1;
+ divider >>= 1;
+ }
+ hd = hd - 1;
+ hs = hs - 1;
+ he = he - 1;
+ ht = ht - 1;
+ vd = m->VDisplay - 1;
+ vs = m->VSyncStart - 1;
+ ve = m->VSyncEnd - 1;
+ vt = m->VTotal - 2;
+ /* G200 cannot work with (ht & 7) == 6 */
+ if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
+ ht++;
+ if (text) {
+ hbe = ht - 1;
+ wd = p->var.xres_virtual / (fwidth * 2);
+ } else {
+ hbe = ht;
+ wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64;
+ }
+
+ hw->CRTCEXT[0] = 0;
+ hw->CRTCEXT[5] = 0;
+ if (m->interlaced) {
+ hw->CRTCEXT[0] = 0x80;
+ hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+ if (!m->dblscan)
+ wd <<= 1;
+ vt &= ~1;
+ }
+ hw->CRTCEXT[0] |= (wd & 0x300) >> 4;
+ hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+ ((hd & 0x100) >> 7) | /* blanking */
+ ((hs & 0x100) >> 6) | /* sync start */
+ (hbe & 0x040); /* end hor. blanking */
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+ hw->CRTCEXT[1] |= 0x88; /* enable horizontal and vertical vidrst */
+ hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
+ ((vd & 0x400) >> 8) | /* disp end */
+ ((vd & 0xC00) >> 7) | /* vblanking start */
+ ((vs & 0xC00) >> 5);
+ if (text)
+ hw->CRTCEXT[3] = 0x00;
+ else
+ hw->CRTCEXT[3] = (divider - 1) | 0x80;
+ hw->CRTCEXT[4] = 0;
+
+ hw->CRTC[0] = ht-4;
+ hw->CRTC[1] = hd;
+ hw->CRTC[2] = hd;
+ hw->CRTC[3] = (hbe & 0x1F) | 0x80;
+ hw->CRTC[4] = hs;
+ hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
+ if (text)
+ hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */
+ hw->CRTC[6] = vt & 0xFF;
+ hw->CRTC[7] = ((vt & 0x100) >> 8) |
+ ((vd & 0x100) >> 7) |
+ ((vs & 0x100) >> 6) |
+ ((vd & 0x100) >> 5) |
+ 0x10 |
+ ((vt & 0x200) >> 4) |
+ ((vd & 0x200) >> 3) |
+ ((vs & 0x200) >> 2);
+ hw->CRTC[8] = 0x00;
+ hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
+ if (text)
+ hw->CRTC[9] |= fontheight(p) - 1;
+ if (m->dblscan && !m->interlaced)
+ hw->CRTC[9] |= 0x80;
+ for (i = 10; i < 16; i++)
+ hw->CRTC[i] = 0x00;
+ hw->CRTC[16] = vs /* & 0xFF */;
+ hw->CRTC[17] = (ve & 0x0F) | 0x20;
+ hw->CRTC[18] = vd /* & 0xFF */;
+ hw->CRTC[19] = wd /* & 0xFF */;
+ hw->CRTC[20] = 0x00;
+ hw->CRTC[21] = vd /* & 0xFF */;
+ hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+ if (text) {
+ if (ACCESS_FBINFO(devflags.textmode) == 1)
+ hw->CRTC[23] = 0xC3;
+ else
+ hw->CRTC[23] = 0xA3;
+ if (ACCESS_FBINFO(devflags.textmode) == 4)
+ hw->CRTC[20] = 0x5F;
+ else
+ hw->CRTC[20] = 0x1F;
+ } else
+ hw->CRTC[23] = 0xC3;
+ hw->CRTC[24] = 0xFF;
+ return 0;
+};
+
+void matroxfb_vgaHWrestore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
+ int i;
+ CRITFLAGS
+
+ DBG("vgaHWrestore")
+
+ dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+ dprintk(KERN_INFO "SEQ regs: ");
+ for (i = 0; i < 5; i++)
+ dprintk("%02X:", hw->SEQ[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "GDC regs: ");
+ for (i = 0; i < 9; i++)
+ dprintk("%02X:", hw->GCTL[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "CRTC regs: ");
+ for (i = 0; i < 25; i++)
+ dprintk("%02X:", hw->CRTC[i]);
+ dprintk("\n");
+ dprintk(KERN_INFO "ATTR regs: ");
+ for (i = 0; i < 21; i++)
+ dprintk("%02X:", hw->ATTR[i]);
+ dprintk("\n");
+
+ CRITBEGIN
+
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, 0);
+ mga_outb(M_MISC_REG, hw->MiscOutReg);
+ for (i = 1; i < 5; i++)
+ mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+ mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+ for (i = 0; i < 25; i++)
+ mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+ for (i = 0; i < 9; i++)
+ mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+ for (i = 0; i < 21; i++) {
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, i);
+ mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+ }
+ mga_outb(M_PALETTE_MASK, 0xFF);
+ mga_outb(M_DAC_REG, 0x00);
+ for (i = 0; i < 768; i++)
+ mga_outb(M_DAC_VAL, hw->DACpal[i]);
+ mga_inb(M_ATTR_RESET);
+ mga_outb(M_ATTR_INDEX, 0x20);
+
+ CRITEND
+}
+
+void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
+ unsigned int size;
+
+ size = ACCESS_FBINFO(fastfont.size);
+ ACCESS_FBINFO(fastfont.size) = 0;
+ if (size) {
+ unsigned int end = ACCESS_FBINFO(video.len_usable);
+
+ if (size < end) {
+ unsigned int start;
+
+ start = (end - size) & PAGE_MASK;
+ if (start >= 0x00100000) {
+ ACCESS_FBINFO(video.len_usable) = start;
+ ACCESS_FBINFO(fastfont.mgabase) = start * 8;
+ ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase);
+ vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start);
+ ACCESS_FBINFO(fastfont.size) = end - start;
+ }
+ }
+ }
+}
+
+#ifndef FNTCHARCNT
+#define FNTCHARCNT(fd) (((int *)(fd))[-3])
+#endif
+
+int matrox_text_loadfont(WPMINFO struct display* p) {
+ unsigned int fsize;
+ unsigned int width;
+ vaddr_t dst;
+ unsigned int i;
+ u_int8_t* font;
+ CRITFLAGS
+
+ if (!p || !p->fontdata)
+ return 0;
+ width = fontwidth(p);
+ fsize = p->userfont?FNTCHARCNT(p->fontdata):256;
+
+ dst = ACCESS_FBINFO(video.vbase);
+ i = 2;
+ font = (u_int8_t*)p->fontdata;
+
+ CRITBEGIN
+
+ mga_setr(M_SEQ_INDEX, 0x02, 0x04);
+ while (fsize--) {
+ int l;
+
+ for (l = 0; l < fontheight(p); l++) {
+ mga_writeb(dst, i, *font++);
+ if (fontwidth(p) > 8) font++;
+ i += ACCESS_FBINFO(devflags.vgastep);
+ }
+ i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
+ }
+ mga_setr(M_SEQ_INDEX, 0x02, 0x03);
+
+ CRITEND
+
+ return 1;
+}
+
+int matroxfb_fastfont_tryset(WPMINFO struct display* p) {
+ unsigned int fsize;
+ unsigned int width;
+ CRITFLAGS
+
+ if (!p || !p->fontdata)
+ return 0;
+ width = fontwidth(p);
+ if (width > 32)
+ return 0;
+ fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
+ if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
+ return 0;
+
+ CRITBEGIN
+
+ mga_outl(M_OPMODE, M_OPMODE_8BPP);
+ if (width <= 8) {
+ if (width == 8)
+ mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize);
+ else {
+ vaddr_t dst;
+ unsigned int i;
+ u_int8_t* font;
+ u_int32_t mask, valid, reg;
+
+ dst = ACCESS_FBINFO(fastfont.vbase);
+ font = (u_int8_t*)p->fontdata;
+ mask = ~0 << (8 - width);
+ valid = 0;
+ reg = 0;
+ i = 0;
+ while (fsize--) {
+ reg |= (*font++ & mask) << (8 - valid);
+ valid += width;
+ if (valid >= 8) {
+ mga_writeb(dst, i++, reg >> 8);
+ reg = reg << 8;
+ valid -= 8;
+ }
+ }
+ if (valid)
+ mga_writeb(dst, i, reg >> 8);
+ }
+ } else if (width <= 16) {
+ if (width == 16)
+ mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2);
+ else {
+ vaddr_t dst;
+ u_int16_t* font;
+ u_int32_t mask, valid, reg;
+ unsigned int i;
+
+ dst = ACCESS_FBINFO(fastfont.vbase);
+ font = (u_int16_t*)p->fontdata;
+ mask = ~0 << (16 - width);
+ valid = 0;
+ reg = 0;
+ i = 0;
+ while (fsize--) {
+ reg |= (ntohs(*font++) & mask) << (16 - valid);
+ valid += width;
+ if (valid >= 16) {
+ mga_writew(dst, i, htons(reg >> 16));
+ i += 2;
+ reg = reg << 16;
+ valid -= 16;
+ }
+ }
+ if (valid)
+ mga_writew(dst, i, htons(reg >> 16));
+ }
+ } else {
+ if (width == 32)
+ mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4);
+ else {
+ vaddr_t dst;
+ u_int32_t* font;
+ u_int32_t mask, valid, reg;
+ unsigned int i;
+
+ dst = ACCESS_FBINFO(fastfont.vbase);
+ font = (u_int32_t*)p->fontdata;
+ mask = ~0 << (32 - width);
+ valid = 0;
+ reg = 0;
+ i = 0;
+ while (fsize--) {
+ reg |= (ntohl(*font) & mask) >> valid;
+ valid += width;
+ if (valid >= 32) {
+ mga_writel(dst, i, htonl(reg));
+ i += 4;
+ valid -= 32;
+ if (valid)
+ reg = (ntohl(*font) & mask) << (width - valid);
+ else
+ reg = 0;
+ }
+ font++;
+ }
+ if (valid)
+ mga_writel(dst, i, htonl(reg));
+ }
+ }
+ mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+
+ CRITEND
+
+ return 1;
+}
+
+EXPORT_SYMBOL(matroxfb_DAC_in);
+EXPORT_SYMBOL(matroxfb_DAC_out);
+EXPORT_SYMBOL(matroxfb_var2my);
+EXPORT_SYMBOL(matroxfb_PLL_calcclock);
+#ifndef CONFIG_FB_MATROX_MULTIHEAD
+struct matrox_fb_info matroxfb_global_mxinfo;
+EXPORT_SYMBOL(matroxfb_global_mxinfo);
+#endif
+EXPORT_SYMBOL(matrox_text_loadfont); /* for matroxfb_accel */
+EXPORT_SYMBOL(matroxfb_createcursorshape); /* accel, DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_fastfont_tryset); /* accel */
+EXPORT_SYMBOL(matroxfb_fastfont_init); /* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */
+#ifdef MATROXFB_USE_SPINLOCK
+spinlock_t matroxfb_spinlock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(matroxfb_spinlock);
+#endif
diff --git a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h
new file mode 100644
index 000000000..b88ccd8ca
--- /dev/null
+++ b/drivers/video/matrox/matroxfb_misc.h
@@ -0,0 +1,21 @@
+#ifndef __MATROXFB_MISC_H__
+#define __MATROXFB_MISC_H__
+
+#include "matroxfb_base.h"
+
+/* also for modules */
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+ unsigned int* in, unsigned int* feed, unsigned int* post);
+static inline int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax,
+ unsigned int* in, unsigned int* feed, unsigned int* post) {
+ return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post);
+}
+
+void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode);
+int matroxfb_vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p);
+void matroxfb_vgaHWrestore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw);
+void matroxfb_fastfont_init(struct matrox_fb_info* minfo);
+int matrox_text_loadfont(WPMINFO struct display* p);
+int matroxfb_fastfont_tryset(WPMINFO struct display* p);
+
+#endif /* __MATROXFB_MISC_H__ */
diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c
deleted file mode 100644
index 8fbff9bc4..000000000
--- a/drivers/video/matroxfb.c
+++ /dev/null
@@ -1,6107 +0,0 @@
-/*
- *
- * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
- *
- * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
- *
- * Version: 1.19 1999/08/05
- *
- * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
- *
- * Contributors: "menion?" <menion@mindless.com>
- * Betatesting, fixes, ideas
- *
- * "Kurt Garloff" <garloff@kg1.ping.de>
- * Betatesting, fixes, ideas, videomodes, videomodes timmings
- *
- * "Tom Rini" <trini@disparity.net>
- * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
- *
- * "Bibek Sahu" <scorpio@dodds.net>
- * Access device through readb|w|l and write b|w|l
- * Extensive debugging stuff
- *
- * "Daniel Haun" <haund@usa.net>
- * Testing, hardware cursor fixes
- *
- * "Scott Wood" <sawst46+@pitt.edu>
- * Fixes
- *
- * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
- * Betatesting
- *
- * "Kelly French" <targon@hazmat.com>
- * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
- * Betatesting, bug reporting
- *
- * "Pablo Bianucci" <pbian@pccp.com.ar>
- * Fixes, ideas, betatesting
- *
- * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
- * Fixes, enhandcements, ideas, betatesting
- *
- * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
- * PPC betatesting, PPC support, backward compatibility
- *
- * "Paul Womar" <Paul@pwomar.demon.co.uk>
- * "Owen Waller" <O.Waller@ee.qub.ac.uk>
- * PPC betatesting
- *
- * "Thomas Pornin" <pornin@bolet.ens.fr>
- * Alpha betatesting
- *
- * "Pieter van Leuven" <pvl@iae.nl>
- * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
- * G100 testing
- *
- * "H. Peter Arvin" <hpa@transmeta.com>
- * Ideas
- *
- * "Cort Dougan" <cort@cs.nmt.edu>
- * CHRP fixes and PReP cleanup
- *
- * "Mark Vojkovich" <mvojkovi@ucsd.edu>
- * G400 support
- *
- * (following author is not in any relation with this code, but his code
- * is included in this driver)
- *
- * Based on framebuffer driver for VBE 2.0 compliant graphic boards
- * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
- *
- * (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
- *
- * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
- *
- */
-
-/* general, but fairly heavy, debugging */
-#undef MATROXFB_DEBUG
-
-/* heavy debugging: */
-/* -- logs putc[s], so everytime a char is displayed, it's logged */
-#undef MATROXFB_DEBUG_HEAVY
-
-/* This one _could_ cause infinite loops */
-/* It _does_ cause lots and lots of messages during idle loops */
-#undef MATROXFB_DEBUG_LOOP
-
-/* Debug register calls, too? */
-#undef MATROXFB_DEBUG_REG
-
-#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/timer.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-#include <asm/unaligned.h>
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
-#if defined(CONFIG_FB_OF)
-#if defined(CONFIG_FB_COMPAT_XPMAC)
-#include <asm/vc_ioctl.h>
-#endif
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <video/macmodes.h>
-#endif
-
-/* always compile support for 32MB... It cost almost nothing */
-#define CONFIG_FB_MATROX_32MB
-
-#define FBCON_HAS_VGATEXT
-
-#ifdef MATROXFB_DEBUG
-
-#define DEBUG
-#define DBG(x) printk(KERN_DEBUG "matroxfb: %s\n", (x));
-
-#ifdef MATROXFB_DEBUG_HEAVY
-#define DBG_HEAVY(x) DBG(x)
-#else /* MATROXFB_DEBUG_HEAVY */
-#define DBG_HEAVY(x) /* DBG_HEAVY */
-#endif /* MATROXFB_DEBUG_HEAVY */
-
-#ifdef MATROXFB_DEBUG_LOOP
-#define DBG_LOOP(x) DBG(x)
-#else /* MATROXFB_DEBUG_LOOP */
-#define DBG_LOOP(x) /* DBG_LOOP */
-#endif /* MATROXFB_DEBUG_LOOP */
-
-#ifdef MATROXFB_DEBUG_REG
-#define DBG_REG(x) DBG(x)
-#else /* MATROXFB_DEBUG_REG */
-#define DBG_REG(x) /* DBG_REG */
-#endif /* MATROXFB_DEBUG_REG */
-
-#else /* MATROXFB_DEBUG */
-
-#define DBG(x) /* DBG */
-#define DBG_HEAVY(x) /* DBG_HEAVY */
-#define DBG_REG(x) /* DBG_REG */
-#define DBG_LOOP(x) /* DBG_LOOP */
-
-#endif /* MATROXFB_DEBUG */
-
-#ifndef __i386__
-#ifndef ioremap_nocache
-#define ioremap_nocache(X,Y) ioremap(X,Y)
-#endif
-#endif
-
-#if defined(__alpha__) || defined(__m68k__)
-#define READx_WORKS
-#define MEMCPYTOIO_WORKS
-#else
-#define READx_FAILS
-/* recheck __ppc__, maybe that __ppc__ needs MEMCPYTOIO_WRITEL */
-/* I benchmarked PII/350MHz with G200... MEMCPY, MEMCPYTOIO and WRITEL are on same speed ( <2% diff) */
-/* so that means that G200 speed (or AGP speed?) is our limit... I do not have benchmark to test, how */
-/* much of PCI bandwidth is used during transfers... */
-#if defined(__i386__)
-#define MEMCPYTOIO_MEMCPY
-#else
-#define MEMCPYTOIO_WRITEL
-#endif
-#endif
-
-#ifdef __sparc__
-#error "Sorry, I have no idea how to do this on sparc... There is mapioaddr... With bus_type parameter..."
-#endif
-
-#if defined(__m68k__)
-#define MAP_BUSTOVIRT
-#else
-#define MAP_IOREMAP
-#endif
-
-#ifdef DEBUG
-#define dprintk(X...) printk(X)
-#else
-#define dprintk(X...)
-#endif
-
-#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
-#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF 0x110A
-#endif
-#ifndef PCI_SS_VENDOR_ID_MATROX
-#define PCI_SS_VENDOR_ID_MATROX PCI_VENDOR_ID_MATROX
-#endif
-#ifndef PCI_DEVICE_ID_MATROX_G200_PCI
-#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
-#endif
-#ifndef PCI_DEVICE_ID_MATROX_G200_AGP
-#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
-#endif
-#ifndef PCI_DEVICE_ID_MATROX_G100
-#define PCI_DEVICE_ID_MATROX_G100 0x1000
-#endif
-#ifndef PCI_DEVICE_ID_MATROX_G100_AGP
-#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001
-#endif
-#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
-#define PCI_DEVICE_ID_MATROX_G400_AGP 0x0525
-#endif
-
-#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
-#define PCI_SS_ID_MATROX_GENERIC 0xFF00
-#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP 0xFF01
-#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP 0xFF02
-#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP 0xFF03
-#define PCI_SS_ID_MATROX_MARVEL_G200_AGP 0xFF04
-#define PCI_SS_ID_MATROX_MGA_G100_PCI 0xFF05
-#define PCI_SS_ID_MATROX_MGA_G100_AGP 0x1001
-#define PCI_SS_ID_SIEMENS_MGA_G100_AGP 0x001E /* 30 */
-#define PCI_SS_ID_SIEMENS_MGA_G200_AGP 0x0032 /* 50 */
-#endif
-
-#define MX_VISUAL_TRUECOLOR FB_VISUAL_DIRECTCOLOR
-#define MX_VISUAL_DIRECTCOLOR FB_VISUAL_TRUECOLOR
-#define MX_VISUAL_PSEUDOCOLOR FB_VISUAL_PSEUDOCOLOR
-
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
-
-/* G100, G200 and Mystique have (almost) same DAC */
-#undef NEED_DAC1064
-#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G100)
-#define NEED_DAC1064 1
-#endif
-
-typedef struct {
- u_int8_t* vaddr;
-} vaddr_t;
-
-#ifdef READx_WORKS
-static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
- return readb(va.vaddr + offs);
-}
-
-static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
- return readw(va.vaddr + offs);
-}
-
-static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
- return readl(va.vaddr + offs);
-}
-
-static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
- writeb(value, va.vaddr + offs);
-}
-
-static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
- writew(value, va.vaddr + offs);
-}
-
-static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
- writel(value, va.vaddr + offs);
-}
-#else
-static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
- return *(volatile u_int8_t*)(va.vaddr + offs);
-}
-
-static inline unsigned int mga_readw(vaddr_t va, unsigned int offs) {
- return *(volatile u_int16_t*)(va.vaddr + offs);
-}
-
-static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
- return *(volatile u_int32_t*)(va.vaddr + offs);
-}
-
-static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
- *(volatile u_int8_t*)(va.vaddr + offs) = value;
-}
-
-static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
- *(volatile u_int16_t*)(va.vaddr + offs) = value;
-}
-
-static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
- *(volatile u_int32_t*)(va.vaddr + offs) = value;
-}
-#endif
-
-static inline void mga_memcpy_toio(vaddr_t va, unsigned int offs, const void* src, int len) {
-#ifdef MEMCPYTOIO_WORKS
- memcpy_toio(va.vaddr + offs, src, len);
-#elif defined(MEMCPYTOIO_WRITEL)
-#define srcd ((const u_int32_t*)src)
- if (offs & 3) {
- while (len >= 4) {
- mga_writel(va, offs, get_unaligned(srcd++));
- offs += 4;
- len -= 4;
- }
- } else {
- while (len >= 4) {
- mga_writel(va, offs, *srcd++);
- offs += 4;
- len -= 4;
- }
- }
-#undef srcd
- if (len) {
- u_int32_t tmp;
-
- memcpy(&tmp, src, len);
- mga_writel(va, offs, tmp);
- }
-#elif defined(MEMCPYTOIO_MEMCPY)
- memcpy(va.vaddr + offs, src, len);
-#else
-#error "Sorry, do not know how to write block of data to device"
-#endif
-}
-
-static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
- va->vaddr += offs;
-}
-
-static inline void* vaddr_va(vaddr_t va) {
- return va.vaddr;
-}
-
-#define MGA_IOREMAP_NORMAL 0
-#define MGA_IOREMAP_NOCACHE 1
-
-#define MGA_IOREMAP_FB MGA_IOREMAP_NOCACHE
-#define MGA_IOREMAP_MMIO MGA_IOREMAP_NOCACHE
-static inline int mga_ioremap(unsigned long phys, unsigned long size, int flags, vaddr_t* virt) {
-#ifdef MAP_IOREMAP
- if (flags & MGA_IOREMAP_NOCACHE)
- virt->vaddr = ioremap_nocache(phys, size);
- else
- virt->vaddr = ioremap(phys, size);
-#else
-#ifdef MAP_BUSTOVIRT
- virt->vaddr = bus_to_virt(phys);
-#else
-#error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up"
-#endif
-#endif
- return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
-}
-
-static inline void mga_iounmap(vaddr_t va) {
-#ifdef MAP_IOREMAP
- iounmap(va.vaddr);
-#endif
-}
-
-struct matroxfb_par
-{
- unsigned int final_bppShift;
- unsigned int cmap_len;
- struct {
- unsigned int bytes;
- unsigned int pixels;
- unsigned int chunks;
- } ydstorg;
- void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int);
- void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int);
-};
-
-struct my_timming {
- unsigned int pixclock;
- unsigned int HDisplay;
- unsigned int HSyncStart;
- unsigned int HSyncEnd;
- unsigned int HTotal;
- unsigned int VDisplay;
- unsigned int VSyncStart;
- unsigned int VSyncEnd;
- unsigned int VTotal;
- unsigned int sync;
- int dblscan;
- int interlaced;
-};
-
-struct matrox_fb_info;
-
-#define MATROX_2MB_WITH_4MB_ADDON
-
-struct matrox_pll_features {
- unsigned int vco_freq_min;
- unsigned int ref_freq;
- unsigned int feed_div_min;
- unsigned int feed_div_max;
- unsigned int in_div_min;
- unsigned int in_div_max;
- unsigned int post_shift_max;
-};
-
-struct matrox_DAC1064_features {
- u_int8_t xvrefctrl;
- unsigned int cursorimage;
-};
-
-struct matrox_accel_features {
- int has_cacheflush;
-};
-
-/* current hardware status */
-struct matrox_hw_state {
- u_int32_t MXoptionReg;
- unsigned char DACclk[6];
- unsigned char DACreg[64];
- unsigned char MiscOutReg;
- unsigned char DACpal[768];
- unsigned char CRTC[25];
- unsigned char CRTCEXT[9];
- unsigned char SEQ[5];
- /* unused for MGA mode, but who knows... */
- unsigned char GCTL[9];
- /* unused for MGA mode, but who knows... */
- unsigned char ATTR[21];
-};
-
-struct matrox_accel_data {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
- unsigned char ramdac_rev;
-#endif
- u_int32_t m_dwg_rect;
- u_int32_t m_opmode;
-};
-
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
-#define ACCESS_FBINFO2(info, x) (info->x)
-#define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x)
-
-#define MINFO minfo
-
-#define WPMINFO struct matrox_fb_info* minfo,
-#define CPMINFO const struct matrox_fb_info* minfo,
-#define PMINFO minfo,
-
-static inline struct matrox_fb_info* mxinfo(const struct display* p) {
- return (struct matrox_fb_info*)p->fb_info;
-}
-
-#define PMXINFO(p) mxinfo(p),
-#define MINFO_FROM(x) struct matrox_fb_info* minfo = x
-#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
-
-#else
-
-struct matrox_fb_info global_mxinfo;
-struct display global_disp;
-
-#define ACCESS_FBINFO(x) (global_mxinfo.x)
-#define ACCESS_FBINFO2(info, x) (global_mxinfo.x)
-
-#define MINFO (&global_mxinfo)
-
-#define WPMINFO
-#define CPMINFO
-#define PMINFO
-
-#if 0
-static inline struct matrox_fb_info* mxinfo(const struct display* p) {
- return &global_mxinfo;
-}
-#endif
-
-#define PMXINFO(p)
-#define MINFO_FROM(x)
-#define MINFO_FROM_DISP(x)
-
-#endif
-
-struct matrox_switch {
- int (*preinit)(WPMINFO struct matrox_hw_state*);
- void (*reset)(WPMINFO struct matrox_hw_state*);
- int (*init)(CPMINFO struct matrox_hw_state*, struct my_timming*, struct display*);
- void (*restore)(WPMINFO struct matrox_hw_state*, struct matrox_hw_state*, struct display*);
-};
-
-struct matrox_fb_info {
- /* fb_info must be first */
- struct fb_info fbcon;
-
- struct matrox_fb_info* next_fb;
-
- struct matroxfb_par curr;
- struct matrox_hw_state hw1;
- struct matrox_hw_state hw2;
- struct matrox_hw_state* newhw;
- struct matrox_hw_state* currenthw;
-
- struct matrox_accel_data accel;
-
- struct pci_dev* pcidev;
-
- struct {
- unsigned long base; /* physical */
- vaddr_t vbase; /* CPU view */
- unsigned int len;
- unsigned int len_usable;
- } video;
-
- struct {
- unsigned long base; /* physical */
- vaddr_t vbase; /* CPU view */
- unsigned int len;
- } mmio;
-
- unsigned int max_pixel_clock;
-
- struct matrox_switch* hw_switch;
- int currcon;
- struct display* currcon_display;
-
- struct {
- struct matrox_pll_features pll;
- struct matrox_DAC1064_features DAC1064;
- struct matrox_accel_features accel;
- } features;
- struct {
- spinlock_t DAC;
- } lock;
-
- int interleave;
- int millenium;
- int milleniumII;
- struct {
- int cfb4;
- const int* vxres;
- int cross4MB;
- int text;
- int plnwt;
- } capable;
- struct {
- unsigned int size;
- unsigned int mgabase;
- vaddr_t vbase;
- } fastfont;
-#ifdef CONFIG_MTRR
- struct {
- int vram;
- int vram_valid;
- } mtrr;
-#endif
- struct {
- int precise_width;
- int mga_24bpp_fix;
- int novga;
- int nobios;
- int nopciretry;
- int noinit;
- int inverse;
- int hwcursor;
- int blink;
- int sgram;
-#ifdef CONFIG_FB_MATROX_32MB
- int support32MB;
-#endif
-
- int accelerator;
- int text_type_aux;
- int video64bits;
- unsigned int vgastep;
- unsigned int textmode;
- unsigned int textstep;
- unsigned int textvram; /* character cells */
- unsigned int ydstorg; /* offset in bytes from video start to usable memory */
- /* 0 except for 6MB Millenium */
- } devflags;
- struct display_switch dispsw;
- struct {
- int x;
- int y;
- unsigned int w;
- unsigned int u;
- unsigned int d;
- unsigned int type;
- int state;
- int redraw;
- struct timer_list timer;
- } cursor;
-#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
- union {
-#ifdef FBCON_HAS_CFB16
- u_int16_t cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
- u_int32_t cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u_int32_t cfb32[16];
-#endif
- } cmap;
-#endif
- struct { unsigned red, green, blue, transp; } palette[256];
-#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
- char matrox_name[32];
-#endif
-};
-
-#if defined(CONFIG_FB_OF)
-unsigned char nvram_read_byte(int);
-int matrox_of_init(struct device_node *dp);
-static int default_vmode = VMODE_NVRAM;
-static int default_cmode = CMODE_NVRAM;
-#endif
-
-#define curr_ydstorg(x) ACCESS_FBINFO2(x, curr.ydstorg.pixels)
-
-#define PCI_OPTION_REG 0x40
-#define PCI_MGA_INDEX 0x44
-#define PCI_MGA_DATA 0x48
-
-#define M_DWGCTL 0x1C00
-#define M_MACCESS 0x1C04
-#define M_CTLWTST 0x1C08
-
-#define M_PLNWT 0x1C1C
-
-#define M_BCOL 0x1C20
-#define M_FCOL 0x1C24
-
-#define M_SGN 0x1C58
-#define M_LEN 0x1C5C
-#define M_AR0 0x1C60
-#define M_AR1 0x1C64
-#define M_AR2 0x1C68
-#define M_AR3 0x1C6C
-#define M_AR4 0x1C70
-#define M_AR5 0x1C74
-#define M_AR6 0x1C78
-
-#define M_CXBNDRY 0x1C80
-#define M_FXBNDRY 0x1C84
-#define M_YDSTLEN 0x1C88
-#define M_PITCH 0x1C8C
-#define M_YDST 0x1C90
-#define M_YDSTORG 0x1C94
-#define M_YTOP 0x1C98
-#define M_YBOT 0x1C9C
-
-/* mystique only */
-#define M_CACHEFLUSH 0x1FFF
-
-#define M_EXEC 0x0100
-
-#define M_DWG_TRAP 0x04
-#define M_DWG_BITBLT 0x08
-#define M_DWG_ILOAD 0x09
-
-#define M_DWG_LINEAR 0x0080
-#define M_DWG_SOLID 0x0800
-#define M_DWG_ARZERO 0x1000
-#define M_DWG_SGNZERO 0x2000
-#define M_DWG_SHIFTZERO 0x4000
-
-#define M_DWG_REPLACE 0x000C0000
-#define M_DWG_REPLACE2 (M_DWG_REPLACE | 0x40)
-#define M_DWG_XOR 0x00060010
-
-#define M_DWG_BFCOL 0x04000000
-#define M_DWG_BMONOWF 0x08000000
-
-#define M_DWG_TRANSC 0x40000000
-
-#define M_FIFOSTATUS 0x1E10
-#define M_STATUS 0x1E14
-
-#define M_IEN 0x1E1C
-
-#define M_VCOUNT 0x1E20
-
-#define M_RESET 0x1E40
-
-#define M_AGP2PLL 0x1E4C
-
-#define M_OPMODE 0x1E54
-#define M_OPMODE_DMA_GEN_WRITE 0x00
-#define M_OPMODE_DMA_BLIT 0x04
-#define M_OPMODE_DMA_VECTOR_WRITE 0x08
-#define M_OPMODE_DMA_LE 0x0000 /* little endian - no transformation */
-#define M_OPMODE_DMA_BE_8BPP 0x0000
-#define M_OPMODE_DMA_BE_16BPP 0x0100
-#define M_OPMODE_DMA_BE_32BPP 0x0200
-#define M_OPMODE_DIR_LE 0x000000 /* little endian - no transformation */
-#define M_OPMODE_DIR_BE_8BPP 0x000000
-#define M_OPMODE_DIR_BE_16BPP 0x010000
-#define M_OPMODE_DIR_BE_32BPP 0x020000
-
-#define M_ATTR_INDEX 0x1FC0
-#define M_ATTR_DATA 0x1FC1
-
-#define M_MISC_REG 0x1FC2
-#define M_3C2_RD 0x1FC2
-
-#define M_SEQ_INDEX 0x1FC4
-#define M_SEQ_DATA 0x1FC5
-
-#define M_MISC_REG_READ 0x1FCC
-
-#define M_GRAPHICS_INDEX 0x1FCE
-#define M_GRAPHICS_DATA 0x1FCF
-
-#define M_CRTC_INDEX 0x1FD4
-
-#define M_ATTR_RESET 0x1FDA
-#define M_3DA_WR 0x1FDA
-
-#define M_EXTVGA_INDEX 0x1FDE
-#define M_EXTVGA_DATA 0x1FDF
-
-/* G200 only */
-#define M_SRCORG 0x2CB4
-
-#define M_RAMDAC_BASE 0x3C00
-
-/* fortunately, same on TVP3026 and MGA1064 */
-#define M_DAC_REG (M_RAMDAC_BASE+0)
-#define M_DAC_VAL (M_RAMDAC_BASE+1)
-#define M_PALETTE_MASK (M_RAMDAC_BASE+2)
-
-#define M_X_INDEX 0x00
-#define M_X_DATAREG 0x0A
-
-#define DAC_XGENIOCTRL 0x2A
-#define DAC_XGENIODATA 0x2B
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-#define TVP3026_INDEX 0x00
-#define TVP3026_PALWRADD 0x00
-#define TVP3026_PALDATA 0x01
-#define TVP3026_PIXRDMSK 0x02
-#define TVP3026_PALRDADD 0x03
-#define TVP3026_CURCOLWRADD 0x04
-#define TVP3026_CLOVERSCAN 0x00
-#define TVP3026_CLCOLOR0 0x01
-#define TVP3026_CLCOLOR1 0x02
-#define TVP3026_CLCOLOR2 0x03
-#define TVP3026_CURCOLDATA 0x05
-#define TVP3026_CURCOLRDADD 0x07
-#define TVP3026_CURCTRL 0x09
-#define TVP3026_X_DATAREG 0x0A
-#define TVP3026_CURRAMDATA 0x0B
-#define TVP3026_CURPOSXL 0x0C
-#define TVP3026_CURPOSXH 0x0D
-#define TVP3026_CURPOSYL 0x0E
-#define TVP3026_CURPOSYH 0x0F
-
-#define TVP3026_XSILICONREV 0x01
-#define TVP3026_XCURCTRL 0x06
-#define TVP3026_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
-#define TVP3026_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
-#define TVP3026_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
-#define TVP3026_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
-#define TVP3026_XCURCTRL_BLANK2048 0x00
-#define TVP3026_XCURCTRL_BLANK4096 0x10
-#define TVP3026_XCURCTRL_INTERLACED 0x20
-#define TVP3026_XCURCTRL_ODD 0x00 /* ext.signal ODD/\EVEN */
-#define TVP3026_XCURCTRL_EVEN 0x40 /* ext.signal EVEN/\ODD */
-#define TVP3026_XCURCTRL_INDIRECT 0x00
-#define TVP3026_XCURCTRL_DIRECT 0x80
-#define TVP3026_XLATCHCTRL 0x0F
-#define TVP3026_XLATCHCTRL_1_1 0x06
-#define TVP3026_XLATCHCTRL_2_1 0x07
-#define TVP3026_XLATCHCTRL_4_1 0x06
-#define TVP3026_XLATCHCTRL_8_1 0x06
-#define TVP3026_XLATCHCTRL_16_1 0x06
-#define TVP3026A_XLATCHCTRL_4_3 0x06 /* ??? do not understand... but it works... !!! */
-#define TVP3026A_XLATCHCTRL_8_3 0x07
-#define TVP3026B_XLATCHCTRL_4_3 0x08
-#define TVP3026B_XLATCHCTRL_8_3 0x06 /* ??? do not understand... but it works... !!! */
-#define TVP3026_XTRUECOLORCTRL 0x18
-#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL 0x00
-#define TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP 0x20
-#define TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR 0x80
-#define TVP3026_XTRUECOLORCTRL_TRUECOLOR 0x40 /* paletized */
-#define TVP3026_XTRUECOLORCTRL_DIRECTCOLOR 0x00
-#define TVP3026_XTRUECOLORCTRL_24_ALTERNATE 0x08 /* 5:4/5:2 instead of 4:3/8:3 */
-#define TVP3026_XTRUECOLORCTRL_RGB_888 0x16 /* 4:3/8:3 (or 5:4/5:2) */
-#define TVP3026_XTRUECOLORCTRL_BGR_888 0x17
-#define TVP3026_XTRUECOLORCTRL_ORGB_8888 0x06
-#define TVP3026_XTRUECOLORCTRL_BGRO_8888 0x07
-#define TVP3026_XTRUECOLORCTRL_RGB_565 0x05
-#define TVP3026_XTRUECOLORCTRL_ORGB_1555 0x04
-#define TVP3026_XTRUECOLORCTRL_RGB_664 0x03
-#define TVP3026_XTRUECOLORCTRL_RGBO_4444 0x01
-#define TVP3026_XMUXCTRL 0x19
-#define TVP3026_XMUXCTRL_MEMORY_8BIT 0x01 /* - */
-#define TVP3026_XMUXCTRL_MEMORY_16BIT 0x02 /* - */
-#define TVP3026_XMUXCTRL_MEMORY_32BIT 0x03 /* 2MB RAM, 512K * 4 */
-#define TVP3026_XMUXCTRL_MEMORY_64BIT 0x04 /* >2MB RAM, 512K * 8 & more */
-#define TVP3026_XMUXCTRL_PIXEL_4BIT 0x40 /* L0,H0,L1,H1... */
-#define TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED 0x60 /* H0,L0,H1,L1... */
-#define TVP3026_XMUXCTRL_PIXEL_8BIT 0x48
-#define TVP3026_XMUXCTRL_PIXEL_16BIT 0x50
-#define TVP3026_XMUXCTRL_PIXEL_32BIT 0x58
-#define TVP3026_XMUXCTRL_VGA 0x98 /* VGA MEMORY, 8BIT PIXEL */
-#define TVP3026_XCLKCTRL 0x1A
-#define TVP3026_XCLKCTRL_DIV1 0x00
-#define TVP3026_XCLKCTRL_DIV2 0x10
-#define TVP3026_XCLKCTRL_DIV4 0x20
-#define TVP3026_XCLKCTRL_DIV8 0x30
-#define TVP3026_XCLKCTRL_DIV16 0x40
-#define TVP3026_XCLKCTRL_DIV32 0x50
-#define TVP3026_XCLKCTRL_DIV64 0x60
-#define TVP3026_XCLKCTRL_CLKSTOPPED 0x70
-#define TVP3026_XCLKCTRL_SRC_CLK0 0x00
-#define TVP3026_XCLKCTRL_SRC_CLK1 0x01
-#define TVP3026_XCLKCTRL_SRC_CLK2 0x02 /* CLK2 is TTL source*/
-#define TVP3026_XCLKCTRL_SRC_NCLK2 0x03 /* not CLK2 is TTL source */
-#define TVP3026_XCLKCTRL_SRC_ECLK2 0x04 /* CLK2 and not CLK2 is ECL source */
-#define TVP3026_XCLKCTRL_SRC_PLL 0x05
-#define TVP3026_XCLKCTRL_SRC_DIS 0x06 /* disable & poweroff internal clock */
-#define TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
-#define TVP3026_XPALETTEPAGE 0x1C
-#define TVP3026_XGENCTRL 0x1D
-#define TVP3026_XGENCTRL_HSYNC_POS 0x00
-#define TVP3026_XGENCTRL_HSYNC_NEG 0x01
-#define TVP3026_XGENCTRL_VSYNC_POS 0x00
-#define TVP3026_XGENCTRL_VSYNC_NEG 0x02
-#define TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
-#define TVP3026_XGENCTRL_BIG_ENDIAN 0x08
-#define TVP3026_XGENCTRL_BLACK_0IRE 0x00
-#define TVP3026_XGENCTRL_BLACK_75IRE 0x10
-#define TVP3026_XGENCTRL_NO_SYNC_ON_GREEN 0x00
-#define TVP3026_XGENCTRL_SYNC_ON_GREEN 0x20
-#define TVP3026_XGENCTRL_OVERSCAN_DIS 0x00
-#define TVP3026_XGENCTRL_OVERSCAN_EN 0x40
-#define TVP3026_XMISCCTRL 0x1E
-#define TVP3026_XMISCCTRL_DAC_PUP 0x00
-#define TVP3026_XMISCCTRL_DAC_PDOWN 0x01
-#define TVP3026_XMISCCTRL_DAC_EXT 0x00 /* or 8, bit 3 is ignored */
-#define TVP3026_XMISCCTRL_DAC_6BIT 0x04
-#define TVP3026_XMISCCTRL_DAC_8BIT 0x0C
-#define TVP3026_XMISCCTRL_PSEL_DIS 0x00
-#define TVP3026_XMISCCTRL_PSEL_EN 0x10
-#define TVP3026_XMISCCTRL_PSEL_LOW 0x00 /* PSEL high selects directcolor */
-#define TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
-#define TVP3026_XGENIOCTRL 0x2A
-#define TVP3026_XGENIODATA 0x2B
-#define TVP3026_XPLLADDR 0x2C
-#define TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
-#define TVP3026_XPLLDATA_N 0x00
-#define TVP3026_XPLLDATA_M 0x01
-#define TVP3026_XPLLDATA_P 0x02
-#define TVP3026_XPLLDATA_STAT 0x03
-#define TVP3026_XPIXPLLDATA 0x2D
-#define TVP3026_XMEMPLLDATA 0x2E
-#define TVP3026_XLOOPPLLDATA 0x2F
-#define TVP3026_XCOLKEYOVRMIN 0x30
-#define TVP3026_XCOLKEYOVRMAX 0x31
-#define TVP3026_XCOLKEYREDMIN 0x32
-#define TVP3026_XCOLKEYREDMAX 0x33
-#define TVP3026_XCOLKEYGREENMIN 0x34
-#define TVP3026_XCOLKEYGREENMAX 0x35
-#define TVP3026_XCOLKEYBLUEMIN 0x36
-#define TVP3026_XCOLKEYBLUEMAX 0x37
-#define TVP3026_XCOLKEYCTRL 0x38
-#define TVP3026_XCOLKEYCTRL_OVR_EN 0x01
-#define TVP3026_XCOLKEYCTRL_RED_EN 0x02
-#define TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
-#define TVP3026_XCOLKEYCTRL_BLUE_EN 0x08
-#define TVP3026_XCOLKEYCTRL_NEGATE 0x10
-#define TVP3026_XCOLKEYCTRL_ZOOM1 0x00
-#define TVP3026_XCOLKEYCTRL_ZOOM2 0x20
-#define TVP3026_XCOLKEYCTRL_ZOOM4 0x40
-#define TVP3026_XCOLKEYCTRL_ZOOM8 0x60
-#define TVP3026_XCOLKEYCTRL_ZOOM16 0x80
-#define TVP3026_XCOLKEYCTRL_ZOOM32 0xA0
-#define TVP3026_XMEMPLLCTRL 0x39
-#define TVP3026_XMEMPLLCTRL_DIV(X) (((X)-1)>>1) /* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
-#define TVP3026_XMEMPLLCTRL_STROBEMKC4 0x08
-#define TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK 0x00 /* MKC4 */
-#define TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL 0x10 /* MKC4 */
-#define TVP3026_XMEMPLLCTRL_RCLK_PIXPLL 0x00
-#define TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL 0x20
-#define TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN 0x40 /* dot clock divided by loop pclk N prescaler */
-#define TVP3026_XSENSETEST 0x3A
-#define TVP3026_XTESTMODEDATA 0x3B
-#define TVP3026_XCRCREML 0x3C
-#define TVP3026_XCRCREMH 0x3D
-#define TVP3026_XCRCBITSEL 0x3E
-#define TVP3026_XID 0x3F
-
-#endif
-
-#ifdef NEED_DAC1064
-
-#define DAC1064_OPT_SCLK_PCI 0x00
-#define DAC1064_OPT_SCLK_PLL 0x01
-#define DAC1064_OPT_SCLK_EXT 0x02
-#define DAC1064_OPT_SCLK_MASK 0x03
-#define DAC1064_OPT_GDIV1 0x04 /* maybe it is GDIV2 on G100 ?! */
-#define DAC1064_OPT_GDIV3 0x00
-#define DAC1064_OPT_MDIV1 0x08
-#define DAC1064_OPT_MDIV2 0x00
-#define DAC1064_OPT_RESERVED 0x10
-
-#define M1064_INDEX 0x00
-#define M1064_PALWRADD 0x00
-#define M1064_PALDATA 0x01
-#define M1064_PIXRDMSK 0x02
-#define M1064_PALRDADD 0x03
-#define M1064_X_DATAREG 0x0A
-#define M1064_CURPOSXL 0x0C /* can be accessed as DWORD */
-#define M1064_CURPOSXH 0x0D
-#define M1064_CURPOSYL 0x0E
-#define M1064_CURPOSYH 0x0F
-
-#define M1064_XCURADDL 0x04
-#define M1064_XCURADDH 0x05
-#define M1064_XCURCTRL 0x06
-#define M1064_XCURCTRL_DIS 0x00 /* transparent, transparent, transparent, transparent */
-#define M1064_XCURCTRL_3COLOR 0x01 /* transparent, 0, 1, 2 */
-#define M1064_XCURCTRL_XGA 0x02 /* 0, 1, transparent, complement */
-#define M1064_XCURCTRL_XWIN 0x03 /* transparent, transparent, 0, 1 */
-#define M1064_XCURCOL0RED 0x08
-#define M1064_XCURCOL0GREEN 0x09
-#define M1064_XCURCOL0BLUE 0x0A
-#define M1064_XCURCOL1RED 0x0C
-#define M1064_XCURCOL1GREEN 0x0D
-#define M1064_XCURCOL1BLUE 0x0E
-#define M1064_XCURCOL2RED 0x10
-#define M1064_XCURCOL2GREEN 0x11
-#define M1064_XCURCOL2BLUE 0x12
-#define DAC1064_XVREFCTRL 0x18
-#define DAC1064_XVREFCTRL_INTERNAL 0x3F
-#define DAC1064_XVREFCTRL_EXTERNAL 0x00
-#define DAC1064_XVREFCTRL_G100_DEFAULT 0x03
-#define M1064_XMULCTRL 0x19
-#define M1064_XMULCTRL_DEPTH_8BPP 0x00 /* 8 bpp paletized */
-#define M1064_XMULCTRL_DEPTH_15BPP_1BPP 0x01 /* 15 bpp paletized + 1 bpp overlay */
-#define M1064_XMULCTRL_DEPTH_16BPP 0x02 /* 16 bpp paletized */
-#define M1064_XMULCTRL_DEPTH_24BPP 0x03 /* 24 bpp paletized */
-#define M1064_XMULCTRL_DEPTH_24BPP_8BPP 0x04 /* 24 bpp direct + 8 bpp overlay paletized */
-#define M1064_XMULCTRL_2G8V16 0x05 /* 15 bpp video direct, half xres, 8bpp paletized */
-#define M1064_XMULCTRL_G16V16 0x06 /* 15 bpp video, 15bpp graphics, one of them paletized */
-#define M1064_XMULCTRL_DEPTH_32BPP 0x07 /* 24 bpp paletized + 8 bpp unused */
-#define M1064_XMULCTRL_GRAPHICS_PALETIZED 0x00
-#define M1064_XMULCTRL_VIDEO_PALETIZED 0x08
-#define M1064_XPIXCLKCTRL 0x1A
-#define M1064_XPIXCLKCTRL_SRC_PCI 0x00
-#define M1064_XPIXCLKCTRL_SRC_PLL 0x01
-#define M1064_XPIXCLKCTRL_SRC_EXT 0x02
-#define M1064_XPIXCLKCTRL_SRC_MASK 0x03
-#define M1064_XPIXCLKCTRL_EN 0x00
-#define M1064_XPIXCLKCTRL_DIS 0x04
-#define M1064_XPIXCLKCTRL_PLL_DOWN 0x00
-#define M1064_XPIXCLKCTRL_PLL_UP 0x08
-#define M1064_XGENCTRL 0x1D
-#define M1064_XGENCTRL_VS_0 0x00
-#define M1064_XGENCTRL_VS_1 0x01
-#define M1064_XGENCTRL_ALPHA_DIS 0x00
-#define M1064_XGENCTRL_ALPHA_EN 0x02
-#define M1064_XGENCTRL_BLACK_0IRE 0x00
-#define M1064_XGENCTRL_BLACK_75IRE 0x10
-#define M1064_XGENCTRL_SYNC_ON_GREEN 0x00
-#define M1064_XGENCTRL_NO_SYNC_ON_GREEN 0x20
-#define M1064_XGENCTRL_SYNC_ON_GREEN_MASK 0x20
-#define M1064_XMISCCTRL 0x1E
-#define M1064_XMISCCTRL_DAC_DIS 0x00
-#define M1064_XMISCCTRL_DAC_EN 0x01
-#define M1064_XMISCCTRL_MFC_VGA 0x00
-#define M1064_XMISCCTRL_MFC_MAFC 0x02
-#define M1064_XMISCCTRL_MFC_DIS 0x06
-#define M1064_XMISCCTRL_DAC_6BIT 0x00
-#define M1064_XMISCCTRL_DAC_8BIT 0x08
-#define M1064_XMISCCTRL_LUT_DIS 0x00
-#define M1064_XMISCCTRL_LUT_EN 0x10
-#define M1064_XGENIOCTRL 0x2A
-#define M1064_XGENIODATA 0x2B
-#define DAC1064_XSYSPLLM 0x2C
-#define DAC1064_XSYSPLLN 0x2D
-#define DAC1064_XSYSPLLP 0x2E
-#define DAC1064_XSYSPLLSTAT 0x2F
-#define M1064_XZOOMCTRL 0x38
-#define M1064_XZOOMCTRL_1 0x00
-#define M1064_XZOOMCTRL_2 0x01
-#define M1064_XZOOMCTRL_4 0x03
-#define M1064_XSENSETEST 0x3A
-#define M1064_XSENSETEST_BCOMP 0x01
-#define M1064_XSENSETEST_GCOMP 0x02
-#define M1064_XSENSETEST_RCOMP 0x04
-#define M1064_XSENSETEST_PDOWN 0x00
-#define M1064_XSENSETEST_PUP 0x80
-#define M1064_XCRCREML 0x3C
-#define M1064_XCRCREMH 0x3D
-#define M1064_XCRCBITSEL 0x3E
-#define M1064_XCOLKEYMASKL 0x40
-#define M1064_XCOLKEYMASKH 0x41
-#define M1064_XCOLKEYL 0x42
-#define M1064_XCOLKEYH 0x43
-#define M1064_XPIXPLLAM 0x44
-#define M1064_XPIXPLLAN 0x45
-#define M1064_XPIXPLLAP 0x46
-#define M1064_XPIXPLLBM 0x48
-#define M1064_XPIXPLLBN 0x49
-#define M1064_XPIXPLLBP 0x4A
-#define M1064_XPIXPLLCM 0x4C
-#define M1064_XPIXPLLCN 0x4D
-#define M1064_XPIXPLLCP 0x4E
-#define M1064_XPIXPLLSTAT 0x4F
-
-#endif
-
-#ifdef __LITTLE_ENDIAN
-#define MX_OPTION_BSWAP 0x00000000
-
-#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_8BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_16BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_24BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_32BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
-#else
-#ifdef __BIG_ENDIAN
-#define MX_OPTION_BSWAP 0x80000000
-
-#define M_OPMODE_4BPP (M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT) /* TODO */
-#define M_OPMODE_8BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_16BPP (M_OPMODE_DMA_BE_16BPP | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
-#define M_OPMODE_24BPP (M_OPMODE_DMA_BE_8BPP | M_OPMODE_DIR_BE_8BPP | M_OPMODE_DMA_BLIT) /* TODO, ?32 */
-#define M_OPMODE_32BPP (M_OPMODE_DMA_BE_32BPP | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
-#else
-#error "Byte ordering have to be defined. Cannot continue."
-#endif
-#endif
-
-#define mga_inb(addr) mga_readb(ACCESS_FBINFO(mmio.vbase), (addr))
-#define mga_inl(addr) mga_readl(ACCESS_FBINFO(mmio.vbase), (addr))
-#define mga_outb(addr,val) mga_writeb(ACCESS_FBINFO(mmio.vbase), (addr), (val))
-#define mga_outw(addr,val) mga_writew(ACCESS_FBINFO(mmio.vbase), (addr), (val))
-#define mga_outl(addr,val) mga_writel(ACCESS_FBINFO(mmio.vbase), (addr), (val))
-#define mga_readr(port,idx) (mga_outb((port),(idx)), mga_inb((port)+1))
-#ifdef __LITTLE_ENDIAN
-#define mga_setr(addr,port,val) mga_outw(addr, ((val)<<8) | (port))
-#else
-#define mga_setr(addr,port,val) do { mga_outb(addr, port); mga_outb((addr)+1, val); } while (0)
-#endif
-
-#ifdef __LITTLE_ENDIAN
-#define mga_fifo(n) do {} while (mga_inb(M_FIFOSTATUS) < (n))
-#else
-#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
-#endif
-
-#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
-
-/* code speedup */
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-#define isInterleave(x) (x->interleave)
-#define isMillenium(x) (x->millenium)
-#define isMilleniumII(x) (x->milleniumII)
-#else
-#define isInterleave(x) (0)
-#define isMillenium(x) (0)
-#define isMilleniumII(x) (0)
-#endif
-
-#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
-
-static void matrox_cfbX_init(WPMINFO struct display* p) {
- u_int32_t maccess;
- u_int32_t mpitch;
- u_int32_t mopmode;
-
- DBG("matrox_cfbX_init")
-
- mpitch = p->var.xres_virtual;
-
- if (p->type == FB_TYPE_TEXT) {
- maccess = 0x00000000;
- mpitch = (mpitch >> 4) | 0x8000; /* set something */
- mopmode = M_OPMODE_8BPP;
- } else {
- switch (p->var.bits_per_pixel) {
- case 4: maccess = 0x00000000; /* accelerate as 8bpp video */
- mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
- mopmode = M_OPMODE_4BPP;
- break;
- case 8: maccess = 0x00000000;
- mopmode = M_OPMODE_8BPP;
- break;
- case 16: if (p->var.green.length == 5)
- maccess = 0xC0000001;
- else
- maccess = 0x40000001;
- mopmode = M_OPMODE_16BPP;
- break;
- case 24: maccess = 0x00000003;
- mopmode = M_OPMODE_24BPP;
- break;
- case 32: maccess = 0x00000002;
- mopmode = M_OPMODE_32BPP;
- break;
- default: maccess = 0x00000000;
- mopmode = 0x00000000;
- break; /* turn off acceleration!!! */
- }
- }
- mga_fifo(8);
- mga_outl(M_PITCH, mpitch);
- mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
- if (ACCESS_FBINFO(capable.plnwt))
- mga_outl(M_PLNWT, -1);
- mga_outl(M_OPMODE, mopmode);
- mga_outl(M_CXBNDRY, 0xFFFF0000);
- mga_outl(M_YTOP, 0);
- mga_outl(M_YBOT, 0x01FFFFFF);
- mga_outl(M_MACCESS, maccess);
- ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
- if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
- ACCESS_FBINFO(accel.m_opmode) = mopmode;
-}
-
-static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
- int pixx = p->var.xres_virtual, start, end;
- MINFO_FROM_DISP(p);
-
- DBG("matrox_cfbX_bmove")
-
- sx *= fontwidth(p);
- dx *= fontwidth(p);
- width *= fontwidth(p);
- height *= fontheight(p);
- sy *= fontheight(p);
- dy *= fontheight(p);
- if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
- mga_fifo(2);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
- M_DWG_BFCOL | M_DWG_REPLACE);
- mga_outl(M_AR5, pixx);
- width--;
- start = sy*pixx+sx+curr_ydstorg(MINFO);
- end = start+width;
- } else {
- mga_fifo(3);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
- mga_outl(M_SGN, 5);
- mga_outl(M_AR5, -pixx);
- width--;
- end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
- start = end+width;
- dy += height-1;
- }
- mga_fifo(4);
- mga_outl(M_AR0, end);
- mga_outl(M_AR3, start);
- mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
- mga_ydstlen(dy, height);
- WaitTillIdle();
-}
-
-#ifdef FBCON_HAS_CFB4
-static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
- int pixx, start, end;
- MINFO_FROM_DISP(p);
- /* both (sx or dx or width) and fontwidth() are odd, so their multiply is
- also odd, that means that we cannot use acceleration */
-
- DBG("matrox_cfb4_bmove")
-
- if ((sx | dx | width) & fontwidth(p) & 1) {
- fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
- return;
- }
- sx *= fontwidth(p);
- dx *= fontwidth(p);
- width *= fontwidth(p);
- height *= fontheight(p);
- sy *= fontheight(p);
- dy *= fontheight(p);
- pixx = p->var.xres_virtual >> 1;
- sx >>= 1;
- dx >>= 1;
- width >>= 1;
- if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
- mga_fifo(2);
- mga_outl(M_AR5, pixx);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
- M_DWG_BFCOL | M_DWG_REPLACE);
- width--;
- start = sy*pixx+sx+curr_ydstorg(MINFO);
- end = start+width;
- } else {
- mga_fifo(3);
- mga_outl(M_SGN, 5);
- mga_outl(M_AR5, -pixx);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
- width--;
- end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO);
- start = end+width;
- dy += height-1;
- }
- mga_fifo(5);
- mga_outl(M_AR0, end);
- mga_outl(M_AR3, start);
- mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
- mga_outl(M_YDST, dy*pixx >> 5);
- mga_outl(M_LEN | M_EXEC, height);
- WaitTillIdle();
-}
-#endif
-
-static void matroxfb_accel_clear(CPMINFO u_int32_t color, int sy, int sx, int height,
- int width) {
-
- DBG("matroxfb_accel_clear")
-
- mga_fifo(5);
- mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
- mga_outl(M_FCOL, color);
- mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
- mga_ydstlen(sy, height);
- WaitTillIdle();
-}
-
-static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
-
- DBG("matrox_cfbX_clear")
-
- matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p),
- height * fontheight(p), width * fontwidth(p));
-}
-
-#ifdef FBCON_HAS_CFB4
-static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
- u_int32_t bgx;
- int whattodo;
- MINFO_FROM_DISP(p);
-
- DBG("matrox_cfb4_clear")
-
- whattodo = 0;
- bgx = attr_bgcol_ec(p, conp);
- bgx |= bgx << 4;
- bgx |= bgx << 8;
- bgx |= bgx << 16;
- sy *= fontheight(p);
- sx *= fontwidth(p);
- height *= fontheight(p);
- width *= fontwidth(p);
- if (sx & 1) {
- sx ++;
- if (!width) return;
- width --;
- whattodo = 1;
- }
- if (width & 1) {
- whattodo |= 2;
- }
- width >>= 1;
- sx >>= 1;
- if (width) {
- mga_fifo(5);
- mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2);
- mga_outl(M_FCOL, bgx);
- mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
- mga_outl(M_YDST, sy * p->var.xres_virtual >> 6);
- mga_outl(M_LEN | M_EXEC, height);
- WaitTillIdle();
- }
- if (whattodo) {
- u_int32_t step = p->var.xres_virtual >> 1;
- vaddr_t vbase = ACCESS_FBINFO(video.vbase);
- if (whattodo & 1) {
- unsigned int uaddr = sy * step + sx - 1;
- u_int32_t loop;
- u_int8_t bgx2 = bgx & 0xF0;
- for (loop = height; loop > 0; loop --) {
- mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
- uaddr += step;
- }
- }
- if (whattodo & 2) {
- unsigned int uaddr = sy * step + sx + width;
- u_int32_t loop;
- u_int8_t bgx2 = bgx & 0x0F;
- for (loop = height; loop > 0; loop --) {
- mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
- uaddr += step;
- }
- }
- }
-}
-#endif
-
-#ifdef FBCON_HAS_CFB8
-static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
- u_int32_t bgx;
-
- DBG("matrox_cfb8_clear")
-
- bgx = attr_bgcol_ec(p, conp);
- bgx |= bgx << 8;
- bgx |= bgx << 16;
- matrox_cfbX_clear(bgx, p, sy, sx, height, width);
-}
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
- u_int32_t bgx;
-
- DBG("matrox_cfb16_clear")
-
- bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
- matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width);
-}
-#endif
-
-#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
-static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) {
- u_int32_t bgx;
-
- DBG("matrox_cfb32_clear")
-
- bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
- matrox_cfbX_clear(bgx, p, sy, sx, height, width);
-}
-#endif
-
-static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
- unsigned int charcell;
- unsigned int ar3;
- MINFO_FROM_DISP(p);
-
- charcell = fontwidth(p) * fontheight(p);
- yy *= fontheight(p);
- xx *= fontwidth(p);
-
- mga_fifo(8);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
-
- mga_outl(M_FCOL, fgx);
- mga_outl(M_BCOL, bgx);
- mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
- ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
- mga_outl(M_AR3, ar3);
- mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
- mga_ydstlen(yy, fontheight(p));
- WaitTillIdle();
-}
-
-static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
- u_int32_t ar0;
- u_int32_t step;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matrox_cfbX_putc");
-
- yy *= fontheight(p);
- xx *= fontwidth(p);
-
-#ifdef __BIG_ENDIAN
- WaitTillIdle();
- mga_outl(M_OPMODE, M_OPMODE_8BPP);
-#else
- mga_fifo(7);
-#endif
- ar0 = fontwidth(p) - 1;
- mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx);
- if (fontwidth(p) <= 8)
- step = 1;
- else if (fontwidth(p) <= 16)
- step = 2;
- else
- step = 4;
- if (fontwidth(p) == step << 3) {
- size_t charcell = fontheight(p)*step;
- /* TODO: Align charcell to 4B for BE */
- mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
- mga_outl(M_FCOL, fgx);
- mga_outl(M_BCOL, bgx);
- mga_outl(M_AR3, 0);
- mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
- mga_ydstlen(yy, fontheight(p));
- mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
- } else {
- u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
- int i;
-
- mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
- mga_outl(M_FCOL, fgx);
- mga_outl(M_BCOL, bgx);
- mga_outl(M_AR5, 0);
- mga_outl(M_AR3, 0);
- mga_outl(M_AR0, ar0);
- mga_ydstlen(yy, fontheight(p));
-
- switch (step) {
- case 1:
- for (i = fontheight(p); i > 0; i--) {
-#ifdef __LITTLE_ENDIAN
- mga_outl(0, *chardata++);
-#else
- mga_outl(0, (*chardata++) << 24);
-#endif
- }
- break;
- case 2:
- for (i = fontheight(p); i > 0; i--) {
-#ifdef __LITTLE_ENDIAN
- mga_outl(0, *(u_int16_t*)chardata);
-#else
- mga_outl(0, (*(u_int16_t*)chardata) << 16);
-#endif
- chardata += 2;
- }
- break;
- case 4:
- mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4);
- break;
- }
- }
- WaitTillIdle();
-#ifdef __BIG_ENDIAN
- mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
-#endif
-}
-
-#ifdef FBCON_HAS_CFB8
-static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb8_putc");
-
- fgx = attr_fgcol(p, c);
- bgx = attr_bgcol(p, c);
- fgx |= (fgx << 8);
- fgx |= (fgx << 16);
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
- ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
-}
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb16_putc");
-
- fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)];
- bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)];
- fgx |= (fgx << 16);
- bgx |= (bgx << 16);
- ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
-}
-#endif
-
-#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
-static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb32_putc");
-
- fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)];
- bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)];
- ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx);
-}
-#endif
-
-static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
- unsigned int charcell;
- MINFO_FROM_DISP(p);
-
- yy *= fontheight(p);
- xx *= fontwidth(p);
- charcell = fontwidth(p) * fontheight(p);
-
- mga_fifo(3);
- mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
- mga_outl(M_FCOL, fgx);
- mga_outl(M_BCOL, bgx);
- while (count--) {
- u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell;
-
- mga_fifo(4);
- mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
- mga_outl(M_AR3, ar3);
- mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
- mga_ydstlen(yy, fontheight(p));
- xx += fontwidth(p);
- }
- WaitTillIdle();
-}
-
-static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
- u_int32_t step;
- u_int32_t ydstlen;
- u_int32_t xlen;
- u_int32_t ar0;
- u_int32_t charcell;
- u_int32_t fxbndry;
- vaddr_t mmio;
- int easy;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfbX_putcs");
-
- yy *= fontheight(p);
- xx *= fontwidth(p);
- if (fontwidth(p) <= 8)
- step = 1;
- else if (fontwidth(p) <= 16)
- step = 2;
- else
- step = 4;
- charcell = fontheight(p)*step;
- xlen = (charcell + 3) & ~3;
- ydstlen = (yy << 16) | fontheight(p);
- if (fontwidth(p) == step << 3) {
- ar0 = fontheight(p)*fontwidth(p) - 1;
- easy = 1;
- } else {
- ar0 = fontwidth(p) - 1;
- easy = 0;
- }
-
-#ifdef __BIG_ENDIAN
- WaitTillIdle();
- mga_outl(M_OPMODE, M_OPMODE_8BPP);
-#else
- mga_fifo(3);
-#endif
- if (easy)
- mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
- else
- mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
- mga_outl(M_FCOL, fgx);
- mga_outl(M_BCOL, bgx);
- fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx;
- mmio = ACCESS_FBINFO(mmio.vbase);
- while (count--) {
- u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
-
- mga_fifo(6);
- mga_writel(mmio, M_FXBNDRY, fxbndry);
- mga_writel(mmio, M_AR0, ar0);
- mga_writel(mmio, M_AR3, 0);
- if (easy) {
- mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
- mga_memcpy_toio(mmio, 0, chardata, xlen);
- } else {
- mga_writel(mmio, M_AR5, 0);
- mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
- switch (step) {
- case 1: {
- u_int8_t* charend = chardata + charcell;
- for (; chardata != charend; chardata++) {
-#ifdef __LITTLE_ENDIAN
- mga_writel(mmio, 0, *chardata);
-#else
- mga_writel(mmio, 0, (*chardata) << 24);
-#endif
- }
- }
- break;
- case 2: {
- u_int8_t* charend = chardata + charcell;
- for (; chardata != charend; chardata += 2) {
-#ifdef __LITTLE_ENDIAN
- mga_writel(mmio, 0, *(u_int16_t*)chardata);
-#else
- mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16);
-#endif
- }
- }
- break;
- default:
- mga_memcpy_toio(mmio, 0, chardata, charcell);
- break;
- }
- }
- fxbndry += fontwidth(p) + (fontwidth(p) << 16);
- }
- WaitTillIdle();
-#ifdef __BIG_ENDIAN
- mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
-#endif
-}
-
-#ifdef FBCON_HAS_CFB8
-static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb8_putcs");
-
- fgx = attr_fgcol(p, scr_readw(s));
- bgx = attr_bgcol(p, scr_readw(s));
- fgx |= (fgx << 8);
- fgx |= (fgx << 16);
- bgx |= (bgx << 8);
- bgx |= (bgx << 16);
- ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
-}
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb16_putcs");
-
- fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
- bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
- fgx |= (fgx << 16);
- bgx |= (bgx << 16);
- ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
-}
-#endif
-
-#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24)
-static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) {
- u_int32_t fgx, bgx;
- MINFO_FROM_DISP(p);
-
- DBG_HEAVY("matroxfb_cfb32_putcs");
-
- fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
- bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, scr_readw(s))];
- ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx);
-}
-#endif
-
-#ifdef FBCON_HAS_CFB4
-static void matrox_cfb4_revc(struct display* p, int xx, int yy) {
- MINFO_FROM_DISP(p);
-
- DBG_LOOP("matroxfb_cfb4_revc");
-
- if (fontwidth(p) & 1) {
- fbcon_cfb4_revc(p, xx, yy);
- return;
- }
- yy *= fontheight(p);
- xx *= fontwidth(p);
- xx |= (xx + fontwidth(p)) << 16;
- xx >>= 1;
-
- mga_fifo(5);
- mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
- mga_outl(M_FCOL, 0xFFFFFFFF);
- mga_outl(M_FXBNDRY, xx);
- mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
- mga_outl(M_LEN | M_EXEC, fontheight(p));
- WaitTillIdle();
-}
-#endif
-
-#ifdef FBCON_HAS_CFB8
-static void matrox_cfb8_revc(struct display* p, int xx, int yy) {
- MINFO_FROM_DISP(p);
-
- DBG_LOOP("matrox_cfb8_revc")
-
- yy *= fontheight(p);
- xx *= fontwidth(p);
-
- mga_fifo(4);
- mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
- mga_outl(M_FCOL, 0x0F0F0F0F);
- mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
- mga_ydstlen(yy, fontheight(p));
- WaitTillIdle();
-}
-#endif
-
-static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
- MINFO_FROM_DISP(p);
-
- DBG_LOOP("matrox_cfbX_revc")
-
- yy *= fontheight(p);
- xx *= fontwidth(p);
-
- mga_fifo(4);
- mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
- mga_outl(M_FCOL, 0xFFFFFFFF);
- mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
- mga_ydstlen(yy, fontheight(p));
- WaitTillIdle();
-}
-
-static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
- unsigned int bottom_height, right_width;
- unsigned int bottom_start, right_start;
- unsigned int cell_h, cell_w;
-
- DBG("matrox_cfbX_clear_margins")
-
- cell_w = fontwidth(p);
- if (!cell_w) return; /* PARANOID */
- right_width = p->var.xres % cell_w;
- right_start = p->var.xres - right_width;
- if (!bottom_only && right_width) {
- /* clear whole right margin, not only visible portion */
- matroxfb_accel_clear( PMXINFO(p)
- /* color */ 0x00000000,
- /* y */ 0,
- /* x */ p->var.xoffset + right_start,
- /* height */ p->var.yres_virtual,
- /* width */ right_width);
- }
- cell_h = fontheight(p);
- if (!cell_h) return; /* PARANOID */
- bottom_height = p->var.yres % cell_h;
- if (bottom_height) {
- bottom_start = p->var.yres - bottom_height;
- matroxfb_accel_clear( PMXINFO(p)
- /* color */ 0x00000000,
- /* y */ p->var.yoffset + bottom_start,
- /* x */ p->var.xoffset,
- /* height */ bottom_height,
- /* width */ right_start);
- }
-}
-
-static void outDAC(CPMINFO int reg, int val) {
- DBG_REG("outDAC");
- mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
- mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
-}
-
-static int inDAC(CPMINFO int reg) {
- DBG_REG("inDAC");
- mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
- return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
-}
-
-#define outTi3026 outDAC
-#define inTi3026 inDAC
-#define outDAC1064 outDAC
-#define inDAC1064 inDAC
-
-static void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) {
- unsigned int h;
- unsigned int cu, cd;
-
- h = fontheight(p);
-
- if (vmode & FB_VMODE_DOUBLE)
- h *= 2;
- cd = h;
- if (cd >= 10)
- cd--;
- switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) {
- case CUR_NONE:
- cu = cd;
- break;
- case CUR_UNDERLINE:
- cu = cd - 2;
- break;
- case CUR_LOWER_THIRD:
- cu = (h * 2) / 3;
- break;
- case CUR_LOWER_HALF:
- cu = h / 2;
- break;
- case CUR_TWO_THIRDS:
- cu = h / 3;
- break;
- case CUR_BLOCK:
- default:
- cu = 0;
- cd = h;
- break;
- }
- ACCESS_FBINFO(cursor.w) = fontwidth(p);
- ACCESS_FBINFO(cursor.u) = cu;
- ACCESS_FBINFO(cursor.d) = cd;
-}
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-#define POS3026_XCURCTRL 20
-
-static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
-#define minfo ((struct matrox_fb_info*)ptr)
- spin_lock(&ACCESS_FBINFO(lock.DAC));
- outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
- ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
- add_timer(&ACCESS_FBINFO(cursor.timer));
- spin_unlock(&ACCESS_FBINFO(lock.DAC));
-#undef minfo
-}
-
-static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) {
- unsigned long flags;
- u_int32_t xline;
- unsigned int i;
- unsigned int to;
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- DBG("matroxfb_ti3026_createcursor");
-
- matroxfb_createcursorshape(PMINFO p, p->var.vmode);
-
- xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
- spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
- mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0);
- to = ACCESS_FBINFO(cursor.u);
- for (i = 0; i < to; i++) {
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- }
- to = ACCESS_FBINFO(cursor.d);
- for (; i < to; i++) {
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- }
- for (; i < 64; i++) {
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0);
- }
- for (i = 0; i < 512; i++)
- mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF);
- spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
-}
-
-static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
- unsigned long flags;
- MINFO_FROM_DISP(p);
-
- DBG("matroxfb_ti3026_cursor")
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- if (mode == CM_ERASE) {
- if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
- spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
- ACCESS_FBINFO(cursor.state) = CM_ERASE;
- del_timer(&ACCESS_FBINFO(cursor.timer));
- outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
- spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
- }
- return;
- }
- if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
- matroxfb_ti3026_createcursor(PMINFO p);
- x *= fontwidth(p);
- y *= fontheight(p);
- y -= p->var.yoffset;
- if (p->var.vmode & FB_VMODE_DOUBLE)
- y *= 2;
- spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
- if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
- ACCESS_FBINFO(cursor.redraw) = 0;
- ACCESS_FBINFO(cursor.x) = x;
- ACCESS_FBINFO(cursor.y) = y;
- x += 64;
- y += 64;
- outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
- mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y);
- mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8);
- }
- ACCESS_FBINFO(cursor.state) = CM_DRAW;
- if (ACCESS_FBINFO(devflags.blink))
- mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
- outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA);
- spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
-}
-#undef POS3026_XCURCTRL
-
-static int matroxfb_ti3026_setfont(struct display* p, int width, int height) {
-
- DBG("matrox_ti3026_setfont");
-
- if (p && p->conp)
- matroxfb_ti3026_createcursor(PMXINFO(p) p);
- return 0;
-}
-#endif
-
-#ifdef NEED_DAC1064
-
-static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
-#define minfo ((struct matrox_fb_info*)ptr)
- spin_lock(&ACCESS_FBINFO(lock.DAC));
- outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
- ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
- add_timer(&ACCESS_FBINFO(cursor.timer));
- spin_unlock(&ACCESS_FBINFO(lock.DAC));
-#undef minfo
-}
-
-static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) {
- vaddr_t cursorbase;
- u_int32_t xline;
- unsigned int i;
- unsigned int h, to;
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- matroxfb_createcursorshape(PMINFO p, p->var.vmode);
-
- xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
- cursorbase = ACCESS_FBINFO(video.vbase);
- h = ACCESS_FBINFO(features.DAC1064.cursorimage);
-
-#ifdef __BIG_ENDIAN
- WaitTillIdle();
- mga_outl(M_OPMODE, M_OPMODE_32BPP);
-#endif
- to = ACCESS_FBINFO(cursor.u);
- for (i = 0; i < to; i++) {
- mga_writel(cursorbase, h, 0);
- mga_writel(cursorbase, h+4, 0);
- mga_writel(cursorbase, h+8, ~0);
- mga_writel(cursorbase, h+12, ~0);
- h += 16;
- }
- to = ACCESS_FBINFO(cursor.d);
- for (; i < to; i++) {
- mga_writel(cursorbase, h, 0);
- mga_writel(cursorbase, h+4, xline);
- mga_writel(cursorbase, h+8, ~0);
- mga_writel(cursorbase, h+12, ~0);
- h += 16;
- }
- for (; i < 64; i++) {
- mga_writel(cursorbase, h, 0);
- mga_writel(cursorbase, h+4, 0);
- mga_writel(cursorbase, h+8, ~0);
- mga_writel(cursorbase, h+12, ~0);
- h += 16;
- }
-#ifdef __BIG_ENDIAN
- mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
-#endif
-}
-
-static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
- unsigned long flags;
- MINFO_FROM_DISP(p);
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- if (mode == CM_ERASE) {
- if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
- spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
- ACCESS_FBINFO(cursor.state) = CM_ERASE;
- del_timer(&ACCESS_FBINFO(cursor.timer));
- outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
- spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
- }
- return;
- }
- if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
- matroxfb_DAC1064_createcursor(PMINFO p);
- x *= fontwidth(p);
- y *= fontheight(p);
- y -= p->var.yoffset;
- if (p->var.vmode & FB_VMODE_DOUBLE)
- y *= 2;
- spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
- if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
- ACCESS_FBINFO(cursor.redraw) = 0;
- ACCESS_FBINFO(cursor.x) = x;
- ACCESS_FBINFO(cursor.y) = y;
- x += 64;
- y += 64;
- outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
- mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x);
- mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8);
- mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y);
- mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8);
- }
- ACCESS_FBINFO(cursor.state) = CM_DRAW;
- if (ACCESS_FBINFO(devflags.blink))
- mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2);
- outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA);
- spin_unlock_irqrestore(&ACCESS_FBINFO(lock.DAC), flags);
-}
-
-static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) {
- if (p && p->conp)
- matroxfb_DAC1064_createcursor(PMXINFO(p) p);
- return 0;
-}
-#endif
-
-#ifndef FNTCHARCNT
-#define FNTCHARCNT(fd) (((int *)(fd))[-3])
-#endif
-
-static int matroxfb_fastfont_tryset(WPMINFO struct display* p) {
- unsigned int fsize;
- unsigned int width;
-
- if (!p || !p->fontdata)
- return 0;
- width = fontwidth(p);
- if (width > 32)
- return 0;
- fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
- if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
- return 0;
-
- mga_outl(M_OPMODE, M_OPMODE_8BPP);
- if (width <= 8) {
- if (width == 8)
- mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize);
- else {
- vaddr_t dst;
- unsigned int i;
- u_int8_t* font;
- u_int32_t mask, valid, reg;
-
- dst = ACCESS_FBINFO(fastfont.vbase);
- font = (u_int8_t*)p->fontdata;
- mask = ~0 << (8 - width);
- valid = 0;
- reg = 0;
- i = 0;
- while (fsize--) {
- reg |= (*font++ & mask) << (8 - valid);
- valid += width;
- if (valid >= 8) {
- mga_writeb(dst, i++, reg >> 8);
- reg = reg << 8;
- valid -= 8;
- }
- }
- if (valid)
- mga_writeb(dst, i, reg >> 8);
- }
- } else if (width <= 16) {
- if (width == 16)
- mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2);
- else {
- vaddr_t dst;
- u_int16_t* font;
- u_int32_t mask, valid, reg;
- unsigned int i;
-
- dst = ACCESS_FBINFO(fastfont.vbase);
- font = (u_int16_t*)p->fontdata;
- mask = ~0 << (16 - width);
- valid = 0;
- reg = 0;
- i = 0;
- while (fsize--) {
- reg |= (ntohs(*font++) & mask) << (16 - valid);
- valid += width;
- if (valid >= 16) {
- mga_writew(dst, i, htons(reg >> 16));
- i += 2;
- reg = reg << 16;
- valid -= 16;
- }
- }
- if (valid)
- mga_writew(dst, i, htons(reg >> 16));
- }
- } else {
- if (width == 32)
- mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4);
- else {
- vaddr_t dst;
- u_int32_t* font;
- u_int32_t mask, valid, reg;
- unsigned int i;
-
- dst = ACCESS_FBINFO(fastfont.vbase);
- font = (u_int32_t*)p->fontdata;
- mask = ~0 << (32 - width);
- valid = 0;
- reg = 0;
- i = 0;
- while (fsize--) {
- reg |= (ntohl(*font) & mask) >> valid;
- valid += width;
- if (valid >= 32) {
- mga_writel(dst, i, htonl(reg));
- i += 4;
- valid -= 32;
- if (valid)
- reg = (ntohl(*font) & mask) << (width - valid);
- else
- reg = 0;
- }
- font++;
- }
- if (valid)
- mga_writel(dst, i, htonl(reg));
- }
- }
- mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
-
- return 1;
-}
-
-static void matrox_text_setup(struct display* p) {
- MINFO_FROM_DISP(p);
-
- p->next_line = p->line_length ? p->line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
- p->next_plane = 0;
-}
-
-static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx,
- int height, int width) {
- unsigned int srcoff;
- unsigned int dstoff;
- unsigned int step;
- MINFO_FROM_DISP(p);
-
- step = ACCESS_FBINFO(devflags.textstep);
- srcoff = (sy * p->next_line) + (sx * step);
- dstoff = (dy * p->next_line) + (dx * step);
- if (dstoff < srcoff) {
- while (height > 0) {
- int i;
- for (i = width; i > 0; dstoff += step, srcoff += step, i--)
- mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
- height--;
- dstoff += p->next_line - width * step;
- srcoff += p->next_line - width * step;
- }
- } else {
- unsigned int off;
-
- off = (height - 1) * p->next_line + (width - 1) * step;
- srcoff += off;
- dstoff += off;
- while (height > 0) {
- int i;
- for (i = width; i > 0; dstoff -= step, srcoff -= step, i--)
- mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff));
- dstoff -= p->next_line - width * step;
- srcoff -= p->next_line - width * step;
- height--;
- }
- }
-}
-
-static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
- int height, int width) {
- unsigned int offs;
- unsigned int val;
- unsigned int step;
- MINFO_FROM_DISP(p);
-
- step = ACCESS_FBINFO(devflags.textstep);
- offs = sy * p->next_line + sx * step;
- val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
-
- while (height > 0) {
- int i;
- for (i = width; i > 0; offs += step, i--)
- mga_writew(ACCESS_FBINFO(video.vbase), offs, val);
- offs += p->next_line - width * step;
- height--;
- }
-}
-
-static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
- unsigned int offs;
- unsigned int chr;
- unsigned int step;
- MINFO_FROM_DISP(p);
-
- step = ACCESS_FBINFO(devflags.textstep);
- offs = yy * p->next_line + xx * step;
- chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
- if (chr & 0x10000) chr |= 0x08;
-
- mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
-}
-
-static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
- int count, int yy, int xx) {
- unsigned int offs;
- unsigned int attr;
- unsigned int step;
- MINFO_FROM_DISP(p);
-
- step = ACCESS_FBINFO(devflags.textstep);
- offs = yy * p->next_line + xx * step;
- attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
-
- while (count-- > 0) {
- unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
- if (chr & 0x10000) chr ^= 0x10008;
- mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
- offs += step;
- }
-}
-
-static void matrox_text_revc(struct display* p, int xx, int yy) {
- unsigned int offs;
- unsigned int step;
- MINFO_FROM_DISP(p);
-
- step = ACCESS_FBINFO(devflags.textstep);
- offs = yy * p->next_line + xx * step + 1;
-
- mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
-}
-
-static int matrox_text_loadfont(WPMINFO struct display* p) {
- unsigned int fsize;
- unsigned int width;
- vaddr_t dst;
- unsigned int i;
- u_int8_t* font;
-
- if (!p || !p->fontdata)
- return 0;
- width = fontwidth(p);
- fsize = p->userfont?FNTCHARCNT(p->fontdata):256;
-
- dst = ACCESS_FBINFO(video.vbase);
- i = 2;
- font = (u_int8_t*)p->fontdata;
-
- mga_setr(M_SEQ_INDEX, 0x02, 0x04);
- while (fsize--) {
- int l;
-
- for (l = 0; l < fontheight(p); l++) {
- mga_writeb(dst, i, *font++);
- if (fontwidth(p) > 8) font++;
- i += ACCESS_FBINFO(devflags.vgastep);
- }
- i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
- }
- mga_setr(M_SEQ_INDEX, 0x02, 0x03);
-
- return 1;
-}
-
-static void matrox_text_createcursor(WPMINFO struct display* p) {
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- matroxfb_createcursorshape(PMINFO p, 0);
-
- mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
- mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
-}
-
-static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
- unsigned int pos;
- MINFO_FROM_DISP(p);
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
-
- if (mode == CM_ERASE) {
- if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
-
- mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
-
- ACCESS_FBINFO(cursor.state) = CM_ERASE;
- }
- return;
- }
- if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type))
- matrox_text_createcursor(PMINFO p);
-
- /* DO NOT CHECK cursor.x != x because of vgaHWinit moves cursor to 0,0 */
- ACCESS_FBINFO(cursor.x) = x;
- ACCESS_FBINFO(cursor.y) = y;
- pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
-
- mga_setr(M_CRTC_INDEX, 0x0F, pos);
- mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
-
- mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
-
- ACCESS_FBINFO(cursor.state) = CM_DRAW;
-}
-
-static void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) {
- unsigned hf;
- unsigned vf;
- unsigned vxres;
- unsigned ych;
-
- hf = fontwidth(p);
- if (!hf) hf = 8;
- /* do not touch xres */
- vxres = (var->xres_virtual + hf - 1) / hf;
- if (vxres >= 256)
- vxres = 255;
- if (vxres < 16)
- vxres = 16;
- vxres = (vxres + 1) & ~1; /* must be even */
- vf = fontheight(p);
- if (!vf) vf = 16;
- if (var->yres < var->yres_virtual) {
- ych = ACCESS_FBINFO(devflags.textvram) / vxres;
- var->yres_virtual = ych * vf;
- } else
- ych = var->yres_virtual / vf;
- if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) {
- ych = ACCESS_FBINFO(devflags.textvram) / vxres;
- var->yres_virtual = ych * vf;
- }
- var->xres_virtual = vxres * hf;
-}
-
-static int matrox_text_setfont(struct display* p, int width, int height) {
- DBG("matrox_text_setfont");
-
- if (p) {
- MINFO_FROM_DISP(p);
-
- matrox_text_round(PMINFO &p->var, p);
- p->next_line = p->line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep));
-
- if (p->conp)
- matrox_text_createcursor(PMINFO p);
- }
- return 0;
-}
-
-#define matrox_cfb16_revc matrox_cfbX_revc
-#define matrox_cfb24_revc matrox_cfbX_revc
-#define matrox_cfb32_revc matrox_cfbX_revc
-
-#define matrox_cfb24_clear matrox_cfb32_clear
-#define matrox_cfb24_putc matrox_cfb32_putc
-#define matrox_cfb24_putcs matrox_cfb32_putcs
-
-#ifdef FBCON_HAS_VGATEXT
-static struct display_switch matroxfb_text = {
- matrox_text_setup, matrox_text_bmove, matrox_text_clear,
- matrox_text_putc, matrox_text_putcs, matrox_text_revc,
- matrox_text_cursor, matrox_text_setfont, NULL,
- FONTWIDTH(8)|FONTWIDTH(9)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB4
-static struct display_switch matroxfb_cfb4 = {
- fbcon_cfb4_setup, matrox_cfb4_bmove, matrox_cfb4_clear,
- fbcon_cfb4_putc, fbcon_cfb4_putcs, matrox_cfb4_revc,
- NULL, NULL, NULL,
- /* cursor... */ /* set_font... */
- FONTWIDTH(8) /* fix, fix, fix it */
-};
-#endif
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch matroxfb_cfb8 = {
- fbcon_cfb8_setup, matrox_cfbX_bmove, matrox_cfb8_clear,
- matrox_cfb8_putc, matrox_cfb8_putcs, matrox_cfb8_revc,
- NULL, NULL, matrox_cfbX_clear_margins,
- ~1 /* FONTWIDTHS */
-};
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static struct display_switch matroxfb_cfb16 = {
- fbcon_cfb16_setup, matrox_cfbX_bmove, matrox_cfb16_clear,
- matrox_cfb16_putc, matrox_cfb16_putcs, matrox_cfb16_revc,
- NULL, NULL, matrox_cfbX_clear_margins,
- ~1 /* FONTWIDTHS */
-};
-#endif
-
-#ifdef FBCON_HAS_CFB24
-static struct display_switch matroxfb_cfb24 = {
- fbcon_cfb24_setup, matrox_cfbX_bmove, matrox_cfb24_clear,
- matrox_cfb24_putc, matrox_cfb24_putcs, matrox_cfb24_revc,
- NULL, NULL, matrox_cfbX_clear_margins,
- ~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */
-};
-#endif
-
-#ifdef FBCON_HAS_CFB32
-static struct display_switch matroxfb_cfb32 = {
- fbcon_cfb32_setup, matrox_cfbX_bmove, matrox_cfb32_clear,
- matrox_cfb32_putc, matrox_cfb32_putcs, matrox_cfb32_revc,
- NULL, NULL, matrox_cfbX_clear_margins,
- ~1 /* FONTWIDTHS */
-};
-#endif
-
-static void initMatrox(WPMINFO struct display* p) {
- struct display_switch *swtmp;
-
- DBG("initMatrox")
-
- if (ACCESS_FBINFO(currcon_display) != p)
- return;
- if (p->dispsw && p->conp)
- fb_con.con_cursor(p->conp, CM_ERASE);
- p->dispsw_data = NULL;
- if ((p->var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) {
- if (p->type == FB_TYPE_TEXT) {
- swtmp = &matroxfb_text;
- } else {
- switch (p->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
- case 4:
- swtmp = &fbcon_cfb4;
- break;
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- swtmp = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
- swtmp = &fbcon_cfb16;
- break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
- swtmp = &fbcon_cfb24;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
- swtmp = &fbcon_cfb32;
- break;
-#endif
- default:
- p->dispsw = &fbcon_dummy;
- return;
- }
- }
- dprintk(KERN_INFO "matroxfb: acceleration disabled\n");
- } else if (p->type == FB_TYPE_TEXT) {
- swtmp = &matroxfb_text;
- } else {
- switch (p->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
- case 4:
- swtmp = &matroxfb_cfb4;
- break;
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- swtmp = &matroxfb_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16);
- swtmp = &matroxfb_cfb16;
- break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24);
- swtmp = &matroxfb_cfb24;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32);
- swtmp = &matroxfb_cfb32;
- break;
-#endif
- default:
- p->dispsw = &fbcon_dummy;
- return;
- }
- }
- memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw)));
- p->dispsw = &ACCESS_FBINFO(dispsw);
- if ((p->type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) {
- if (isMillenium(MINFO)) {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
- ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor;
- ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont;
-#endif
- } else {
-#ifdef NEED_DAC1064
- ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor;
- ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont;
-#endif
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * card parameters
- */
-
-/* --------------------------------------------------------------------- */
-
-static struct fb_var_screeninfo vesafb_defined __initdata = {
- 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
- 0,0, /* virtual -> visible no offset */
- 8, /* depth -> load bits_per_pixel */
- 0, /* greyscale ? */
- {0,0,0}, /* R */
- {0,0,0}, /* G */
- {0,0,0}, /* B */
- {0,0,0}, /* transparency */
- 0, /* standard pixel format */
- FB_ACTIVATE_NOW,
- -1,-1,
- FB_ACCELF_TEXT, /* accel flags */
- 39721L,48L,16L,33L,10L,
- 96L,2L,~0, /* No sync info */
- FB_VMODE_NONINTERLACED,
- {0,0,0,0,0,0}
-};
-
-
-
-/* --------------------------------------------------------------------- */
-
-static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
- unsigned int pos;
- unsigned short p0, p1, p2;
-#ifdef CONFIG_FB_MATROX_32MB
- unsigned int p3;
-#endif
- struct display *disp;
-
- DBG("matrox_pan_var")
-
- disp = ACCESS_FBINFO(currcon_display);
- if (disp->type == FB_TYPE_TEXT) {
- pos = var->yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(disp)?fontwidth(disp):8);
- } else {
- pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
- pos += ACCESS_FBINFO(curr.ydstorg.chunks);
- }
- p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
- p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
- p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
-#ifdef CONFIG_FB_MATROX_32MB
- p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
-#endif
-
- mga_setr(M_CRTC_INDEX, 0x0D, p0);
- mga_setr(M_CRTC_INDEX, 0x0C, p1);
-#ifdef CONFIG_FB_MATROX_32MB
- if (ACCESS_FBINFO(devflags.support32MB))
- mga_setr(M_EXTVGA_INDEX, 0x08, p3);
-#endif
- mga_setr(M_EXTVGA_INDEX, 0x00, p2);
-}
-
- /*
- * Open/Release the frame buffer device
- */
-
-static int matroxfb_open(struct fb_info *info, int user)
-{
- DBG_LOOP("matroxfb_open")
-
- /*
- * Nothing, only a usage count for the moment
- */
- MOD_INC_USE_COUNT;
- return(0);
-}
-
-static int matroxfb_release(struct fb_info *info, int user)
-{
- DBG_LOOP("matroxfb_release")
-
- MOD_DEC_USE_COUNT;
- return(0);
-}
-
-static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info* info) {
-#define minfo ((struct matrox_fb_info*)info)
-
- DBG("matroxfb_pan_display")
-
- if (var->vmode & FB_VMODE_YWRAP) {
- if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
- return -EINVAL;
- } else {
- if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
- var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
- return -EINVAL;
- }
- if (con == ACCESS_FBINFO(currcon))
- matrox_pan_var(PMINFO var);
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
- if (var->vmode & FB_VMODE_YWRAP)
- fb_display[con].var.vmode |= FB_VMODE_YWRAP;
- else
- fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
- return 0;
-#undef minfo
-}
-
-static int matroxfb_updatevar(int con, struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- DBG("matroxfb_updatevar");
-
- matrox_pan_var(PMINFO &fb_display[con].var);
- return 0;
-#undef minfo
-}
-
-static int matroxfb_get_final_bppShift(CPMINFO int bpp) {
- int bppshft2;
-
- DBG("matroxfb_get_final_bppShift")
-
- bppshft2 = bpp;
- if (!bppshft2) {
- return 8;
- }
- if (isInterleave(MINFO))
- bppshft2 >>= 1;
- if (ACCESS_FBINFO(devflags.video64bits))
- bppshft2 >>= 1;
- return bppshft2;
-}
-
-static int matroxfb_test_and_set_rounding(CPMINFO int xres, int bpp) {
- int over;
- int rounding;
-
- DBG("matroxfb_test_and_set_rounding")
-
- switch (bpp) {
- case 0: return xres;
- case 4: rounding = 128;
- break;
- case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
- break;
- case 16: rounding = 32;
- break;
- case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
- break;
- default: rounding = 16;
- /* on G400, 16 really does not work */
- if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
- rounding = 32;
- break;
- }
- if (isInterleave(MINFO)) {
- rounding *= 2;
- }
- over = xres % rounding;
- if (over)
- xres += rounding-over;
- return xres;
-}
-
-static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) {
- const int* width;
- int xres_new;
-
- DBG("matroxfb_pitch_adjust")
-
- if (!bpp) return xres;
-
- width = ACCESS_FBINFO(capable.vxres);
-
- if (ACCESS_FBINFO(devflags.precise_width)) {
- while (*width) {
- if ((*width >= xres) && (matroxfb_test_and_set_rounding(PMINFO *width, bpp) == *width)) {
- break;
- }
- width++;
- }
- xres_new = *width;
- } else {
- xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp);
- }
- if (!xres_new) return 0;
- if (xres != xres_new) {
- printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new);
- }
- return xres_new;
-}
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static const unsigned char DACseq[] =
-{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
- TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
- TVP3026_XPALETTEPAGE,
- TVP3026_XGENCTRL,
- TVP3026_XMISCCTRL,
- TVP3026_XGENIOCTRL,
- TVP3026_XGENIODATA,
- TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
- TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
- TVP3026_XCOLKEYCTRL,
- TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
-
-#define POS3026_XLATCHCTRL 0
-#define POS3026_XTRUECOLORCTRL 1
-#define POS3026_XMUXCTRL 2
-#define POS3026_XCLKCTRL 3
-#define POS3026_XGENCTRL 5
-#define POS3026_XMISCCTRL 6
-#define POS3026_XMEMPLLCTRL 18
-#define POS3026_XCURCTRL 20
-
-static const unsigned char MGADACbpp32[] =
-{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
- 0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
- 0x00,
- TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
- TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
- 0x00,
- 0x1E,
- 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF,
- TVP3026_XCOLKEYCTRL_ZOOM1,
- 0x00, 0x00, TVP3026_XCURCTRL_DIS };
-#endif /* CONFIG_FB_MATROX_MILLENIUM */
-
-static int PLL_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
- unsigned int bestdiff = ~0;
- unsigned int bestvco = 0;
- unsigned int fxtal = ACCESS_FBINFO(features.pll.ref_freq);
- unsigned int fwant;
- unsigned int p;
-
- DBG("PLL_calcclock")
-
- fwant = freq;
-
-#ifdef DEBUG
- printk(KERN_ERR "post_shift_max: %d\n", ACCESS_FBINFO(features.pll.post_shift_max));
- printk(KERN_ERR "ref_freq: %d\n", ACCESS_FBINFO(features.pll.ref_freq));
- printk(KERN_ERR "freq: %d\n", freq);
- printk(KERN_ERR "vco_freq_min: %d\n", ACCESS_FBINFO(features.pll.vco_freq_min));
- printk(KERN_ERR "in_div_min: %d\n", ACCESS_FBINFO(features.pll.in_div_min));
- printk(KERN_ERR "in_div_max: %d\n", ACCESS_FBINFO(features.pll.in_div_max));
- printk(KERN_ERR "feed_div_min: %d\n", ACCESS_FBINFO(features.pll.feed_div_min));
- printk(KERN_ERR "feed_div_max: %d\n", ACCESS_FBINFO(features.pll.feed_div_max));
- printk(KERN_ERR "fmax: %d\n", fmax);
-#endif
- for (p = 1; p <= ACCESS_FBINFO(features.pll.post_shift_max); p++) {
- if (fwant * 2 > fmax)
- break;
- fwant *= 2;
- }
- if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) fwant = ACCESS_FBINFO(features.pll.vco_freq_min);
- if (fwant > fmax) fwant = fmax;
- for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
- unsigned int m;
-
- if (fwant < ACCESS_FBINFO(features.pll.vco_freq_min)) break;
- for (m = ACCESS_FBINFO(features.pll.in_div_min); m <= ACCESS_FBINFO(features.pll.in_div_max); m++) {
- unsigned int diff, fvco;
- unsigned int n;
-
- n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
- if (n > ACCESS_FBINFO(features.pll.feed_div_max))
- break;
- if (n < ACCESS_FBINFO(features.pll.feed_div_min))
- n = ACCESS_FBINFO(features.pll.feed_div_min);
- fvco = (fxtal * (n + 1)) / (m + 1);
- if (fvco < fwant)
- diff = fwant - fvco;
- else
- diff = fvco - fwant;
- if (diff < bestdiff) {
- bestdiff = diff;
- *post = p;
- *in = m;
- *feed = n;
- bestvco = fvco;
- }
- }
- }
- dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
- return bestvco;
-}
-
-#ifdef NEED_DAC1064
-static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) {
- unsigned int fvco;
- unsigned int p;
-
- DBG("DAC1064_calcclock")
-
- fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
- p = (1 << p) - 1;
- if (fvco <= 100000)
- ;
- else if (fvco <= 140000)
- p |= 0x08;
- else if (fvco <= 180000)
- p |= 0x10;
- else
- p |= 0x18;
- *post = p;
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) {
- unsigned int fvco;
- unsigned int lin, lfeed, lpost;
-
- DBG("Ti3026_calcclock")
-
- fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost);
- fvco >>= (*post = lpost);
- *in = 64 - lin;
- *feed = 64 - lfeed;
- return fvco;
-}
-
-static int Ti3026_setpclk(CPMINFO struct matrox_hw_state* hw, int clk, struct display* p) {
- unsigned int f_pll;
- unsigned int pixfeed, pixin, pixpost;
-
- DBG("Ti3026_setpclk")
-
- f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost);
-
- hw->DACclk[0] = pixin | 0xC0;
- hw->DACclk[1] = pixfeed;
- hw->DACclk[2] = pixpost | 0xB0;
-
- if (p->type == FB_TYPE_TEXT) {
- hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL;
- hw->DACclk[3] = 0xFD;
- hw->DACclk[4] = 0x3D;
- hw->DACclk[5] = 0x70;
- } else {
- unsigned int loopfeed, loopin, looppost, loopdiv, z;
- unsigned int Bpp;
-
- Bpp = ACCESS_FBINFO(curr.final_bppShift);
-
- if (p->var.bits_per_pixel == 24) {
- loopfeed = 3; /* set lm to any possible value */
- loopin = 3 * 32 / Bpp;
- } else {
- loopfeed = 4;
- loopin = 4 * 32 / Bpp;
- }
- z = (110000 * loopin) / (f_pll * loopfeed);
- loopdiv = 0; /* div 2 */
- if (z < 2)
- looppost = 0;
- else if (z < 4)
- looppost = 1;
- else if (z < 8)
- looppost = 2;
- else {
- looppost = 3;
- loopdiv = z/16;
- }
- if (p->var.bits_per_pixel == 24) {
- hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
- hw->DACclk[4] = (65 - loopfeed) | 0x80;
- if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) {
- if (isInterleave(MINFO))
- hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
- else {
- hw->DACclk[4] &= ~0xC0;
- hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
- }
- } else {
- if (isInterleave(MINFO))
- ; /* default... */
- else {
- hw->DACclk[4] ^= 0xC0; /* change from 0x80 to 0x40 */
- hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
- }
- }
- hw->DACclk[5] = looppost | 0xF8;
- if (ACCESS_FBINFO(devflags.mga_24bpp_fix))
- hw->DACclk[5] ^= 0x40;
- } else {
- hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
- hw->DACclk[4] = 65 - loopfeed;
- hw->DACclk[5] = looppost | 0xF0;
- }
- hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
- }
- return 0;
-}
-#endif
-
-static void var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
- unsigned int pixclock = var->pixclock;
-
- DBG("var2my")
-
- if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
- mt->pixclock = 1000000000 / pixclock;
- if (mt->pixclock < 1) mt->pixclock = 1;
- mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
- mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
- mt->HDisplay = var->xres;
- mt->HSyncStart = mt->HDisplay + var->right_margin;
- mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
- mt->HTotal = mt->HSyncEnd + var->left_margin;
- mt->VDisplay = var->yres;
- mt->VSyncStart = mt->VDisplay + var->lower_margin;
- mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
- mt->VTotal = mt->VSyncEnd + var->upper_margin;
- mt->sync = var->sync;
-}
-
-static int vgaHWinit(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
- unsigned int hd, hs, he, hbe, ht;
- unsigned int vd, vs, ve, vt;
- unsigned int wd;
- unsigned int divider;
- int i;
- int text = p->type == FB_TYPE_TEXT;
- int fwidth;
-
- if (text) {
- fwidth = fontwidth(p);
- if (!fwidth) fwidth = 8;
- } else
- fwidth = 8;
-
- DBG("vgaHWinit")
-
- hw->SEQ[0] = 0x00;
- if (fwidth == 9)
- hw->SEQ[1] = 0x00;
- else
- hw->SEQ[1] = 0x01; /* or 0x09 */
- hw->SEQ[2] = 0x0F; /* bitplanes */
- hw->SEQ[3] = 0x00;
- if (text)
- hw->SEQ[4] = 0x02;
- else
- hw->SEQ[4] = 0x0E;
- /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millenium code... Hope that by MGA1064 too */
- if (m->dblscan) {
- m->VTotal <<= 1;
- m->VDisplay <<= 1;
- m->VSyncStart <<= 1;
- m->VSyncEnd <<= 1;
- }
- if (m->interlaced) {
- m->VTotal >>= 1;
- m->VDisplay >>= 1;
- m->VSyncStart >>= 1;
- m->VSyncEnd >>= 1;
- }
-
- /* GCTL is ignored when not using 0xA0000 aperture */
- hw->GCTL[0] = 0x00;
- hw->GCTL[1] = 0x00;
- hw->GCTL[2] = 0x00;
- hw->GCTL[3] = 0x00;
- hw->GCTL[4] = 0x00;
- if (text) {
- hw->GCTL[5] = 0x10;
- hw->GCTL[6] = 0x02;
- } else {
- hw->GCTL[5] = 0x40;
- hw->GCTL[6] = 0x05;
- }
- hw->GCTL[7] = 0x0F;
- hw->GCTL[8] = 0xFF;
-
- /* Whole ATTR is ignored in PowerGraphics mode */
- for (i = 0; i < 16; i++)
- hw->ATTR[i] = i;
- if (text) {
- hw->ATTR[16] = 0x04;
- } else {
- hw->ATTR[16] = 0x41;
- }
- hw->ATTR[17] = 0xFF;
- hw->ATTR[18] = 0x0F;
- if (fwidth == 9)
- hw->ATTR[19] = 0x08;
- else
- hw->ATTR[19] = 0x00;
- hw->ATTR[20] = 0x00;
-
- if (text) {
- hd = m->HDisplay / fwidth;
- hs = m->HSyncStart / fwidth;
- he = m->HSyncEnd / fwidth;
- ht = m->HTotal / fwidth;
- divider = 8;
- } else {
- hd = m->HDisplay >> 3;
- hs = m->HSyncStart >> 3;
- he = m->HSyncEnd >> 3;
- ht = m->HTotal >> 3;
- /* standard timmings are in 8pixels, but for interleaved we cannot */
- /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
- /* using 16 or more pixels per unit can save us */
- divider = ACCESS_FBINFO(curr.final_bppShift);
- }
- while (divider & 3) {
- hd >>= 1;
- hs >>= 1;
- he >>= 1;
- ht >>= 1;
- divider <<= 1;
- }
- divider = divider / 4;
- /* divider can be from 1 to 8 */
- while (divider > 8) {
- hd <<= 1;
- hs <<= 1;
- he <<= 1;
- ht <<= 1;
- divider >>= 1;
- }
- hd = hd - 1;
- hs = hs - 1;
- he = he - 1;
- ht = ht - 1;
- vd = m->VDisplay - 1;
- vs = m->VSyncStart - 1;
- ve = m->VSyncEnd - 1;
- vt = m->VTotal - 2;
- /* G200 cannot work with (ht & 7) == 6 */
- if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
- ht++;
- if (text) {
- hbe = ht - 1;
- wd = p->var.xres_virtual / (fwidth * 2);
- } else {
- hbe = ht;
- wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64;
- }
-
- hw->CRTCEXT[0] = 0;
- hw->CRTCEXT[5] = 0;
- if (m->interlaced) {
- hw->CRTCEXT[0] = 0x80;
- hw->CRTCEXT[5] = (hs + he - ht) >> 1;
- if (!m->dblscan)
- wd <<= 1;
- vt &= ~1;
- }
- hw->CRTCEXT[0] |= (wd & 0x300) >> 4;
- hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
- ((hd & 0x100) >> 7) | /* blanking */
- ((hs & 0x100) >> 6) | /* sync start */
- (hbe & 0x040); /* end hor. blanking */
- hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) |
- ((vd & 0x400) >> 8) | /* disp end */
- ((vd & 0xC00) >> 7) | /* vblanking start */
- ((vs & 0xC00) >> 5);
- if (text)
- hw->CRTCEXT[3] = 0x00;
- else
- hw->CRTCEXT[3] = (divider - 1) | 0x80;
- hw->CRTCEXT[4] = 0;
-
- hw->CRTC[0] = ht-4;
- hw->CRTC[1] = hd;
- hw->CRTC[2] = hd;
- hw->CRTC[3] = (hbe & 0x1F) | 0x80;
- hw->CRTC[4] = hs;
- hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
- if (text)
- hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */
- hw->CRTC[6] = vt & 0xFF;
- hw->CRTC[7] = ((vt & 0x100) >> 8) |
- ((vd & 0x100) >> 7) |
- ((vs & 0x100) >> 6) |
- ((vd & 0x100) >> 5) |
- 0x10 |
- ((vt & 0x200) >> 4) |
- ((vd & 0x200) >> 3) |
- ((vs & 0x200) >> 2);
- hw->CRTC[8] = 0x00;
- hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40;
- if (text)
- hw->CRTC[9] |= fontheight(p) - 1;
- if (m->dblscan && !m->interlaced)
- hw->CRTC[9] |= 0x80;
- for (i = 10; i < 16; i++)
- hw->CRTC[i] = 0x00;
- hw->CRTC[16] = vs /* & 0xFF */;
- hw->CRTC[17] = (ve & 0x0F) | 0x20;
- hw->CRTC[18] = vd /* & 0xFF */;
- hw->CRTC[19] = wd /* & 0xFF */;
- hw->CRTC[20] = 0x00;
- hw->CRTC[21] = vd /* & 0xFF */;
- hw->CRTC[22] = (vt + 1) /* & 0xFF */;
- if (text) {
- if (ACCESS_FBINFO(devflags.textmode) == 1)
- hw->CRTC[23] = 0xC3;
- else
- hw->CRTC[23] = 0xA3;
- if (ACCESS_FBINFO(devflags.textmode) == 4)
- hw->CRTC[20] = 0x5F;
- else
- hw->CRTC[20] = 0x1F;
- } else
- hw->CRTC[23] = 0xC3;
- hw->CRTC[24] = 0xFF;
- return 0;
-};
-
-#ifdef NEED_DAC1064
-
-static const unsigned char MGA1064_DAC_regs[] = {
- M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
- M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
- M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
- M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
- DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
- M1064_XMISCCTRL,
- M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
- M1064_XCRCBITSEL,
- M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
-
-#define POS1064_XCURADDL 0
-#define POS1064_XCURADDH 1
-#define POS1064_XVREFCTRL 12
-#define POS1064_XMULCTRL 13
-#define POS1064_XGENCTRL 15
-#define POS1064_XMISCCTRL 16
-
-static const unsigned char MGA1064_DAC[] = {
- 0x00, 0x00, M1064_XCURCTRL_DIS,
- 0x00, 0x00, 0x00, /* black */
- 0xFF, 0xFF, 0xFF, /* white */
- 0xFF, 0x00, 0x00, /* red */
- 0x00, 0,
- M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
- M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
- M1064_XMISCCTRL_DAC_EN | M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_8BIT | M1064_XMISCCTRL_LUT_EN,
- 0x10, 0x3F, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
- 0x00,
- 0x00, 0x00, 0xFF, 0xFF};
-
-static void DAC1064_setpclk(CPMINFO struct matrox_hw_state* hw, unsigned long fout) {
- unsigned int m, n, p;
-
- DBG("DAC1064_setpclk")
-
- DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
- hw->DACclk[0] = m;
- hw->DACclk[1] = n;
- hw->DACclk[2] = p;
-}
-
-static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
- u_int32_t mx;
-
- DBG("DAC1064_setmclk")
-
- if (ACCESS_FBINFO(devflags.noinit)) {
- /* read MCLK and give up... */
- hw->DACclk[3] = inDAC1064(PMINFO DAC1064_XSYSPLLM);
- hw->DACclk[4] = inDAC1064(PMINFO DAC1064_XSYSPLLN);
- hw->DACclk[5] = inDAC1064(PMINFO DAC1064_XSYSPLLP);
- return;
- }
- mx = hw->MXoptionReg | 0x00000004;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
- mx &= ~0x000000BB;
- if (oscinfo & DAC1064_OPT_GDIV1)
- mx |= 0x00000008;
- if (oscinfo & DAC1064_OPT_MDIV1)
- mx |= 0x00000010;
- if (oscinfo & DAC1064_OPT_RESERVED)
- mx |= 0x00000080;
- if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
- /* select PCI clock until we have setup oscilator... */
- int clk;
- unsigned int m, n, p;
-
- /* powerup system PLL, select PCI clock */
- mx |= 0x00000020;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
- mx &= ~0x00000004;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
-
- /* !!! you must not access device if MCLK is not running !!!
- Doing so cause immediate PCI lockup :-( Maybe they should
- generate ABORT or I/O (parity...) error and Linux should
- recover from this... (kill driver/process). But world is not
- perfect... */
- /* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
- select PLL... because of PLL can be stopped at this time) */
- DAC1064_calcclock(PMINFO fmem, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
- outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3] = m);
- outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4] = n);
- outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5] = p);
- for (clk = 65536; clk; --clk) {
- if (inDAC1064(PMINFO DAC1064_XSYSPLLSTAT) & 0x40)
- break;
- }
- if (!clk)
- printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
- /* select PLL */
- mx |= 0x00000005;
- } else {
- /* select specified system clock source */
- mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
- }
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
- mx &= ~0x00000004;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mx);
- hw->MXoptionReg = mx;
-}
-
-static int DAC1064_init_1(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display *p) {
-
- DBG("DAC1064_init_1")
-
- memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
- if (p->type == FB_TYPE_TEXT) {
- hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_EN
- | M1064_XMISCCTRL_MFC_DIS
- | M1064_XMISCCTRL_DAC_6BIT
- | M1064_XMISCCTRL_LUT_EN;
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP
- | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- } else {
- switch (p->var.bits_per_pixel) {
- /* case 4: not supported by MGA1064 DAC */
- case 8:
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- break;
- case 16:
- if (p->var.green.length == 5)
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- else
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- break;
- case 24:
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- break;
- case 32:
- hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
- break;
- default:
- return 1; /* unsupported depth */
- }
- }
- hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
- hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
- hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
- hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
- hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
- return 0;
-}
-
-static int DAC1064_init_2(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
-
- DBG("DAC1064_init_2")
-
- DAC1064_setpclk(PMINFO hw, m->pixclock);
- if (p->var.bits_per_pixel > 16) { /* 256 entries */
- int i;
-
- for (i = 0; i < 256; i++) {
- hw->DACpal[i * 3 + 0] = i;
- hw->DACpal[i * 3 + 1] = i;
- hw->DACpal[i * 3 + 2] = i;
- }
- } else if (p->var.bits_per_pixel > 8) {
- if (p->var.green.length == 5) { /* 0..31, 128..159 */
- int i;
-
- for (i = 0; i < 32; i++) {
- /* with p15 == 0 */
- hw->DACpal[i * 3 + 0] = i << 3;
- hw->DACpal[i * 3 + 1] = i << 3;
- hw->DACpal[i * 3 + 2] = i << 3;
- /* with p15 == 1 */
- hw->DACpal[(i + 128) * 3 + 0] = i << 3;
- hw->DACpal[(i + 128) * 3 + 1] = i << 3;
- hw->DACpal[(i + 128) * 3 + 2] = i << 3;
- }
- } else {
- int i;
-
- for (i = 0; i < 64; i++) { /* 0..63 */
- hw->DACpal[i * 3 + 0] = i << 3;
- hw->DACpal[i * 3 + 1] = i << 2;
- hw->DACpal[i * 3 + 2] = i << 3;
- }
- }
- } else {
- memset(hw->DACpal, 0, 768);
- }
- return 0;
-}
-
-static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
-
- DBG("DAC1064_restore_1")
-
- outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
- outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
- outDAC1064(PMINFO DAC1064_XSYSPLLP, hw->DACclk[5]);
- if (!oldhw || memcmp(hw->DACreg, oldhw->DACreg, sizeof(MGA1064_DAC_regs))) {
- unsigned int i;
-
- for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
- outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
- }
-}
-
-static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
- unsigned int i;
- unsigned int tmout;
-
- DBG("DAC1064_restore_2")
-
- for (i = 0; i < 3; i++)
- outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
- for (tmout = 500000; tmout; tmout--) {
- if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
- break;
- udelay(10);
- }
-
- if (!tmout)
- printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
-
- if (p && p->conp) {
- if (p->type == FB_TYPE_TEXT) {
- matrox_text_createcursor(PMINFO p);
- matrox_text_loadfont(PMINFO p);
- i = 0;
- } else {
- matroxfb_DAC1064_createcursor(PMINFO p);
- i = matroxfb_fastfont_tryset(PMINFO p);
- }
- } else
- i = 0;
- if (i) {
- ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc;
- ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs;
- } else {
- ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc;
- ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
- }
-#ifdef DEBUG
- dprintk(KERN_DEBUG "DAC1064regs ");
- for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
- dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], hw->DACreg[i]);
- if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
- }
- dprintk("\n" KERN_DEBUG "DAC1064clk ");
- for (i = 0; i < 6; i++)
- dprintk("C%02X=%02X ", i, hw->DACclk[i]);
- dprintk("\n");
-#endif
-}
-#endif /* NEED_DAC1064 */
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static int MGA1064_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
-
- DBG("MGA1064_init")
-
- if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
- if (vgaHWinit(PMINFO hw, m, p)) return 1;
-
- hw->MiscOutReg = 0xCB;
- if (m->sync & FB_SYNC_HOR_HIGH_ACT)
- hw->MiscOutReg &= ~0x40;
- if (m->sync & FB_SYNC_VERT_HIGH_ACT)
- hw->MiscOutReg &= ~0x80;
- if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
- hw->CRTCEXT[3] |= 0x40;
-
- if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
- return 0;
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_G100
-static int MGAG100_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
-
- DBG("MGAG100_init")
-
- if (DAC1064_init_1(PMINFO hw, m, p)) return 1;
- hw->MXoptionReg &= ~0x2000;
- if (vgaHWinit(PMINFO hw, m, p)) return 1;
-
- hw->MiscOutReg = 0xEF;
- if (m->sync & FB_SYNC_HOR_HIGH_ACT)
- hw->MiscOutReg &= ~0x40;
- if (m->sync & FB_SYNC_VERT_HIGH_ACT)
- hw->MiscOutReg &= ~0x80;
- if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
- hw->CRTCEXT[3] |= 0x40;
-
- if (DAC1064_init_2(PMINFO hw, m, p)) return 1;
- return 0;
-}
-#endif /* G100 */
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static int Ti3026_init(CPMINFO struct matrox_hw_state* hw, struct my_timming* m, struct display* p) {
- u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
-
- DBG("Ti3026_init")
-
- memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg));
- if (p->type == FB_TYPE_TEXT) {
- hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;
- hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
- hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA;
- hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL |
- TVP3026_XCLKCTRL_DIV4;
- hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
- } else {
- switch (p->var.bits_per_pixel) {
- case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */
- hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
- hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
- hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
- hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
- break;
- case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; /* or _4_1, they are same */
- hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
- hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
- hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
- hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
- break;
- case 16:
- /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */
- hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
- hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
- hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
- break;
- case 24:
- /* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
- hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
- hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
- hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
- break;
- case 32:
- /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */
- hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
- break;
- default:
- return 1; /* TODO: failed */
- }
- }
- if (vgaHWinit(PMINFO hw, m, p)) return 1;
-
- /* set SYNC */
- hw->MiscOutReg = 0xCB;
- if (m->sync & FB_SYNC_HOR_HIGH_ACT)
- hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
- if (m->sync & FB_SYNC_VERT_HIGH_ACT)
- hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
- if (m->sync & FB_SYNC_ON_GREEN)
- hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
-
- /* set DELAY */
- if (ACCESS_FBINFO(video.len) < 0x400000)
- hw->CRTCEXT[3] |= 0x08;
- else if (ACCESS_FBINFO(video.len) > 0x400000)
- hw->CRTCEXT[3] |= 0x10;
-
- /* set HWCURSOR */
- if (m->interlaced) {
- hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
- }
- if (m->HTotal >= 1536)
- hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
-
- /* set interleaving */
- hw->MXoptionReg &= ~0x00001000;
- if ((p->type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000;
-
- /* set DAC */
- Ti3026_setpclk(PMINFO hw, m->pixclock, p);
- return 0;
-}
-#endif /* CONFIG_FB_MATROX_MILLENIUM */
-
-static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
-
- DBG("matroxfb_get_cmap_len")
-
- switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_VGATEXT
- case 0:
- return 16; /* pseudocolor... 16 entries HW palette */
-#endif
-#ifdef FBCON_HAS_CFB4
- case 4:
- return 16; /* pseudocolor... 16 entries HW palette */
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- return 256; /* pseudocolor... 256 entries HW palette */
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- return 16; /* directcolor... 16 entries SW palette */
- /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- return 16; /* directcolor... 16 entries SW palette */
- /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- return 16; /* directcolor... 16 entries SW palette */
- /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
-#endif
- }
- return 16; /* return something reasonable... or panic()? */
-}
-
-static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
- unsigned int vramlen;
- unsigned int memlen;
-
- DBG("matroxfb_decode_var")
-
- switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_VGATEXT
- case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
- break;
-#endif
-#ifdef FBCON_HAS_CFB4
- case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL;
- break;
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8: break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16: break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24: break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32: break;
-#endif
- default: return -EINVAL;
- }
- *ydstorg = 0;
- vramlen = ACCESS_FBINFO(video.len_usable);
- if (var->bits_per_pixel) {
- var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
- memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
- if (memlen > vramlen) {
- var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
- memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
- }
- /* There is hardware bug that no line can cross 4MB boundary */
- /* give up for CFB24, it is impossible to easy workaround it */
- /* for other try to do something */
- if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
- if (var->bits_per_pixel == 24) {
- /* sorry */
- } else {
- unsigned int linelen;
- unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
- unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
- unsigned int max_yres;
-
- while (m1) {
- int t;
-
- while (m2 >= m1) m2 -= m1;
- t = m1;
- m1 = m2;
- m2 = t;
- }
- m2 = linelen * PAGE_SIZE / m2;
- *ydstorg = m2 = 0x400000 % m2;
- max_yres = (vramlen - m2) / linelen;
- if (var->yres_virtual > max_yres)
- var->yres_virtual = max_yres;
- }
- }
- } else {
- matrox_text_round(PMINFO var, p);
-#if 0
-/* we must limit pixclock by mclk...
- Millenium I: 66 MHz = 15000
- Millenium II: 61 MHz = 16300
- Millenium G200: 83 MHz = 12000 */
- if (var->pixclock < 15000)
- var->pixclock = 15000; /* limit for "normal" gclk & mclk */
-#endif
- }
- /* YDSTLEN contains only signed 16bit value */
- if (var->yres_virtual > 32767)
- var->yres_virtual = 32767;
- if (var->yres_virtual < var->yres)
- var->yres = var->yres_virtual;
- if (var->xres_virtual < var->xres)
- var->xres = var->xres_virtual;
- if (var->xoffset + var->xres > var->xres_virtual)
- var->xoffset = var->xres_virtual - var->xres;
- if (var->yoffset + var->yres > var->yres_virtual)
- var->yoffset = var->yres_virtual - var->yres;
-
- if (var->bits_per_pixel == 0) {
- var->red.offset = 0;
- var->red.length = 6;
- var->green.offset = 0;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 6;
- var->transp.offset = 0;
- var->transp.length = 0;
- *visual = MX_VISUAL_PSEUDOCOLOR;
- } else if (var->bits_per_pixel == 4) {
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- *visual = MX_VISUAL_PSEUDOCOLOR;
- } else if (var->bits_per_pixel <= 8) {
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- *visual = MX_VISUAL_PSEUDOCOLOR;
- } else {
- if (var->bits_per_pixel <= 16) {
- if (var->green.length == 5) {
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 15;
- var->transp.length = 1;
- } else {
- 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;
- }
- } else if (var->bits_per_pixel <= 24) {
- 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;
- } else {
- 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;
- }
- dprintk("matroxfb: truecolor: "
- "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
- var->transp.length,
- var->red.length,
- var->green.length,
- var->blue.length,
- var->transp.offset,
- var->red.offset,
- var->green.offset,
- var->blue.offset);
- *visual = MX_VISUAL_DIRECTCOLOR;
- }
- *video_cmap_len = matroxfb_get_cmap_len(var);
- dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
- var->xres_virtual, var->yres_virtual);
- return 0;
-}
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
- unsigned int f_pll;
- unsigned int pclk_m, pclk_n, pclk_p;
- unsigned int mclk_m, mclk_n, mclk_p;
- unsigned int rfhcnt, mclk_ctl;
- int tmout;
-
- DBG("ti3026_setMCLK")
-
- f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p);
-
- /* save pclk */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
- pclk_n = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFD);
- pclk_m = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
- pclk_p = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
-
- /* stop pclk */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
-
- /* set pclk to new mclk */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_m);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
-
- /* wait for PLL to lock */
- for (tmout = 500000; tmout; tmout--) {
- if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
- break;
- udelay(10);
- };
- if (!tmout)
- printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
-
- /* output pclk on mclk pin */
- mclk_ctl = inTi3026(PMINFO TVP3026_XMEMPLLCTRL);
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
-
- /* stop MCLK */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFB);
- outTi3026(PMINFO TVP3026_XMEMPLLDATA, 0x00);
-
- /* set mclk to new freq */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xF3);
- outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
- outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_m);
- outTi3026(PMINFO TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
-
- /* wait for PLL to lock */
- for (tmout = 500000; tmout; tmout--) {
- if (inTi3026(PMINFO TVP3026_XMEMPLLDATA) & 0x40)
- break;
- udelay(10);
- }
- if (!tmout)
- printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
-
- f_pll = f_pll * 333 / (10000 << mclk_p);
- if (isMilleniumII(MINFO)) {
- rfhcnt = (f_pll - 128) / 256;
- if (rfhcnt > 15)
- rfhcnt = 15;
- } else {
- rfhcnt = (f_pll - 64) / 128;
- if (rfhcnt > 15)
- rfhcnt = 0;
- }
- hw->MXoptionReg = (hw->MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-
- /* output MCLK to MCLK pin */
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, (mclk_ctl ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
-
- /* stop PCLK */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFE);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
-
- /* restore pclk */
- outTi3026(PMINFO TVP3026_XPLLADDR, 0xFC);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_n);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_m);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, pclk_p);
-
- /* wait for PLL to lock */
- for (tmout = 500000; tmout; tmout--) {
- if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
- break;
- udelay(10);
- }
- if (!tmout)
- printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
-}
-
-static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
-
- DBG("ti3026_ramdac_init")
-
- ACCESS_FBINFO(features.pll.vco_freq_min) = 110000;
- ACCESS_FBINFO(features.pll.ref_freq) = 114545;
- ACCESS_FBINFO(features.pll.feed_div_min) = 2;
- ACCESS_FBINFO(features.pll.feed_div_max) = 24;
- ACCESS_FBINFO(features.pll.in_div_min) = 2;
- ACCESS_FBINFO(features.pll.in_div_max) = 63;
- ACCESS_FBINFO(features.pll.post_shift_max) = 3;
- if (ACCESS_FBINFO(devflags.noinit))
- return;
- ti3026_setMCLK(PMINFO hw, 60000);
-}
-#endif
-
-static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
- unsigned int size;
-
- size = ACCESS_FBINFO(fastfont.size);
- ACCESS_FBINFO(fastfont.size) = 0;
- if (size) {
- unsigned int end = ACCESS_FBINFO(video.len_usable);
-
- if (size < end) {
- unsigned int start;
-
- start = (end - size) & PAGE_MASK;
- if (start >= 0x00100000) {
- ACCESS_FBINFO(video.len_usable) = start;
- ACCESS_FBINFO(fastfont.mgabase) = start * 8;
- ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase);
- vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start);
- ACCESS_FBINFO(fastfont.size) = end - start;
- }
- }
- }
-}
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
-
- DBG("MGA1064_ramdac_init");
-
- /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */
- ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
- ACCESS_FBINFO(features.pll.ref_freq) = 14318;
- ACCESS_FBINFO(features.pll.feed_div_min) = 100;
- ACCESS_FBINFO(features.pll.feed_div_max) = 127;
- ACCESS_FBINFO(features.pll.in_div_min) = 1;
- ACCESS_FBINFO(features.pll.in_div_max) = 31;
- ACCESS_FBINFO(features.pll.post_shift_max) = 3;
- ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_EXTERNAL;
- /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
- DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
-}
-
-static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
- static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960,
- 1024, 1152, 1280, 1600, 1664, 1920,
- 2048, 0};
- DBG("MGA1064_preinit")
-
- /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
- ACCESS_FBINFO(capable.text) = 1;
- ACCESS_FBINFO(capable.vxres) = vxres_mystique;
- ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
- ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
-
- if (ACCESS_FBINFO(devflags.noinit))
- return 0; /* do not modify settings */
- hw->MXoptionReg &= 0xC0000100;
- hw->MXoptionReg |= 0x00094E20;
- if (ACCESS_FBINFO(devflags.novga))
- hw->MXoptionReg &= ~0x00000100;
- if (ACCESS_FBINFO(devflags.nobios))
- hw->MXoptionReg &= ~0x40000000;
- if (ACCESS_FBINFO(devflags.nopciretry))
- hw->MXoptionReg |= 0x20000000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- mga_setr(M_SEQ_INDEX, 0x01, 0x20);
- mga_outl(M_CTLWTST, 0x00000000);
- udelay(200);
- mga_outl(M_MACCESS, 0x00008000);
- udelay(100);
- mga_outl(M_MACCESS, 0x0000C000);
- return 0;
-}
-
-static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
-
- DBG("MGA1064_reset");
-
- ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
- if (ACCESS_FBINFO(devflags.hwcursor))
- ACCESS_FBINFO(video.len_usable) -= 1024;
- matroxfb_fastfont_init(MINFO);
- MGA1064_ramdac_init(PMINFO hw);
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_G100
-/* BIOS environ */
-static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
- /* G100 wants 0x10, G200 SGRAM does not care... */
-#if 0
-static int def50 = 0; /* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
-#endif
-
-static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
- int reg;
- int selClk;
- int clk;
-
- DBG("MGAG100_progPixClock")
-
- outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
- M1064_XPIXCLKCTRL_PLL_UP);
- switch (flags & 3) {
- case 0: reg = M1064_XPIXPLLAM; break;
- case 1: reg = M1064_XPIXPLLBM; break;
- default: reg = M1064_XPIXPLLCM; break;
- }
- outDAC1064(PMINFO reg++, m);
- outDAC1064(PMINFO reg++, n);
- outDAC1064(PMINFO reg, p);
- selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
- /* there should be flags & 0x03 & case 0/1/else */
- /* and we should first select source and after that we should wait for PLL */
- /* and we are waiting for PLL with oscilator disabled... Is it right? */
- switch (flags & 0x03) {
- case 0x00: break;
- case 0x01: selClk |= 4; break;
- default: selClk |= 0x0C; break;
- }
- mga_outb(M_MISC_REG, selClk);
- for (clk = 500000; clk; clk--) {
- if (inDAC1064(PMINFO M1064_XPIXPLLSTAT) & 0x40)
- break;
- udelay(10);
- };
- if (!clk)
- printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
- selClk = inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
- switch (flags & 0x0C) {
- case 0x00: selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
- case 0x04: selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
- default: selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
- }
- outDAC1064(PMINFO M1064_XPIXCLKCTRL, selClk);
- outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
-}
-
-static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
- unsigned int m, n, p;
-
- DBG("MGAG100_setPixClock")
-
- DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p);
- MGAG100_progPixClock(PMINFO flags, m, n, p);
-}
-
-static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
- static const int vxres_g100[] = { 512, 640, 768, 800, 832, 960,
- 1024, 1152, 1280, 1600, 1664, 1920,
- 2048, 0};
- u_int32_t reg50;
-#if 0
- u_int32_t q;
-#endif
-
- DBG("MGAG100_preinit")
-
- /* there are some instabilities if in_div > 19 && vco < 61000 */
- ACCESS_FBINFO(features.pll.vco_freq_min) = 62000;
- ACCESS_FBINFO(features.pll.ref_freq) = 27000;
- ACCESS_FBINFO(features.pll.feed_div_min) = 7;
- ACCESS_FBINFO(features.pll.feed_div_max) = 127;
- ACCESS_FBINFO(features.pll.in_div_min) = 1;
- ACCESS_FBINFO(features.pll.in_div_max) = 31;
- ACCESS_FBINFO(features.pll.post_shift_max) = 3;
- ACCESS_FBINFO(features.DAC1064.xvrefctrl) = DAC1064_XVREFCTRL_G100_DEFAULT;
- /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */
- ACCESS_FBINFO(capable.text) = 1;
- ACCESS_FBINFO(capable.vxres) = vxres_g100;
- ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
- ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
- ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
-
- if (ACCESS_FBINFO(devflags.noinit))
- return 0;
- hw->MXoptionReg &= 0xC0000100;
- hw->MXoptionReg |= 0x00078020;
- if (ACCESS_FBINFO(devflags.novga))
- hw->MXoptionReg &= ~0x00000100;
- if (ACCESS_FBINFO(devflags.nobios))
- hw->MXoptionReg &= ~0x40000000;
- if (ACCESS_FBINFO(devflags.nopciretry))
- hw->MXoptionReg |= 0x20000000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- pci_read_config_dword(ACCESS_FBINFO(pcidev), 0x50, &reg50);
- reg50 &= ~0x3000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
-
- DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
-
- if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100) {
- hw->MXoptionReg |= 0x1080;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- mga_outl(M_CTLWTST, 0x00000300);
- /* mga_outl(M_CTLWTST, 0x03258A31); */
- udelay(100);
- mga_outb(0x1C05, 0x00);
- mga_outb(0x1C05, 0x80);
- udelay(100);
- mga_outb(0x1C05, 0x40);
- mga_outb(0x1C05, 0xC0);
- udelay(100);
- reg50 &= ~0xFF;
- reg50 |= 0x07;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), 0x50, reg50);
- /* it should help with G100 */
- mga_outb(M_GRAPHICS_INDEX, 6);
- mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
- mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
- mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
- mga_writeb(ACCESS_FBINFO(video.vbase), 0x0000, 0xAA);
- mga_writeb(ACCESS_FBINFO(video.vbase), 0x0800, 0x55);
- mga_writeb(ACCESS_FBINFO(video.vbase), 0x4000, 0x55);
-#if 0
- if (mga_readb(ACCESS_FBINFO(video.vbase), 0x0000) != 0xAA) {
- hw->MXoptionReg &= ~0x1000;
- }
-#endif
- } else {
- hw->MXoptionReg |= 0x00000C00;
- if (ACCESS_FBINFO(devflags.sgram))
- hw->MXoptionReg |= 0x4000;
- mga_outl(M_CTLWTST, 0x042450A1);
- mga_outb(0x1E47, 0x00);
- mga_outb(0x1E46, 0x00);
- udelay(10);
- mga_outb(0x1C05, 0x00);
- mga_outb(0x1C05, 0x80);
- udelay(100);
- mga_outw(0x1E44, 0x0108);
- }
- hw->MXoptionReg = (hw->MXoptionReg & ~0x1F8000) | 0x78000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- return 0;
-}
-
-static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
- u_int8_t b;
-
- DBG("MGAG100_reset")
-
- ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024;
- if (ACCESS_FBINFO(devflags.hwcursor))
- ACCESS_FBINFO(video.len_usable) -= 1024;
- matroxfb_fastfont_init(MINFO);
-
- {
-#ifdef G100_BROKEN_IBM_82351
- u_int32_t d;
-
- find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
- pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
- if (b == ACCESS_FBINFO(pcidev)->bus->number) {
- pci_write_config_byte(ibm, PCI_COMMAND+1, 0); /* disable back-to-back & SERR */
- pci_write_config_byte(ibm, 0x41, 0xF4); /* ??? */
- pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0); /* ??? */
- pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00); /* ??? */
- }
-#endif
- if (!ACCESS_FBINFO(devflags.noinit)) {
- if (x7AF4 & 8) {
- hw->MXoptionReg |= 0x40;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- }
- mga_setr(M_EXTVGA_INDEX, 0x06, 0x50);
- }
- }
- DAC1064_setmclk(PMINFO hw, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
- if (ACCESS_FBINFO(devflags.noinit))
- return;
- MGAG100_setPixClock(PMINFO 4, 25175);
- MGAG100_setPixClock(PMINFO 5, 28322);
- if (x7AF4 & 0x10) {
- b = inDAC1064(PMINFO M1064_XGENIODATA) & ~1;
- outDAC1064(PMINFO M1064_XGENIODATA, b);
- b = inDAC1064(PMINFO M1064_XGENIOCTRL) | 1;
- outDAC1064(PMINFO M1064_XGENIOCTRL, b);
- }
-}
-#endif
-
-static void vgaHWrestore(CPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw) {
- int i;
-
- DBG("vgaHWrestore")
-
- dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
- dprintk(KERN_INFO "SEQ regs: ");
- for (i = 0; i < 5; i++)
- dprintk("%02X:", hw->SEQ[i]);
- dprintk("\n");
- dprintk(KERN_INFO "GDC regs: ");
- for (i = 0; i < 9; i++)
- dprintk("%02X:", hw->GCTL[i]);
- dprintk("\n");
- dprintk(KERN_INFO "CRTC regs: ");
- for (i = 0; i < 25; i++)
- dprintk("%02X:", hw->CRTC[i]);
- dprintk("\n");
- dprintk(KERN_INFO "ATTR regs: ");
- for (i = 0; i < 21; i++)
- dprintk("%02X:", hw->ATTR[i]);
- dprintk("\n");
-
- mga_inb(M_ATTR_RESET);
- mga_outb(M_ATTR_INDEX, 0);
- mga_outb(M_MISC_REG, hw->MiscOutReg);
- for (i = 1; i < 5; i++)
- mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
- mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
- for (i = 0; i < 25; i++)
- mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
- for (i = 0; i < 9; i++)
- mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
- for (i = 0; i < 21; i++) {
- mga_inb(M_ATTR_RESET);
- mga_outb(M_ATTR_INDEX, i);
- mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
- }
- mga_outb(M_PALETTE_MASK, 0xFF);
- mga_outb(M_DAC_REG, 0x00);
- for (i = 0; i < 768; i++)
- mga_outb(M_DAC_VAL, hw->DACpal[i]);
- mga_inb(M_ATTR_RESET);
- mga_outb(M_ATTR_INDEX, 0x20);
-}
-
-static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *fb_info)
-{
- struct display* p;
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
- struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
-#endif
-
- DBG("matrox_setcolreg")
-
- /*
- * 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.
- */
-
- if (regno >= ACCESS_FBINFO(curr.cmap_len))
- return 1;
-
- ACCESS_FBINFO(palette[regno].red) = red;
- ACCESS_FBINFO(palette[regno].green) = green;
- ACCESS_FBINFO(palette[regno].blue) = blue;
- ACCESS_FBINFO(palette[regno].transp) = transp;
-
- p = ACCESS_FBINFO(currcon_display);
- if (p->var.grayscale) {
- /* gray = 0.30*R + 0.59*G + 0.11*B */
- red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
- }
-
- red = CNVT_TOHW(red, p->var.red.length);
- green = CNVT_TOHW(green, p->var.green.length);
- blue = CNVT_TOHW(blue, p->var.blue.length);
- transp = CNVT_TOHW(transp, p->var.transp.length);
-
- switch (p->var.bits_per_pixel) {
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT)
-#ifdef FBCON_HAS_VGATEXT
- case 0:
-#endif
-#ifdef FBCON_HAS_CFB4
- case 4:
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
-#endif
- mga_outb(M_DAC_REG, regno);
- mga_outb(M_DAC_VAL, red);
- mga_outb(M_DAC_VAL, green);
- mga_outb(M_DAC_VAL, blue);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- ACCESS_FBINFO(cmap.cfb16[regno]) =
- (red << p->var.red.offset) |
- (green << p->var.green.offset) |
- (blue << p->var.blue.offset) |
- (transp << p->var.transp.offset); /* for 1:5:5:5 */
- break;
-#endif
-#ifdef FBCON_HAS_CFB24
- case 24:
- ACCESS_FBINFO(cmap.cfb24[regno]) =
- (red << p->var.red.offset) |
- (green << p->var.green.offset) |
- (blue << p->var.blue.offset);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- ACCESS_FBINFO(cmap.cfb32[regno]) =
- (red << p->var.red.offset) |
- (green << p->var.green.offset) |
- (blue << p->var.blue.offset) |
- (transp << p->var.transp.offset); /* 8:8:8:8 */
- break;
-#endif
- }
- return 0;
-}
-
-static void do_install_cmap(WPMINFO struct display* dsp)
-{
- DBG("do_install_cmap")
-
- if (dsp->cmap.len)
- fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
- else
- fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
- 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
-}
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static void MGA1064_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
- int i;
-
- DBG("MGA1064_restore")
-
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
- mga_outb(M_IEN, 0x00);
- mga_outb(M_CACHEFLUSH, 0x00);
-
- DAC1064_restore_1(PMINFO hw, oldhw);
- vgaHWrestore(PMINFO hw, oldhw);
- for (i = 0; i < 6; i++)
- mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
- DAC1064_restore_2(PMINFO hw, oldhw, p);
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_G100
-static void MGAG100_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
- int i;
-
- DBG("MGAG100_restore")
-
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-
- DAC1064_restore_1(PMINFO hw, oldhw);
- vgaHWrestore(PMINFO hw, oldhw);
-#ifdef CONFIG_FB_MATROX_32MB
- if (ACCESS_FBINFO(devflags.support32MB))
- mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
-#endif
- for (i = 0; i < 6; i++)
- mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
- DAC1064_restore_2(PMINFO hw, oldhw, p);
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static void Ti3026_restore(WPMINFO struct matrox_hw_state* hw, struct matrox_hw_state* oldhw, struct display* p) {
- int i;
-
- DBG("Ti3026_restore")
-
- dprintk(KERN_INFO "EXTVGA regs: ");
- for (i = 0; i < 6; i++)
- dprintk("%02X:", hw->CRTCEXT[i]);
- dprintk("\n");
-
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-
- vgaHWrestore(PMINFO hw, oldhw);
-
- for (i = 0; i < 6; i++)
- mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
-
- for (i = 0; i < 21; i++) {
- outTi3026(PMINFO DACseq[i], hw->DACreg[i]);
- }
- if (oldhw) {
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
- oldhw->DACclk[0] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
- oldhw->DACclk[3] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x15);
- oldhw->DACclk[1] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
- oldhw->DACclk[4] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
- oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
- oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
- }
- if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
- /* agrhh... setting up PLL is very slow on Millenium... */
- /* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
- /* Maybe even we should call schedule() ? */
-
- outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
- outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0);
-
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
- for (i = 0; i < 3; i++)
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, hw->DACclk[i]);
- /* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
- if (hw->MiscOutReg & 0x08) {
- int tmout;
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
- for (tmout = 500000; tmout; --tmout) {
- if (inTi3026(PMINFO TVP3026_XPIXPLLDATA) & 0x40)
- break;
- udelay(10);
- }
-
- if (!tmout)
- printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
- else
- dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
- }
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
- for (i = 3; i < 6; i++)
- outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
- if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
- int tmout;
-
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
- for (tmout = 500000; tmout; --tmout) {
- if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40)
- break;
- udelay(10);
- }
- if (!tmout)
- printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
- else
- dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
- }
- }
- if (p && p->conp) {
- if (p->type == FB_TYPE_TEXT) {
- matrox_text_createcursor(PMINFO p);
- matrox_text_loadfont(PMINFO p);
- i = 0;
- } else {
- matroxfb_ti3026_createcursor(PMINFO p);
- i = matroxfb_fastfont_tryset(PMINFO p);
- }
- } else
- i = 0;
- if (i) {
- ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc;
- ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs;
- } else {
- ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc;
- ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
- }
-
- dprintk(KERN_DEBUG "3026DACregs ");
- for (i = 0; i < 21; i++) {
- dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
- if ((i & 0x7) == 0x7) dprintk("\n" KERN_DEBUG "continuing... ");
- }
- dprintk("\n" KERN_DEBUG "DACclk ");
- for (i = 0; i < 6; i++)
- dprintk("C%02X=%02X ", i, hw->DACclk[i]);
- dprintk("\n");
-}
-#endif
-
-static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct display* p;
- DBG("matroxfb_get_fix")
-
-#define minfo ((struct matrox_fb_info*)info)
-
- if (con >= 0)
- p = fb_display + con;
- else
- p = ACCESS_FBINFO(fbcon.disp);
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id,"MATROX");
-
- fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
- fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
- fix->type = p->type;
- fix->type_aux = p->type_aux;
- fix->visual = p->visual;
- fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
- fix->ypanstep = 1;
- fix->ywrapstep = 0;
- fix->line_length = p->line_length;
- fix->mmio_start = ACCESS_FBINFO(mmio.base);
- fix->mmio_len = ACCESS_FBINFO(mmio.len);
- fix->accel = ACCESS_FBINFO(devflags.accelerator);
- return 0;
-#undef minfo
-}
-
-static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- DBG("matroxfb_get_var")
-
- if(con < 0)
- *var=ACCESS_FBINFO(fbcon.disp)->var;
- else
- *var=fb_display[con].var;
- return 0;
-#undef minfo
-}
-
-static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- int err;
- int visual;
- int cmap_len;
- unsigned int ydstorg;
- struct display* display;
- int chgvar;
-
- DBG("matroxfb_set_var")
-
- if (con >= 0)
- display = fb_display + con;
- else
- display = ACCESS_FBINFO(fbcon.disp);
- if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0)
- return err;
- switch (var->activate & FB_ACTIVATE_MASK) {
- case FB_ACTIVATE_TEST: return 0;
- case FB_ACTIVATE_NXTOPEN: /* ?? */
- case FB_ACTIVATE_NOW: break; /* continue */
- default: return -EINVAL; /* unknown */
- }
- if (con >= 0) {
- chgvar = ((display->var.xres != var->xres) ||
- (display->var.yres != var->yres) ||
- (display->var.xres_virtual != var->xres_virtual) ||
- (display->var.yres_virtual != var->yres_virtual) ||
- (display->var.bits_per_pixel != var->bits_per_pixel) ||
- memcmp(&display->var.red, &var->red, sizeof(var->red)) ||
- memcmp(&display->var.green, &var->green, sizeof(var->green)) ||
- memcmp(&display->var.blue, &var->blue, sizeof(var->blue)));
- } else {
- chgvar = 0;
- }
- display->var = *var;
- /* cmap */
- display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
- display->visual = visual;
- display->ypanstep = 1;
- display->ywrapstep = 0;
- if (var->bits_per_pixel) {
- display->type = FB_TYPE_PACKED_PIXELS;
- display->type_aux = 0;
- display->next_line = display->line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
- } else {
- display->type = FB_TYPE_TEXT;
- display->type_aux = ACCESS_FBINFO(devflags.text_type_aux);
- display->next_line = display->line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep);
- }
- display->can_soft_blank = 1;
- display->inverse = ACCESS_FBINFO(devflags.inverse);
- /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */
- /* next_plane, fontdata, _font*, userfont */
- initMatrox(PMINFO display); /* dispsw */
- /* dispsw, scrollmode, yscroll */
- /* fgshift, bgshift, charmask */
- if (chgvar && info && info->changevar)
- info->changevar(con);
- if (con == ACCESS_FBINFO(currcon)) {
- unsigned int pos;
-
- ACCESS_FBINFO(curr.cmap_len) = cmap_len;
- if (display->type == FB_TYPE_TEXT) {
- /* textmode must be in first megabyte, so no ydstorg allowed */
- ACCESS_FBINFO(curr.ydstorg.bytes) = 0;
- ACCESS_FBINFO(curr.ydstorg.chunks) = 0;
- ACCESS_FBINFO(curr.ydstorg.pixels) = 0;
- } else {
- ydstorg += ACCESS_FBINFO(devflags.ydstorg);
- ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg;
- ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2);
- if (var->bits_per_pixel == 4)
- ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg;
- else
- ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel;
- }
- ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel);
- if (visual == MX_VISUAL_PSEUDOCOLOR) {
- int i;
-
- for (i = 0; i < 16; i++) {
- int j;
-
- j = color_table[i];
- ACCESS_FBINFO(palette[i].red) = default_red[j];
- ACCESS_FBINFO(palette[i].green) = default_grn[j];
- ACCESS_FBINFO(palette[i].blue) = default_blu[j];
- }
- }
-
- { struct my_timming mt;
- struct matrox_hw_state* hw;
- struct matrox_hw_state* ohw;
-
- var2my(var, &mt);
- hw = ACCESS_FBINFO(newhw);
- ohw = ACCESS_FBINFO(currenthw);
-
- /* MXoptionReg is not set from scratch */
- hw->MXoptionReg = ohw->MXoptionReg;
- /* DACclk[3]..[5] are not initialized with DAC1064 */
- memcpy(hw->DACclk, ohw->DACclk, sizeof(hw->DACclk));
- /* others are initialized by init() */
-
- del_timer(&ACCESS_FBINFO(cursor.timer));
- ACCESS_FBINFO(cursor.state) = CM_ERASE;
-
- ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display));
- if (display->type == FB_TYPE_TEXT) {
- if (fontheight(display))
- pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8);
- else
- pos = 0;
- } else {
- pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32;
- pos += ACCESS_FBINFO(curr.ydstorg.chunks);
- }
-
- hw->CRTC[0x0D] = pos & 0xFF;
- hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
- hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
- hw->CRTCEXT[8] = pos >> 21;
- ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
- ACCESS_FBINFO(cursor.redraw) = 1;
- ACCESS_FBINFO(currenthw) = hw;
- ACCESS_FBINFO(newhw) = ohw;
- matrox_cfbX_init(PMINFO display);
- do_install_cmap(PMINFO display);
-#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
- if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
- int vmode, cmode;
-
- display_info.width = var->xres;
- display_info.height = var->yres;
- display_info.depth = var->bits_per_pixel;
- display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8;
- if (mac_var_to_vmode(var, &vmode, &cmode))
- display_info.mode = 0;
- else
- display_info.mode = vmode;
- strcpy(display_info.name, ACCESS_FBINFO(matrox_name));
- display_info.fb_address = ACCESS_FBINFO(video.base);
- display_info.cmap_adr_address = 0;
- display_info.cmap_data_address = 0;
- display_info.disp_reg_address = ACCESS_FBINFO(mmio.base);
- }
-#endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */
- }
- }
- return 0;
-#undef minfo
-}
-
-static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info)
-{
-
- DBG("matrox_getcolreg")
-
-#define minfo ((struct matrox_fb_info*)info)
- /*
- * Read a single color register and split it into colors/transparent.
- * Return != 0 for invalid regno.
- */
-
- if (regno >= ACCESS_FBINFO(curr.cmap_len))
- return 1;
-
- *red = ACCESS_FBINFO(palette[regno].red);
- *green = ACCESS_FBINFO(palette[regno].green);
- *blue = ACCESS_FBINFO(palette[regno].blue);
- *transp = ACCESS_FBINFO(palette[regno].transp);
- return 0;
-#undef minfo
-}
-
-static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
- : fb_display + con;
-
- DBG("matroxfb_get_cmap")
-
- if (con == ACCESS_FBINFO(currcon)) /* current console? */
- return fb_get_cmap(cmap, kspc, matrox_getcolreg, info);
- else if (dsp->cmap.len) /* non default colormap? */
- fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)),
- cmap, kspc ? 0 : 2);
- return 0;
-#undef minfo
-}
-
-static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- unsigned int cmap_len;
- struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
-#define minfo ((struct matrox_fb_info*)info)
-
- DBG("matroxfb_set_cmap")
-
- cmap_len = matroxfb_get_cmap_len(&dsp->var);
- if (dsp->cmap.len != cmap_len) {
- int err;
-
- err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
- if (err)
- return err;
- }
- if (con == ACCESS_FBINFO(currcon)) { /* current console? */
- return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
- } else
- fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
- return 0;
-#undef minfo
-}
-
-static int matroxfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info)
-{
-
- DBG("matroxfb_ioctl")
-
- return -EINVAL;
-}
-
-static struct fb_ops matroxfb_ops = {
- matroxfb_open,
- matroxfb_release,
- matroxfb_get_fix,
- matroxfb_get_var,
- matroxfb_set_var,
- matroxfb_get_cmap,
- matroxfb_set_cmap,
- matroxfb_pan_display,
- matroxfb_ioctl,
- NULL /* mmap */
-};
-
-static int matroxfb_switch(int con, struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- struct fb_cmap* cmap;
-
- DBG("matroxfb_switch");
-
- if (ACCESS_FBINFO(currcon) >= 0) {
- /* Do we have to save the colormap? */
- cmap = &(ACCESS_FBINFO(currcon_display)->cmap);
- dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(currcon), cmap->len);
-
- if (cmap->len) {
- dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
- fb_get_cmap(cmap, 1, matrox_getcolreg, info);
-#ifdef DEBUG
- if (cmap->red) {
- dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]);
- }
-#endif
- }
- }
- ACCESS_FBINFO(currcon) = con;
- ACCESS_FBINFO(currcon_display) = fb_display + con;
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
-#ifdef DEBUG
- cmap = &fb_display[con].cmap;
- dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len);
- dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
- if (fb_display[con].cmap.red) {
- dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]);
- }
-#endif
- matroxfb_set_var(&fb_display[con].var, con, info);
-#ifdef DEBUG
- dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len);
- dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp);
- if (fb_display[con].cmap.red) {
- dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]);
- }
-#endif
- return 0;
-#undef minfo
-}
-
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void matroxfb_blank(int blank, struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
- int seq;
- int crtc;
-
- DBG("matroxfb_blank")
-
- switch (blank) {
- case 1: seq = 0x20; crtc = 0x00; break; /* works ??? */
- case 2: seq = 0x20; crtc = 0x10; break;
- case 3: seq = 0x20; crtc = 0x20; break;
- case 4: seq = 0x20; crtc = 0x30; break;
- default: seq = 0x00; crtc = 0x00; break;
- }
-
- mga_outb(M_SEQ_INDEX, 1);
- mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
- mga_outb(M_EXTVGA_INDEX, 1);
- mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
-
-#undef minfo
-}
-
-#define RSResolution(X) ((X) & 0x0F)
-#define RS640x400 1
-#define RS640x480 2
-#define RS800x600 3
-#define RS1024x768 4
-#define RS1280x1024 5
-#define RS1600x1200 6
-#define RS768x576 7
-#define RS960x720 8
-#define RS1152x864 9
-#define RS1408x1056 10
-#define RS640x350 11
-#define RS1056x344 12 /* 132 x 43 text */
-#define RS1056x400 13 /* 132 x 50 text */
-#define RS1056x480 14 /* 132 x 60 text */
-#define RSNoxNo 15
-/* 10-FF */
-static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
- { 640, 400, 48, 16, 39, 8, 96, 2, 70 },
- { 640, 480, 48, 16, 33, 10, 96, 2, 60 },
- { 800, 600, 144, 24, 28, 8, 112, 6, 60 },
- { 1024, 768, 160, 32, 30, 4, 128, 4, 60 },
- { 1280, 1024, 224, 32, 32, 4, 136, 4, 60 },
- { 1600, 1200, 272, 48, 32, 5, 152, 5, 60 },
- { 768, 576, 144, 16, 28, 6, 112, 4, 60 },
- { 960, 720, 144, 24, 28, 8, 112, 4, 60 },
- { 1152, 864, 192, 32, 30, 4, 128, 4, 60 },
- { 1408, 1056, 256, 40, 32, 5, 144, 5, 60 },
- { 640, 350, 48, 16, 39, 8, 96, 2, 70 },
- { 1056, 344, 96, 24, 59, 44, 160, 2, 70 },
- { 1056, 400, 96, 24, 39, 8, 160, 2, 70 },
- { 1056, 480, 96, 24, 36, 12, 160, 3, 60 },
- { 0, 0, ~0, ~0, ~0, ~0, 0, 0, 0 }
-};
-
-#define RSDepth(X) (((X) >> 8) & 0x0F)
-#define RS8bpp 0x1
-#define RS15bpp 0x2
-#define RS16bpp 0x3
-#define RS32bpp 0x4
-#define RS4bpp 0x5
-#define RS24bpp 0x6
-#define RSText 0x7
-#define RSText8 0x8
-/* 9-F */
-static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] __initdata = {
- { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
- { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
- { { 11, 5, 0}, { 6, 5, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
- { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
- { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
- { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
- { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
- { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
-};
-
-#define RSCreate(X,Y) ((X) | ((Y) << 8))
-static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
-/* default must be first */
-#ifdef FBCON_HAS_CFB8
- { ~0, RSCreate(RSNoxNo, RS8bpp ) },
- { 0x101, RSCreate(RS640x480, RS8bpp ) },
- { 0x100, RSCreate(RS640x400, RS8bpp ) },
- { 0x180, RSCreate(RS768x576, RS8bpp ) },
- { 0x103, RSCreate(RS800x600, RS8bpp ) },
- { 0x188, RSCreate(RS960x720, RS8bpp ) },
- { 0x105, RSCreate(RS1024x768, RS8bpp ) },
- { 0x190, RSCreate(RS1152x864, RS8bpp ) },
- { 0x107, RSCreate(RS1280x1024, RS8bpp ) },
- { 0x198, RSCreate(RS1408x1056, RS8bpp ) },
- { 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
-#endif
-#ifdef FBCON_HAS_CFB16
- { ~0, RSCreate(RSNoxNo, RS15bpp) },
- { 0x110, RSCreate(RS640x480, RS15bpp) },
- { 0x181, RSCreate(RS768x576, RS15bpp) },
- { 0x113, RSCreate(RS800x600, RS15bpp) },
- { 0x189, RSCreate(RS960x720, RS15bpp) },
- { 0x116, RSCreate(RS1024x768, RS15bpp) },
- { 0x191, RSCreate(RS1152x864, RS15bpp) },
- { 0x119, RSCreate(RS1280x1024, RS15bpp) },
- { 0x199, RSCreate(RS1408x1056, RS15bpp) },
- { 0x11D, RSCreate(RS1600x1200, RS15bpp) },
- { 0x111, RSCreate(RS640x480, RS16bpp) },
- { 0x182, RSCreate(RS768x576, RS16bpp) },
- { 0x114, RSCreate(RS800x600, RS16bpp) },
- { 0x18A, RSCreate(RS960x720, RS16bpp) },
- { 0x117, RSCreate(RS1024x768, RS16bpp) },
- { 0x192, RSCreate(RS1152x864, RS16bpp) },
- { 0x11A, RSCreate(RS1280x1024, RS16bpp) },
- { 0x19A, RSCreate(RS1408x1056, RS16bpp) },
- { 0x11E, RSCreate(RS1600x1200, RS16bpp) },
-#endif
-#ifdef FBCON_HAS_CFB24
- { ~0, RSCreate(RSNoxNo, RS24bpp) },
- { 0x1B2, RSCreate(RS640x480, RS24bpp) },
- { 0x184, RSCreate(RS768x576, RS24bpp) },
- { 0x1B5, RSCreate(RS800x600, RS24bpp) },
- { 0x18C, RSCreate(RS960x720, RS24bpp) },
- { 0x1B8, RSCreate(RS1024x768, RS24bpp) },
- { 0x194, RSCreate(RS1152x864, RS24bpp) },
- { 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
- { 0x19C, RSCreate(RS1408x1056, RS24bpp) },
- { 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
-#endif
-#ifdef FBCON_HAS_CFB32
- { ~0, RSCreate(RSNoxNo, RS32bpp) },
- { 0x112, RSCreate(RS640x480, RS32bpp) },
- { 0x183, RSCreate(RS768x576, RS32bpp) },
- { 0x115, RSCreate(RS800x600, RS32bpp) },
- { 0x18B, RSCreate(RS960x720, RS32bpp) },
- { 0x118, RSCreate(RS1024x768, RS32bpp) },
- { 0x193, RSCreate(RS1152x864, RS32bpp) },
- { 0x11B, RSCreate(RS1280x1024, RS32bpp) },
- { 0x19B, RSCreate(RS1408x1056, RS32bpp) },
- { 0x11F, RSCreate(RS1600x1200, RS32bpp) },
-#endif
-#ifdef FBCON_HAS_VGATEXT
- { ~0, RSCreate(RSNoxNo, RSText) },
- { 0x002, RSCreate(RS640x400, RSText) }, /* 80x25 */
- { 0x003, RSCreate(RS640x400, RSText) }, /* 80x25 */
- { 0x007, RSCreate(RS640x400, RSText) }, /* 80x25 */
- { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */
- { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */
- { 0x109, RSCreate(RS1056x400, RSText) }, /* 132x25 */
- { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */
- { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */
- { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */
-#endif
-#ifdef FBCON_HAS_CFB4
- { ~0, RSCreate(RSNoxNo, RS4bpp ) },
- { 0x010, RSCreate(RS640x350, RS4bpp ) },
- { 0x012, RSCreate(RS640x480, RS4bpp ) },
- { 0x102, RSCreate(RS800x600, RS4bpp ) },
- { 0x104, RSCreate(RS1024x768, RS4bpp ) },
- { 0x106, RSCreate(RS1280x1024, RS4bpp ) },
-#endif
- { 0, 0 }};
-
-/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
-static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */
-static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
-static int inv24 = 0; /* "matrox:inv24" */
-static int cross4MB = -1; /* "matrox:cross4MB" */
-static int disabled = 0; /* "matrox:disabled" */
-static int noaccel = 0; /* "matrox:noaccel" */
-static int nopan = 0; /* "matrox:nopan" */
-static int no_pci_retry = 0; /* "matrox:nopciretry" */
-static int novga = 0; /* "matrox:novga" */
-static int nobios = 0; /* "matrox:nobios" */
-static int noinit = 1; /* "matrox:init" */
-static int inverse = 0; /* "matrox:inverse" */
-static int hwcursor = 1; /* "matrox:nohwcursor" */
-static int blink = 1; /* "matrox:noblink" */
-static int sgram = 0; /* "matrox:sgram" */
-#ifdef CONFIG_MTRR
-static int mtrr = 1; /* "matrox:nomtrr" */
-#endif
-static int grayscale = 0; /* "matrox:grayscale" */
-static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */
-static int dev = -1; /* "matrox:dev:xxxxx" */
-static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */
-static int depth = -1; /* "matrox:depth:xxxxx" */
-static unsigned int xres = 0; /* "matrox:xres:xxxxx" */
-static unsigned int yres = 0; /* "matrox:yres:xxxxx" */
-static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */
-static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */
-static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */
-static unsigned int left = ~0; /* "matrox:left:xxxxx" */
-static unsigned int right = ~0; /* "matrox:right:xxxxx" */
-static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */
-static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */
-static int sync = -1; /* "matrox:sync:xxxxx" */
-static unsigned int fv = 0; /* "matrox:fv:xxxxx" */
-static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */
-static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */
-static char fontname[64]; /* "matrox:font:xxxxx" */
-
-#ifndef MODULE
-static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */
-#endif
-
-#ifndef MODULE
-int __init matroxfb_setup(char *options) {
- char *this_opt;
-
- DBG("matroxfb_setup")
-
- fontname[0] = '\0';
-
- if (!options || !*options)
- return 0;
-
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
- if (!*this_opt) continue;
-
- dprintk("matroxfb_setup: option %s\n", this_opt);
-
- if (!strncmp(this_opt, "dev:", 4))
- dev = simple_strtoul(this_opt+4, NULL, 0);
- else if (!strncmp(this_opt, "depth:", 6)) {
- switch (simple_strtoul(this_opt+6, NULL, 0)) {
- case 0: depth = RSText; break;
- case 4: depth = RS4bpp; break;
- case 8: depth = RS8bpp; break;
- case 15:depth = RS15bpp; break;
- case 16:depth = RS16bpp; break;
- case 24:depth = RS24bpp; break;
- case 32:depth = RS32bpp; break;
- default:
- printk(KERN_ERR "matroxfb: unsupported color depth\n");
- }
- } else if (!strncmp(this_opt, "xres:", 5))
- xres = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "yres:", 5))
- yres = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "vslen:", 6))
- vslen = simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "hslen:", 6))
- hslen = simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "left:", 5))
- left = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "right:", 6))
- right = simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "upper:", 6))
- upper = simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "lower:", 6))
- lower = simple_strtoul(this_opt+6, NULL, 0);
- else if (!strncmp(this_opt, "pixclock:", 9))
- pixclock = simple_strtoul(this_opt+9, NULL, 0);
- else if (!strncmp(this_opt, "sync:", 5))
- sync = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "vesa:", 5))
- vesa = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "font:", 5))
- strncpy(fontname, this_opt+5, sizeof(fontname)-1);
- else if (!strncmp(this_opt, "maxclk:", 7))
- maxclk = simple_strtoul(this_opt+7, NULL, 0);
- else if (!strncmp(this_opt, "fh:", 3))
- fh = simple_strtoul(this_opt+3, NULL, 0);
- else if (!strncmp(this_opt, "fv:", 3))
- fv = simple_strtoul(this_opt+3, NULL, 0);
- else if (!strncmp(this_opt, "mem:", 4))
- mem = simple_strtoul(this_opt+4, NULL, 0);
- else if (!strncmp(this_opt, "mode:", 5))
- strncpy(videomode, this_opt+5, sizeof(videomode)-1);
-#ifdef CONFIG_FB_OF
- else if (!strncmp(this_opt, "vmode:", 6)) {
- unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
- if (vmode > 0 && vmode <= VMODE_MAX)
- default_vmode = vmode;
- } else if (!strncmp(this_opt, "cmode:", 6)) {
- unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
- switch (cmode) {
- case 0:
- case 8:
- default_cmode = CMODE_8;
- break;
- case 15:
- case 16:
- default_cmode = CMODE_16;
- break;
- case 24:
- case 32:
- default_cmode = CMODE_32;
- break;
- }
- }
-#endif
- else if (!strncmp(this_opt, "fastfont:", 9))
- fastfont = simple_strtoul(this_opt+9, NULL, 0);
- else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */
- fastfont = 0;
- else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */
- disabled = 1;
- else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */
- disabled = 0;
- else if (!strcmp(this_opt, "sgram")) /* nosgram == sdram */
- sgram = 1;
- else if (!strcmp(this_opt, "sdram"))
- sgram = 0;
- else {
- int value = 1;
-
- if (!strncmp(this_opt, "no", 2)) {
- value = 0;
- this_opt += 2;
- }
- if (! strcmp(this_opt, "inverse"))
- inverse = value;
- else if (!strcmp(this_opt, "accel"))
- noaccel = !value;
- else if (!strcmp(this_opt, "pan"))
- nopan = !value;
- else if (!strcmp(this_opt, "pciretry"))
- no_pci_retry = !value;
- else if (!strcmp(this_opt, "vga"))
- novga = !value;
- else if (!strcmp(this_opt, "bios"))
- nobios = !value;
- else if (!strcmp(this_opt, "init"))
- noinit = !value;
-#ifdef CONFIG_MTRR
- else if (!strcmp(this_opt, "mtrr"))
- mtrr = value;
-#endif
- else if (!strcmp(this_opt, "inv24"))
- inv24 = value;
- else if (!strcmp(this_opt, "cross4MB"))
- cross4MB = value;
- else if (!strcmp(this_opt, "hwcursor"))
- hwcursor = value;
- else if (!strcmp(this_opt, "blink"))
- blink = value;
- else if (!strcmp(this_opt, "grayscale"))
- grayscale = value;
- else {
- strncpy(videomode, this_opt, sizeof(videomode)-1);
- }
- }
- }
- return 0;
-}
-#endif /* !MODULE */
-
-static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
- vaddr_t vm;
- unsigned int offs;
- unsigned int offs2;
- unsigned char store;
- unsigned char bytes[32];
- unsigned char* tmp;
- unsigned long cbase;
- unsigned long mbase;
- unsigned int clen;
- unsigned int mlen;
-
- DBG("matroxfb_getmemory")
-
- vm = ACCESS_FBINFO(video.vbase);
- maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */
- /* at least 2MB */
- if (maxSize < 0x0200000) return 0;
- if (maxSize > 0x2000000) maxSize = 0x2000000;
-
- mga_outb(M_EXTVGA_INDEX, 0x03);
- mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
-
- store = mga_readb(vm, 0x1234);
- tmp = bytes;
- for (offs = 0x100000; offs < maxSize; offs += 0x200000)
- *tmp++ = mga_readb(vm, offs);
- for (offs = 0x100000; offs < maxSize; offs += 0x200000)
- mga_writeb(vm, offs, 0x02);
- if (ACCESS_FBINFO(features.accel.has_cacheflush))
- mga_outb(M_CACHEFLUSH, 0x00);
- else
- mga_writeb(vm, 0x1234, 0x99);
- cbase = mbase = 0;
- clen = mlen = 0;
- for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
- if (mga_readb(vm, offs) != 0x02)
- continue;
- mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
- if (mga_readb(vm, offs))
- continue;
- if (offs - 0x100000 == cbase + clen) {
- clen += 0x200000;
- } else {
- cbase = offs - 0x100000;
- clen = 0x200000;
- }
- if ((clen > mlen)
-#ifndef MATROX_2MB_WITH_4MB_ADDON
- && (cbase == 0)
-#endif
- ) {
- mbase = cbase;
- mlen = clen;
- }
- }
- tmp = bytes;
- for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
- mga_writeb(vm, offs2, *tmp++);
- mga_writeb(vm, 0x1234, store);
-
- mga_outb(M_EXTVGA_INDEX, 0x03);
- mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80);
-
- *realOffset = mbase;
- *realSize = mlen;
-#ifdef CONFIG_FB_MATROX_MILLENIUM
- ACCESS_FBINFO(interleave) = !(!isMillenium(MINFO) || (mbase & 0x3FFFFF) || (mlen & 0x3FFFFF));
-#endif
- return 1;
-}
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
- static const int vxres_mill2[] = { 512, 640, 768, 800, 832, 960,
- 1024, 1152, 1280, 1600, 1664, 1920,
- 2048, 0};
- static const int vxres_mill1[] = { 640, 768, 800, 960,
- 1024, 1152, 1280, 1600, 1920,
- 2048, 0};
-
- DBG("Ti3026_preinit")
-
- ACCESS_FBINFO(millenium) = 1;
- ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL);
- ACCESS_FBINFO(capable.cfb4) = 1;
- ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */
- ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
- ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
-
- if (ACCESS_FBINFO(devflags.noinit))
- return 0;
- /* preserve VGA I/O, BIOS and PPC */
- hw->MXoptionReg &= 0xC0000100;
- hw->MXoptionReg |= 0x002C0000;
- if (ACCESS_FBINFO(devflags.novga))
- hw->MXoptionReg &= ~0x00000100;
- if (ACCESS_FBINFO(devflags.nobios))
- hw->MXoptionReg &= ~0x40000000;
- if (ACCESS_FBINFO(devflags.nopciretry))
- hw->MXoptionReg |= 0x20000000;
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-
- ACCESS_FBINFO(accel.ramdac_rev) = inTi3026(PMINFO TVP3026_XSILICONREV);
-
- outTi3026(PMINFO TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
- outTi3026(PMINFO TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
- outTi3026(PMINFO TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
-
- outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
- outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0x00);
- outTi3026(PMINFO TVP3026_XPIXPLLDATA, 0x00);
-
- mga_outb(M_MISC_REG, 0x67);
-
- outTi3026(PMINFO TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
-
- mga_outl(M_RESET, 1);
- udelay(250);
- mga_outl(M_RESET, 0);
- udelay(250);
- mga_outl(M_MACCESS, 0x00008000);
- udelay(10);
- return 0;
-}
-
-static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
-
- DBG("Ti3026_reset")
-
- matroxfb_fastfont_init(MINFO);
-
- ti3026_ramdac_init(PMINFO hw);
-}
-#endif
-
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct matrox_switch matrox_millenium = {
- Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore
-};
-#endif
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct matrox_switch matrox_mystique = {
- MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore
-};
-#endif
-
-#ifdef CONFIG_FB_MATROX_G100
-static struct matrox_switch matrox_G100 = {
- MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore
-};
-#endif
-
-struct video_board {
- int maxvram;
- int maxdisplayable;
- int accelID;
- struct matrox_switch* lowlevel;
- };
-#ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct video_board vbMillenium __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W, &matrox_millenium};
-static struct video_board vbMillenium2 __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W, &matrox_millenium};
-static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
-#endif /* CONFIG_FB_MATROX_MILLENIUM */
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct video_board vbMystique __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG, &matrox_mystique};
-#endif /* CONFIG_FB_MATROX_MYSTIQUE */
-#ifdef CONFIG_FB_MATROX_G100
-static struct video_board vbG100 __initdata = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100, &matrox_G100};
-static struct video_board vbG200 __initdata = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200, &matrox_G100};
-#ifdef CONFIG_FB_MATROX_32MB
-/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
- whole 32MB */
-static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
-#else
-static struct video_board vbG400 __initdata = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400, &matrox_G100};
-#endif
-#endif
-
-#define DEVF_VIDEO64BIT 0x01
-#define DEVF_SWAPS 0x02
-#define DEVF_MILLENIUM 0x04
-#define DEVF_MILLENIUM2 0x08
-#define DEVF_CROSS4MB 0x10
-#define DEVF_TEXT4B 0x20
-#define DEVF_DDC_8_2 0x40
-#define DEVF_DMA 0x80
-#define DEVF_SUPPORT32MB 0x100
-#define DEVF_ANY_VXRES 0x200
-#define DEVF_TEXT16B 0x400
-
-#define DEVF_G100 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
-#define DEVF_G200 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
-#define DEVF_G400 (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B)
-
-static struct board {
- unsigned short vendor, device, rev, svid, sid;
- unsigned int flags;
- unsigned int maxclk;
- struct video_board* base;
- const char* name;
- } dev_list[] __initdata = {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF,
- 0, 0,
- DEVF_MILLENIUM | DEVF_TEXT4B,
- 230000,
- &vbMillenium,
- "Millennium (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, 0xFF,
- 0, 0,
- DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
- 220000,
- &vbMillenium2,
- "Millennium II (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, 0xFF,
- 0, 0,
- DEVF_MILLENIUM | DEVF_MILLENIUM2 | DEVF_SWAPS,
- 250000,
- &vbMillenium2A,
- "Millennium II (AGP)"},
-#endif
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02,
- 0, 0,
- DEVF_VIDEO64BIT,
- 180000,
- &vbMystique,
- "Mystique (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0xFF,
- 0, 0,
- DEVF_VIDEO64BIT | DEVF_SWAPS,
- 220000,
- &vbMystique,
- "Mystique 220 (PCI)"},
-#endif
-#ifdef CONFIG_FB_MATROX_G100
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_PCI,
- DEVF_G100,
- 230000,
- &vbG100,
- "MGA-G100 (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100, 0xFF,
- 0, 0,
- DEVF_G100,
- 230000,
- &vbG100,
- "unknown G100 (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
- DEVF_G100,
- 230000,
- &vbG100,
- "MGA-G100 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MGA_G100_AGP,
- DEVF_G100,
- 230000,
- &vbG100,
- "MGA-G100 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
- PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G100_AGP,
- DEVF_G100,
- 230000,
- &vbG100,
- "MGA-G100 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
- DEVF_G100,
- 230000,
- &vbG100,
- "Productiva G100 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, 0xFF,
- 0, 0,
- DEVF_G100,
- 230000,
- &vbG100,
- "unknown G100 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
- 0, 0,
- DEVF_G200,
- 250000,
- &vbG200,
- "unknown G200 (PCI)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_GENERIC,
- DEVF_G200,
- 220000,
- &vbG200,
- "MGA-G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
- DEVF_G200,
- 230000,
- &vbG200,
- "Mystique G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
- DEVF_G200,
- 250000,
- &vbG200,
- "Millennium G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- PCI_SS_VENDOR_ID_MATROX, PCI_SS_ID_MATROX_MARVEL_G200_AGP,
- DEVF_G200,
- 230000,
- &vbG200,
- "Marvel G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- PCI_SS_VENDOR_ID_SIEMENS_NIXDORF, PCI_SS_ID_SIEMENS_MGA_G200_AGP,
- DEVF_G200,
- 230000,
- &vbG200,
- "MGA-G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, 0xFF,
- 0, 0,
- DEVF_G200,
- 230000,
- &vbG200,
- "unknown G200 (AGP)"},
- {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400_AGP, 0xFF,
- 0, 0,
- DEVF_G400,
- 360000,
- &vbG400,
- "unknown G400 (AGP)"},
-#endif
- {0, 0, 0xFF,
- 0, 0,
- 0,
- 0,
- NULL,
- NULL}};
-
-#ifndef MODULE
- /* it cannot be static const struct due to __initdata
- marker */
- static struct fb_videomode defaultmode __initdata = {
- /* 640x480 @ 60Hz, 31.5 kHz */
- NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
- 0, FB_VMODE_NONINTERLACED
- };
-#endif /* !MODULE */
-
-static int __init initMatrox2(WPMINFO struct display* d, struct board* b){
- unsigned long ctrlptr_phys = 0;
- unsigned long video_base_phys = 0;
- unsigned int memsize;
- struct matrox_hw_state* hw = ACCESS_FBINFO(currenthw);
-
- DBG("initMatrox2")
-
- /* set default values... */
- vesafb_defined.accel_flags = FB_ACCELF_TEXT;
-
- ACCESS_FBINFO(hw_switch) = b->base->lowlevel;
- ACCESS_FBINFO(devflags.accelerator) = b->base->accelID;
- ACCESS_FBINFO(max_pixel_clock) = b->maxclk;
-
- printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
- ACCESS_FBINFO(capable.plnwt) = 1;
- ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
- if (b->flags & DEVF_TEXT4B) {
- ACCESS_FBINFO(devflags.vgastep) = 4;
- ACCESS_FBINFO(devflags.textmode) = 4;
- ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
- } else if (b->flags & DEVF_TEXT16B) {
- ACCESS_FBINFO(devflags.vgastep) = 16;
- ACCESS_FBINFO(devflags.textmode) = 1;
- ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP16;
- } else {
- ACCESS_FBINFO(devflags.vgastep) = 8;
- ACCESS_FBINFO(devflags.textmode) = 1;
- ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
- }
-#ifdef CONFIG_FB_MATROX_32MB
- ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
-#endif
- ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
- ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
- ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
-
- if (ACCESS_FBINFO(capable.cross4MB) < 0)
- ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
- if (b->flags & DEVF_SWAPS) {
- ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
- video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
- } else {
- ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
- video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
- }
- if (!ctrlptr_phys) {
- printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
- return -EINVAL;
- }
- if (!video_base_phys) {
- printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
- return -EINVAL;
- }
- if (mga_ioremap(ctrlptr_phys, 16384, MGA_IOREMAP_MMIO, &ACCESS_FBINFO(mmio.vbase))) {
- printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
- return -ENOMEM;
- }
- ACCESS_FBINFO(mmio.base) = ctrlptr_phys;
- ACCESS_FBINFO(mmio.len) = 16384;
- memsize = b->base->maxvram;
-/* convert mem (autodetect k, M) */
- if (mem < 1024) mem *= 1024;
- if (mem < 0x00100000) mem *= 1024;
-
- if (mem && (mem < memsize))
- memsize = mem;
- ACCESS_FBINFO(video.base) = video_base_phys;
- if (mga_ioremap(video_base_phys, memsize, MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
- printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
- video_base_phys, memsize);
- mga_iounmap(ACCESS_FBINFO(mmio.vbase));
- return -ENOMEM;
- }
- {
- u_int32_t cmd;
- u_int32_t mga_option;
-
- /* Matrox MilleniumII is deactivated on bootup, but address
- regions are assigned to board. So we have to enable it */
- pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, &mga_option);
- pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
- mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
- if ((cmd & PCI_COMMAND_MEMORY) !=
- PCI_COMMAND_MEMORY) {
- /* But if we have to enable it, we have probably to
- disable VGA I/O and BIOS... Sure? */
- dprintk(KERN_WARNING "matroxfb: PCI BIOS did not enable device!\n");
- cmd = (cmd | PCI_COMMAND_MEMORY) & ~PCI_COMMAND_VGA_PALETTE;
- mga_option &= 0xBFFFFEFF;
- /* we must not enable VGA, BIOS if PCI BIOS did not enable device itself */
- ACCESS_FBINFO(devflags.novga) = 1;
- ACCESS_FBINFO(devflags.nobios) = 1;
- /* we must initialize device if PCI BIOS did not enable it.
- It probably means that it is second head ... */
- ACCESS_FBINFO(devflags.noinit) = 0;
- }
- mga_option |= MX_OPTION_BSWAP;
- if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, NULL)) {
- if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
- printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
- }
- mga_option |= 0x20000000;
- ACCESS_FBINFO(devflags.nopciretry) = 1;
- }
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, cmd);
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, mga_option);
- hw->MXoptionReg = mga_option;
-
- /* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
- /* maybe preinit() candidate, but it is same... for all devices... at this time... */
- pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_MGA_INDEX, 0x00003C00);
- }
-
- if (ACCESS_FBINFO(hw_switch)->preinit(PMINFO hw)) {
- mga_iounmap(ACCESS_FBINFO(video.vbase));
- mga_iounmap(ACCESS_FBINFO(mmio.vbase));
- return -ENXIO;
- }
-
- {
- unsigned int offs;
-
- if (!matroxfb_getmemory(PMINFO memsize, &offs, &ACCESS_FBINFO(video.len)) || !ACCESS_FBINFO(video.len)) {
- printk(KERN_ERR "matroxfb: cannot determine memory size\n");
- mga_iounmap(ACCESS_FBINFO(video.vbase));
- mga_iounmap(ACCESS_FBINFO(mmio.vbase));
- return -ENOMEM;
- }
-#ifdef MATROX_2MB_WITH_4MB_ADDON
-#ifdef FBCON_HAS_CFB24
- {
- unsigned int end = offs + ACCESS_FBINFO(video.len);
-
- if (offs)
- offs = ((offs - 1) / (4096 * 3) + 1) * 4096 * 3;
- ACCESS_FBINFO(video.len) = end - offs;
- }
-#endif
- ACCESS_FBINFO(devflags.ydstorg) = offs;
- video_base_phys += offs;
- if (offs)
- ACCESS_FBINFO(capable.text) = 0;
-#else
- ACCESS_FBINFO(devflags.ydstorg) = 0;
-#endif
- }
- ACCESS_FBINFO(currcon) = -1;
- ACCESS_FBINFO(currcon_display) = d;
- mga_iounmap(ACCESS_FBINFO(video.vbase));
- ACCESS_FBINFO(video.base) = video_base_phys;
- if (mga_ioremap(video_base_phys, ACCESS_FBINFO(video.len), MGA_IOREMAP_FB, &ACCESS_FBINFO(video.vbase))) {
- printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
- video_base_phys, ACCESS_FBINFO(video.len));
- mga_iounmap(ACCESS_FBINFO(mmio.vbase));
- return -ENOMEM;
- }
- ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
- if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
- ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
-#ifdef CONFIG_MTRR
- if (mtrr) {
- ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
- ACCESS_FBINFO(mtrr.vram_valid) = 1;
- printk(KERN_INFO "matroxfb: MTRR's turned on\n");
- }
-#endif /* CONFIG_MTRR */
-
- if (!ACCESS_FBINFO(devflags.novga))
- request_region(0x3C0, 32, "matrox");
- ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
-
-/* validate params, autodetect k, M */
- if (fh < 1000) fh *= 1000; /* 1kHz minimum */
- if (maxclk < 1000) maxclk *= 1000; /* kHz -> Hz, MHz -> kHz */
- if (maxclk < 1000000) maxclk *= 1000; /* kHz -> Hz, 1MHz minimum */
- if (vesa != ~0)
- vesa &= 0x1DFF; /* mask out clearscreen, acceleration and so on */
-
- ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
- ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
- ACCESS_FBINFO(fbcon.monspecs.vfmin) = 0;
- ACCESS_FBINFO(fbcon.monspecs.vfmax) = fv;
- ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */
-
-/* static settings */
- for (RSptr = vesamap; RSptr->vesa; RSptr++) {
- if (RSptr->vesa == vesa) break;
- }
- if (!RSptr->vesa) {
- printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
- RSptr = vesamap;
- }
- {
- int res = RSResolution(RSptr->info)-1;
- if (left == ~0)
- left = timmings[res].left;
- if (!xres)
- xres = timmings[res].xres;
- if (right == ~0)
- right = timmings[res].right;
- if (!hslen)
- hslen = timmings[res].hslen;
- if (upper == ~0)
- upper = timmings[res].upper;
- if (!yres)
- yres = timmings[res].yres;
- if (lower == ~0)
- lower = timmings[res].lower;
- if (!vslen)
- vslen = timmings[res].vslen;
- if (!(fv||fh||maxclk||pixclock))
- fv = timmings[res].vfreq;
- if (depth == -1)
- depth = RSDepth(RSptr->info);
- }
- if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
- strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
- }
- vesafb_defined.red = colors[depth-1].red;
- vesafb_defined.green = colors[depth-1].green;
- vesafb_defined.blue = colors[depth-1].blue;
- vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
- vesafb_defined.grayscale = grayscale;
- vesafb_defined.vmode = 0;
- if (noaccel)
- vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
-
- strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA");
- ACCESS_FBINFO(fbcon.changevar) = NULL;
- ACCESS_FBINFO(fbcon.node) = -1;
- ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops;
- ACCESS_FBINFO(fbcon.disp) = d;
- ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
- ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
- ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
- ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
- ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
-
-#ifndef MODULE
- /* mode database is marked __init ... */
- {
- fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
- NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
- }
-#endif /* !MODULE */
-
- /* mode modifiers */
- if (hslen)
- vesafb_defined.hsync_len = hslen;
- if (vslen)
- vesafb_defined.vsync_len = vslen;
- if (left != ~0)
- vesafb_defined.left_margin = left;
- if (right != ~0)
- vesafb_defined.right_margin = right;
- if (upper != ~0)
- vesafb_defined.upper_margin = upper;
- if (lower != ~0)
- vesafb_defined.lower_margin = lower;
- if (xres)
- vesafb_defined.xres = xres;
- if (yres)
- vesafb_defined.yres = yres;
- if (sync != -1)
- vesafb_defined.sync = sync;
- else if (vesafb_defined.sync == ~0) {
- vesafb_defined.sync = 0;
- if (yres < 400)
- vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
- else if (yres < 480)
- vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
- }
-
- /* fv, fh, maxclk limits was specified */
- {
- unsigned int tmp;
-
- if (fv) {
- tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
- + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
- if ((tmp < fh) || (fh == 0)) fh = tmp;
- }
- if (fh) {
- tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
- + vesafb_defined.right_margin + vesafb_defined.hsync_len);
- if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
- }
- maxclk = (maxclk + 499) / 500;
- if (maxclk) {
- tmp = (2000000000 + maxclk) / maxclk;
- if (tmp > pixclock) pixclock = tmp;
- }
- }
- if (pixclock) {
- if (pixclock < 2000) /* > 500MHz */
- pixclock = 4000; /* 250MHz */
- if (pixclock > 1000000)
- pixclock = 1000000; /* 1MHz */
- vesafb_defined.pixclock = pixclock;
- }
-
- /* FIXME: Where to move this?! */
-#if defined(CONFIG_FB_OF)
-#if defined(CONFIG_FB_COMPAT_XPMAC)
- strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */
- strncat(ACCESS_FBINFO(matrox_name), b->name, 26);
- if (!console_fb_info)
- console_fb_info = &ACCESS_FBINFO(fbcon);
-#endif
- if ((xres <= 640) && (yres <= 480)) {
- struct fb_var_screeninfo var;
- if (default_vmode == VMODE_NVRAM) {
- default_vmode = nvram_read_byte(NV_VMODE);
- if (default_vmode <= 0 || default_vmode > VMODE_MAX)
- default_vmode = VMODE_CHOOSE;
- }
- if (default_vmode <= 0 || default_vmode > VMODE_MAX)
- default_vmode = VMODE_640_480_60;
- if (default_cmode == CMODE_NVRAM)
- default_cmode = nvram_read_byte(NV_CMODE);
- if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
- default_cmode = CMODE_8;
- if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
- var.accel_flags = vesafb_defined.accel_flags;
- var.xoffset = var.yoffset = 0;
- vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
- }
- }
-#endif
- vesafb_defined.xres_virtual = vesafb_defined.xres;
- if (nopan) {
- vesafb_defined.yres_virtual = vesafb_defined.yres;
- } else {
- vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
- to yres_virtual * xres_virtual < 2^32 */
- }
- if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
- printk(KERN_ERR "matroxfb: cannot set required parameters\n");
- return -EINVAL;
- }
-
- printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
- vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
- vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
- printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
- ACCESS_FBINFO(video.base), vaddr_va(ACCESS_FBINFO(video.vbase)), ACCESS_FBINFO(video.len));
-
-/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
- * and we do not want currcon == 0 for subsequent framebuffers */
-
- if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
- return -EINVAL;
- }
- printk("fb%d: %s frame buffer device\n",
- GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
- if (ACCESS_FBINFO(currcon) < 0) {
- /* there is no console on this fb... but we have to initialize hardware
- * until someone tells me what is proper thing to do */
- printk(KERN_INFO "fb%d: initializing hardware\n",
- GET_FB_IDX(ACCESS_FBINFO(fbcon.node)));
- matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon));
- }
- return 0;
-}
-
-static struct matrox_fb_info* fb_list = NULL;
-
-static int __init matrox_init(void){
- struct pci_dev* pdev = NULL;
-
- DBG("matrox_init")
-
- if (disabled)
- return -ENXIO;
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
- struct board* b;
- u_int8_t rev;
- u_int16_t svid;
- u_int16_t sid;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- svid = pdev->subsystem_vendor;
- sid = pdev->subsystem_device;
- for (b = dev_list; b->vendor; b++) {
- if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
- if (b->svid)
- if ((b->svid != svid) || (b->sid != sid)) continue;
- if (dev <= 0) {
- struct matrox_fb_info* minfo;
- struct display* d;
- int err;
-
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
- minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL);
- if (minfo) {
- d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL);
- if (d) {
-#else
- minfo = &global_mxinfo;
- d = &global_disp;
-#endif
- memset(MINFO, 0, sizeof(*MINFO));
- memset(d, 0, sizeof(*d));
-
- ACCESS_FBINFO(currenthw) = &ACCESS_FBINFO(hw1);
- ACCESS_FBINFO(newhw) = &ACCESS_FBINFO(hw2);
- ACCESS_FBINFO(pcidev) = pdev;
- /* CMDLINE */
- memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname)));
- /* DEVFLAGS */
- ACCESS_FBINFO(devflags.inverse) = inverse;
- ACCESS_FBINFO(devflags.novga) = novga;
- ACCESS_FBINFO(devflags.nobios) = nobios;
- ACCESS_FBINFO(devflags.noinit) = noinit;
- ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry;
- ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24;
- ACCESS_FBINFO(devflags.precise_width) = option_precise_width;
- ACCESS_FBINFO(devflags.hwcursor) = hwcursor;
- ACCESS_FBINFO(devflags.blink) = blink;
- ACCESS_FBINFO(devflags.sgram) = sgram;
- ACCESS_FBINFO(capable.cross4MB) = cross4MB;
-
- ACCESS_FBINFO(fastfont.size) = fastfont;
-
- ACCESS_FBINFO(cursor.state) = CM_ERASE;
- ACCESS_FBINFO(cursor.timer.prev) = ACCESS_FBINFO(cursor.timer.next) = NULL;
- ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO;
- spin_lock_init(&ACCESS_FBINFO(lock.DAC));
-
- err = initMatrox2(PMINFO d, b);
- if (!err) {
- ACCESS_FBINFO(next_fb) = fb_list;
- fb_list = MINFO;
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
- goto leave;
-#else
- return 0;
-#endif
- }
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
- kfree(d);
- }
- kfree(minfo);
- }
-#endif
- }
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
-leave:;
-#endif
- if (dev == 0) return 0;
- if (dev > 0) dev--;
- break;
- }
- }
- return 0;
-}
-
-#ifndef MODULE
-static int __init initialized = 0;
-
-int __init matroxfb_init(void)
-{
- DBG("matroxfb_init")
-
- if (!initialized) {
- initialized = 1;
- matrox_init();
- }
- if (!fb_list) return -ENXIO;
- return 0;
-}
-
-#if defined(CONFIG_FB_OF)
-int __init matrox_of_init(struct device_node *dp){
- DBG("matrox_of_init");
-
- if (!initialized) {
- initialized = 1;
- matrox_init();
- }
- if (!fb_list) return -ENXIO;
- return 0;
-}
-#endif /* CONFIG_FB_OF */
-
-#else
-
-MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
-MODULE_PARM(mem, "i");
-MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
-MODULE_PARM(disabled, "i");
-MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled), meaningless for module (default=0)");
-MODULE_PARM(noaccel, "i");
-MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
-MODULE_PARM(nopan, "i");
-MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
-MODULE_PARM(no_pci_retry, "i");
-MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
-MODULE_PARM(novga, "i");
-MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
-MODULE_PARM(nobios, "i");
-MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
-MODULE_PARM(noinit, "i");
-MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
-MODULE_PARM(mtrr, "i");
-MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
-MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
-MODULE_PARM(inv24, "i");
-MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
-MODULE_PARM(inverse, "i");
-MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
-MODULE_PARM(dev, "i");
-MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
-#else
-MODULE_PARM(dev, "i");
-MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=first working)");
-#endif
-MODULE_PARM(vesa, "i");
-MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
-MODULE_PARM(xres, "i");
-MODULE_PARM_DESC(xres, "Horizontal resolutioni (px), overrides xres from vesa (default=vesa)");
-MODULE_PARM(yres, "i");
-MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
-MODULE_PARM(upper, "i");
-MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
-MODULE_PARM(lower, "i");
-MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
-MODULE_PARM(vslen, "i");
-MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
-MODULE_PARM(left, "i");
-MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
-MODULE_PARM(right, "i");
-MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
-MODULE_PARM(hslen, "i");
-MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
-MODULE_PARM(pixclock, "i");
-MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
-MODULE_PARM(sync, "i");
-MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
-MODULE_PARM(depth, "i");
-MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
-MODULE_PARM(maxclk, "i");
-MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
-MODULE_PARM(fh, "i");
-MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
-MODULE_PARM(fv, "i");
-MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
-"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n");
-MODULE_PARM(hwcursor, "i");
-MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)");
-MODULE_PARM(blink, "i");
-MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)");
-MODULE_PARM(fastfont, "i");
-MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)");
-MODULE_PARM(grayscale, "i");
-MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
-MODULE_PARM(cross4MB, "i");
-MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
-#ifdef CONFIG_FB_OF
-MODULE_PARM(vmode, "i");
-MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
-MODULE_PARM(cmode, "i");
-MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
-#endif
-
-int __init init_module(void){
-
- DBG("init_module")
-
-#ifdef DEBUG
- if( disabled )
- return -ENXIO;
-#endif /* DEBUG */
-
- if (depth == 0)
- depth = RSText;
- else if (depth == 4)
- depth = RS4bpp;
- else if (depth == 8)
- depth = RS8bpp;
- else if (depth == 15)
- depth = RS15bpp;
- else if (depth == 16)
- depth = RS16bpp;
- else if (depth == 24)
- depth = RS24bpp;
- else if (depth == 32)
- depth = RS32bpp;
- else if (depth != -1) {
- printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
- depth = -1;
- }
- matrox_init();
- if (!fb_list) return -ENXIO;
- return 0;
-}
-
-void cleanup_module(void) {
-
- DBG("cleanup_module")
-
-#ifdef DEBUG
- if( disabled )
- return;
-#endif /* DEBUG */
-
- while (fb_list) {
- struct matrox_fb_info* minfo;
-
- minfo = fb_list;
- fb_list = fb_list->next_fb;
- unregister_framebuffer(&ACCESS_FBINFO(fbcon));
- del_timer(&ACCESS_FBINFO(cursor.timer));
-#ifdef CONFIG_MTRR
- if (ACCESS_FBINFO(mtrr.vram_valid))
- mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
-#endif
- mga_iounmap(ACCESS_FBINFO(mmio.vbase));
- mga_iounmap(ACCESS_FBINFO(video.vbase));
-#ifdef CONFIG_FB_MATROX_MULTIHEAD
- kfree_s(ACCESS_FBINFO(fbcon.disp), sizeof(struct display));
- kfree_s(minfo, sizeof(struct matrox_fb_info));
-#endif
- }
-}
-#endif /* MODULE */
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c
index 696845f8a..1180d3ee0 100644
--- a/drivers/video/vgacon.c
+++ b/drivers/video/vgacon.c
@@ -106,7 +106,14 @@ static int vga_can_do_color = 0; /* Do we support colors? */
static unsigned int vga_default_font_height; /* Height of default screen font */
static unsigned char vga_video_type; /* Card type */
static unsigned char vga_hardscroll_enabled;
+#ifdef CONFIG_IA64_SOFTSDV_HACKS
+/*
+ * SoftSDV doesn't have hardware assist VGA scrolling
+ */
+static unsigned char vga_hardscroll_user_enable = 0;
+#else
static unsigned char vga_hardscroll_user_enable = 1;
+#endif
static unsigned char vga_font_is_default = 1;
static int vga_vesa_blanked;
static int vga_palette_blanked;
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 823893aad..11b485b05 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -77,10 +77,6 @@ static struct file_operations proc_bus_zorro_operations = {
read: proc_bus_zorro_read,
};
-static struct inode_operations proc_bus_zorro_inode_operations = {
- &proc_bus_zorro_operations, /* default base directory file-ops */
-};
-
static int
get_zorro_dev_info(char *buf, char **start, off_t pos, int count)
{
@@ -118,7 +114,7 @@ static int __init zorro_proc_attach_device(u_int slot)
entry = create_proc_entry(name, 0, proc_bus_zorro_dir);
if (!entry)
return -ENOMEM;
- entry->ops = &proc_bus_zorro_inode_operations;
+ entry->proc_fops = &proc_bus_zorro_operations;
entry->data = &zorro_autocon[slot];
entry->size = sizeof(struct zorro_dev);
return 0;
diff --git a/fs/Config.in b/fs/Config.in
index eb4a5f78a..ff031ab44 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -24,7 +24,7 @@ dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CON
dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
-tristate 'Compressed ROM file sytem support' CONFIG_CRAMFS
+tristate 'Compressed ROM file system support' CONFIG_CRAMFS
tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
if [ "$CONFIG_ISO9660_FS" != "n" ]; then
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index abda2e2d0..9e1a59ed2 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -96,6 +96,7 @@ extern struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry);
/* dir_*.c */
extern struct inode_operations adfs_dir_inode_operations;
+extern struct file_operations adfs_dir_operations;
extern struct adfs_dir_ops adfs_f_dir_ops;
extern struct adfs_dir_ops adfs_fplus_dir_ops;
@@ -103,6 +104,7 @@ extern int adfs_dir_update(struct super_block *sb, struct object_info *obj);
/* file.c */
extern struct inode_operations adfs_file_inode_operations;
+extern struct file_operations adfs_file_operations;
extern inline __u32 signed_asl(__u32 val, signed int shift)
{
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 140e28598..a7da5eeda 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -188,14 +188,8 @@ out:
return ret;
}
-static ssize_t
-adfs_dir_no_read(struct file *filp, char *buf, size_t siz, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-static struct file_operations adfs_dir_operations = {
- read: adfs_dir_no_read,
+struct file_operations adfs_dir_operations = {
+ read: generic_read_dir,
readdir: adfs_readdir,
fsync: file_fsync,
};
@@ -296,7 +290,6 @@ struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry)
* directories can handle most operations...
*/
struct inode_operations adfs_dir_inode_operations = {
- &adfs_dir_operations, /* default directory file-ops */
- NULL, /* create */
- adfs_lookup, /* lookup */
+ lookup: adfs_lookup,
+ setattr: adfs_notify_change,
};
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index 0d5f4346e..0cd28ca47 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -33,7 +33,7 @@
* We have mostly NULLs here: the current defaults are OK for
* the adfs filesystem.
*/
-static struct file_operations adfs_file_operations = {
+struct file_operations adfs_file_operations = {
read: generic_file_read,
mmap: generic_file_mmap,
fsync: file_fsync,
@@ -43,8 +43,9 @@ static struct file_operations adfs_file_operations = {
};
struct inode_operations adfs_file_inode_operations = {
- &adfs_file_operations, /* default file operations */
+ setattr: adfs_notify_change,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+ &adfs_file_operations, /* default file operations */
readpage: generic_readpage,
bmap: adfs_bmap,
#endif
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 7a759c050..6eb08c857 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -283,10 +283,12 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
inode->i_atime =
inode->i_ctime = adfs_adfs2unix_time(inode);
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(inode->i_mode)) {
inode->i_op = &adfs_dir_inode_operations;
- else if (S_ISREG(inode->i_mode)) {
+ inode->i_fop = &adfs_dir_operations;
+ } else if (S_ISREG(inode->i_mode)) {
inode->i_op = &adfs_file_inode_operations;
+ inode->i_fop = &adfs_file_operations;
inode->i_mapping->a_ops = &adfs_aops;
inode->u.adfs_i.mmu_private = inode->i_size;
}
@@ -298,17 +300,6 @@ out:
}
/*
- * This is no longer a valid way to obtain the metadata associated with the
- * inode number on this filesystem. This means that this filesystem cannot
- * be shared via NFS.
- */
-void adfs_read_inode(struct inode *inode)
-{
- adfs_error(inode->i_sb, "unsupported method of reading inode");
- make_bad_inode(inode);
-}
-
-/*
* Validate and convert a changed access mode/time to their ADFS equivalents.
* adfs_write_inode will actually write the information back to the directory
* later.
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 7b7eb2d0e..7c80a6958 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -231,17 +231,10 @@ static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
}
static struct super_operations adfs_sops = {
- adfs_read_inode, /* read_inode */
- adfs_write_inode, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- adfs_notify_change, /* notify_change */
- adfs_put_super, /* put_super */
- NULL, /* write_super */
- adfs_statfs, /* statfs */
- adfs_remount, /* remount_fs */
- NULL, /* clear_inode */
- NULL /* umount_begin */
+ write_inode: adfs_write_inode,
+ put_super: adfs_put_super,
+ statfs: adfs_statfs,
+ remount_fs: adfs_remount,
};
static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index b554daf0c..3fc8409b0 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -25,10 +25,9 @@
#include <linux/amigaffs.h>
static int affs_readdir(struct file *, void *, filldir_t);
-static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *);
-static struct file_operations affs_dir_operations = {
- read: affs_dir_read,
+struct file_operations affs_dir_operations = {
+ read: generic_read_dir,
readdir: affs_readdir,
fsync: file_fsync,
};
@@ -37,24 +36,17 @@ static struct file_operations affs_dir_operations = {
* directories can handle most operations...
*/
struct inode_operations affs_dir_inode_operations = {
- &affs_dir_operations, /* default directory file-ops */
- affs_create, /* create */
- affs_lookup, /* lookup */
- affs_link, /* link */
- affs_unlink, /* unlink */
- affs_symlink, /* symlink */
- affs_mkdir, /* mkdir */
- affs_rmdir, /* rmdir */
- NULL, /* mknod */
- affs_rename, /* rename */
+ create: affs_create,
+ lookup: affs_lookup,
+ link: affs_link,
+ unlink: affs_unlink,
+ symlink: affs_symlink,
+ mkdir: affs_mkdir,
+ rmdir: affs_rmdir,
+ rename: affs_rename,
+ setattr: affs_notify_change,
};
-static ssize_t
-affs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int
affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 8881fe3e4..069964acb 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -43,7 +43,7 @@ static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count,
static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos);
static int alloc_ext_cache(struct inode *inode);
-static struct file_operations affs_file_operations = {
+struct file_operations affs_file_operations = {
read: generic_file_read,
write: affs_file_write,
mmap: generic_file_mmap,
@@ -51,47 +51,16 @@ static struct file_operations affs_file_operations = {
};
struct inode_operations affs_file_inode_operations = {
- &affs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- affs_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ truncate: affs_truncate,
+ setattr: affs_notify_change,
};
-static struct file_operations affs_file_operations_ofs = {
+struct file_operations affs_file_operations_ofs = {
read: affs_file_read_ofs,
write: affs_file_write_ofs,
fsync: file_fsync,
};
-struct inode_operations affs_file_inode_operations_ofs = {
- &affs_file_operations_ofs, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- affs_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
-};
-
#define AFFS_ISINDEX(x) ((x < 129) || \
(x < 512 && (x & 1) == 0) || \
(x < 1024 && (x & 3) == 0) || \
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index e0d411861..1e5647c39 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -162,22 +162,24 @@ affs_read_inode(struct inode *inode)
sys_tz.tz_minuteswest * 60;
affs_brelse(bh);
- inode->i_op = NULL;
if (S_ISREG(inode->i_mode)) {
if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
- inode->i_op = &affs_file_inode_operations_ofs;
+ inode->i_op = &affs_file_inode_operations;
+ inode->i_fop = &affs_file_operations_ofs;
return;
}
inode->i_op = &affs_file_inode_operations;
+ inode->i_fop = &affs_file_operations;
inode->i_mapping->a_ops = &affs_aops;
inode->u.affs_i.mmu_private = inode->i_size;
} else if (S_ISDIR(inode->i_mode)) {
/* Maybe it should be controlled by mount parameter? */
inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations;
+ inode->i_fop = &affs_dir_operations;
}
else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &affs_symlink_inode_operations;
inode->i_data.a_ops = &affs_symlink_aops;
}
}
@@ -295,24 +297,16 @@ affs_new_inode(const struct inode *dir)
sb = dir->i_sb;
inode->i_sb = sb;
- inode->i_flags = 0;
if (!(block = affs_new_header((struct inode *)dir))) {
iput(inode);
return NULL;
}
- inode->i_count = 1;
- inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_ino = block;
- inode->i_op = NULL;
- inode->i_blocks = 0;
- inode->i_size = 0;
- inode->i_mode = 0;
- inode->i_blksize = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->u.affs_i.i_original = 0;
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index d2c27b9d1..8ebf8319b 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -274,9 +274,11 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode)
pr_debug("AFFS: ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
- inode->i_op = &affs_file_inode_operations_ofs;
+ inode->i_op = &affs_file_inode_operations;
+ inode->i_fop = &affs_file_operations_ofs;
else {
inode->i_op = &affs_file_inode_operations;
+ inode->i_fop = &affs_file_operations;
inode->i_mapping->a_ops = &affs_aops;
inode->u.affs_i.mmu_private = inode->i_size;
}
@@ -314,6 +316,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
goto out;
inode->i_op = &affs_dir_inode_operations;
+ inode->i_fop = &affs_dir_operations;
error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
if (error)
goto out_iput;
@@ -403,7 +406,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
if (!inode)
goto out;
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &affs_symlink_inode_operations;
inode->i_data.a_ops = &affs_symlink_aops;
inode->i_mode = S_IFLNK | 0777;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
@@ -495,6 +498,7 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
goto out;
inode->i_op = oldinode->i_op;
+ inode->i_fop = oldinode->i_fop;
inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode);
inode->u.affs_i.i_original = oldinode->i_ino;
inode->u.affs_i.i_hlink = 1;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index fe5fd1042..9eed5c09e 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -98,15 +98,14 @@ affs_write_super(struct super_block *sb)
}
static struct super_operations affs_sops = {
- affs_read_inode,
- affs_write_inode,
- affs_put_inode,
- affs_delete_inode,
- affs_notify_change,
- affs_put_super,
- affs_write_super,
- affs_statfs,
- affs_remount
+ read_inode: affs_read_inode,
+ write_inode: affs_write_inode,
+ put_inode: affs_put_inode,
+ delete_inode: affs_delete_inode,
+ put_super: affs_put_super,
+ write_super: affs_write_super,
+ statfs: affs_statfs,
+ remount_fs: affs_remount,
};
static int
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 885d5099d..cd02b93dd 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -74,3 +74,9 @@ fail:
struct address_space_operations affs_symlink_aops = {
readpage: affs_symlink_readpage,
};
+
+struct inode_operations affs_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ setattr: affs_notify_change,
+};
diff --git a/fs/attr.c b/fs/attr.c
index 1639308b9..304ebd3db 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -92,8 +92,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
attr->ia_mtime = now;
if (inode->i_sb && inode->i_sb->s_op &&
- inode->i_sb->s_op->notify_change)
- error = inode->i_sb->s_op->notify_change(dentry, attr);
+ inode->i_op->setattr)
+ error = inode->i_op->setattr(dentry, attr);
else {
error = inode_change_ok(inode, attr);
if (!error)
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 731f9168f..51305918b 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -140,6 +140,8 @@ struct autofs_dir_ent *autofs_expire(struct super_block *,struct autofs_sb_info
extern struct inode_operations autofs_root_inode_operations;
extern struct inode_operations autofs_symlink_inode_operations;
extern struct inode_operations autofs_dir_inode_operations;
+extern struct file_operations autofs_root_operations;
+extern struct file_operations autofs_dir_operations;
/* Initializing function */
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index a62fd6c54..b71c3a819 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -42,13 +42,12 @@ static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
return NULL;
}
-static struct file_operations autofs_dir_operations = {
+struct file_operations autofs_dir_operations = {
+ read: generic_read_dir,
readdir: autofs_dir_readdir,
};
struct inode_operations autofs_dir_inode_operations = {
- &autofs_dir_operations, /* file operations */
- NULL, /* create */
- autofs_dir_lookup, /* lookup */
+ lookup: autofs_dir_lookup,
};
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index 77844cf0e..a67ca9822 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -60,15 +60,12 @@ static void autofs_read_inode(struct inode *inode);
static void autofs_write_inode(struct inode *inode);
static struct super_operations autofs_sops = {
- autofs_read_inode,
- autofs_write_inode,
- autofs_put_inode,
- autofs_delete_inode,
- NULL, /* notify_change */
- autofs_put_super,
- NULL, /* write_super */
- autofs_statfs,
- NULL
+ read_inode: autofs_read_inode,
+ write_inode: autofs_write_inode,
+ put_inode: autofs_put_inode,
+ delete_inode: autofs_delete_inode,
+ put_super: autofs_put_super,
+ statfs: autofs_statfs,
};
static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
@@ -300,8 +297,8 @@ static void autofs_read_inode(struct inode *inode)
/* Initialize to the default case (stub directory) */
- inode->i_op = NULL;
inode->i_op = &autofs_dir_inode_operations;
+ inode->i_fop = &autofs_dir_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
inode->i_nlink = 2;
inode->i_size = 0;
@@ -312,6 +309,7 @@ static void autofs_read_inode(struct inode *inode)
if ( ino == AUTOFS_ROOT_INO ) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &autofs_root_inode_operations;
+ inode->i_fop = &autofs_root_operations;
inode->i_uid = inode->i_gid = 0; /* Changed in read_super */
return;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index e2c03ff34..ea517f0b1 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -23,20 +23,18 @@ static int autofs_root_rmdir(struct inode *,struct dentry *);
static int autofs_root_mkdir(struct inode *,struct dentry *,int);
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
-static struct file_operations autofs_root_operations = {
+struct file_operations autofs_root_operations = {
+ read: generic_read_dir,
readdir: autofs_root_readdir,
ioctl: autofs_root_ioctl,
};
struct inode_operations autofs_root_inode_operations = {
- &autofs_root_operations, /* file operations */
- NULL, /* create */
- autofs_root_lookup, /* lookup */
- NULL, /* link */
- autofs_root_unlink, /* unlink */
- autofs_root_symlink, /* symlink */
- autofs_root_mkdir, /* mkdir */
- autofs_root_rmdir, /* rmdir */
+ lookup: autofs_root_lookup,
+ unlink: autofs_root_unlink,
+ symlink: autofs_root_symlink,
+ mkdir: autofs_root_mkdir,
+ rmdir: autofs_root_rmdir,
};
static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 102f7213e..b55afd6c4 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -155,6 +155,8 @@ int autofs4_expire_multi(struct super_block *, struct autofs_sb_info *, int *);
extern struct inode_operations autofs4_symlink_inode_operations;
extern struct inode_operations autofs4_dir_inode_operations;
extern struct inode_operations autofs4_root_inode_operations;
+extern struct file_operations autofs4_dir_operations;
+extern struct file_operations autofs4_root_operations;
/* Initializing function */
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 9c8bd133f..40d149272 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -410,10 +410,13 @@ static void autofs4_read_inode(struct inode *inode)
if (S_ISDIR(inf->mode)) {
inode->i_nlink = 2;
- if (inode->i_ino == AUTOFS_ROOT_INO)
+ if (inode->i_ino == AUTOFS_ROOT_INO) {
inode->i_op = &autofs4_root_inode_operations;
- else
+ inode->i_fop = &autofs4_root_operations;
+ } else {
inode->i_op = &autofs4_dir_inode_operations;
+ inode->i_fop = &autofs4_dir_operations;
+ }
} else if (S_ISLNK(inf->mode)) {
inode->i_op = &autofs4_symlink_inode_operations;
}
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index b7e4bcd0c..05045d408 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -25,33 +25,31 @@ static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *);
-static struct file_operations autofs4_root_operations = {
- readdir: autofs4_dir_readdir, /* readdir */
- ioctl: autofs4_root_ioctl, /* ioctl */
+struct file_operations autofs4_root_operations = {
+ read: generic_read_dir,
+ readdir: autofs4_dir_readdir,
+ ioctl: autofs4_root_ioctl,
};
-struct inode_operations autofs4_root_inode_operations = {
- &autofs4_root_operations, /* file operations */
-
- lookup: autofs4_root_lookup, /* lookup */
- unlink: autofs4_dir_unlink, /* unlink */
- symlink: autofs4_dir_symlink, /* symlink */
- mkdir: autofs4_dir_mkdir, /* mkdir */
- rmdir: autofs4_dir_rmdir, /* rmdir */
+struct file_operations autofs4_dir_operations = {
+ read: generic_read_dir,
+ readdir: autofs4_dir_readdir,
};
-static struct file_operations autofs4_dir_operations = {
- readdir: autofs4_dir_readdir, /* readdir */
+struct inode_operations autofs4_root_inode_operations = {
+ lookup: autofs4_root_lookup,
+ unlink: autofs4_dir_unlink,
+ symlink: autofs4_dir_symlink,
+ mkdir: autofs4_dir_mkdir,
+ rmdir: autofs4_dir_rmdir,
};
struct inode_operations autofs4_dir_inode_operations = {
- &autofs4_dir_operations, /* file operations */
-
- lookup: autofs4_dir_lookup, /* lookup */
- unlink: autofs4_dir_unlink, /* unlink */
- symlink: autofs4_dir_symlink, /* symlink */
- mkdir: autofs4_dir_mkdir, /* mkdir */
- rmdir: autofs4_dir_rmdir, /* rmdir */
+ lookup: autofs4_dir_lookup,
+ unlink: autofs4_dir_unlink,
+ symlink: autofs4_dir_symlink,
+ mkdir: autofs4_dir_mkdir,
+ rmdir: autofs4_dir_rmdir,
};
static inline struct dentry *nth_child(struct dentry *dir, int nr)
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 931a32a4e..adb26f415 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -47,21 +47,20 @@ static struct file_operations bad_file_ops =
struct inode_operations bad_inode_ops =
{
- &bad_file_ops, /* default file operations */
- EIO_ERROR, /* create */
- EIO_ERROR, /* lookup */
- EIO_ERROR, /* link */
- EIO_ERROR, /* unlink */
- EIO_ERROR, /* symlink */
- EIO_ERROR, /* mkdir */
- EIO_ERROR, /* rmdir */
- EIO_ERROR, /* mknod */
- EIO_ERROR, /* rename */
- EIO_ERROR, /* readlink */
- bad_follow_link, /* follow_link */
- EIO_ERROR, /* truncate */
- EIO_ERROR, /* permission */
- EIO_ERROR /* revalidate */
+ create: EIO_ERROR,
+ lookup: EIO_ERROR,
+ link: EIO_ERROR,
+ unlink: EIO_ERROR,
+ symlink: EIO_ERROR,
+ mkdir: EIO_ERROR,
+ rmdir: EIO_ERROR,
+ mknod: EIO_ERROR,
+ rename: EIO_ERROR,
+ readlink: EIO_ERROR,
+ follow_link: bad_follow_link,
+ truncate: EIO_ERROR,
+ permission: EIO_ERROR,
+ revalidate: EIO_ERROR,
};
@@ -78,6 +77,7 @@ void make_bad_inode(struct inode * inode)
inode->i_mode = S_IFREG;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &bad_inode_ops;
+ inode->i_fop = &bad_file_ops;
}
/*
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 83b3e517b..44e96e101 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -23,11 +23,6 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
static struct buffer_head * bfs_find_entry(struct inode * dir,
const char * name, int namelen, struct bfs_dirent ** res_dir);
-static ssize_t bfs_dir_read(struct file * f, char * buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
{
struct inode * dir = f->f_dentry->d_inode;
@@ -75,10 +70,10 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
return 0;
}
-static struct file_operations bfs_dir_operations = {
- read: bfs_dir_read,
- readdir: bfs_readdir,
- fsync: file_fsync,
+struct file_operations bfs_dir_operations = {
+ read: generic_read_dir,
+ readdir: bfs_readdir,
+ fsync: file_fsync,
};
extern void dump_imap(const char *, struct super_block *);
@@ -107,6 +102,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
inode->i_op = &bfs_file_inops;
+ inode->i_fop = &bfs_file_operations;
inode->i_mapping->a_ops = &bfs_aops;
inode->i_mode = mode;
inode->i_ino = inode->iu_dsk_ino = ino;
@@ -256,15 +252,10 @@ end_rename:
}
struct inode_operations bfs_dir_inops = {
- default_file_ops: &bfs_dir_operations,
create: bfs_create,
lookup: bfs_lookup,
link: bfs_link,
unlink: bfs_unlink,
- symlink: NULL,
- mkdir: NULL,
- rmdir: NULL,
- mknod: NULL,
rename: bfs_rename,
};
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index fe90391f1..aba9cefd1 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -18,7 +18,7 @@
#define dprintf(x...)
#endif
-static struct file_operations bfs_file_operations = {
+struct file_operations bfs_file_operations = {
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
@@ -156,5 +156,4 @@ struct address_space_operations bfs_aops = {
};
struct inode_operations bfs_file_inops = {
- default_file_ops: &bfs_file_operations,
};
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 14e440f27..79c7c6507 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -59,12 +59,13 @@ static void bfs_read_inode(struct inode * inode)
if (di->i_vtype == BFS_VDIR) {
inode->i_mode |= S_IFDIR;
inode->i_op = &bfs_dir_inops;
+ inode->i_fop = &bfs_dir_operations;
} else if (di->i_vtype == BFS_VREG) {
inode->i_mode |= S_IFREG;
inode->i_op = &bfs_file_inops;
+ inode->i_fop = &bfs_file_operations;
inode->i_mapping->a_ops = &bfs_aops;
- } else
- inode->i_op = NULL;
+ }
inode->i_uid = di->i_uid;
inode->i_gid = di->i_gid;
@@ -209,15 +210,10 @@ static void bfs_write_super(struct super_block *s)
static struct super_operations bfs_sops = {
read_inode: bfs_read_inode,
write_inode: bfs_write_inode,
- put_inode: NULL,
delete_inode: bfs_delete_inode,
- notify_change: NULL,
put_super: bfs_put_super,
write_super: bfs_write_super,
statfs: bfs_statfs,
- remount_fs: NULL,
- clear_inode: NULL,
- umount_begin: NULL
};
void dump_imap(const char *prefix, struct super_block * s)
@@ -337,7 +333,6 @@ static struct file_system_type bfs_fs_type = {
name: "bfs",
fs_flags: FS_REQUIRES_DEV,
read_super: bfs_read_super,
- next: NULL
};
#ifdef MODULE
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 743375bc9..7ce625d6d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -225,8 +225,8 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
goto out;
if (!elf_check_arch(interp_elf_ex->e_machine))
goto out;
- if (!interpreter_dentry->d_inode->i_op ||
- !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)
+ if (!interpreter_dentry->d_inode->i_fop ||
+ !interpreter_dentry->d_inode->i_fop->mmap)
goto out;
/*
@@ -432,9 +432,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
}
#endif
- if (!bprm->dentry->d_inode->i_op ||
- !bprm->dentry->d_inode->i_op->default_file_ops ||
- !bprm->dentry->d_inode->i_op->default_file_ops->mmap)
+ if (!bprm->dentry->d_inode->i_fop||!bprm->dentry->d_inode->i_fop->mmap)
goto out;
/* Now read in all of the header information */
@@ -838,7 +836,7 @@ do_load_elf_library(int fd)
/* First of all, some simple consistency checks */
if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
!elf_check_arch(elf_ex.e_machine) ||
- (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+ (!inode->i_fop || !inode->i_fop->mmap))
goto out_putf;
/* Now read in all of the header information */
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 446a22623..2c76e5592 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -36,9 +36,8 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
/* First of all, some simple consistency checks */
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
(!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
- (!bprm->dentry->d_inode->i_op ||
- !bprm->dentry->d_inode->i_op->default_file_ops ||
- !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
+ (!bprm->dentry->d_inode->i_fop ||
+ !bprm->dentry->d_inode->i_fop->mmap)) {
return -ENOEXEC;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b5d665c29..c455a735d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -193,7 +193,7 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
if (blk_size[MAJOR(dev)])
size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
else
- size = INT_MAX;
+ size = (loff_t) INT_MAX << BLOCK_SIZE_BITS;
if (offset > size)
left = 0;
@@ -672,10 +672,6 @@ struct file_operations def_blk_fops = {
ioctl: blkdev_ioctl,
};
-struct inode_operations blkdev_inode_operations = {
- &def_blk_fops, /* default file operations */
-};
-
const char * bdevname(kdev_t dev)
{
static char buffer[32];
diff --git a/fs/buffer.c b/fs/buffer.c
index 7da594637..6d31f18e8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1532,10 +1532,10 @@ static int __block_commit_write(struct inode *inode, struct page *page,
* mark_buffer_uptodate() functions propagate buffer state into the
* page struct once IO has completed.
*/
-static inline int __block_read_full_page(struct inode *inode, struct page *page,
- get_block_t *get_block)
+int block_read_full_page(struct page *page, get_block_t *get_block)
{
- unsigned long iblock;
+ struct inode *inode = (struct inode*)page->mapping->host;
+ unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
unsigned long kaddr = 0;
@@ -1550,6 +1550,7 @@ static inline int __block_read_full_page(struct inode *inode, struct page *page,
blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
iblock = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+ lblock = (inode->i_size+blocksize-1) >> inode->i_sb->s_blocksize_bits;
bh = head;
nr = 0;
i = 0;
@@ -1559,7 +1560,8 @@ static inline int __block_read_full_page(struct inode *inode, struct page *page,
continue;
if (!buffer_mapped(bh)) {
- get_block(inode, iblock, bh, 0);
+ if (iblock < lblock)
+ get_block(inode, iblock, bh, 0);
if (!buffer_mapped(bh)) {
if (!kaddr)
kaddr = kmap(page);
@@ -1704,13 +1706,30 @@ int generic_commit_write(struct file *file, struct page *page,
int block_write_full_page(struct page *page, get_block_t *get_block)
{
struct inode *inode = (struct inode*)page->mapping->host;
- return __block_write_full_page(inode, page, get_block);
-}
+ unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset;
+ int err;
-int block_read_full_page(struct page *page, get_block_t *get_block)
-{
- struct inode *inode = (struct inode*)page->mapping->host;
- return __block_read_full_page(inode, page, get_block);
+ /* easy case */
+ if (page->index < end_index)
+ return __block_write_full_page(inode, page, get_block);
+
+ /* things got complicated... */
+ offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+ /* OK, are we completely out? */
+ if (page->index >= end_index+1 || !offset)
+ return -EIO;
+ /* Sigh... will have to work, then... */
+ err = __block_prepare_write(inode, page, 0, offset, get_block);
+ if (!err) {
+ memset((char *)page_address(page)+offset, 0, PAGE_CACHE_SIZE-offset);
+ __block_commit_write(inode,page,0,offset);
+done:
+ kunmap(page);
+ return err;
+ }
+ ClearPageUptodate(page);
+ goto done;
}
int generic_block_bmap(struct address_space *mapping, long block, get_block_t *get_block)
@@ -1735,10 +1754,10 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
mark_buffer_uptodate(bh, uptodate);
kiobuf = bh->b_kiobuf;
- if (atomic_dec_and_test(&kiobuf->io_count))
- kiobuf->end_io(kiobuf);
if (!uptodate)
kiobuf->errno = -EIO;
+ if (atomic_dec_and_test(&kiobuf->io_count))
+ kiobuf->end_io(kiobuf);
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 88e954eeb..47f853c14 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -25,6 +25,12 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
return 1;
}
+static struct inode_operations coda_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ setattr: coda_notify_change,
+};
+
/* cnode.c */
static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
{
@@ -35,12 +41,14 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
coda_vattr_to_iattr(inode, attr);
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &coda_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_fop = &coda_file_operations;
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &coda_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_fop = &coda_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &coda_symlink_inode_operations;
inode->i_data.a_ops = &coda_symlink_aops;
} else
init_special_inode(inode, inode->i_mode, attr->va_rdev);
@@ -259,6 +267,7 @@ int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
*inode = iget(sb, CTL_INO);
if ( *inode ) {
(*inode)->i_op = &coda_ioctl_inode_operations;
+ (*inode)->i_fop = &coda_ioctl_operations;
(*inode)->i_mode = 00444;
error = 0;
} else {
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 3eecd4a5a..dac8e8884 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -65,24 +65,22 @@ struct dentry_operations coda_dentry_operations =
struct inode_operations coda_dir_inode_operations =
{
- &coda_dir_operations,
- coda_create, /* create */
- coda_lookup, /* lookup */
- coda_link, /* link */
- coda_unlink, /* unlink */
- coda_symlink, /* symlink */
- coda_mkdir, /* mkdir */
- coda_rmdir, /* rmdir */
- coda_mknod, /* mknod */
- coda_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- coda_permission, /* permission */
- coda_revalidate_inode /* revalidate */
+ create: coda_create,
+ lookup: coda_lookup,
+ link: coda_link,
+ unlink: coda_unlink,
+ symlink: coda_symlink,
+ mkdir: coda_mkdir,
+ rmdir: coda_rmdir,
+ mknod: coda_mknod,
+ rename: coda_rename,
+ permission: coda_permission,
+ revalidate: coda_revalidate_inode,
+ setattr: coda_notify_change,
};
struct file_operations coda_dir_operations = {
+ read: generic_read_dir,
readdir: coda_readdir,
open: coda_open,
release: coda_release,
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 82f661111..ab805cf11 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -33,21 +33,9 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
int coda_fsync(struct file *, struct dentry *dentry);
struct inode_operations coda_file_inode_operations = {
- &coda_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- coda_permission, /* permission */
- coda_revalidate_inode /* revalidate */
+ permission: coda_permission,
+ revalidate: coda_revalidate_inode,
+ setattr: coda_notify_change,
};
struct file_operations coda_file_operations = {
@@ -133,7 +121,7 @@ void coda_prepare_openfile(struct inode *i, struct file *coda_file,
cont_file->f_flags = coda_file->f_flags;
atomic_set(&cont_file->f_count, atomic_read(&coda_file->f_count));
cont_file->f_owner = coda_file->f_owner;
- cont_file->f_op = cont_inode->i_op->default_file_ops;
+ cont_file->f_op = cont_inode->i_fop;
cont_file->f_dentry = cont_dentry;
cont_file->f_dentry->d_inode = cont_inode;
return ;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index b389b623e..1f82ef5bd 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -34,7 +34,6 @@
/* VFS super_block ops */
static struct super_block *coda_read_super(struct super_block *, void *, int);
static void coda_read_inode(struct inode *);
-static int coda_notify_change(struct dentry *dentry, struct iattr *attr);
static void coda_put_inode(struct inode *);
static void coda_delete_inode(struct inode *);
static void coda_put_super(struct super_block *);
@@ -44,17 +43,11 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf,
/* exported operations */
struct super_operations coda_super_operations =
{
- coda_read_inode, /* read_inode */
- NULL, /* write_inode */
- coda_put_inode, /* put_inode */
- coda_delete_inode, /* delete_inode */
- coda_notify_change, /* notify_change */
- coda_put_super, /* put_super */
- NULL, /* write_super */
- coda_statfs, /* statfs */
- NULL, /* remount_fs */
- NULL, /* no clear inode */
- NULL /* umount attempt begin */
+ read_inode: coda_read_inode,
+ put_inode: coda_put_inode,
+ delete_inode: coda_delete_inode,
+ put_super: coda_put_super,
+ statfs: coda_statfs,
};
static struct super_block * coda_read_super(struct super_block *sb,
@@ -213,7 +206,7 @@ static void coda_delete_inode(struct inode *inode)
EXIT;
}
-static int coda_notify_change(struct dentry *de, struct iattr *iattr)
+int coda_notify_change(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
struct coda_inode_info *cii;
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 9a900a91a..533e83a54 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -34,21 +34,8 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
/* exported from this file */
struct inode_operations coda_ioctl_inode_operations =
{
- &coda_ioctl_operations,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- coda_ioctl_permission, /* permission */
- NULL /* revalidate */
+ permission: coda_ioctl_permission,
+ setattr: coda_notify_change,
};
struct file_operations coda_ioctl_operations = {
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index b9ab3c4c4..89b9719f5 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -23,8 +23,8 @@
#include "cramfs.h"
static struct super_operations cramfs_ops;
-static struct inode_operations cramfs_file_inode_operations;
static struct inode_operations cramfs_dir_inode_operations;
+static struct file_operations cramfs_directory_operations;
static struct address_space_operations cramfs_aops;
/* These two macros may change in future, to provide better st_ino
@@ -52,11 +52,12 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
without -noleaf option. */
insert_inode_hash(inode);
if (S_ISREG(inode->i_mode)) {
- inode->i_op = &cramfs_file_inode_operations;
+ inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &cramfs_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &cramfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &cramfs_directory_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_data.a_ops = &cramfs_aops;
} else {
@@ -352,41 +353,23 @@ static struct address_space_operations cramfs_aops = {
/*
* Our operations:
- *
- * A regular file can be read and mmap'ed.
*/
-static struct file_operations cramfs_file_operations = {
- read: generic_file_read,
- mmap: generic_file_mmap,
-};
/*
* A directory can only readdir
*/
static struct file_operations cramfs_directory_operations = {
+ read: generic_read_dir,
readdir: cramfs_readdir,
};
-static struct inode_operations cramfs_file_inode_operations = {
- &cramfs_file_operations,
-};
-
static struct inode_operations cramfs_dir_inode_operations = {
- &cramfs_directory_operations,
- NULL, /* create */
- cramfs_lookup, /* lookup */
+ lookup: cramfs_lookup,
};
static struct super_operations cramfs_ops = {
- NULL, /* read inode */
- NULL, /* write inode */
- NULL, /* put inode */
- NULL, /* delete inode */
- NULL, /* notify change */
- cramfs_put_super, /* put super */
- NULL, /* write super */
- cramfs_statfs, /* statfs */
- NULL /* remount */
+ put_super: cramfs_put_super,
+ statfs: cramfs_statfs,
};
static struct file_system_type cramfs_fs_type = {
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index ed9e04d69..ad50e21b9 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -729,7 +729,6 @@ static struct devfs_entry *search_for_entry_in_dir (struct devfs_entry *parent,
return search_for_entry (parent,
curr->u.symlink.linkname, curr->u.symlink.length,
FALSE, FALSE, NULL, TRUE);
- return curr;
} /* End Function search_for_entry_in_dir */
static struct devfs_entry *create_entry (struct devfs_entry *parent,
@@ -2185,6 +2184,7 @@ static int get_removable_partition (struct devfs_entry *dir, const char *name,
/* Superblock operations follow */
extern struct inode_operations devfs_iops;
+static struct file_operations devfs_fops;
static void devfs_read_inode (struct inode *inode)
{
@@ -2206,6 +2206,7 @@ static void devfs_read_inode (struct inode *inode)
inode->i_blocks = 0;
inode->i_blksize = 1024;
inode->i_op = &devfs_iops;
+ inode->i_fop = &devfs_fops;
inode->i_rdev = NODEV;
if ( S_ISCHR (di->mode) )
inode->i_rdev = MKDEV (di->de->u.fcb.u.device.major,
@@ -2219,7 +2220,7 @@ static void devfs_read_inode (struct inode *inode)
else printk ("%s: read_inode(%d): no block device from bdget()\n",
DEVFS_NAME, (int) inode->i_ino);
}
- else if ( S_ISFIFO (di->mode) ) inode->i_op = &fifo_inode_operations;
+ else if ( S_ISFIFO (di->mode) ) inode->i_fop = &def_fifo_fops;
else if ( S_ISREG (di->mode) ) inode->i_size = di->de->u.fcb.u.file.size;
inode->i_mode = di->mode;
inode->i_uid = di->uid;
@@ -2322,7 +2323,6 @@ static struct super_operations devfs_sops =
{
read_inode: devfs_read_inode,
write_inode: devfs_write_inode,
- notify_change: devfs_notify_change,
put_super: devfs_put_super,
statfs: devfs_statfs,
};
@@ -3126,16 +3126,16 @@ static struct dentry *devfs_follow_link (struct dentry *dentry,
static struct inode_operations devfs_iops =
{
- default_file_ops: &devfs_fops,
- lookup: devfs_lookup,
- link: devfs_link,
- unlink: devfs_unlink,
- symlink: devfs_symlink,
- mkdir: devfs_mkdir,
- rmdir: devfs_rmdir,
- mknod: devfs_mknod,
- readlink: devfs_readlink,
- follow_link: devfs_follow_link,
+ lookup: devfs_lookup,
+ link: devfs_link,
+ unlink: devfs_unlink,
+ symlink: devfs_symlink,
+ mkdir: devfs_mkdir,
+ rmdir: devfs_rmdir,
+ mknod: devfs_mknod,
+ readlink: devfs_readlink,
+ follow_link: devfs_follow_link,
+ setattr: devfs_notify_change,
};
static struct super_block *devfs_read_super (struct super_block *sb,
diff --git a/fs/devices.c b/fs/devices.c
index 607a96edd..2c53934b9 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -160,10 +160,6 @@ static struct file_operations def_chr_fops = {
open: chrdev_open,
};
-static struct inode_operations chrdev_inode_operations = {
- &def_chr_fops /* default file operations */
-};
-
/*
* Print device name (in decimal, hexadecimal or symbolic)
* Note: returns pointer to static data!
@@ -189,16 +185,15 @@ const char * cdevname(kdev_t dev)
void init_special_inode(struct inode *inode, umode_t mode, int rdev)
{
inode->i_mode = mode;
- inode->i_op = NULL;
if (S_ISCHR(mode)) {
- inode->i_op = &chrdev_inode_operations;
+ inode->i_fop = &def_chr_fops;
inode->i_rdev = to_kdev_t(rdev);
} else if (S_ISBLK(mode)) {
- inode->i_op = &blkdev_inode_operations;
+ inode->i_fop = &def_blk_fops;
inode->i_rdev = to_kdev_t(rdev);
inode->i_bdev = bdget(rdev);
} else if (S_ISFIFO(mode))
- inode->i_op = &fifo_inode_operations;
+ inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode))
;
else
diff --git a/fs/devpts/devpts_i.h b/fs/devpts/devpts_i.h
index fd6f71e0d..7dcd8cfd2 100644
--- a/fs/devpts/devpts_i.h
+++ b/fs/devpts/devpts_i.h
@@ -40,4 +40,4 @@ extern inline struct devpts_sb_info *SBI(struct super_block *sb)
}
extern struct inode_operations devpts_root_inode_operations;
-extern struct inode_operations devpts_device_inode_operations;
+extern struct file_operations devpts_root_operations;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 56433a343..dab1864cb 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -62,16 +62,10 @@ static void devpts_read_inode(struct inode *inode);
static void devpts_write_inode(struct inode *inode);
static struct super_operations devpts_sops = {
- devpts_read_inode,
- devpts_write_inode,
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- devpts_put_super,
- NULL, /* write_super */
- devpts_statfs,
- NULL, /* remount_fs */
- NULL, /* clear_inode */
+ read_inode: devpts_read_inode,
+ write_inode: devpts_write_inode,
+ put_super: devpts_put_super,
+ statfs: devpts_statfs,
};
static int devpts_parse_options(char *options, struct devpts_sb_info *sbi)
@@ -264,7 +258,6 @@ static void devpts_read_inode(struct inode *inode)
ino_t ino = inode->i_ino;
struct devpts_sb_info *sbi = SBI(inode->i_sb);
- inode->i_op = NULL;
inode->i_mode = 0;
inode->i_nlink = 0;
inode->i_size = 0;
@@ -276,6 +269,7 @@ static void devpts_read_inode(struct inode *inode)
if ( ino == 1 ) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &devpts_root_inode_operations;
+ inode->i_fop = &devpts_root_operations;
inode->i_nlink = 2;
return;
}
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index 5af3967e2..ed6258663 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -20,14 +20,13 @@ static int devpts_root_readdir(struct file *,void *,filldir_t);
static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
static int devpts_revalidate(struct dentry *, int);
-static struct file_operations devpts_root_operations = {
+struct file_operations devpts_root_operations = {
+ read: generic_read_dir,
readdir: devpts_root_readdir,
};
struct inode_operations devpts_root_inode_operations = {
- &devpts_root_operations, /* file operations */
- NULL, /* create */
- devpts_root_lookup, /* lookup */
+ lookup: devpts_root_lookup,
};
static struct dentry_operations devpts_dentry_operations = {
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 1283f9fdc..2829a60eb 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -8,14 +8,13 @@
static int efs_readdir(struct file *, void *, filldir_t);
-static struct file_operations efs_dir_operations = {
+struct file_operations efs_dir_operations = {
+ read: generic_read_dir,
readdir: efs_readdir,
};
struct inode_operations efs_dir_inode_operations = {
- &efs_dir_operations, /* default directory file-ops */
- NULL, /* create */
- efs_lookup, /* lookup */
+ lookup: efs_lookup,
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
diff --git a/fs/efs/file.c b/fs/efs/file.c
index 3c6de9b28..67f58987e 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -60,12 +60,3 @@ int efs_bmap(struct inode *inode, efs_block_t block) {
return efs_map_block(inode, block);
}
-
-static struct file_operations efs_file_operations = {
- read: generic_file_read,
- mmap: generic_file_mmap,
-};
-
-struct inode_operations efs_file_inode_operations = {
- &efs_file_operations, /* default file operations */
-};
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 0206ae6d5..93edbaac6 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -137,9 +137,10 @@ void efs_read_inode(struct inode *inode) {
switch (inode->i_mode & S_IFMT) {
case S_IFDIR:
inode->i_op = &efs_dir_inode_operations;
+ inode->i_fop = &efs_dir_operations;
break;
case S_IFREG:
- inode->i_op = &efs_file_inode_operations;
+ inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &efs_aops;
break;
case S_IFLNK:
@@ -161,16 +162,7 @@ void efs_read_inode(struct inode *inode) {
read_inode_error:
printk(KERN_WARNING "EFS: failed to read inode %lu\n", inode->i_ino);
- inode->i_mode = S_IFREG;
- inode->i_atime = 0;
- inode->i_ctime = 0;
- inode->i_mtime = 0;
- inode->i_nlink = 1;
- inode->i_size = 0;
- inode->i_blocks = 0;
- inode->i_uid = 0;
- inode->i_gid = 0;
- inode->i_op = NULL;
+ make_bad_inode(inode);
return;
}
diff --git a/fs/efs/super.c b/fs/efs/super.c
index df0f167cb..4522b2cfe 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -21,15 +21,9 @@ static struct file_system_type efs_fs_type = {
};
static struct super_operations efs_superblock_operations = {
- efs_read_inode, /* read_inode */
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- efs_put_super, /* put_super */
- NULL, /* write_super */
- efs_statfs, /* statfs */
- NULL /* remount */
+ read_inode: efs_read_inode,
+ put_super: efs_put_super,
+ statfs: efs_statfs,
};
int __init init_efs_fs(void) {
diff --git a/fs/exec.c b/fs/exec.c
index efbf9a8ef..886e9ab8c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -88,7 +88,7 @@ int open_dentry(struct dentry * dentry, int mode)
l = &inode->i_sb->s_files;
error = -EINVAL;
- if (!inode->i_op || !inode->i_op->default_file_ops)
+ if (!inode->i_fop)
goto out;
fd = get_unused_fd();
if (fd >= 0) {
@@ -101,7 +101,7 @@ int open_dentry(struct dentry * dentry, int mode)
f->f_dentry = dentry;
f->f_pos = 0;
f->f_reada = 0;
- f->f_op = inode->i_op->default_file_ops;
+ f->f_op = inode->i_fop;
if (f->f_op->open) {
error = f->f_op->open(inode,f);
if (error)
@@ -352,7 +352,7 @@ int read_exec(struct dentry *dentry, unsigned long offset,
struct inode * inode = dentry->d_inode;
int result = -ENOEXEC;
- if (!inode->i_op || !inode->i_op->default_file_ops)
+ if (!inode->i_fop)
goto end_readexec;
if (init_private_file(&file, dentry, 1))
goto end_readexec;
@@ -900,7 +900,7 @@ int do_coredump(long signr, struct pt_regs * regs)
if (!S_ISREG(inode->i_mode))
goto close_fail;
- if (!inode->i_op || !inode->i_op->default_file_ops)
+ if (!inode->i_fop)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 1d45d3514..29753ba9e 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -20,39 +20,15 @@
#include <linux/fs.h>
-
-
-static ssize_t ext2_dir_read (struct file * filp, char * buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int ext2_readdir(struct file *, void *, filldir_t);
-static struct file_operations ext2_dir_operations = {
- read: ext2_dir_read,
+struct file_operations ext2_dir_operations = {
+ read: generic_read_dir,
readdir: ext2_readdir,
ioctl: ext2_ioctl,
fsync: ext2_sync_file,
};
-/*
- * directories can handle most operations...
- */
-struct inode_operations ext2_dir_inode_operations = {
- &ext2_dir_operations, /* default directory file-ops */
- ext2_create, /* create */
- ext2_lookup, /* lookup */
- ext2_link, /* link */
- ext2_unlink, /* unlink */
- ext2_symlink, /* symlink */
- ext2_mkdir, /* mkdir */
- ext2_rmdir, /* rmdir */
- ext2_mknod, /* mknod */
- ext2_rename, /* rename */
-};
-
int ext2_check_dir_entry (const char * function, struct inode * dir,
struct ext2_dir_entry_2 * de,
struct buffer_head * bh,
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 5c4639175..d2c137e2c 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -95,7 +95,7 @@ static int ext2_open_file (struct inode * inode, struct file * filp)
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
*/
-static struct file_operations ext2_file_operations = {
+struct file_operations ext2_file_operations = {
llseek: ext2_file_lseek,
read: generic_file_read,
write: generic_file_write,
@@ -107,6 +107,5 @@ static struct file_operations ext2_file_operations = {
};
struct inode_operations ext2_file_inode_operations = {
- &ext2_file_operations,
truncate: ext2_truncate,
};
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index d519f6001..72437bb89 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -469,7 +469,6 @@ repeat:
inode->u.ext2_i.i_dir_acl = 0;
inode->u.ext2_i.i_dtime = 0;
inode->u.ext2_i.i_block_group = i;
- inode->i_op = NULL;
if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
inode->i_flags |= MS_SYNCHRONOUS;
insert_inode_hash(inode);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a520ab40f..cfaf5d4d3 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -50,7 +50,7 @@ void ext2_delete_inode (struct inode * inode)
if (is_bad_inode(inode) ||
inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
- return;
+ goto no_delete;
inode->u.ext2_i.i_dtime = CURRENT_TIME;
mark_inode_dirty(inode);
ext2_update_inode(inode, IS_SYNC(inode));
@@ -60,6 +60,10 @@ void ext2_delete_inode (struct inode * inode)
ext2_free_inode (inode);
unlock_kernel();
+ return;
+no_delete:
+ clear_inode(inode); /* We must guarantee clearing of inode... */
+ unlock_kernel();
}
#define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)]))
@@ -751,10 +755,12 @@ void ext2_read_inode (struct inode * inode)
/* Nothing to do */ ;
else if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
+ inode->i_fop = &ext2_file_operations;
inode->i_mapping->a_ops = &ext2_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &ext2_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
if (!inode->i_blocks)
inode->i_op = &ext2_fast_symlink_inode_operations;
else {
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index c2e5630ca..79caca33b 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -159,7 +159,7 @@ failure:
return NULL;
}
-struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
struct ext2_dir_entry_2 * de;
@@ -369,7 +369,7 @@ static inline void ext2_set_de_type(struct super_block *sb,
* If the create succeeds, we fill in the inode information
* with d_instantiate().
*/
-int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
+static int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh;
@@ -384,6 +384,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
return err;
inode->i_op = &ext2_file_inode_operations;
+ inode->i_fop = &ext2_file_operations;
inode->i_mapping->a_ops = &ext2_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -407,7 +408,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
return 0;
}
-int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
struct buffer_head * bh;
@@ -445,7 +446,7 @@ out_no_entry:
goto out;
}
-int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh, * dir_block;
@@ -462,6 +463,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
goto out;
inode->i_op = &ext2_dir_inode_operations;
+ inode->i_fop = &ext2_dir_operations;
inode->i_size = inode->i_sb->s_blocksize;
inode->i_blocks = 0;
dir_block = ext2_bread (inode, 0, 1, &err);
@@ -579,7 +581,7 @@ static int empty_dir (struct inode * inode)
return 1;
}
-int ext2_rmdir (struct inode * dir, struct dentry *dentry)
+static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -630,7 +632,7 @@ end_rmdir:
return retval;
}
-int ext2_unlink(struct inode * dir, struct dentry *dentry)
+static int ext2_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -678,7 +680,7 @@ end_unlink:
return retval;
}
-int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
+static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct inode * inode;
struct ext2_dir_entry_2 * de;
@@ -733,7 +735,7 @@ out_no_entry:
goto out;
}
-int ext2_link (struct dentry * old_dentry,
+static int ext2_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
@@ -776,7 +778,7 @@ int ext2_link (struct dentry * old_dentry,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir,struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -894,3 +896,18 @@ end_rename:
brelse (new_bh);
return retval;
}
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations ext2_dir_inode_operations = {
+ create: ext2_create,
+ lookup: ext2_lookup,
+ link: ext2_link,
+ unlink: ext2_unlink,
+ symlink: ext2_symlink,
+ mkdir: ext2_mkdir,
+ rmdir: ext2_rmdir,
+ mknod: ext2_mknod,
+ rename: ext2_rename,
+};
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 8a06df18b..b4cdc5868 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -121,15 +121,14 @@ void ext2_put_super (struct super_block * sb)
}
static struct super_operations ext2_sops = {
- ext2_read_inode,
- ext2_write_inode,
- ext2_put_inode,
- ext2_delete_inode,
- NULL,
- ext2_put_super,
- ext2_write_super,
- ext2_statfs,
- ext2_remount
+ read_inode: ext2_read_inode,
+ write_inode: ext2_write_inode,
+ put_inode: ext2_put_inode,
+ delete_inode: ext2_delete_inode,
+ put_super: ext2_put_super,
+ write_super: ext2_write_super,
+ statfs: ext2_statfs,
+ remount_fs: ext2_remount,
};
/*
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 804876270..8afd15335 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -34,14 +34,8 @@
#define PRINTK(X)
-static ssize_t fat_dir_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
struct file_operations fat_dir_operations = {
- read: fat_dir_read,
+ read: generic_read_dir,
readdir: fat_readdir,
ioctl: fat_dir_ioctl,
fsync: file_fsync,
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index 590b585dd..b8bcbd9e6 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -15,8 +15,6 @@
#include "msbuffer.h"
#include "tables.h"
-extern struct file_operations fat_dir_operations;
-
EXPORT_SYMBOL(fat_new_dir);
EXPORT_SYMBOL(fat_bmap);
EXPORT_SYMBOL(fat_get_block);
@@ -25,7 +23,6 @@ EXPORT_SYMBOL(fat_cache_inval_inode);
EXPORT_SYMBOL(fat_clear_inode);
EXPORT_SYMBOL(fat_date_unix2dos);
EXPORT_SYMBOL(fat_delete_inode);
-EXPORT_SYMBOL(fat_dir_operations);
EXPORT_SYMBOL(fat_esc2uni);
EXPORT_SYMBOL(fat_file_read);
EXPORT_SYMBOL(fat_file_write);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 0c535b8da..4481a6df9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -30,7 +30,7 @@
#define PRINTK(x)
#define Printk(x) printk x
-static struct file_operations fat_file_operations = {
+struct file_operations fat_file_operations = {
read: fat_file_read,
write: fat_file_write,
mmap: generic_file_mmap,
@@ -38,19 +38,8 @@ static struct file_operations fat_file_operations = {
};
struct inode_operations fat_file_inode_operations = {
- &fat_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- fat_truncate, /* truncate */
+ truncate: fat_truncate,
+ setattr: fat_notify_change,
};
ssize_t fat_file_read(
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 90b288832..63af738a3 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -375,6 +375,7 @@ static void fat_read_root(struct inode *inode)
inode->i_version = ++event;
inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;
inode->i_op = sbi->dir_ops;
+ inode->i_fop = &fat_dir_operations;
if (sbi->fat_bits == 32) {
MSDOS_I(inode)->i_start = sbi->root_cluster;
if ((nr = MSDOS_I(inode)->i_start) != 0) {
@@ -406,16 +407,11 @@ static void fat_read_root(struct inode *inode)
}
static struct super_operations fat_sops = {
- NULL,
- fat_write_inode,
- NULL,
- fat_delete_inode,
- fat_notify_change,
- fat_put_super,
- NULL, /* write_super */
- fat_statfs,
- NULL, /* remount */
- fat_clear_inode
+ write_inode: fat_write_inode,
+ delete_inode: fat_delete_inode,
+ put_super: fat_put_super,
+ statfs: fat_statfs,
+ clear_inode: fat_clear_inode,
};
/*
@@ -788,6 +784,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
~sbi->options.fs_umask) | S_IFDIR;
inode->i_op = sbi->dir_ops;
+ inode->i_fop = &fat_dir_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32) {
@@ -830,6 +827,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
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;
inode->i_mapping->a_ops = &fat_aops;
MSDOS_I(inode)->mmu_private = inode->i_size;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 255267da8..d6cebd646 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -259,7 +259,7 @@ out:
/* Table to convert sigio signal codes into poll band bitmaps */
-static int band_table[NSIGPOLL+1] = {
+static long band_table[NSIGPOLL+1] = {
~0,
POLLIN | POLLRDNORM, /* POLL_IN */
POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */
@@ -291,7 +291,7 @@ static void send_sigio_to_task(struct task_struct *p,
si.si_errno = 0;
si.si_code = reason;
if (reason < 0 || reason > NSIGPOLL)
- si.si_band = ~0;
+ si.si_band = ~0L;
else
si.si_band = band_table[reason];
si.si_fd = fa->fa_fd;
diff --git a/fs/fifo.c b/fs/fifo.c
index fd48328e9..33663cdf2 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -152,10 +152,6 @@ err_nolock_nocleanup:
* is contain the open that then fills in the correct operations
* depending on the access mode of the file...
*/
-static struct file_operations def_fifo_fops = {
+struct file_operations def_fifo_fops = {
open: fifo_open, /* will set read or write pipe_fops */
};
-
-struct inode_operations fifo_inode_operations = {
- &def_fifo_fops, /* default file operations */
-};
diff --git a/fs/file_table.c b/fs/file_table.c
index ee2f4e788..3f795576e 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -99,7 +99,7 @@ struct file * get_empty_filp(void)
/*
* Clear and initialize a (private) struct file for the given dentry,
* and call the open function (if any). The caller must verify that
- * inode->i_op and inode->i_op->default_file_ops are not NULL.
+ * inode->i_fop is not NULL.
*/
int init_private_file(struct file *filp, struct dentry *dentry, int mode)
{
@@ -109,7 +109,7 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
filp->f_dentry = dentry;
filp->f_uid = current->fsuid;
filp->f_gid = current->fsgid;
- filp->f_op = dentry->d_inode->i_op->default_file_ops;
+ filp->f_op = dentry->d_inode->i_fop;
if (filp->f_op->open)
return filp->f_op->open(dentry->d_inode, filp);
else
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 6d1110096..40f8d2e5f 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -157,19 +157,6 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry,
/*================ Global functions ================*/
/*
- * hfs_dir_read()
- *
- * This is the read() entry in the file_operations structure for HFS
- * directories. It simply returns an error code, since reading is not
- * supported.
- */
-hfs_rwret_t hfs_dir_read(struct file * filp, char *buf,
- hfs_rwarg_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-/*
* hfs_create()
*
* This is the create() entry in the inode_operations structure for
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index e0dab7583..bca53e087 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -57,35 +57,31 @@ const struct hfs_name hfs_cap_reserved2[] = {
#define DOT_FINDERINFO (&hfs_cap_reserved1[3])
#define DOT_ROOTINFO (&hfs_cap_reserved2[0])
-static struct file_operations hfs_cap_dir_operations = {
- read: hfs_dir_read,
+struct file_operations hfs_cap_dir_operations = {
+ read: generic_read_dir,
readdir: cap_readdir,
fsync: file_fsync,
};
struct inode_operations hfs_cap_ndir_inode_operations = {
- &hfs_cap_dir_operations,/* default directory file-ops */
- hfs_create, /* create */
- cap_lookup, /* lookup */
- NULL, /* link */
- hfs_unlink, /* unlink */
- NULL, /* symlink */
- hfs_mkdir, /* mkdir */
- hfs_rmdir, /* rmdir */
- NULL, /* mknod */
- hfs_rename, /* rename */
+ create: hfs_create,
+ lookup: cap_lookup,
+ unlink: hfs_unlink,
+ mkdir: hfs_mkdir,
+ rmdir: hfs_rmdir,
+ rename: hfs_rename,
+ setattr: hfs_notify_change,
};
struct inode_operations hfs_cap_fdir_inode_operations = {
- &hfs_cap_dir_operations,/* default directory file-ops */
- NULL, /* create */
- cap_lookup, /* lookup */
+ lookup: cap_lookup,
+ setattr: hfs_notify_change,
};
struct inode_operations hfs_cap_rdir_inode_operations = {
- &hfs_cap_dir_operations,/* default directory file-ops */
- hfs_create, /* create */
- cap_lookup, /* lookup */
+ create: hfs_create,
+ lookup: cap_lookup,
+ setattr: hfs_notify_change,
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index f3469b402..3d613a8e3 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -56,23 +56,20 @@ const struct hfs_name hfs_dbl_reserved2[] = {
#define ROOTINFO (&hfs_dbl_reserved2[0])
#define PCNT_ROOTINFO (&hfs_dbl_reserved2[1])
-static struct file_operations hfs_dbl_dir_operations = {
- read: hfs_dir_read,
+struct file_operations hfs_dbl_dir_operations = {
+ read: generic_read_dir,
readdir: dbl_readdir,
fsync: file_fsync,
};
struct inode_operations hfs_dbl_dir_inode_operations = {
- &hfs_dbl_dir_operations,/* default directory file-ops */
- dbl_create, /* create */
- dbl_lookup, /* lookup */
- NULL, /* link */
- dbl_unlink, /* unlink */
- NULL, /* symlink */
- dbl_mkdir, /* mkdir */
- dbl_rmdir, /* rmdir */
- NULL, /* mknod */
- dbl_rename, /* rename */
+ create: dbl_create,
+ lookup: dbl_lookup,
+ unlink: dbl_unlink,
+ mkdir: dbl_mkdir,
+ rmdir: dbl_rmdir,
+ rename: dbl_rename,
+ setattr: hfs_notify_change,
};
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index 05a646384..992a94b67 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -62,36 +62,28 @@ const struct hfs_name hfs_nat_reserved2[] = {
#define DOT_PARENT (&hfs_nat_reserved1[3])
#define ROOTINFO (&hfs_nat_reserved2[0])
-static struct file_operations hfs_nat_dir_operations = {
- read: hfs_dir_read,
+struct file_operations hfs_nat_dir_operations = {
+ read: generic_read_dir,
readdir: nat_readdir,
fsync: file_fsync,
};
struct inode_operations hfs_nat_ndir_inode_operations = {
- &hfs_nat_dir_operations,/* default directory file-ops */
- hfs_create, /* create */
- nat_lookup, /* lookup */
- NULL, /* link */
- hfs_unlink, /* unlink */
- NULL, /* symlink */
- hfs_mkdir, /* mkdir */
- nat_rmdir, /* rmdir */
- NULL, /* mknod */
- hfs_rename, /* rename */
+ create: hfs_create,
+ lookup: nat_lookup,
+ unlink: hfs_unlink,
+ mkdir: hfs_mkdir,
+ rmdir: nat_rmdir,
+ rename: hfs_rename,
+ setattr: hfs_notify_change,
};
struct inode_operations hfs_nat_hdir_inode_operations = {
- &hfs_nat_dir_operations,/* default directory file-ops */
- hfs_create, /* create */
- nat_lookup, /* lookup */
- NULL, /* link */
- nat_hdr_unlink, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- nat_hdr_rename, /* rename */
+ create: hfs_create,
+ lookup: nat_lookup,
+ unlink: nat_hdr_unlink,
+ rename: nat_hdr_rename,
+ setattr: hfs_notify_change,
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index bb0868fca..4d4a3e9b8 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -31,7 +31,7 @@ static void hfs_file_truncate(struct inode *);
/*================ Global variables ================*/
-static struct file_operations hfs_file_operations = {
+struct file_operations hfs_file_operations = {
read: hfs_file_read,
write: hfs_file_write,
mmap: generic_file_mmap,
@@ -39,19 +39,8 @@ static struct file_operations hfs_file_operations = {
};
struct inode_operations hfs_file_inode_operations = {
- &hfs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- hfs_file_truncate, /* truncate */
+ truncate: hfs_file_truncate,
+ setattr: hfs_notify_change,
};
/*================ Variable-like macros ================*/
diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
index 77625077f..2268185e6 100644
--- a/fs/hfs/file_cap.c
+++ b/fs/hfs/file_cap.c
@@ -31,8 +31,6 @@ static hfs_rwret_t cap_info_read(struct file *, char *,
hfs_rwarg_t, loff_t *);
static hfs_rwret_t cap_info_write(struct file *, const char *,
hfs_rwarg_t, loff_t *);
-static void cap_info_truncate(struct inode *);
-
/*================ Function-like macros ================*/
/*
@@ -46,26 +44,14 @@ static void cap_info_truncate(struct inode *);
/*================ Global variables ================*/
-static struct file_operations hfs_cap_info_operations = {
+struct file_operations hfs_cap_info_operations = {
read: cap_info_read,
write: cap_info_write,
fsync: file_fsync,
};
struct inode_operations hfs_cap_info_inode_operations = {
- &hfs_cap_info_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- cap_info_truncate, /* truncate */
+ setattr: hfs_notify_change_cap,
};
/*================ File-local functions ================*/
@@ -265,17 +251,3 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
mark_inode_dirty(inode);
return count;
}
-
-/*
- * cap_info_truncate()
- *
- * This is the truncate field in the inode_operations structure for
- * CAP metadata files.
- */
-static void cap_info_truncate(struct inode *inode)
-{
- if (inode->i_size > HFS_FORK_MAX) {
- inode->i_size = HFS_FORK_MAX;
- mark_inode_dirty(inode);
- }
-}
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index b0cf0291e..80e47fc62 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -43,30 +43,16 @@
static hfs_rwret_t hdr_read(struct file *, char *, hfs_rwarg_t, loff_t *);
static hfs_rwret_t hdr_write(struct file *, const char *,
hfs_rwarg_t, loff_t *);
-static void hdr_truncate(struct inode *);
-
/*================ Global variables ================*/
-static struct file_operations hfs_hdr_operations = {
+struct file_operations hfs_hdr_operations = {
read: hdr_read,
write: hdr_write,
fsync: file_fsync,
};
struct inode_operations hfs_hdr_inode_operations = {
- &hfs_hdr_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- hdr_truncate, /* truncate */
+ setattr: hfs_notify_change_hdr,
};
const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
@@ -962,13 +948,13 @@ done:
* header files. The purpose is to allocate or release blocks as needed
* to satisfy a change in file length.
*/
-static void hdr_truncate(struct inode *inode)
+void hdr_truncate(struct inode *inode, size_t size)
{
struct hfs_cat_entry *entry = HFS_I(inode)->entry;
struct hfs_hdr_layout *layout;
- size_t size = inode->i_size;
int lcv, last;
+ inode->i_size = size;
if (!HFS_I(inode)->layout) {
HFS_I(inode)->layout = dup_layout(HFS_I(inode)->default_layout);
}
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 60014426b..34e365663 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -106,7 +106,9 @@ void hfs_put_inode(struct inode * inode)
* to permissions must be applied to all other in-core inodes which
* correspond to the same HFS file.
*/
-int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
+enum {HFS_NORM, HFS_HDR, HFS_CAP};
+
+static int __hfs_notify_change(struct dentry *dentry, struct iattr * attr, int kind)
{
struct inode *inode = dentry->d_inode;
struct hfs_cat_entry *entry = HFS_I(inode)->entry;
@@ -148,6 +150,22 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
}
attr->ia_mode &= ~hsb->s_umask;
}
+ /*
+ * Normal files handle size change in normal way.
+ * Oddballs are served here.
+ */
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (kind == HFS_CAP) {
+ inode->i_size = attr->ia_size;
+ if (inode->i_size > HFS_FORK_MAX)
+ inode->i_size = HFS_FORK_MAX;
+ mark_inode_dirty(inode);
+ attr->ia_valid &= ~ATTR_SIZE;
+ } else if (kind == HFS_HDR) {
+ hdr_truncate(inode, attr->ia_size);
+ attr->ia_valid &= ~ATTR_SIZE;
+ }
+ }
inode_setattr(inode, attr);
/* We wouldn't want to mess with the sizes of the other fork */
@@ -184,6 +202,21 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
return 0;
}
+int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
+{
+ return __hfs_notify_change(dentry, attr, HFS_NORM);
+}
+
+int hfs_notify_change_cap(struct dentry *dentry, struct iattr * attr)
+{
+ return __hfs_notify_change(dentry, attr, HFS_CAP);
+}
+
+int hfs_notify_change_hdr(struct dentry *dentry, struct iattr * attr)
+{
+ return __hfs_notify_change(dentry, attr, HFS_HDR);
+}
+
static int hfs_writepage(struct dentry *dentry, struct page *page)
{
return block_write_full_page(page,hfs_get_block);
@@ -329,10 +362,12 @@ void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
inode->i_nlink = 1;
inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
inode->i_op = &hfs_cap_info_inode_operations;
+ inode->i_fop = &hfs_cap_info_operations;
} else if (entry->type == HFS_CDR_FIL) {
init_file_inode(inode, (type == HFS_CAP_DATA) ?
HFS_FK_DATA : HFS_FK_RSRC);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
@@ -345,16 +380,19 @@ void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
inode->i_mode = S_IRWXUGO | S_IFDIR;
inode->i_nlink = hdir->dirs + 4;
inode->i_op = &hfs_cap_ndir_inode_operations;
+ inode->i_fop = &hfs_cap_dir_operations;
HFS_I(inode)->file_type = HFS_CAP_NORM;
} else if (type == HFS_CAP_FDIR) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
inode->i_nlink = 2;
inode->i_op = &hfs_cap_fdir_inode_operations;
+ inode->i_fop = &hfs_cap_dir_operations;
HFS_I(inode)->file_type = HFS_CAP_FNDR;
} else if (type == HFS_CAP_RDIR) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
inode->i_nlink = 2;
inode->i_op = &hfs_cap_rdir_inode_operations;
+ inode->i_fop = &hfs_cap_dir_operations;
HFS_I(inode)->file_type = HFS_CAP_RSRC;
}
}
@@ -385,9 +423,11 @@ void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
HFS_I(inode)->default_layout = &hfs_dbl_dir_hdr_layout;
}
inode->i_op = &hfs_hdr_inode_operations;
+ inode->i_fop = &hfs_hdr_operations;
} else if (entry->type == HFS_CDR_FIL) {
init_file_inode(inode, HFS_FK_DATA);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
@@ -398,6 +438,7 @@ void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
inode->i_size = 3 + 2 * (hdir->dirs + hdir->files);
inode->i_mode = S_IRWXUGO | S_IFDIR;
inode->i_op = &hfs_dbl_dir_inode_operations;
+ inode->i_fop = &hfs_dbl_dir_operations;
HFS_I(inode)->file_type = HFS_DBL_NORM;
HFS_I(inode)->dir_size = 2;
}
@@ -426,11 +467,13 @@ void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
inode->i_nlink = 1;
}
inode->i_op = &hfs_hdr_inode_operations;
+ inode->i_fop = &hfs_hdr_operations;
HFS_I(inode)->default_layout = (version == 2) ?
&hfs_nat2_hdr_layout : &hfs_nat_hdr_layout;
} else if (entry->type == HFS_CDR_FIL) {
init_file_inode(inode, HFS_FK_DATA);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_fop = &hfs_file_operations;
inode->i_mapping->a_ops = &hfs_aops;
inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
@@ -449,5 +492,6 @@ void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
inode->i_op = &hfs_nat_hdir_inode_operations;
HFS_I(inode)->file_type = HFS_NAT_HDR;
}
+ inode->i_fop = &hfs_nat_dir_operations;
}
}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index cb10a760c..3ed8307a0 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -42,15 +42,11 @@ static void hfs_write_super(struct super_block *);
/*================ Global variables ================*/
static struct super_operations hfs_super_operations = {
- hfs_read_inode, /* read_inode */
- NULL, /* write_inode */
- hfs_put_inode, /* put_inode - in inode.c */
- NULL, /* delete_inode */
- hfs_notify_change, /* notify_change - in inode.c */
- hfs_put_super, /* put_super */
- hfs_write_super, /* write_super */
- hfs_statfs, /* statfs */
- NULL /* remount_fs */
+ read_inode: hfs_read_inode,
+ put_inode: hfs_put_inode,
+ put_super: hfs_put_super,
+ write_super: hfs_write_super,
+ statfs: hfs_statfs,
};
/*================ File-local variables ================*/
@@ -72,7 +68,6 @@ static struct file_system_type hfs_fs = {
static void hfs_read_inode(struct inode *inode)
{
inode->i_mode = 0;
- inode->i_op = NULL;
}
/*
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 280c47244..a2f33d56d 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -8,11 +8,6 @@
#include "hpfs_fn.h"
-ssize_t hpfs_dir_read(struct file *filp, char *name, size_t len, loff_t *loff)
-{
- return -EISDIR;
-}
-
int hpfs_dir_release(struct inode *inode, struct file *filp)
{
hpfs_del_pos(inode, &filp->f_pos);
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index f0324cffa..44d1037cf 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -224,7 +224,6 @@ void hpfs_set_dentry_operations(struct dentry *);
/* dir.c */
-ssize_t hpfs_dir_read(struct file *, char *, size_t, loff_t *);
int hpfs_dir_release(struct inode *, struct file *);
loff_t hpfs_dir_lseek(struct file *, loff_t, int);
int hpfs_readdir(struct file *, void *, filldir_t);
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 2fa2d0dd4..c8283c672 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -8,7 +8,7 @@
#include "hpfs_fn.h"
-static const struct file_operations hpfs_file_ops =
+static struct file_operations hpfs_file_ops =
{
read: generic_file_read,
write: hpfs_file_write,
@@ -18,45 +18,33 @@ static const struct file_operations hpfs_file_ops =
fsync: hpfs_file_fsync,
};
-static const struct inode_operations hpfs_file_iops =
+static struct inode_operations hpfs_file_iops =
{
- (nonconst *) & hpfs_file_ops, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- hpfs_truncate, /* truncate */
+ truncate: hpfs_truncate,
+ setattr: hpfs_notify_change,
};
-static const struct file_operations hpfs_dir_ops =
+static struct file_operations hpfs_dir_ops =
{
llseek: hpfs_dir_lseek,
- read: hpfs_dir_read,
+ read: generic_read_dir,
readdir: hpfs_readdir,
open: hpfs_open,
release: hpfs_dir_release,
fsync: hpfs_file_fsync,
};
-static const struct inode_operations hpfs_dir_iops =
+static struct inode_operations hpfs_dir_iops =
{
- (nonconst *) & hpfs_dir_ops, /* default directory file ops */
- hpfs_create, /* create */
- hpfs_lookup, /* lookup */
- NULL, /* link */
- hpfs_unlink, /* unlink */
- hpfs_symlink, /* symlink */
- hpfs_mkdir, /* mkdir */
- hpfs_rmdir, /* rmdir */
- hpfs_mknod, /* mknod */
- hpfs_rename, /* rename */
+ create: hpfs_create,
+ lookup: hpfs_lookup,
+ unlink: hpfs_unlink,
+ symlink: hpfs_symlink,
+ mkdir: hpfs_mkdir,
+ rmdir: hpfs_rmdir,
+ mknod: hpfs_mknod,
+ rename: hpfs_rename,
+ setattr: hpfs_notify_change,
};
struct address_space_operations hpfs_symlink_aops = {
@@ -70,7 +58,6 @@ void hpfs_read_inode(struct inode *i)
struct super_block *sb = i->i_sb;
unsigned char *ea;
int ea_size;
- i->i_op = 0;
init_MUTEX(&i->i_hpfs_sem);
i->i_uid = sb->s_hpfs_uid;
i->i_gid = sb->s_hpfs_gid;
@@ -104,14 +91,16 @@ void hpfs_read_inode(struct inode *i)
if (i->i_sb->s_hpfs_rd_inode == 2) {
i->i_mode |= S_IFREG;
i->i_mode &= ~0111;
- i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_op = &hpfs_file_iops;
+ i->i_fop = &hpfs_file_ops;
i->i_nlink = 1;
return;
}
if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) {
/*i->i_mode |= S_IFREG;
i->i_mode &= ~0111;
- i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_op = &hpfs_file_iops;
+ i->i_fop = &hpfs_file_ops;
i->i_nlink = 0;*/
make_bad_inode(i);
return;
@@ -171,7 +160,8 @@ void hpfs_read_inode(struct inode *i)
if (fnode->dirflag) {
unsigned n_dnodes, n_subdirs;
i->i_mode |= S_IFDIR;
- i->i_op = (struct inode_operations *) &hpfs_dir_iops;
+ i->i_op = &hpfs_dir_iops;
+ i->i_fop = &hpfs_dir_ops;
i->i_hpfs_parent_dir = fnode->up;
i->i_hpfs_dno = fnode->u.external[0].disk_secno;
if (sb->s_hpfs_chk >= 2) {
@@ -186,7 +176,8 @@ void hpfs_read_inode(struct inode *i)
} else {
i->i_mode |= S_IFREG;
if (!i->i_hpfs_ea_mode) i->i_mode &= ~0111;
- i->i_op = (struct inode_operations *) &hpfs_file_iops;
+ i->i_op = &hpfs_file_iops;
+ i->i_fop = &hpfs_file_ops;
i->i_nlink = 1;
i->i_size = fnode->file_size;
i->i_blocks = ((i->i_size + 511) >> 9) + 1;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index c6291c83a..8937bb90e 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -152,19 +152,13 @@ int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
/* Super operations */
-static const struct super_operations hpfs_sops =
+static struct super_operations hpfs_sops =
{
- hpfs_read_inode, /* read_inode */
- NULL, /* write_inode */
- NULL, /* put_inode */
- hpfs_delete_inode, /* delete inode */
- hpfs_notify_change, /* notify_change */
- hpfs_put_super, /* put_super */
- NULL, /* write_super */
- hpfs_statfs, /* statfs */
- hpfs_remount_fs, /* remount_fs */
- NULL, /* clear inode */
- NULL, /* umount_begin */
+ read_inode: hpfs_read_inode,
+ delete_inode: hpfs_delete_inode,
+ put_super: hpfs_put_super,
+ statfs: hpfs_statfs,
+ remount_fs: hpfs_remount_fs,
};
/*
@@ -437,7 +431,7 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
s->s_magic = HPFS_SUPER_MAGIC;
s->s_blocksize = 512;
s->s_blocksize_bits = 9;
- s->s_op = (struct super_operations *) &hpfs_sops;
+ s->s_op = &hpfs_sops;
s->s_hpfs_root = superblock->root;
s->s_hpfs_fs_size = superblock->n_sectors;
diff --git a/fs/inode.c b/fs/inode.c
index e6cb6ef59..9b216857d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -471,9 +471,12 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
static void clean_inode(struct inode *inode)
{
static struct address_space_operations empty_aops = {};
+ static struct inode_operations empty_iops = {};
+ static struct file_operations empty_fops = {};
memset(&inode->u, 0, sizeof(inode->u));
inode->i_sock = 0;
- inode->i_op = NULL;
+ inode->i_op = &empty_iops;
+ inode->i_fop = &empty_fops;
inode->i_nlink = 1;
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
diff --git a/fs/isofs/Makefile b/fs/isofs/Makefile
index 2b2af2ade..b6cbdc6af 100644
--- a/fs/isofs/Makefile
+++ b/fs/isofs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := isofs.o
-O_OBJS := namei.o inode.o file.o dir.o util.o rock.o
+O_OBJS := namei.o inode.o dir.o util.o rock.o
ifdef CONFIG_JOLIET
O_OBJS += joliet.o
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 35f37a1bf..cbb213668 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -26,8 +26,9 @@
static int isofs_readdir(struct file *, void *, filldir_t);
-static struct file_operations isofs_dir_operations =
+struct file_operations isofs_dir_operations =
{
+ read: generic_read_dir,
readdir: isofs_readdir,
};
@@ -36,9 +37,7 @@ static struct file_operations isofs_dir_operations =
*/
struct inode_operations isofs_dir_inode_operations =
{
- &isofs_dir_operations, /* default directory file-ops */
- NULL, /* create */
- isofs_lookup, /* lookup */
+ lookup: isofs_lookup,
};
static int isofs_name_translate(char * old, int len, char * new)
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
deleted file mode 100644
index 9de31e024..000000000
--- a/fs/isofs/file.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/fs/isofs/file.c
- *
- * (C) 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem.
- *
- * (C) 1991 Linus Torvalds - minix filesystem
- *
- * isofs regular file handling primitives
- */
-
-#include <linux/sched.h>
-#include <linux/iso_fs.h>
-#include <linux/fcntl.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/fs.h>
-
-/*
- * We have mostly NULLs here: the current defaults are OK for
- * the isofs filesystem.
- */
-static struct file_operations isofs_file_operations = {
- read: generic_file_read,
- mmap: generic_file_mmap,
-};
-
-struct inode_operations isofs_file_inode_operations = {
- &isofs_file_operations, /* default file operations */
-};
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 2c67d9e5a..b4a633e9f 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -77,15 +77,9 @@ static void isofs_read_inode(struct inode *);
static int isofs_statfs (struct super_block *, struct statfs *, int);
static struct super_operations isofs_sops = {
- isofs_read_inode,
- NULL, /* write_inode */
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- isofs_put_super,
- NULL, /* write_super */
- isofs_statfs,
- NULL
+ read_inode: isofs_read_inode,
+ put_super: isofs_put_super,
+ statfs: isofs_statfs,
};
static struct dentry_operations isofs_dentry_ops[] = {
@@ -1259,7 +1253,6 @@ static void isofs_read_inode(struct inode * inode)
}
/* Install the inode operations vector */
- inode->i_op = NULL;
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
if (inode->i_sb->u.isofs_sb.s_cruft != 'y' &&
(volume_seq_no != 0) && (volume_seq_no != 1)) {
@@ -1268,11 +1261,12 @@ static void isofs_read_inode(struct inode * inode)
#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
{
if (S_ISREG(inode->i_mode)) {
- inode->i_op = &isofs_file_inode_operations;
+ inode->i_fop = &generic_ro_fops;
inode->i_data.a_ops = &isofs_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &isofs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &isofs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_data.a_ops = &isofs_symlink_aops;
} else
@@ -1283,14 +1277,7 @@ static void isofs_read_inode(struct inode * inode)
fail:
/* With a data error we return this information */
- inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
- inode->u.isofs_i.i_first_extent = 0;
- inode->i_size = 0;
- inode->i_blocks = inode->i_blksize = 0;
- inode->i_nlink = 1;
- inode->i_uid = inode->i_gid = 0;
- inode->i_mode = S_IFREG; /*Regular file, no one gets to read*/
- inode->i_op = NULL;
+ make_bad_inode(inode);
return;
}
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 21057e7dc..0a504e59d 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -289,7 +289,6 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = NULL;
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 02bde162d..6443f05ed 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -12,38 +12,14 @@
#include <linux/minix_fs.h>
#include <linux/stat.h>
-#include <asm/uaccess.h>
-
-static ssize_t minix_dir_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int minix_readdir(struct file *, void *, filldir_t);
-static struct file_operations minix_dir_operations = {
- read: minix_dir_read,
+struct file_operations minix_dir_operations = {
+ read: generic_read_dir,
readdir: minix_readdir,
fsync: file_fsync,
};
-/*
- * directories can handle most operations...
- */
-struct inode_operations minix_dir_inode_operations = {
- &minix_dir_operations, /* default directory file-ops */
- minix_create, /* create */
- minix_lookup, /* lookup */
- minix_link, /* link */
- minix_unlink, /* unlink */
- minix_symlink, /* symlink */
- minix_mkdir, /* mkdir */
- minix_rmdir, /* rmdir */
- minix_mknod, /* mknod */
- minix_rename, /* rename */
-};
-
static int minix_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 61d0e3f02..c0b5ad89f 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -6,18 +6,6 @@
* minix regular file handling primitives
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
#include <linux/fs.h>
#include <linux/minix_fs.h>
@@ -25,7 +13,7 @@
* We have mostly NULLs here: the current defaults are OK for
* the minix filesystem.
*/
-static struct file_operations minix_file_operations = {
+struct file_operations minix_file_operations = {
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
@@ -33,6 +21,5 @@ static struct file_operations minix_file_operations = {
};
struct inode_operations minix_file_inode_operations = {
- &minix_file_operations,
truncate: minix_truncate,
};
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 9620870ad..1d9ebb062 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -85,15 +85,13 @@ static void minix_put_super(struct super_block *sb)
}
static struct super_operations minix_sops = {
- minix_read_inode,
- minix_write_inode,
- NULL, /* put_inode */
- minix_delete_inode,
- NULL, /* notify_change */
- minix_put_super,
- minix_write_super,
- minix_statfs,
- minix_remount
+ read_inode: minix_read_inode,
+ write_inode: minix_write_inode,
+ delete_inode: minix_delete_inode,
+ put_super: minix_put_super,
+ write_super: minix_write_super,
+ statfs: minix_statfs,
+ remount_fs: minix_remount,
};
static int minix_remount (struct super_block * sb, int * flags, char * data)
@@ -1054,7 +1052,6 @@ static void V1_minix_read_inode(struct inode * inode)
int block, ino;
ino = inode->i_ino;
- inode->i_op = NULL;
inode->i_mode = 0;
if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
@@ -1083,10 +1080,12 @@ static void V1_minix_read_inode(struct inode * inode)
inode->u.minix_i.u.i1_data[block] = raw_inode->i_zone[block];
if (S_ISREG(inode->i_mode)) {
inode->i_op = &minix_file_inode_operations;
+ inode->i_fop = &minix_file_operations;
inode->i_mapping->a_ops = &minix_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &minix_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &minix_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &minix_aops;
} else
@@ -1104,7 +1103,6 @@ static void V2_minix_read_inode(struct inode * inode)
int block, ino;
ino = inode->i_ino;
- inode->i_op = NULL;
inode->i_mode = 0;
if (!ino || ino > inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
@@ -1135,10 +1133,12 @@ static void V2_minix_read_inode(struct inode * inode)
inode->u.minix_i.u.i2_data[block] = raw_inode->i_zone[block];
if (S_ISREG(inode->i_mode)) {
inode->i_op = &minix_file_inode_operations;
+ inode->i_fop = &minix_file_operations;
inode->i_mapping->a_ops = &minix_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &minix_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &minix_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &minix_aops;
} else
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index de2d0f279..baef110d2 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -115,7 +115,7 @@ struct dentry_operations minix_dentry_operations = {
0 /* compare */
};
-struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode = NULL;
struct minix_dir_entry * de;
@@ -206,7 +206,7 @@ static int minix_add_entry(struct inode * dir,
return 0;
}
-int minix_create(struct inode * dir, struct dentry *dentry, int mode)
+static int minix_create(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
@@ -219,6 +219,7 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &minix_file_inode_operations;
+ inode->i_fop = &minix_file_operations;
inode->i_mapping->a_ops = &minix_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -237,7 +238,7 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
return 0;
}
-int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
+static int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
int error;
struct inode * inode;
@@ -266,7 +267,7 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
return 0;
}
-int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
+static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
@@ -283,6 +284,7 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &minix_dir_inode_operations;
+ inode->i_fop = &minix_dir_operations;
inode->i_size = 2 * info->s_dirsize;
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
@@ -377,7 +379,7 @@ bad_dir:
return 1;
}
-int minix_rmdir(struct inode * dir, struct dentry *dentry)
+static int minix_rmdir(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -422,7 +424,7 @@ end_rmdir:
return retval;
}
-int minix_unlink(struct inode * dir, struct dentry *dentry)
+static int minix_unlink(struct inode * dir, struct dentry *dentry)
{
int retval;
struct inode * inode;
@@ -457,7 +459,7 @@ end_unlink:
return retval;
}
-int minix_symlink(struct inode * dir, struct dentry *dentry,
+static int minix_symlink(struct inode * dir, struct dentry *dentry,
const char * symname)
{
struct minix_dir_entry * de;
@@ -502,7 +504,7 @@ fail:
goto out;
}
-int minix_link(struct dentry * old_dentry, struct inode * dir,
+static int minix_link(struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
int error;
@@ -540,7 +542,7 @@ int minix_link(struct dentry * old_dentry, struct inode * dir,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct inode * new_dir, struct dentry *new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -630,3 +632,18 @@ end_rename:
brelse(new_bh);
return retval;
}
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations minix_dir_inode_operations = {
+ create: minix_create,
+ lookup: minix_lookup,
+ link: minix_link,
+ unlink: minix_unlink,
+ symlink: minix_symlink,
+ mkdir: minix_mkdir,
+ rmdir: minix_rmdir,
+ mknod: minix_mknod,
+ rename: minix_rename,
+};
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 155489072..d74c71049 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -585,16 +585,13 @@ rename_done:
/* The public inode operations for the msdos fs */
struct inode_operations msdos_dir_inode_operations = {
- &fat_dir_operations, /* default directory file-ops */
- msdos_create, /* create */
- msdos_lookup, /* lookup */
- NULL, /* link */
- msdos_unlink, /* unlink */
- NULL, /* symlink */
- msdos_mkdir, /* mkdir */
- msdos_rmdir, /* rmdir */
- NULL, /* mknod */
- msdos_rename, /* rename */
+ create: msdos_create,
+ lookup: msdos_lookup,
+ unlink: msdos_unlink,
+ mkdir: msdos_mkdir,
+ rmdir: msdos_rmdir,
+ rename: msdos_rename,
+ setattr: fat_notify_change,
};
static void msdos_put_super_callback(struct super_block *sb)
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index e5e91a24c..5c23664e3 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -31,7 +31,6 @@ static void ncp_read_volume_list(struct file *, void *, filldir_t,
static void ncp_do_readdir(struct file *, void *, filldir_t,
struct ncp_cache_control *);
-static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
static int ncp_readdir(struct file *, void *, filldir_t);
static int ncp_create(struct inode *, struct dentry *, int);
@@ -45,42 +44,27 @@ static int ncp_rename(struct inode *, struct dentry *,
extern int ncp_symlink(struct inode *, struct dentry *, const char *);
#endif
-static struct file_operations ncp_dir_operations =
+struct file_operations ncp_dir_operations =
{
- read: ncp_dir_read,
+ read: generic_read_dir,
readdir: ncp_readdir,
ioctl: ncp_ioctl,
};
struct inode_operations ncp_dir_inode_operations =
{
- &ncp_dir_operations, /* default directory file ops */
- ncp_create, /* create */
- ncp_lookup, /* lookup */
- NULL, /* link */
- ncp_unlink, /* unlink */
+ create: ncp_create,
+ lookup: ncp_lookup,
+ unlink: ncp_unlink,
#ifdef CONFIG_NCPFS_EXTRAS
- ncp_symlink, /* symlink */
-#else
- NULL, /* symlink */
+ symlink: ncp_symlink,
#endif
- ncp_mkdir, /* mkdir */
- ncp_rmdir, /* rmdir */
- NULL, /* mknod */
- ncp_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow link */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
+ mkdir: ncp_mkdir,
+ rmdir: ncp_rmdir,
+ rename: ncp_rename,
+ setattr: ncp_notify_change,
};
-static ssize_t
-ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
/*
* Dentry operations routines
*/
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 09b95cd4f..657e924de 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -275,7 +275,7 @@ out:
return already_written ? already_written : errno;
}
-static struct file_operations ncp_file_operations =
+struct file_operations ncp_file_operations =
{
read: ncp_file_read,
write: ncp_file_write,
@@ -286,19 +286,5 @@ static struct file_operations ncp_file_operations =
struct inode_operations ncp_file_inode_operations =
{
- &ncp_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ setattr: ncp_notify_change,
};
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index fdbf5fc82..85cc9bd39 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -38,15 +38,10 @@ static int ncp_statfs(struct super_block *, struct statfs *, int);
static struct super_operations ncp_sops =
{
- NULL, /* read inode */
- NULL, /* write inode */
- ncp_put_inode, /* put inode */
- ncp_delete_inode, /* delete inode */
- ncp_notify_change, /* notify change */
- ncp_put_super, /* put superblock */
- NULL, /* write superblock */
- ncp_statfs, /* stat filesystem */
- NULL /* remount */
+ put_inode: ncp_put_inode,
+ delete_inode: ncp_delete_inode,
+ put_super: ncp_put_super,
+ statfs: ncp_statfs,
};
extern struct dentry_operations ncp_dentry_operations;
@@ -201,6 +196,12 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
ncp_update_inode(inode, nwinfo);
}
+static struct inode_operations ncp_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ setattr: ncp_notify_change,
+};
+
/*
* Get a new inode.
*/
@@ -222,11 +223,13 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
ncp_set_attr(inode, info);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ncp_file_inode_operations;
+ inode->i_fop = &ncp_file_operations;
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ncp_dir_inode_operations;
+ inode->i_fop = &ncp_dir_operations;
#ifdef CONFIG_NCPFS_EXTRAS
} else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &ncp_symlink_inode_operations;
inode->i_data.a_ops = &ncp_symlink_aops;
#endif
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 82d3f5bc3..9dfc2f055 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -38,7 +38,6 @@
static int nfs_safe_remove(struct dentry *);
-static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
static int nfs_readdir(struct file *, void *, filldir_t);
static struct dentry *nfs_lookup(struct inode *, struct dentry *);
static int nfs_create(struct inode *, struct dentry *, int);
@@ -51,37 +50,27 @@ static int nfs_mknod(struct inode *, struct dentry *, int, int);
static int nfs_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
-static struct file_operations nfs_dir_operations = {
- read: nfs_dir_read,
+struct file_operations nfs_dir_operations = {
+ read: generic_read_dir,
readdir: nfs_readdir,
open: nfs_open,
release: nfs_release,
};
struct inode_operations nfs_dir_inode_operations = {
- &nfs_dir_operations, /* default directory file-ops */
- nfs_create, /* create */
- nfs_lookup, /* lookup */
- nfs_link, /* link */
- nfs_unlink, /* unlink */
- nfs_symlink, /* symlink */
- nfs_mkdir, /* mkdir */
- nfs_rmdir, /* rmdir */
- nfs_mknod, /* mknod */
- nfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- NULL, /* permission */
- nfs_revalidate, /* revalidate */
+ create: nfs_create,
+ lookup: nfs_lookup,
+ link: nfs_link,
+ unlink: nfs_unlink,
+ symlink: nfs_symlink,
+ mkdir: nfs_mkdir,
+ rmdir: nfs_rmdir,
+ mknod: nfs_mknod,
+ rename: nfs_rename,
+ revalidate: nfs_revalidate,
+ setattr: nfs_notify_change,
};
-static ssize_t
-nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
/* Each readdir response is composed of entries which look
* like the following, as per the NFSv2 RFC:
*
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 911b61b9c..9a91bb1ab 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -40,7 +40,7 @@ static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
static int nfs_file_flush(struct file *);
static int nfs_fsync(struct file *, struct dentry *dentry);
-static struct file_operations nfs_file_operations = {
+struct file_operations nfs_file_operations = {
read: nfs_file_read,
write: nfs_file_write,
mmap: nfs_file_mmap,
@@ -52,21 +52,8 @@ static struct file_operations nfs_file_operations = {
};
struct inode_operations nfs_file_inode_operations = {
- &nfs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- NULL, /* permission */
- nfs_revalidate, /* revalidate */
+ revalidate: nfs_revalidate,
+ setattr: nfs_notify_change,
};
/* Hack for future NFS swap support */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 16b3624c1..7d2a6c146 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -44,23 +44,17 @@ static void nfs_invalidate_inode(struct inode *);
static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
-static int nfs_notify_change(struct dentry *, struct iattr *);
static void nfs_put_super(struct super_block *);
static void nfs_umount_begin(struct super_block *);
static int nfs_statfs(struct super_block *, struct statfs *, int);
static struct super_operations nfs_sops = {
- nfs_read_inode, /* read inode */
- NULL, /* write inode */
- nfs_put_inode, /* put inode */
- nfs_delete_inode, /* delete inode */
- nfs_notify_change, /* notify change */
- nfs_put_super, /* put superblock */
- NULL, /* write superblock */
- nfs_statfs, /* stat filesystem */
- NULL, /* no remount */
- NULL, /* no clear inode */
- nfs_umount_begin /* umount attempt begin */
+ read_inode: nfs_read_inode,
+ put_inode: nfs_put_inode,
+ delete_inode: nfs_delete_inode,
+ put_super: nfs_put_super,
+ statfs: nfs_statfs,
+ umount_begin: nfs_umount_begin,
};
struct rpc_stat nfs_rpcstat = { &nfs_program };
@@ -78,7 +72,6 @@ nfs_read_inode(struct inode * inode)
inode->i_blksize = inode->i_sb->s_blocksize;
inode->i_mode = 0;
inode->i_rdev = 0;
- inode->i_op = NULL;
NFS_FILEID(inode) = 0;
NFS_FSID(inode) = 0;
NFS_CACHEINV(inode);
@@ -477,12 +470,17 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
NFS_FILEID(inode) = fattr->fileid;
NFS_FSID(inode) = fattr->fsid;
inode->i_mode = fattr->mode;
+ /* Why so? Because we want revalidate for devices/FIFOs, and
+ * that's precisely what we have in nfs_file_inode_operations.
+ */
+ inode->i_op = &nfs_file_inode_operations;
if (S_ISREG(inode->i_mode)) {
- inode->i_op = &nfs_file_inode_operations;
+ inode->i_fop = &nfs_file_operations;
inode->i_data.a_ops = &nfs_file_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &nfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
+ inode->i_fop = &nfs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
init_special_inode(inode, inode->i_mode, fattr->rdev);
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index ab0ebf145..9f5a95ff9 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -104,4 +104,6 @@ nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
struct inode_operations nfs_symlink_inode_operations = {
readlink: nfs_readlink,
follow_link: nfs_follow_link,
+ revalidate: nfs_revalidate,
+ setattr: nfs_notify_change,
};
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index a13e26fd0..5f847bec8 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -416,9 +416,23 @@ wait_on_write_request(struct nfs_wreq *req)
int
nfs_writepage(struct dentry * dentry, struct page *page)
{
- int result = nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE);
- if ( result == PAGE_SIZE) return 0;
- return result;
+ struct inode *inode = dentry->d_inode;
+ unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset = PAGE_CACHE_SIZE;
+ int err;
+
+ /* easy case */
+ if (page->index < end_index)
+ goto do_it;
+ /* things got complicated... */
+ offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+ /* OK, are we completely out? */
+ if (page->index >= end_index+1 || !offset)
+ return -EIO;
+do_it:
+ err = nfs_writepage_sync(dentry, inode, page, 0, offset);
+ if ( err == offset) return 0;
+ return err;
}
/*
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 63c8fec93..aa03c0a16 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -76,7 +76,7 @@ static int get_ino_name(struct dentry *dentry, struct qstr *name, unsigned long
if (!dir || !S_ISDIR(dir->i_mode))
goto out;
error = -EINVAL;
- if (!dir->i_op || !dir->i_op->default_file_ops)
+ if (!dir->i_fop)
goto out;
/*
* Open the directory ...
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5ea680286..c0f7da6cc 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -432,14 +432,14 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = nfserr_perm;
if (IS_APPEND(inode) || IS_ISMNDLK(inode))
goto out;
- if (!inode->i_op || !inode->i_op->default_file_ops)
+ if (!inode->i_fop)
goto out;
if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0)
goto out_nfserr;
memset(filp, 0, sizeof(*filp));
- filp->f_op = inode->i_op->default_file_ops;
+ filp->f_op = inode->i_fop;
atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry;
if (access & MAY_WRITE) {
@@ -512,8 +512,7 @@ nfsd_sync_dir(struct dentry *dp)
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *);
- if (inode->i_op->default_file_ops
- && (fsync = inode->i_op->default_file_ops->fsync)) {
+ if (inode->i_fop && (fsync = inode->i_fop->fsync)) {
fsync(NULL, dp);
}
}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index fff05ca9b..139ff0d0b 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -412,7 +412,6 @@ static struct file_operations ntfs_file_operations_nommap = {
};
static struct inode_operations ntfs_inode_operations_nobmap = {
- &ntfs_file_operations_nommap,
};
#ifdef CONFIG_NTFS_RW
@@ -466,6 +465,7 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
}
/* It's not a directory */
r->i_op=&ntfs_inode_operations_nobmap;
+ r->i_fop=&ntfs_file_operations_nommap,
r->i_mode=S_IFREG|S_IRUGO;
#ifdef CONFIG_NTFS_RW
r->i_mode|=S_IWUGO;
@@ -529,6 +529,7 @@ _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
}
/* It's a directory */
r->i_op = &ntfs_dir_inode_operations;
+ r->i_fop = &ntfs_dir_operations;
r->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
#ifdef CONFIG_NTFS_RW
r->i_mode|=S_IWUGO;
@@ -570,32 +571,19 @@ static struct file_operations ntfs_file_operations = {
};
static struct inode_operations ntfs_inode_operations = {
- &ntfs_file_operations,
};
static struct file_operations ntfs_dir_operations = {
+ read: generic_read_dir,
readdir: ntfs_readdir,
};
static struct inode_operations ntfs_dir_inode_operations = {
- &ntfs_dir_operations,
+ lookup: ntfs_lookup,
#ifdef CONFIG_NTFS_RW
- ntfs_create, /* create */
-#else
- NULL,
+ create: ntfs_create,
+ mkdir: _linux_ntfs_mkdir,
#endif
- ntfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
-#ifdef CONFIG_NTFS_RW
- _linux_ntfs_mkdir, /* mkdir */
-#else
- NULL,
-#endif
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
};
static int ntfs_writepage(struct dentry *dentry, struct page *page)
@@ -636,7 +624,6 @@ static void ntfs_read_inode(struct inode* inode)
ntfs_attribute *si;
vol=NTFS_INO2VOL(inode);
- inode->i_op=NULL;
inode->i_mode=0;
ntfs_debug(DEBUG_OTHER, "ntfs_read_inode %x\n",(unsigned)inode->i_ino);
@@ -693,16 +680,19 @@ static void ntfs_read_inode(struct inode* inode)
inode->i_size = at ? at->size : 0;
inode->i_op=&ntfs_dir_inode_operations;
+ inode->i_fop=&ntfs_dir_operations;
inode->i_mode=S_IFDIR|S_IRUGO|S_IXUGO;
}
else
{
if (can_mmap) {
inode->i_op = &ntfs_inode_operations;
+ inode->i_fop = &ntfs_file_operations;
inode->i_mapping->a_ops = &ntfs_aops;
inode->u.ntfs_i.mmu_private = inode->i_size;
} else {
inode->i_op=&ntfs_inode_operations_nobmap;
+ inode->i_fop=&ntfs_file_operations_nommap,
}
inode->i_mode=S_IFREG|S_IRUGO;
}
@@ -806,20 +796,14 @@ static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
/* Define the super block operation that are implemented */
static struct super_operations ntfs_super_operations = {
- ntfs_read_inode,
+ read_inode: ntfs_read_inode,
#ifdef CONFIG_NTFS_RW
- ntfs_write_inode,
-#else
- NULL,
+ write_inode: ntfs_write_inode,
#endif
- NULL, /* put_inode */
- NULL, /* delete_inode */
- NULL, /* notify_change */
- ntfs_put_super,
- NULL, /* write_super */
- ntfs_statfs,
- ntfs_remount_fs, /* remount */
- _ntfs_clear_inode, /* clear_inode */
+ put_super: ntfs_put_super,
+ statfs: ntfs_statfs,
+ remount_fs: ntfs_remount_fs,
+ clear_inode: _ntfs_clear_inode,
};
/* Called to mount a filesystem by read_super() in fs/super.c
diff --git a/fs/open.c b/fs/open.c
index 7896b0a2e..e7b119df7 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -680,7 +680,7 @@ struct file *filp_open(const char * filename, int flags, int mode)
f->f_reada = 0;
f->f_op = NULL;
if (inode->i_op)
- f->f_op = inode->i_op->default_file_ops;
+ f->f_op = inode->i_fop;
if (inode->i_sb)
file_move(f, &inode->i_sb->s_files);
if (f->f_op && f->f_op->open) {
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index e43f8feec..b03172491 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -558,31 +558,24 @@ static struct file_operations openpromfs_prop_ops = {
release: property_release,
};
-static struct inode_operations openpromfs_prop_inode_ops = {
- &openpromfs_prop_ops, /* default property file-ops */
-};
-
static struct file_operations openpromfs_nodenum_ops = {
read: nodenum_read,
};
-static struct inode_operations openpromfs_nodenum_inode_ops = {
- &openpromfs_nodenum_ops,/* default .node file-ops */
-};
-
-static struct file_operations openprom_alias_operations = {
+static struct file_operations openprom_operations = {
+ read: generic_read_dir,
readdir: openpromfs_readdir,
};
static struct inode_operations openprom_alias_inode_operations = {
- &openprom_alias_operations,/* default aliases directory file-ops */
- openpromfs_create, /* create */
- openpromfs_lookup, /* lookup */
- NULL, /* link */
- openpromfs_unlink, /* unlink */
+ create: openpromfs_create,
+ lookup: openpromfs_lookup,
+ unlink: openpromfs_unlink,
};
-extern struct inode_operations openprom_inode_operations;
+static struct inode_operations openprom_inode_operations = {
+ lookup: openpromfs_lookup,
+};
static int lookup_children(u16 n, const char * name, int len)
{
@@ -710,11 +703,12 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr
inode->i_op = &openprom_alias_inode_operations;
} else
inode->i_op = &openprom_inode_operations;
+ inode->i_fop = &openprom_operations;
inode->i_nlink = 2;
break;
case OPFSL_NODENUM:
inode->i_mode = S_IFREG | S_IRUGO;
- inode->i_op = &openpromfs_nodenum_inode_ops;
+ inode->i_fop = &openpromfs_nodenum_ops;
inode->i_nlink = 1;
inode->u.generic_ip = (void *)(long)(n);
break;
@@ -729,7 +723,7 @@ static struct dentry *openpromfs_lookup(struct inode * dir, struct dentry *dentr
inode->i_mode |= S_IWUSR;
}
}
- inode->i_op = &openpromfs_prop_inode_ops;
+ inode->i_fop = &openpromfs_prop_ops;
inode->i_nlink = 1;
if (inode->i_size < 0)
inode->i_size = 0;
@@ -845,7 +839,7 @@ static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode
if (!inode)
return -EINVAL;
inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
- inode->i_op = &openpromfs_prop_inode_ops;
+ inode->i_fop = &openpromfs_prop_ops;
inode->i_nlink = 1;
if (inode->i_size < 0) inode->i_size = 0;
inode->u.generic_ip = (void *)(long)(((u16)aliases) |
@@ -976,22 +970,12 @@ static u16 get_nodes (u16 parent, u32 node)
return n;
}
-
-static struct file_operations openprom_operations = {
- readdir: openpromfs_readdir,
-};
-
-static struct inode_operations openprom_inode_operations = {
- &openprom_operations,/* default net directory file-ops */
- NULL, /* create */
- openpromfs_lookup, /* lookup */
-};
-
static void openprom_read_inode(struct inode * inode)
{
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
if (inode->i_ino == OPENPROM_ROOT_INO) {
inode->i_op = &openprom_inode_operations;
+ inode->i_fop = &openprom_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
}
}
@@ -1017,15 +1001,9 @@ static int openprom_statfs(struct super_block *sb, struct statfs *buf, int bufsi
}
static struct super_operations openprom_sops = {
- openprom_read_inode,
- NULL,
- NULL,
- NULL,
- NULL,
- openprom_put_super,
- NULL,
- openprom_statfs,
- NULL
+ read_inode: openprom_read_inode,
+ put_super: openprom_put_super,
+ statfs: openprom_statfs,
};
struct super_block *openprom_read_super(struct super_block *s,void *data,
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 31e1e64b6..836d43bf3 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -397,11 +397,15 @@ void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
int first_minor = drive << dev->minor_shift;
int end_minor = first_minor + dev->max_p;
- blk_size[dev->major] = NULL;
+ if(!dev->sizes)
+ blk_size[dev->major] = NULL;
+
dev->part[first_minor].nr_sects = size;
/* No Such Agen^Wdevice or no minors to use for partitions */
if (!size || minors == 1)
return;
+
+ blk_size[dev->major] = NULL;
check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
/*
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 904b6b0ed..2f315ccd9 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -351,7 +351,7 @@ int msdos_partition(struct gendisk *hd, kdev_t dev,
int tested_for_xlate = 0;
read_mbr:
-#endif
+#endif /* CONFIG_BLK_DEV_IDE */
if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
if (warn_no_part) printk(" unable to read partition table\n");
return -1;
@@ -359,7 +359,7 @@ read_mbr:
data = bh->b_data;
#ifdef CONFIG_BLK_DEV_IDE
check_table:
-#endif
+#endif /* CONFIG_BLK_DEV_IDE */
/* Use bforget(), because we may have changed the disk geometry */
if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
bforget(bh);
diff --git a/fs/pipe.c b/fs/pipe.c
index 2dea69d60..6f8452534 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -533,7 +533,6 @@ struct file_operations rdwr_pipe_fops = {
static struct inode * get_pipe_inode(void)
{
- extern struct inode_operations pipe_inode_operations;
struct inode *inode = get_empty_inode();
unsigned long page;
@@ -548,7 +547,7 @@ static struct inode * get_pipe_inode(void)
if (!inode->i_pipe)
goto fail_page;
- inode->i_op = &pipe_inode_operations;
+ inode->i_fop = &rdwr_pipe_fops;
init_waitqueue_head(PIPE_WAIT(*inode));
PIPE_BASE(*inode) = (char *) page;
@@ -578,10 +577,6 @@ fail_inode:
return NULL;
}
-struct inode_operations pipe_inode_operations = {
- &rdwr_pipe_fops,
-};
-
int do_pipe(int *fd)
{
struct inode * inode;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index cdd2116b2..54d93e131 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -208,10 +208,6 @@ static struct file_operations proc_maps_operations = {
read: pid_maps_read,
};
-struct inode_operations proc_maps_inode_operations = {
- &proc_maps_operations, /* default base directory file-ops */
-};
-
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
static ssize_t proc_info_read(struct file * file, char * buf,
@@ -259,10 +255,6 @@ static struct file_operations proc_info_file_operations = {
read: proc_info_read,
};
-static struct inode_operations proc_info_inode_operations = {
- &proc_info_file_operations, /* default proc file-ops */
-};
-
#define MAY_PTRACE(p) \
(p==current||(p->p_pptr==current&&(p->flags&PF_PTRACED)&&p->state==TASK_STOPPED))
@@ -350,21 +342,7 @@ static struct file_operations proc_mem_operations = {
};
static struct inode_operations proc_mem_inode_operations = {
- &proc_mem_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL /* revalidate */
+ permission: proc_permission,
};
static struct dentry * proc_pid_follow_link(struct dentry *dentry,
@@ -453,14 +431,6 @@ static struct inode_operations proc_pid_link_inode_operations = {
follow_link: proc_pid_follow_link
};
-/* reading from directory - bad */
-
-static ssize_t proc_dir_read (struct file * filp, char * buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
struct pid_entry {
int type;
int len;
@@ -744,28 +714,16 @@ out:
}
static struct file_operations proc_fd_operations = {
- read: proc_dir_read, /* read - bad */
- readdir: proc_readfd, /* readdir */
+ read: generic_read_dir,
+ readdir: proc_readfd,
};
/*
* proc directories can do almost nothing..
*/
static struct inode_operations proc_fd_inode_operations = {
- &proc_fd_operations, /* default base directory file-ops */
- NULL, /* create */
- proc_lookupfd, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- proc_permission, /* permission */
+ lookup: proc_lookupfd,
+ permission: proc_permission,
};
static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
@@ -801,6 +759,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
case PROC_PID_FD:
inode->i_nlink = 2;
inode->i_op = &proc_fd_inode_operations;
+ inode->i_fop = &proc_fd_operations;
break;
case PROC_PID_EXE:
inode->i_op = &proc_pid_link_inode_operations;
@@ -815,36 +774,37 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
inode->u.proc_i.op.proc_get_link = proc_root_link;
break;
case PROC_PID_ENVIRON:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_environ;
break;
case PROC_PID_STATUS:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_status;
break;
case PROC_PID_STAT:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_stat;
break;
case PROC_PID_CMDLINE:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_cmdline;
break;
case PROC_PID_STATM:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_statm;
break;
case PROC_PID_MAPS:
- inode->i_op = &proc_maps_inode_operations;
+ inode->i_fop = &proc_maps_operations;
break;
#ifdef __SMP__
case PROC_PID_CPU:
- inode->i_op = &proc_info_inode_operations;
+ inode->i_fop = &proc_info_file_operations;
inode->u.proc_i.op.proc_read = proc_pid_cpu;
break;
#endif
case PROC_PID_MEM:
inode->i_op = &proc_mem_inode_operations;
+ inode->i_fop = &proc_mem_operations;
break;
default:
printk("procfs: impossible type (%d)",p->type);
@@ -860,14 +820,12 @@ out:
}
static struct file_operations proc_base_operations = {
- read: proc_dir_read, /* read - bad */
- readdir: proc_base_readdir, /* readdir */
+ read: generic_read_dir,
+ readdir: proc_base_readdir,
};
static struct inode_operations proc_base_inode_operations = {
- &proc_base_operations, /* default base directory file-ops */
- NULL, /* create */
- proc_base_lookup, /* lookup */
+ lookup: proc_base_lookup,
};
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
@@ -910,6 +868,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
goto out;
inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
inode->i_op = &proc_base_inode_operations;
+ inode->i_fop = &proc_base_operations;
inode->i_nlink = 3;
inode->i_flags|=S_IMMUTABLE;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index ad42f4fbc..fcfadbc99 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -37,10 +37,6 @@ static struct file_operations proc_file_operations = {
write: proc_file_write,
};
-static struct inode_operations proc_file_inode_operations = {
- &proc_file_operations, /* default proc file-ops */
-};
-
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
@@ -343,10 +339,8 @@ static struct file_operations proc_dir_operations = {
/*
* proc directories can do almost nothing..
*/
-struct inode_operations proc_dir_inode_operations = {
- &proc_dir_operations, /* default net directory file-ops */
- NULL, /* create */
- proc_lookup, /* lookup */
+static struct inode_operations proc_dir_inode_operations = {
+ lookup: proc_lookup,
};
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
@@ -361,15 +355,17 @@ int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
dp->parent = dir;
dir->subdir = dp;
if (S_ISDIR(dp->mode)) {
- if (dp->ops == NULL)
- dp->ops = &proc_dir_inode_operations;
+ if (dp->proc_iops == NULL) {
+ dp->proc_fops = &proc_dir_operations;
+ dp->proc_iops = &proc_dir_inode_operations;
+ }
dir->nlink++;
} else if (S_ISLNK(dp->mode)) {
- if (dp->ops == NULL)
- dp->ops = &proc_link_inode_operations;
+ if (dp->proc_iops == NULL)
+ dp->proc_iops = &proc_link_inode_operations;
} else if (S_ISREG(dp->mode)) {
- if (dp->ops == NULL)
- dp->ops = &proc_file_inode_operations;
+ if (dp->proc_fops == NULL)
+ dp->proc_fops = &proc_file_operations;
}
return 0;
}
@@ -490,7 +486,8 @@ struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *paren
memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
ent->name = ((char *) ent) + sizeof(*ent);
ent->namelen = len;
- ent->ops = &proc_dir_inode_operations;
+ ent->proc_fops = &proc_dir_operations;
+ ent->proc_iops = &proc_dir_inode_operations;
ent->nlink = 2;
ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
@@ -522,7 +519,8 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
if (S_ISDIR(mode)) {
if ((mode & S_IALLUGO) == 0)
mode |= S_IRUGO | S_IXUGO;
- ent->ops = &proc_dir_inode_operations;
+ ent->proc_fops = &proc_dir_operations;
+ ent->proc_iops = &proc_dir_inode_operations;
ent->nlink = 2;
} else {
if ((mode & S_IFMT) == 0)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index ffe846e5c..84a23a7f5 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -95,10 +95,6 @@ static void proc_put_super(struct super_block *sb)
*p = (struct super_block *)(*p)->u.generic_sbp;
}
-static void proc_write_inode(struct inode * inode)
-{
-}
-
static void proc_read_inode(struct inode * inode)
{
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -120,15 +116,11 @@ static int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
}
static struct super_operations proc_sops = {
- proc_read_inode,
- proc_write_inode,
- proc_put_inode,
- proc_delete_inode, /* delete_inode(struct inode *) */
- NULL,
- proc_put_super,
- NULL,
- proc_statfs,
- NULL
+ read_inode: proc_read_inode,
+ put_inode: proc_put_inode,
+ delete_inode: proc_delete_inode,
+ put_super: proc_put_super,
+ statfs: proc_statfs,
};
@@ -195,8 +187,12 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
__MOD_INC_USE_COUNT(de->owner);
if (S_ISBLK(de->mode)||S_ISCHR(de->mode)||S_ISFIFO(de->mode))
init_special_inode(inode,de->mode,kdev_t_to_nr(de->rdev));
- else if (de->ops)
- inode->i_op = de->ops;
+ else {
+ if (de->proc_iops)
+ inode->i_op = de->proc_iops;
+ if (de->proc_fops)
+ inode->i_fop = de->proc_fops;
+ }
}
out:
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 01ac4fe2a..13ec76b02 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -26,15 +26,11 @@ static int open_kcore(struct inode * inode, struct file * filp)
static ssize_t read_kcore(struct file *, char *, size_t, loff_t *);
-static struct file_operations proc_kcore_operations = {
+struct file_operations proc_kcore_operations = {
read: read_kcore,
open: open_kcore,
};
-struct inode_operations proc_kcore_inode_operations = {
- &proc_kcore_operations,
-};
-
#ifdef CONFIG_KCORE_AOUT
static ssize_t read_kcore(struct file *file, char *buf, size_t count, loff_t *ppos)
{
@@ -323,7 +319,7 @@ static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t
* and after elf_kcore_store_hdr() returns.
* For now assume that num_vma does not change (TA)
*/
- proc_root_kcore.size = size = get_kcore_size(&num_vma, &elf_buflen);
+ proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen);
if (buflen == 0 || *fpos >= size)
return 0;
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index a8fe0fc3c..149ad0aaa 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -45,13 +45,9 @@ static unsigned int kmsg_poll(struct file *file, poll_table * wait)
}
-static struct file_operations proc_kmsg_operations = {
+struct file_operations proc_kmsg_operations = {
read: kmsg_read,
poll: kmsg_poll,
open: kmsg_open,
release: kmsg_release,
};
-
-struct inode_operations proc_kmsg_inode_operations = {
- &proc_kmsg_operations, /* default base directory file-ops */
-};
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 3ad4bfabf..1f7ba6b99 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -598,28 +598,11 @@ static struct file_operations proc_profile_operations = {
write: write_profile,
};
-static struct inode_operations proc_profile_inode_operations = {
- &proc_profile_operations,
-};
-
-static struct proc_dir_entry proc_root_kmsg = {
- 0, 4, "kmsg",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kmsg_inode_operations
-};
-struct proc_dir_entry proc_root_kcore = {
- 0, 5, "kcore",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kcore_inode_operations
-};
-static struct proc_dir_entry proc_root_profile = {
- 0, 7, "profile",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_profile_inode_operations
-};
+struct proc_dir_entry *proc_root_kcore;
void __init proc_misc_init(void)
{
+ struct proc_dir_entry *entry;
static struct {
char *name;
int (*read_proc)(char*,char**,off_t,int,int*,void*);
@@ -665,11 +648,25 @@ void __init proc_misc_init(void)
create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
/* And now for trickier ones */
- proc_register(&proc_root, &proc_root_kmsg);
- proc_register(&proc_root, &proc_root_kcore);
- proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
+ entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
+ if (entry)
+ entry->proc_fops = &proc_kmsg_operations;
+ proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
+ if (proc_root_kcore) {
+ proc_root_kcore->proc_fops = &proc_kcore_operations;
+ proc_root_kcore->size =
+ (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
+ }
if (prof_shift) {
- proc_register(&proc_root, &proc_root_profile);
- proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
+ entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
+ if (entry) {
+ entry->proc_fops = &proc_profile_operations;
+ entry->size = (1+prof_len) * sizeof(unsigned int);
+ }
}
+#ifdef __powerpc__
+ entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
+ if (entry)
+ entry->proc_fops = &ppc_htab_operations;
+#endif
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8bacabed2..6cdb2ad19 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -51,13 +51,6 @@ static struct proc_dir_entry proc_root_self = {
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
64, &proc_self_inode_operations,
};
-#ifdef __powerpc__
-static struct proc_dir_entry proc_root_ppc_htab = {
- 0, 8, "ppc_htab",
- S_IFREG | S_IRUGO|S_IWUSR, 1, 0, 0,
- 0, &proc_ppc_htab_inode_operations,
-};
-#endif
void __init proc_root_init(void)
{
@@ -143,16 +136,14 @@ static int proc_root_readdir(struct file * filp,
* directory handling functions for that..
*/
static struct file_operations proc_root_operations = {
- readdir: proc_root_readdir,
+ readdir: proc_root_readdir,
};
/*
* proc root can do almost nothing..
*/
static struct inode_operations proc_root_inode_operations = {
- &proc_root_operations, /* default base directory file-ops */
- NULL, /* create */
- proc_root_lookup, /* lookup */
+ lookup: proc_root_lookup,
};
/*
@@ -161,7 +152,7 @@ static struct inode_operations proc_root_inode_operations = {
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,
+ 0, &proc_root_inode_operations, &proc_root_operations,
NULL, NULL,
NULL,
&proc_root, NULL
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 068c56535..4b146945a 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -78,21 +78,19 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
return 0;
}
-static struct file_operations qnx4_dir_operations =
+struct file_operations qnx4_dir_operations =
{
- readdir: qnx4_readdir,
- fsync: file_fsync,
+ read: generic_read_dir,
+ readdir: qnx4_readdir,
+ fsync: file_fsync,
};
struct inode_operations qnx4_dir_inode_operations =
{
- default_file_ops: &qnx4_dir_operations,
+ lookup: qnx4_lookup,
#ifdef CONFIG_QNX4FS_RW
- create: qnx4_create,
-#endif
- lookup: qnx4_lookup,
-#ifdef CONFIG_QNX4FS_RW
- unlink: qnx4_unlink,
- rmdir: qnx4_rmdir,
+ create: qnx4_create,
+ unlink: qnx4_unlink,
+ rmdir: qnx4_rmdir,
#endif
};
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index 6eb3ca0a5..c3cc930e3 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -22,7 +22,7 @@
* We have mostly NULL's here: the current defaults are ok for
* the qnx4 filesystem.
*/
-static struct file_operations qnx4_file_operations =
+struct file_operations qnx4_file_operations =
{
read: generic_file_read,
#ifdef CONFIG_QNX4FS_RW
@@ -36,7 +36,6 @@ static struct file_operations qnx4_file_operations =
struct inode_operations qnx4_file_inode_operations =
{
- default_file_ops: &qnx4_file_operations,
#ifdef CONFIG_QNX4FS_RW
truncate: qnx4_truncate,
#endif
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index ed405897a..49bad450e 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -231,7 +231,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
block = le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_blk) + iblock - 1;
} else {
// iblock is beyond first extent. We have to follow the extent chain.
- i_xblk = qnx4_inode->i_xblk;
+ i_xblk = le32_to_cpu(qnx4_inode->i_xblk);
offset = iblock - le32_to_cpu(qnx4_inode->i_first_xtnt.xtnt_size);
ix = 0;
while ( --nxtnt > 0 ) {
@@ -455,7 +455,6 @@ static void qnx4_read_inode(struct inode *inode)
int block, ino;
ino = inode->i_ino;
- inode->i_op = NULL;
inode->i_mode = 0;
QNX4DEBUG(("Reading inode : [%d]\n", ino));
@@ -488,11 +487,13 @@ static void qnx4_read_inode(struct inode *inode)
memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &qnx4_file_inode_operations;
+ inode->i_fop = &qnx4_file_operations;
inode->i_mapping->a_ops = &qnx4_aops;
inode->u.qnx4_i.mmu_private = inode->i_size;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &qnx4_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &qnx4_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &qnx4_aops;
inode->u.qnx4_i.mmu_private = inode->i_size;
diff --git a/fs/read_write.c b/fs/read_write.c
index 6abc2c396..e82aaea96 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -13,6 +13,16 @@
#include <asm/uaccess.h>
+struct file_operations generic_ro_fops = {
+ read: generic_file_read,
+ mmap: generic_file_mmap,
+};
+
+ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
loff_t default_llseek(struct file *file, loff_t offset, int origin)
{
long long retval;
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index ab5972591..b95dfa219 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -450,27 +450,13 @@ static struct address_space_operations romfs_aops = {
readpage: romfs_readpage
};
-static struct file_operations romfs_file_operations = {
- read: generic_file_read,
- mmap: generic_file_mmap,
-};
-
-static struct inode_operations romfs_file_inode_operations = {
- &romfs_file_operations,
-};
-
static struct file_operations romfs_dir_operations = {
+ read: generic_read_dir,
readdir: romfs_readdir,
};
-/* Merged dir/symlink op table. readdir/lookup/readlink/follow_link
- * will protect from type mismatch.
- */
-
static struct inode_operations romfs_dir_inode_operations = {
- &romfs_dir_operations,
- NULL, /* create */
- romfs_lookup, /* lookup */
+ lookup: romfs_lookup,
};
static mode_t romfs_modemap[] =
@@ -479,18 +465,6 @@ static mode_t romfs_modemap[] =
S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
};
-static struct inode_operations *romfs_inoops[] =
-{
- NULL, /* hardlink, handled elsewhere */
- &romfs_dir_inode_operations,
- &romfs_file_inode_operations,
- &page_symlink_inode_operations,
- NULL, /* device/fifo/socket nodes, */
- NULL, /* set by init_special_inode */
- NULL,
- NULL,
-};
-
static void
romfs_read_inode(struct inode *i)
{
@@ -498,7 +472,6 @@ romfs_read_inode(struct inode *i)
struct romfs_inode ri;
ino = i->i_ino & ROMFH_MASK;
- i->i_op = NULL;
i->i_mode = 0;
/* Loop for finding the real hard link */
@@ -534,32 +507,38 @@ romfs_read_inode(struct inode *i)
/* Compute permissions */
ino = romfs_modemap[nextfh & ROMFH_TYPE];
/* only "normal" files have ops */
- if ((i->i_op = romfs_inoops[nextfh & ROMFH_TYPE])) {
- if (nextfh & ROMFH_EXEC)
- ino |= S_IXUGO;
- i->i_mode = ino;
- if (S_ISDIR(ino))
+ switch (nextfh & ROMFH_TYPE) {
+ case 1:
i->i_size = i->u.romfs_i.i_metasize;
- else
+ i->i_op = &romfs_dir_inode_operations;
+ i->i_fop = &romfs_dir_operations;
+ if (nextfh & ROMFH_EXEC)
+ ino |= S_IXUGO;
+ i->i_mode = ino;
+ break;
+ case 2:
+ i->i_fop = &generic_ro_fops;
i->i_data.a_ops = &romfs_aops;
- } else {
- /* depending on MBZ for sock/fifos */
- nextfh = ntohl(ri.spec);
- nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
- init_special_inode(i, ino, nextfh);
+ if (nextfh & ROMFH_EXEC)
+ ino |= S_IXUGO;
+ i->i_mode = ino;
+ break;
+ case 3:
+ i->i_op = &page_symlink_inode_operations;
+ i->i_mode = S_IRWXUGO;
+ break;
+ default:
+ /* depending on MBZ for sock/fifos */
+ nextfh = ntohl(ri.spec);
+ nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
+ init_special_inode(i, ino, nextfh);
}
}
static struct super_operations romfs_ops = {
- romfs_read_inode, /* read inode */
- NULL, /* write inode */
- NULL, /* put inode */
- NULL, /* delete inode */
- NULL, /* notify change */
- romfs_put_super, /* put super */
- NULL, /* write super */
- romfs_statfs, /* statfs */
- NULL /* remount */
+ read_inode: romfs_read_inode,
+ put_super: romfs_put_super,
+ statfs: romfs_statfs,
};
static struct file_system_type romfs_fs_type = {
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 68351b4b4..ca98fc9ca 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -18,7 +18,6 @@
/* #define pr_debug printk */
#define SMBFS_MAX_AGE 5*HZ
-static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *);
static int smb_readdir(struct file *, void *, filldir_t);
static int smb_dir_open(struct inode *, struct file *);
@@ -30,9 +29,9 @@ static int smb_unlink(struct inode *, struct dentry *);
static int smb_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
-static struct file_operations smb_dir_operations =
+struct file_operations smb_dir_operations =
{
- read: smb_dir_read,
+ read: generic_read_dir,
readdir: smb_readdir,
ioctl: smb_ioctl,
open: smb_dir_open,
@@ -40,29 +39,16 @@ static struct file_operations smb_dir_operations =
struct inode_operations smb_dir_inode_operations =
{
- &smb_dir_operations, /* default directory file ops */
- smb_create, /* create */
- smb_lookup, /* lookup */
- NULL, /* link */
- smb_unlink, /* unlink */
- NULL, /* symlink */
- smb_mkdir, /* mkdir */
- smb_rmdir, /* rmdir */
- NULL, /* mknod */
- smb_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- NULL, /* permission */
- smb_revalidate_inode, /* revalidate */
+ create: smb_create,
+ lookup: smb_lookup,
+ unlink: smb_unlink,
+ mkdir: smb_mkdir,
+ rmdir: smb_rmdir,
+ rename: smb_rename,
+ revalidate: smb_revalidate_inode,
+ setattr: smb_notify_change,
};
-static ssize_t
-smb_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int
smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index a62de1256..1360ca994 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -169,17 +169,25 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
static int
smb_writepage(struct dentry *dentry, struct page *page)
{
- int result;
-
-#ifdef SMBFS_PARANOIA
- if (!PageLocked(page))
- printk("smb_writepage: page not already locked!\n");
-#endif
+ struct inode *inode = dentry->d_inode;
+ unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset = PAGE_CACHE_SIZE;
+ int err;
+
+ /* easy case */
+ if (page->index < end_index)
+ goto do_it;
+ /* things got complicated... */
+ offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+ /* OK, are we completely out? */
+ if (page->index >= end_index+1 || !offset)
+ return -EIO;
+do_it:
get_page(page);
- result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
+ err = smb_writepage_sync(dentry, page, 0, offset);
SetPageUptodate(page);
put_page(page);
- return result;
+ return err;
}
static int
@@ -376,7 +384,7 @@ printk("smb_file_permission: mode=%x, mask=%x\n", mode, mask);
return error;
}
-static struct file_operations smb_file_operations =
+struct file_operations smb_file_operations =
{
read: smb_file_read,
write: smb_file_write,
@@ -389,19 +397,7 @@ static struct file_operations smb_file_operations =
struct inode_operations smb_file_inode_operations =
{
- &smb_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- smb_file_permission, /* permission */
- smb_revalidate_inode, /* revalidate */
+ permission: smb_file_permission,
+ revalidate: smb_revalidate_inode,
+ setattr: smb_notify_change,
};
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 9a7560aa4..3b13fdd80 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -29,7 +29,6 @@
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
-static void smb_read_inode(struct inode *);
static void smb_put_inode(struct inode *);
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
@@ -38,15 +37,10 @@ static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
static struct super_operations smb_sops =
{
- smb_read_inode, /* read inode */
- NULL, /* write inode */
- smb_put_inode, /* put inode */
- smb_delete_inode, /* delete inode */
- smb_notify_change, /* notify change */
- smb_put_super, /* put superblock */
- NULL, /* write superblock */
- smb_statfs, /* stat filesystem */
- NULL /* remount filesystem */
+ put_inode: smb_put_inode,
+ delete_inode: smb_delete_inode,
+ put_super: smb_put_super,
+ statfs: smb_statfs,
};
/* FIXME: Look at all inodes whether so that we do not get duplicate
@@ -84,11 +78,12 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
smb_set_inode_attr(result, fattr);
if (S_ISREG(result->i_mode)) {
result->i_op = &smb_file_inode_operations;
+ result->i_fop = &smb_file_operations;
result->i_data.a_ops = &smb_file_aops;
- } else if (S_ISDIR(result->i_mode))
+ } else if (S_ISDIR(result->i_mode)) {
result->i_op = &smb_dir_inode_operations;
- else
- result->i_op = NULL;
+ result->i_fop = &smb_dir_operations;
+ }
insert_inode_hash(result);
return result;
}
@@ -152,14 +147,6 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode->u.smbfs_i.oldmtime = jiffies;
}
-static void
-smb_read_inode(struct inode *inode)
-{
- /* Now it can be called only by NFS */
- printk("smb_read_inode called from invalid point\n");
- return;
-}
-
/*
* This is called if the connection has gone bad ...
* try to kill off all the current inodes.
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 5d8ddc962..a2325d3c8 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -15,6 +15,7 @@
#include <linux/net.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
+#include <linux/smp_lock.h>
#include <net/scm.h>
#include <net/ip.h>
@@ -79,13 +80,33 @@ _send(struct socket *socket, const void *buff, int len)
return err;
}
+struct data_callback {
+ struct tq_struct cb;
+ struct sock *sk;
+};
/*
* N.B. What happens if we're in here when the socket closes??
*/
static void
-smb_data_callback(struct sock *sk, int len)
+found_data(struct sock *sk)
{
- struct socket *socket = sk->socket;
+ /*
+ * FIXME: copied from sock_def_readable, it should be a call to
+ * server->data_ready() -- manfreds@colorfullife.com
+ */
+ read_lock(&sk->callback_lock);
+ if(!sk->dead) {
+ wake_up_interruptible(sk->sleep);
+ sock_wake_async(sk->socket,1,POLL_IN);
+ }
+ read_unlock(&sk->callback_lock);
+}
+
+static void
+smb_data_callback(void* ptr)
+{
+ struct data_callback* job=ptr;
+ struct socket *socket = job->sk->socket;
unsigned char peek_buf[4];
int result;
mm_segment_t fs;
@@ -93,10 +114,11 @@ smb_data_callback(struct sock *sk, int len)
fs = get_fs();
set_fs(get_ds());
+ lock_kernel();
while (1)
{
result = -EIO;
- if (sk->dead)
+ if (job->sk->dead)
{
#ifdef SMBFS_PARANOIA
printk("smb_data_callback: sock dead!\n");
@@ -120,12 +142,30 @@ smb_data_callback(struct sock *sk, int len)
if (result == -EAGAIN)
break;
}
+ unlock_kernel();
set_fs(fs);
if (result != -EAGAIN)
- {
- wake_up_interruptible(sk->sleep);
+ found_data(job->sk);
+ kfree(ptr);
+}
+
+static void
+smb_data_ready(struct sock *sk, int len)
+{
+ struct data_callback* job;
+ job = kmalloc(sizeof(struct data_callback),GFP_ATOMIC);
+ if(job == 0) {
+ printk("smb_data_ready(): lost SESSION KEEPALIVE due to OOM.\n");
+ found_data(sk);
+ return;
}
+ job->cb.next = NULL;
+ job->cb.sync = 0;
+ job->cb.routine = smb_data_callback;
+ job->cb.data = job;
+ job->sk = sk;
+ queue_task(&job->cb, &tq_scheduler);
}
int
@@ -182,8 +222,8 @@ smb_catch_keepalive(struct smb_sb_info *server)
/*
* Install the callback atomically to avoid races ...
*/
- data_ready = xchg(&sk->data_ready, smb_data_callback);
- if (data_ready != smb_data_callback)
+ data_ready = xchg(&sk->data_ready, smb_data_ready);
+ if (data_ready != smb_data_ready)
{
server->data_ready = data_ready;
error = 0;
@@ -232,10 +272,10 @@ smb_dont_catch_keepalive(struct smb_sb_info *server)
*/
data_ready = xchg(&sk->data_ready, server->data_ready);
server->data_ready = NULL;
- if (data_ready != smb_data_callback)
+ if (data_ready != smb_data_ready)
{
printk("smb_dont_catch_keepalive: "
- "sk->data_callback != smb_data_callback\n");
+ "sk->data_ready != smb_data_ready\n");
}
error = 0;
out:
@@ -256,7 +296,7 @@ smb_close_socket(struct smb_sb_info *server)
printk("smb_close_socket: closing socket %p\n", server_sock(server));
#endif
#ifdef SMBFS_PARANOIA
-if (server_sock(server)->sk->data_ready == smb_data_callback)
+if (server_sock(server)->sk->data_ready == smb_data_ready)
printk("smb_close_socket: still catching keepalives!\n");
#endif
server->sock_file = NULL;
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index f21a47578..57968a839 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -19,38 +19,14 @@
#include <linux/stat.h>
#include <linux/string.h>
-#include <asm/uaccess.h>
-
-static ssize_t sysv_dir_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
-{
- return -EISDIR;
-}
-
static int sysv_readdir(struct file *, void *, filldir_t);
-static struct file_operations sysv_dir_operations = {
- read: sysv_dir_read,
+struct file_operations sysv_dir_operations = {
+ read: generic_read_dir,
readdir: sysv_readdir,
fsync: file_fsync,
};
-/*
- * directories can handle most operations...
- */
-struct inode_operations sysv_dir_inode_operations = {
- &sysv_dir_operations, /* default directory file-ops */
- sysv_create, /* create */
- sysv_lookup, /* lookup */
- sysv_link, /* link */
- sysv_unlink, /* unlink */
- sysv_symlink, /* symlink */
- sysv_mkdir, /* mkdir */
- sysv_rmdir, /* rmdir */
- sysv_mknod, /* mknod */
- sysv_rename, /* rename */
-};
-
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index b60a1d02e..d68967b19 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -13,21 +13,14 @@
* SystemV/Coherent regular file handling primitives
*/
-#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sysv_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/pagemap.h>
/*
* We have mostly NULLs here: the current defaults are OK for
* the coh filesystem.
*/
-static struct file_operations sysv_file_operations = {
+struct file_operations sysv_file_operations = {
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
@@ -35,6 +28,6 @@ static struct file_operations sysv_file_operations = {
};
struct inode_operations sysv_file_inode_operations = {
- &sysv_file_operations,
truncate: sysv_truncate,
+ setattr: sysv_notify_change,
};
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 2826286cc..0bdceb2f5 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -156,7 +156,6 @@ struct inode * sysv_new_inode(const struct inode * dir)
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = ino;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = NULL;
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 6580b6125..2c79b3c71 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -68,19 +68,15 @@ static void sysv_delete_inode(struct inode *inode)
static void sysv_put_super(struct super_block *);
static void sysv_write_super(struct super_block *);
static void sysv_read_inode(struct inode *);
-static int sysv_notify_change(struct dentry *, struct iattr *);
static int sysv_statfs(struct super_block *, struct statfs *, int);
static struct super_operations sysv_sops = {
- sysv_read_inode,
- sysv_write_inode,
- NULL, /* nothing special on put_inode() */
- sysv_delete_inode,
- sysv_notify_change,
- sysv_put_super,
- sysv_write_super,
- sysv_statfs,
- NULL /* remount_fs */
+ read_inode: sysv_read_inode,
+ write_inode: sysv_write_inode,
+ delete_inode: sysv_delete_inode,
+ put_super: sysv_put_super,
+ write_super: sysv_write_super,
+ statfs: sysv_statfs,
};
/* The following functions try to recognize specific filesystems.
@@ -1027,6 +1023,12 @@ static inline void coh_write3byte (unsigned char * p, unsigned long val)
*(unsigned short *)(p+1) = (unsigned short) val;
}
+struct inode_operations sysv_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ setattr: sysv_notify_change,
+};
+
static void sysv_read_inode(struct inode *inode)
{
struct super_block * sb = inode->i_sb;
@@ -1036,7 +1038,6 @@ static void sysv_read_inode(struct inode *inode)
umode_t mode;
ino = inode->i_ino;
- inode->i_op = NULL;
inode->i_mode = 0;
if (!ino || ino > sb->sv_ninodes) {
printk("Bad inode number on dev %s"
@@ -1085,11 +1086,13 @@ static void sysv_read_inode(struct inode *inode)
read3byte(&raw_inode->i_a.i_addb[3*block]);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &sysv_file_inode_operations;
+ inode->i_fop = &sysv_file_operations;
inode->i_mapping->a_ops = &sysv_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &sysv_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_fop = &sysv_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &sysv_symlink_inode_operations;
inode->i_mapping->a_ops = &sysv_aops;
} else
init_special_inode(inode, inode->i_mode,raw_inode->i_a.i_rdev);
@@ -1097,7 +1100,7 @@ static void sysv_read_inode(struct inode *inode)
}
/* To avoid inconsistencies between inodes in memory and inodes on disk. */
-static int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
+int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
int error;
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 9661af99c..a7b871073 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -101,7 +101,7 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
return NULL;
}
-struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
{
struct inode * inode = NULL;
struct sysv_dir_entry * de;
@@ -193,7 +193,7 @@ static int sysv_add_entry(struct inode * dir,
return 0;
}
-int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
+static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
{
int error;
struct inode * inode;
@@ -204,6 +204,7 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &sysv_file_inode_operations;
+ inode->i_fop = &sysv_file_operations;
inode->i_mapping->a_ops = &sysv_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -222,7 +223,7 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
return 0;
}
-int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
+static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
{
int error;
struct inode * inode;
@@ -256,7 +257,7 @@ int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
return 0;
}
-int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
+static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
{
int error;
struct inode * inode;
@@ -275,6 +276,7 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &sysv_dir_inode_operations;
+ inode->i_fop = &sysv_dir_operations;
inode->i_size = 2 * SYSV_DIRSIZE;
dir_block = sysv_file_bread(inode,0,1);
if (!dir_block) {
@@ -370,7 +372,7 @@ bad_dir:
return 1;
}
-int sysv_rmdir(struct inode * dir, struct dentry * dentry)
+static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -407,7 +409,7 @@ end_rmdir:
return retval;
}
-int sysv_unlink(struct inode * dir, struct dentry * dentry)
+static int sysv_unlink(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -438,7 +440,7 @@ end_unlink:
return retval;
}
-int sysv_symlink(struct inode * dir, struct dentry * dentry,
+static int sysv_symlink(struct inode * dir, struct dentry * dentry,
const char * symname)
{
struct inode * inode;
@@ -456,7 +458,7 @@ int sysv_symlink(struct inode * dir, struct dentry * dentry,
goto out;
inode->i_mode = S_IFLNK | 0777;
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &sysv_symlink_inode_operations;
inode->i_mapping->a_ops = &sysv_aops;
err = block_symlink(inode, symname, l);
if (err)
@@ -479,7 +481,7 @@ out_no_entry:
goto out;
}
-int sysv_link(struct dentry * old_dentry, struct inode * dir,
+static int sysv_link(struct dentry * old_dentry, struct inode * dir,
struct dentry * dentry)
{
struct inode *oldinode = old_dentry->d_inode;
@@ -523,7 +525,7 @@ int sysv_link(struct dentry * old_dentry, struct inode * dir,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -604,3 +606,19 @@ end_rename:
brelse(new_bh);
return retval;
}
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations sysv_dir_inode_operations = {
+ create: sysv_create,
+ lookup: sysv_lookup,
+ link: sysv_link,
+ unlink: sysv_unlink,
+ symlink: sysv_symlink,
+ mkdir: sysv_mkdir,
+ rmdir: sysv_rmdir,
+ mknod: sysv_mknod,
+ rename: sysv_rename,
+ setattr: sysv_notify_change,
+};
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 963d20344..c31ff527a 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -49,39 +49,13 @@ static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
/* readdir and lookup functions */
-static struct file_operations udf_dir_operations = {
+struct file_operations udf_dir_operations = {
+ read: generic_read_dir,
readdir: udf_readdir,
ioctl: udf_ioctl,
fsync: udf_sync_file,
};
-struct inode_operations udf_dir_inode_operations = {
- &udf_dir_operations,
-#if CONFIG_UDF_RW == 1
- udf_create, /* create */
-#else
- NULL, /* create */
-#endif
- udf_lookup, /* lookup */
-#if CONFIG_UDF_RW == 1
- udf_link, /* link */
- udf_unlink, /* unlink */
- udf_symlink, /* symlink */
- udf_mkdir, /* mkdir */
- udf_rmdir, /* rmdir */
- udf_mknod, /* mknod */
- udf_rename, /* rename */
-#else
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
-#endif
-};
-
/*
* udf_readdir
*
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 546ac95b8..cea86257b 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -349,7 +349,7 @@ static int udf_open_file(struct inode * inode, struct file * filp)
return 0;
}
-static struct file_operations udf_file_operations = {
+struct file_operations udf_file_operations = {
llseek: udf_file_llseek,
read: generic_file_read,
write: udf_file_write,
@@ -361,7 +361,6 @@ static struct file_operations udf_file_operations = {
};
struct inode_operations udf_file_inode_operations = {
- &udf_file_operations,
#if CONFIG_UDF_RW == 1
truncate: udf_truncate,
#endif
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 8badac9d9..1f3300b7f 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -151,7 +151,6 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_IN_ICB;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
UDF_I_UMTIME(inode) = UDF_I_UATIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME;
- inode->i_op = NULL;
insert_inode_hash(inode);
mark_inode_dirty(inode);
unlock_super(sb);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 752a00339..335f54c75 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1077,6 +1077,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
case FILE_TYPE_DIRECTORY:
{
inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
inode->i_mode |= S_IFDIR;
inode->i_nlink ++;
break;
@@ -1089,6 +1090,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
else
inode->i_data.a_ops = &udf_aops;
inode->i_op = &udf_file_inode_operations;
+ inode->i_fop = &udf_file_operations;
inode->i_mode |= S_IFREG;
break;
}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index aff491ef5..f31bff3fc 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -289,7 +289,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
* Written, tested, and released.
*/
-struct dentry *
+static struct dentry *
udf_lookup(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = NULL;
@@ -631,7 +631,7 @@ static int udf_delete_entry(struct FileIdentDesc *fi,
return udf_write_fi(cfi, fi, fibh, NULL, NULL);
}
-int udf_create(struct inode *dir, struct dentry *dentry, int mode)
+static int udf_create(struct inode *dir, struct dentry *dentry, int mode)
{
struct udf_fileident_bh fibh;
struct inode *inode;
@@ -644,6 +644,7 @@ int udf_create(struct inode *dir, struct dentry *dentry, int mode)
inode->i_data.a_ops = &udf_adinicb_aops;
inode->i_op = &udf_file_inode_operations;
+ inode->i_fop = &udf_file_operations;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -672,7 +673,7 @@ int udf_create(struct inode *dir, struct dentry *dentry, int mode)
return 0;
}
-int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
+static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
{
struct inode * inode;
struct udf_fileident_bh fibh;
@@ -686,8 +687,6 @@ int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
- inode->i_mode = mode;
- inode->i_op = NULL;
if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
{
udf_debug("udf_add_entry failure!\n");
@@ -717,7 +716,7 @@ out:
return err;
}
-int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct udf_fileident_bh fibh;
@@ -736,6 +735,7 @@ int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
goto out;
inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
inode->i_size = (sizeof(struct FileIdentDesc) + 3) & ~3;
UDF_I_LENALLOC(inode) = inode->i_size;
loc = UDF_I_LOCATION(inode).logicalBlockNum;
@@ -860,7 +860,7 @@ static int empty_dir(struct inode *dir)
return 1;
}
-int udf_rmdir(struct inode * dir, struct dentry * dentry)
+static int udf_rmdir(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -906,7 +906,7 @@ out:
return retval;
}
-int udf_unlink(struct inode * dir, struct dentry * dentry)
+static int udf_unlink(struct inode * dir, struct dentry * dentry)
{
int retval;
struct inode * inode;
@@ -955,7 +955,7 @@ out:
return retval;
}
-int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
{
struct inode * inode;
struct PathComponent *pc;
@@ -1075,7 +1075,7 @@ out:
return err;
}
-int udf_link(struct dentry * old_dentry, struct inode * dir,
+static int udf_link(struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
@@ -1127,7 +1127,7 @@ int udf_link(struct dentry * old_dentry, struct inode * dir,
/* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
+static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry)
{
struct inode * old_inode, * new_inode;
@@ -1270,3 +1270,17 @@ end_rename:
}
return retval;
}
+
+struct inode_operations udf_dir_inode_operations = {
+ lookup: udf_lookup,
+#if CONFIG_UDF_RW == 1
+ create: udf_create,
+ link: udf_link,
+ unlink: udf_unlink,
+ symlink: udf_symlink,
+ mkdir: udf_mkdir,
+ rmdir: udf_rmdir,
+ mknod: udf_mknod,
+ rename: udf_rename,
+#endif
+};
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 272b9eacb..ed98bf802 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -105,25 +105,15 @@ static struct file_system_type udf_fstype = {
/* Superblock operations */
static struct super_operations udf_sb_ops =
{
- udf_read_inode, /* read_inode */
+ read_inode: udf_read_inode,
+ put_inode: udf_put_inode,
+ put_super: udf_put_super,
+ statfs: udf_statfs,
+ remount_fs: udf_remount_fs,
#if CONFIG_UDF_RW == 1
- udf_write_inode, /* write_inode */
-#else
- NULL, /* write_inode */
+ write_inode: udf_write_inode,
+ delete_inode: udf_delete_inode,
#endif
- udf_put_inode, /* put_inode */
-#if CONFIG_UDF_RW == 1
- udf_delete_inode, /* delete_inode */
-#else
- NULL, /* delete_inode */
-#endif
- NULL, /* notify_change */
- udf_put_super, /* put_super */
- NULL, /* write_super */
- udf_statfs, /* statfs */
- udf_remount_fs, /* remount_fs */
- NULL, /* clear_inode */
- NULL, /* umount_begin */
};
struct udf_options
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 39418f730..74a84f36c 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -63,6 +63,8 @@ struct super_block;
extern struct inode_operations udf_dir_inode_operations;
extern struct inode_operations udf_file_inode_operations;
+extern struct file_operations udf_dir_operations;
+extern struct file_operations udf_file_operations;
extern struct address_space_operations udf_adinicb_aops;
extern struct address_space_operations udf_symlink_aops;
@@ -118,15 +120,6 @@ extern void udf_warning(struct super_block *, const char *, const char *, ...);
/* namei.c */
extern int udf_write_fi(struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *);
-extern struct dentry * udf_lookup(struct inode *, struct dentry *);
-extern int udf_create(struct inode *, struct dentry *, int);
-extern int udf_mknod(struct inode *, struct dentry *, int, int);
-extern int udf_mkdir(struct inode *, struct dentry *, int);
-extern int udf_rmdir(struct inode *, struct dentry *);
-extern int udf_unlink(struct inode *, struct dentry *);
-extern int udf_symlink(struct inode *, struct dentry *, const char *);
-extern int udf_link(struct dentry *, struct inode *, struct dentry *);
-extern int udf_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
/* file.c */
extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile
index f8326866d..39d0d39ef 100644
--- a/fs/ufs/Makefile
+++ b/fs/ufs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := ufs.o
-O_OBJS := acl.o balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
+O_OBJS := balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
namei.o super.o symlink.o truncate.o util.o
M_OBJS := $(O_TARGET)
diff --git a/fs/ufs/acl.c b/fs/ufs/acl.c
deleted file mode 100644
index b002d3398..000000000
--- a/fs/ufs/acl.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * linux/fs/ufs/acl.c
- *
- * Copyright (C) 1998
- * Daniel Pirkl <daniel.pirkl@email.cz>
- * Charles University, Faculty of Mathematics and Physics
- *
- * from
- *
- * linux/fs/ext2/acl.c
- *
- * Copyright (C) 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- */
-
-/*
- * This file will contain the Access Control Lists management for UFS
- */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ufs_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-
-/*
- * ufs_permission ()
- *
- * Check for access rights
- */
-int ufs_permission (struct inode * inode, int mask)
-{
- unsigned short mode = inode->i_mode;
-
- /*
- * Nobody gets write access to a file on a readonly-fs
- */
- if ((mask & S_IWOTH) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
- IS_RDONLY(inode))
- return -EROFS;
- /*
- * Nobody gets write access to an immutable file
- */
- if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
- return -EACCES;
-
- /*
- * If no ACL, checks using the file mode
- */
- else if (current->fsuid == inode->i_uid)
- mode >>= 6;
- else if (in_group_p (inode->i_gid))
- mode >>= 3;
- /*
- * Access is always granted for root. We now check last,
- * though, for BSD process accounting correctness
- */
- if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
- return 0;
- if ((mask == S_IROTH) ||
- (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
- if (capable(CAP_DAC_READ_SEARCH))
- return 0;
- return -EACCES;
-}
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 0e4e3a720..28798e294 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -177,25 +177,8 @@ int ufs_check_dir_entry (const char * function, struct inode * dir,
return (error_msg == NULL ? 1 : 0);
}
-static struct file_operations ufs_dir_operations = {
+struct file_operations ufs_dir_operations = {
+ read: generic_read_dir,
readdir: ufs_readdir,
fsync: file_fsync,
};
-
-struct inode_operations ufs_dir_inode_operations = {
- &ufs_dir_operations, /* default directory file operations */
- ufs_create, /* create */
- ufs_lookup, /* lookup */
- ufs_link, /* link */
- ufs_unlink, /* unlink */
- ufs_symlink, /* symlink */
- ufs_mkdir, /* mkdir */
- ufs_rmdir, /* rmdir */
- ufs_mknod, /* mknod */
- ufs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- ufs_permission, /* permission */
- NULL /* revalidate */
-};
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 384774cc5..2a27f6f23 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -71,7 +71,7 @@ static long long ufs_file_lseek(
* We have mostly NULL's here: the current defaults are ok for
* the ufs filesystem.
*/
-static struct file_operations ufs_file_operations = {
+struct file_operations ufs_file_operations = {
llseek: ufs_file_lseek,
read: generic_file_read,
write: generic_file_write,
@@ -79,6 +79,5 @@ static struct file_operations ufs_file_operations = {
};
struct inode_operations ufs_file_inode_operations = {
- &ufs_file_operations,
truncate: ufs_truncate,
};
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 8b1943a84..93b520a0b 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -290,7 +290,6 @@ cg_found:
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
inode->u.ufs_i.i_lastfrag = 0;
- inode->i_op = NULL;
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index de2eec9a8..af07961e1 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -641,14 +641,14 @@ void ufs_read_inode (struct inode * inode)
}
- inode->i_op = NULL;
-
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ufs_file_inode_operations;
+ inode->i_fop = &ufs_file_operations;
inode->i_mapping->a_ops = &ufs_aops;
- } else if (S_ISDIR(inode->i_mode))
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ufs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode)) {
+ inode->i_fop = &ufs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
if (!inode->i_blocks)
inode->i_op = &ufs_fast_symlink_inode_operations;
else {
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 71198abc4..a36a6c3af 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -183,7 +183,7 @@ failed:
return NULL;
}
-struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
{
struct super_block * sb;
struct inode * inode;
@@ -403,7 +403,7 @@ static int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir,
* If the create succeeds, we fill in the inode information
* with d_instantiate().
*/
-int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
+static int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct super_block * sb;
struct inode * inode;
@@ -424,6 +424,7 @@ int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
if (!inode)
return err;
inode->i_op = &ufs_file_inode_operations;
+ inode->i_fop = &ufs_file_operations;
inode->i_mapping->a_ops = &ufs_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -450,7 +451,7 @@ int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
return 0;
}
-int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+static int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct super_block * sb;
struct inode * inode;
@@ -494,7 +495,7 @@ out_no_entry:
goto out;
}
-int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct super_block * sb;
struct inode * inode;
@@ -516,6 +517,7 @@ int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
goto out;
inode->i_op = &ufs_dir_inode_operations;
+ inode->i_fop = &ufs_dir_operations;
inode->i_size = UFS_SECTOR_SIZE;
dir_block = ufs_bread (inode, 0, 1, &err);
if (!dir_block) {
@@ -631,7 +633,7 @@ static int ufs_empty_dir (struct inode * inode)
return 1;
}
-int ufs_rmdir (struct inode * dir, struct dentry *dentry)
+static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
{
struct super_block *sb;
int retval;
@@ -690,7 +692,7 @@ end_rmdir:
return retval;
}
-int ufs_unlink(struct inode * dir, struct dentry *dentry)
+static int ufs_unlink(struct inode * dir, struct dentry *dentry)
{
struct super_block * sb;
int retval;
@@ -749,7 +751,7 @@ end_unlink:
/*
* Create symbolic link. We use only slow symlinks at this time.
*/
-int ufs_symlink (struct inode * dir, struct dentry * dentry,
+static int ufs_symlink (struct inode * dir, struct dentry * dentry,
const char * symname)
{
struct super_block * sb = dir->i_sb;
@@ -813,7 +815,7 @@ out_no_entry:
goto out;
}
-int ufs_link (struct dentry * old_dentry, struct inode * dir,
+static int ufs_link (struct dentry * old_dentry, struct inode * dir,
struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
@@ -857,7 +859,7 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir,
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+static int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
struct inode * new_dir, struct dentry * new_dentry )
{
struct super_block * sb;
@@ -973,3 +975,15 @@ end_rename:
return retval;
}
+
+struct inode_operations ufs_dir_inode_operations = {
+ create: ufs_create,
+ lookup: ufs_lookup,
+ link: ufs_link,
+ unlink: ufs_unlink,
+ symlink: ufs_symlink,
+ mkdir: ufs_mkdir,
+ rmdir: ufs_rmdir,
+ mknod: ufs_mknod,
+ rename: ufs_rename,
+};
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 901c91ff2..80e97bb06 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -173,6 +173,8 @@ void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab)
}
#endif /* UFS_SUPER_DEBUG_MORE */
+static struct super_operations ufs_super_ops;
+
static char error_buf[1024];
void ufs_error (struct super_block * sb, const char * function,
@@ -947,15 +949,14 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
}
static struct super_operations ufs_super_ops = {
- ufs_read_inode,
- ufs_write_inode,
- ufs_put_inode,
- ufs_delete_inode,
- NULL, /* notify_change() */
- ufs_put_super,
- ufs_write_super,
- ufs_statfs,
- ufs_remount
+ read_inode: ufs_read_inode,
+ write_inode: ufs_write_inode,
+ put_inode: ufs_put_inode,
+ delete_inode: ufs_delete_inode,
+ put_super: ufs_put_super,
+ write_super: ufs_write_super,
+ statfs: ufs_statfs,
+ remount_fs: ufs_remount,
};
static struct file_system_type ufs_fs_type = {
diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c
index 6eebff74a..58755dd2c 100644
--- a/fs/umsdos/check.c
+++ b/fs/umsdos/check.c
@@ -84,7 +84,6 @@ void check_sb (struct super_block *sb, const char c)
/*
* check an inode
*/
-extern struct inode_operations umsdos_rdir_inode_operations;
void check_inode (struct inode *inode)
{
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 366657ae6..be27c54a7 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -52,17 +52,6 @@ struct dentry_operations umsdos_dentry_operations =
umsdos_dentry_dput /* d_delete(struct dentry *) */
};
-
-/*
- * So grep * doesn't complain in the presence of directories.
- */
-
-int dummy_dir_read (struct file *filp, char *buff, size_t size, loff_t *count)
-{
- return -EISDIR;
-}
-
-
struct UMSDOS_DIR_ONCE {
void *dirbuf;
filldir_t filldir;
@@ -800,23 +789,23 @@ out_noread:
}
-static struct file_operations umsdos_dir_operations =
+struct file_operations umsdos_dir_operations =
{
- read: dummy_dir_read,
+ read: generic_read_dir,
readdir: UMSDOS_readdir,
ioctl: UMSDOS_ioctl_dir,
};
struct inode_operations umsdos_dir_inode_operations =
{
- &umsdos_dir_operations, /* default directory file-ops */
- UMSDOS_create, /* create */
- UMSDOS_lookup, /* lookup */
- UMSDOS_link, /* link */
- UMSDOS_unlink, /* unlink */
- UMSDOS_symlink, /* symlink */
- UMSDOS_mkdir, /* mkdir */
- UMSDOS_rmdir, /* rmdir */
- UMSDOS_mknod, /* mknod */
- UMSDOS_rename, /* rename */
+ create: UMSDOS_create,
+ lookup: UMSDOS_lookup,
+ link: UMSDOS_link,
+ unlink: UMSDOS_unlink,
+ symlink: UMSDOS_symlink,
+ mkdir: UMSDOS_mkdir,
+ rmdir: UMSDOS_rmdir,
+ mknod: UMSDOS_mknod,
+ rename: UMSDOS_rename,
+ setattr: UMSDOS_notify_change,
};
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 95d6528f3..7908144d7 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -20,8 +20,6 @@
#include <linux/list.h>
extern struct dentry_operations umsdos_dentry_operations;
-extern struct inode_operations umsdos_rdir_inode_operations;
-
struct dentry *saved_root = NULL; /* Original root if changed */
struct inode *pseudo_root = NULL; /* Useful to simulate the pseudo DOS */
@@ -42,7 +40,7 @@ void fill_new_filp (struct file *filp, struct dentry *dentry)
filp->f_reada = 1;
filp->f_flags = O_RDWR;
filp->f_dentry = dentry;
- filp->f_op = dentry->d_inode->i_op->default_file_ops;
+ filp->f_op = dentry->d_inode->i_fop;
}
@@ -100,10 +98,12 @@ void umsdos_setup_dir(struct dentry *dir)
inode->u.umsdos_i.dir_info.pid = 0;
inode->i_op = &umsdos_rdir_inode_operations;
+ inode->i_fop = &umsdos_rdir_operations;
if (umsdos_have_emd(dir)) {
Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
dir->d_parent->d_name.name, dir->d_name.name));
inode->i_op = &umsdos_dir_inode_operations;
+ inode->i_fop = &umsdos_dir_operations;
}
}
@@ -126,7 +126,16 @@ void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
return;
}
+static struct inode_operations umsdos_file_inode_operations = {
+ truncate: fat_truncate,
+ setattr: UMSDOS_notify_change,
+};
+static struct inode_operations umsdos_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ setattr: UMSDOS_notify_change,
+};
/*
* Connect the proper tables in the inode and add some info.
@@ -150,13 +159,14 @@ PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
dentry, f_pos));
umsdos_set_dirinfo_new(dentry, f_pos);
+ inode->i_op = &umsdos_file_inode_operations;
if (S_ISREG (inode->i_mode)) {
- /* All set */
+ /* address_space operations already set */
} else if (S_ISDIR (inode->i_mode)) {
umsdos_setup_dir(dentry);
} else if (S_ISLNK (inode->i_mode)) {
/* address_space operations already set */
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &umsdos_symlink_inode_operations;
} else
init_special_inode(inode, inode->i_mode,
kdev_t_to_nr(inode->i_rdev));
@@ -307,16 +317,12 @@ void UMSDOS_write_inode (struct inode *inode)
static struct super_operations umsdos_sops =
{
- NULL, /* read_inode */
- UMSDOS_write_inode, /* write_inode */
- UMSDOS_put_inode, /* put_inode */
- fat_delete_inode, /* delete_inode */
- UMSDOS_notify_change, /* notify_change */
- UMSDOS_put_super, /* put_super */
- NULL, /* write_super */
- fat_statfs, /* statfs */
- NULL, /* remount_fs */
- fat_clear_inode /* clear_inode */
+ write_inode: UMSDOS_write_inode,
+ put_inode: UMSDOS_put_inode,
+ delete_inode: fat_delete_inode,
+ put_super: UMSDOS_put_super,
+ statfs: fat_statfs,
+ clear_inode: fat_clear_inode,
};
/*
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index a466a9396..d05dfed73 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -218,23 +218,20 @@ out:
* have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
* from the one with full UMSDOS semantics.
*/
-static struct file_operations umsdos_rdir_operations =
+struct file_operations umsdos_rdir_operations =
{
- read: dummy_dir_read,
+ read: generic_read_dir,
readdir: UMSDOS_rreaddir,
ioctl: UMSDOS_ioctl_dir,
};
struct inode_operations umsdos_rdir_inode_operations =
{
- &umsdos_rdir_operations, /* default directory file-ops */
- msdos_create, /* create */
- UMSDOS_rlookup, /* lookup */
- NULL, /* link */
- msdos_unlink, /* unlink */
- NULL, /* symlink */
- msdos_mkdir, /* mkdir */
- UMSDOS_rrmdir, /* rmdir */
- NULL, /* mknod */
- msdos_rename, /* rename */
+ create: msdos_create,
+ lookup: UMSDOS_rlookup,
+ unlink: msdos_unlink,
+ mkdir: msdos_mkdir,
+ rmdir: UMSDOS_rrmdir,
+ rename: msdos_rename,
+ setattr: UMSDOS_notify_change,
};
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 0aced9465..b07708286 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -1266,16 +1266,13 @@ rename_done:
/* Public inode operations for the VFAT fs */
struct inode_operations vfat_dir_inode_operations = {
- &fat_dir_operations, /* default directory file-ops */
- vfat_create, /* create */
- vfat_lookup, /* lookup */
- NULL, /* link */
- vfat_unlink, /* unlink */
- NULL, /* symlink */
- vfat_mkdir, /* mkdir */
- vfat_rmdir, /* rmdir */
- NULL, /* mknod */
- vfat_rename, /* rename */
+ create: vfat_create,
+ lookup: vfat_lookup,
+ unlink: vfat_unlink,
+ mkdir: vfat_mkdir,
+ rmdir: vfat_rmdir,
+ rename: vfat_rename,
+ setattr: fat_notify_change,
};
struct super_block *vfat_read_super(struct super_block *sb,void *data,
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index 67b74d356..81f7b8268 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -41,7 +41,7 @@ extern __inline__ void atomic_add(int i, atomic_t * v)
" addl %0,%2,%0\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
@@ -56,7 +56,7 @@ extern __inline__ void atomic_sub(int i, atomic_t * v)
" subl %0,%2,%0\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v))
@@ -76,7 +76,7 @@ extern __inline__ long atomic_add_return(int i, atomic_t * v)
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
@@ -94,7 +94,7 @@ extern __inline__ long atomic_sub_return(int i, atomic_t * v)
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
:"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result)
diff --git a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
index c590d9e51..0d7a881a7 100644
--- a/include/asm-alpha/bitops.h
+++ b/include/asm-alpha/bitops.h
@@ -31,7 +31,7 @@ extern __inline__ void set_bit(unsigned long nr, volatile void * addr)
" stl_c %0,%1\n"
" beq %0,3f\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
@@ -52,7 +52,7 @@ extern __inline__ void clear_bit(unsigned long nr, volatile void * addr)
" stl_c %0,%1\n"
" beq %0,3f\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
@@ -69,7 +69,7 @@ extern __inline__ void change_bit(unsigned long nr, volatile void * addr)
" xor %0,%2,%0\n"
" stl_c %0,%1\n"
" beq %0,3f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m)
@@ -92,7 +92,7 @@ extern __inline__ int test_and_set_bit(unsigned long nr,
" beq %0,3f\n"
" mb\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
@@ -117,7 +117,7 @@ extern __inline__ int test_and_clear_bit(unsigned long nr,
" beq %0,3f\n"
" mb\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
@@ -140,7 +140,7 @@ extern __inline__ int test_and_change_bit(unsigned long nr,
" stl_c %0,%1\n"
" beq %0,3f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*m), "=&r" (oldbit)
diff --git a/include/asm-alpha/parport.h b/include/asm-alpha/parport.h
index bc6b79597..d1099fd8c 100644
--- a/include/asm-alpha/parport.h
+++ b/include/asm-alpha/parport.h
@@ -43,6 +43,8 @@ parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
count++;
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
+ count += parport_pc_init_superio ();
+
/* Probe all the likely ports. */
if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0], NULL))
count++;
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 0cf0e1c75..4695112ce 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -118,7 +118,8 @@ extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int);
again owns the buffer. */
extern inline void
-pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, int direction)
+pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size,
+ int direction)
{
/* Nothing to do. */
}
@@ -128,19 +129,17 @@ pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, int dir
for a scatter-gather list, same rules and usage. */
extern inline void
-pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int direction)
+pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents,
+ int direction)
{
/* Nothing to do. */
}
/* Return whether the given PCI device DMA address mask can
- * be supported properly. For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
-{
- return 1;
-}
+ be supported properly. For example, if your device can
+ only drive the low 24-bits during PCI bus mastering, then
+ you would pass 0x00ffffff as the mask to this function. */
+
+extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask);
#endif /* __ALPHA_PCI_H */
diff --git a/include/asm-alpha/semaphore-helper.h b/include/asm-alpha/semaphore-helper.h
index 0577d2c93..2812510db 100644
--- a/include/asm-alpha/semaphore-helper.h
+++ b/include/asm-alpha/semaphore-helper.h
@@ -34,7 +34,7 @@ waking_non_zero(struct semaphore *sem)
" stl_c %0,%2\n"
" beq %0,3f\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
: "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
@@ -104,7 +104,7 @@ waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
" stq_c %1,%4\n"
" beq %1,3f\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(tmp3), "=m"(*sem)
diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h
index 6cf9873f5..38bc05c6e 100644
--- a/include/asm-alpha/semaphore.h
+++ b/include/asm-alpha/semaphore.h
@@ -116,7 +116,7 @@ extern inline void down(struct semaphore * sem)
" beq $28,2f\n"
" blt $24,3f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%1\n"
" jsr $28,($27),__down_failed\n"
@@ -153,7 +153,7 @@ extern inline int down_interruptible(struct semaphore * sem)
" blt $24,3f\n"
" mov $31,%0\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%2\n"
" jsr $28,($27),__down_failed_interruptible\n"
@@ -216,7 +216,7 @@ extern inline int down_trylock(struct semaphore * sem)
" stq_c %1,%4\n"
" beq %1,3f\n"
"2:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
@@ -253,7 +253,7 @@ extern inline void up(struct semaphore * sem)
" beq $28,2f\n"
" ble $24,3f\n"
"4:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%1\n"
" jsr $28,($27),__up_wakeup\n"
@@ -379,7 +379,7 @@ extern inline void down_read(struct rw_semaphore *sem)
" beq $28,2f\n"
" blt $25,3f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%1\n"
" jsr $28,($27),__down_read_failed\n"
@@ -429,7 +429,7 @@ extern inline void down_write(struct rw_semaphore *sem)
" beq $28,2f\n"
" bne $25,3f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%1\n"
" jsr $28,($27),__down_write_failed\n"
@@ -488,7 +488,7 @@ extern inline void up_read(struct rw_semaphore *sem)
" beq $28,2f\n"
" beq $24,3f\n"
"4:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: lda $24,%1\n"
" mov 0,$25\n"
@@ -538,7 +538,7 @@ extern inline void up_write(struct rw_semaphore *sem)
" beq $28,2f\n"
" blt $24,3f\n"
"4:\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
"3: ldah $25,%3($24)\n"
/* Only do the wake if we're no longer negative. */
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
index 6153b2a86..c14eb0909 100644
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -78,7 +78,7 @@ static inline void spin_lock(spinlock_t * lock)
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: ldl %0,%1\n"
" blbs %0,2b\n"
" br 1b\n"
@@ -114,7 +114,7 @@ static inline void write_lock(rwlock_t * lock)
" stl_c %1,%0\n"
" beq %1,6f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: ldl %1,%0\n"
" bne %1,6b\n"
" br 1b\n"
@@ -135,7 +135,7 @@ static inline void read_lock(rwlock_t * lock)
" stl_c %1,%0\n"
" beq %1,6f\n"
"4: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: ldl %1,%0\n"
" blbs %1,6b\n"
" br 1b\n"
@@ -160,7 +160,7 @@ static inline void read_unlock(rwlock_t * lock)
" addl %1,2,%1\n"
" stl_c %1,%0\n"
" beq %1,6f\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"6: br 1b\n"
".previous"
: "=m" (__dummy_lock(lock)), "=&r" (regx)
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 15472dfbd..49d68b447 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -259,11 +259,31 @@ __CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
__CALL_PAL_W1(wrusp, unsigned long);
__CALL_PAL_W1(wrvptptr, unsigned long);
-#define __cli() ((void) swpipl(7))
-#define __sti() ((void) swpipl(0))
+#define IPL_MIN 0
+#define IPL_SW0 1
+#define IPL_SW1 2
+#define IPL_DEV0 3
+#define IPL_DEV1 4
+#define IPL_TIMER 5
+#define IPL_PERF 6
+#define IPL_POWERFAIL 6
+#define IPL_MCHECK 7
+#define IPL_MAX 7
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+#undef IPL_MIN
+#define IPL_MIN __min_ipl
+extern int __min_ipl;
+#endif
+
+#define getipl() (rdps() & 7)
+#define setipl(ipl) ((void) swpipl(ipl))
+
+#define __cli() setipl(IPL_MAX)
+#define __sti() setipl(IPL_MIN)
#define __save_flags(flags) ((flags) = rdps())
-#define __save_and_cli(flags) ((flags) = swpipl(7))
-#define __restore_flags(flags) ((void) swpipl(flags))
+#define __save_and_cli(flags) ((flags) = swpipl(IPL_MAX))
+#define __restore_flags(flags) setipl(flags)
#define local_irq_save(flags) __save_and_cli(flags)
#define local_irq_restore(flags) __restore_flags(flags)
@@ -332,7 +352,7 @@ __xchg_u32(volatile int *m, unsigned long val)
" stl_c %1,%2\n"
" beq %1,2f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=&r" (val), "=&r" (dummy), "=m" (*m)
@@ -352,7 +372,7 @@ __xchg_u64(volatile long *m, unsigned long val)
" stq_c %1,%2\n"
" beq %1,2f\n"
" mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"2: br 1b\n"
".previous"
: "=&r" (val), "=&r" (dummy), "=m" (*m)
@@ -408,7 +428,7 @@ __cmpxchg_u32(volatile int *m, int old, int new)
" stl_c %1,%2\n"
" beq %1,3f\n"
"2: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
: "=&r"(prev), "=&r"(cmp), "=m"(*m)
@@ -430,7 +450,7 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
" stq_c %1,%2\n"
" beq %1,3f\n"
"2: mb\n"
- ".section .text2,\"ax\"\n"
+ ".subsection 2\n"
"3: br 1b\n"
".previous"
: "=&r"(prev), "=&r"(cmp), "=m"(*m)
diff --git a/include/asm-arm/arch-arc/io.h b/include/asm-arm/arch-arc/io.h
index c7d6b9e2b..e42c80b02 100644
--- a/include/asm-arm/arch-arc/io.h
+++ b/include/asm-arm/arch-arc/io.h
@@ -91,7 +91,7 @@ extern __inline__ unsigned int __ioaddr (unsigned int port) \
DECLARE_IO(char,b,"b")
DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
+DECLARE_IO(int,l,"")
#undef DECLARE_IO
#undef DECLARE_DYN_IN
diff --git a/include/asm-arm/arch-cl7500/io.h b/include/asm-arm/arch-cl7500/io.h
index bdbbefce3..37f44316c 100644
--- a/include/asm-arm/arch-cl7500/io.h
+++ b/include/asm-arm/arch-cl7500/io.h
@@ -92,7 +92,7 @@ extern __inline__ unsigned int __ioaddr (unsigned int port) \
DECLARE_IO(char,b,"b")
DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
+DECLARE_IO(int,l,"")
#undef DECLARE_IO
#undef DECLARE_DYN_IN
diff --git a/include/asm-arm/arch-ebsa110/io.h b/include/asm-arm/arch-ebsa110/io.h
index 4f936f0e9..bca7df287 100644
--- a/include/asm-arm/arch-ebsa110/io.h
+++ b/include/asm-arm/arch-ebsa110/io.h
@@ -67,7 +67,7 @@ extern __inline__ unsigned int __ioaddr (unsigned int port) \
DECLARE_IO(char,b,"b")
DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
+DECLARE_IO(int,l,"")
#undef DECLARE_IO
#undef DECLARE_DYN_OUT
diff --git a/include/asm-arm/arch-ebsa285/io.h b/include/asm-arm/arch-ebsa285/io.h
index 877625fa8..8f24298b2 100644
--- a/include/asm-arm/arch-ebsa285/io.h
+++ b/include/asm-arm/arch-ebsa285/io.h
@@ -45,7 +45,7 @@ extern __inline__ unsigned long ___mem_isa(unsigned long a)
* Generic virtual read/write
*/
#define __arch_getb(a) (*(volatile unsigned char *)(a))
-#define __arch_getl(a) (*(volatile unsigned long *)(a))
+#define __arch_getl(a) (*(volatile unsigned int *)(a))
extern __inline__ unsigned int __arch_getw(unsigned long a)
{
@@ -58,7 +58,7 @@ extern __inline__ unsigned int __arch_getw(unsigned long a)
#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
-#define __arch_putl(v,a) (*(volatile unsigned long *)(a) = (v))
+#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
extern __inline__ void __arch_putw(unsigned int value, unsigned long a)
{
diff --git a/include/asm-arm/arch-nexuspci/io.h b/include/asm-arm/arch-nexuspci/io.h
index f70fbadbd..3c8d15b3d 100644
--- a/include/asm-arm/arch-nexuspci/io.h
+++ b/include/asm-arm/arch-nexuspci/io.h
@@ -46,7 +46,7 @@ extern __inline__ unsigned int __ioaddr (unsigned int port) \
DECLARE_IO(char,b,"b","Jr")
DECLARE_IO(short,w,"h","r")
-DECLARE_IO(long,l,"","Jr")
+DECLARE_IO(int,l,"","Jr")
#undef DECLARE_IO
#undef DECLARE_DYN_OUT
diff --git a/include/asm-arm/arch-rpc/io.h b/include/asm-arm/arch-rpc/io.h
index 2e093217c..508560bda 100644
--- a/include/asm-arm/arch-rpc/io.h
+++ b/include/asm-arm/arch-rpc/io.h
@@ -90,7 +90,7 @@ extern __inline__ unsigned int __ioaddr (unsigned int port) \
DECLARE_IO(char,b,"b")
DECLARE_IO(short,w,"")
-DECLARE_IO(long,l,"")
+DECLARE_IO(int,l,"")
#undef DECLARE_IO
#undef DECLARE_DYN_IN
diff --git a/include/asm-arm/arch-sa1100/io.h b/include/asm-arm/arch-sa1100/io.h
index 3e0001a1a..d1d8aa11a 100644
--- a/include/asm-arm/arch-sa1100/io.h
+++ b/include/asm-arm/arch-sa1100/io.h
@@ -20,7 +20,7 @@
* Generic virtual read/write
*/
#define __arch_getb(a) (*(volatile unsigned char *)(a))
-#define __arch_getl(a) (*(volatile unsigned long *)(a))
+#define __arch_getl(a) (*(volatile unsigned int *)(a))
extern __inline__ unsigned int __arch_getw(unsigned long a)
{
@@ -33,7 +33,7 @@ extern __inline__ unsigned int __arch_getw(unsigned long a)
#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v))
-#define __arch_putl(v,a) (*(volatile unsigned long *)(a) = (v))
+#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
extern __inline__ void __arch_putw(unsigned int value, unsigned long a)
{
diff --git a/include/asm-arm/parport.h b/include/asm-arm/parport.h
index b61c0d62c..fddb4f548 100644
--- a/include/asm-arm/parport.h
+++ b/include/asm-arm/parport.h
@@ -43,6 +43,8 @@ parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
count++;
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
+ count += parport_pc_init_superio ();
+
/* Probe all the likely ports. */
if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0], NULL))
count++;
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index 0112f9b35..51805488f 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -84,6 +84,17 @@ static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
return c != 0;
}
+static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ LOCK "incl %0; sete %1"
+ :"=m" (__atomic_fool_gcc(v)), "=qm" (c)
+ :"m" (__atomic_fool_gcc(v)));
+ return c != 0;
+}
+
extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v)
{
unsigned char c;
diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
index 610db5633..6b8e92620 100644
--- a/include/asm-i386/hardirq.h
+++ b/include/asm-i386/hardirq.h
@@ -2,25 +2,24 @@
#define __ASM_HARDIRQ_H
#include <linux/threads.h>
-
-extern unsigned int local_irq_count[NR_CPUS];
+#include <linux/irq.h>
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
#define in_interrupt() ({ int __cpu = smp_processor_id(); \
- (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+ (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
-#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
#ifndef __SMP__
-#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#define hardirq_endlock(cpu) do { } while (0)
-#define irq_enter(cpu, irq) (local_irq_count[cpu]++)
-#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
+#define irq_enter(cpu, irq) (local_irq_count(cpu)++)
+#define irq_exit(cpu, irq) (local_irq_count(cpu)--)
#define synchronize_irq() barrier()
@@ -31,7 +30,16 @@ extern unsigned int local_irq_count[NR_CPUS];
extern unsigned char global_irq_holder;
extern unsigned volatile int global_irq_lock;
-extern atomic_t global_irq_count;
+
+static inline int irqs_running (void)
+{
+ int i;
+
+ for (i = 0; i < smp_num_cpus; i++)
+ if (local_irq_count(i))
+ return 1;
+ return 0;
+}
static inline void release_irqlock(int cpu)
{
@@ -44,8 +52,7 @@ static inline void release_irqlock(int cpu)
static inline void irq_enter(int cpu, int irq)
{
- ++local_irq_count[cpu];
- atomic_inc(&global_irq_count);
+ ++local_irq_count(cpu);
while (test_bit(0,&global_irq_lock)) {
/* nothing */;
@@ -54,13 +61,12 @@ static inline void irq_enter(int cpu, int irq)
static inline void irq_exit(int cpu, int irq)
{
- atomic_dec(&global_irq_count);
- --local_irq_count[cpu];
+ --local_irq_count(cpu);
}
static inline int hardirq_trylock(int cpu)
{
- return !local_irq_count[cpu] && !test_bit(0,&global_irq_lock);
+ return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock);
}
#define hardirq_endlock(cpu) do { } while (0)
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index f6c102a7e..920faed06 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -179,13 +179,21 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
"pushl $"#nr"-256\n\t" \
"jmp common_interrupt");
+extern unsigned long prof_cpu_mask;
/*
* x86 profiling function, SMP safe. We might want to do this in
* assembly totally?
*/
static inline void x86_do_profile (unsigned long eip)
{
- if (prof_buffer && current->pid) {
+ /*
+ * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
+ * (default is all CPUs.)
+ */
+ if (!((1<<smp_processor_id()) & prof_cpu_mask))
+ return;
+
+ if (prof_buffer) {
eip -= (unsigned long) &_stext;
eip >>= prof_shift;
/*
diff --git a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
index 7597fd40a..eaa803cb0 100644
--- a/include/asm-i386/mpspec.h
+++ b/include/asm-i386/mpspec.h
@@ -152,7 +152,8 @@ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
extern unsigned int boot_cpu_id;
extern unsigned long phys_cpu_present_map;
extern int smp_found_config;
-extern void init_smp_config(void);
+extern void find_smp_config (void);
+extern void get_smp_config (void);
extern int nr_ioapics;
extern int apic_version [NR_CPUS];
extern int mp_bus_id_to_type [MAX_MP_BUSSES];
diff --git a/include/asm-i386/parport.h b/include/asm-i386/parport.h
index 1c2855bbe..432fc56f7 100644
--- a/include/asm-i386/parport.h
+++ b/include/asm-i386/parport.h
@@ -15,19 +15,10 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
-/* If parport_cs (PCMCIA) is managing ports for us, we'll need the
- * probing routines forever; otherwise we can lose them at boot time. */
-#ifdef CONFIG_PARPORT_PC_PCMCIA
-#define __maybe_initdata
-#define __maybe_init
-#else
-#define __maybe_initdata __initdata
-#define __maybe_init __init
-#endif
-
-static int __maybe_init parport_pc_init_pci(int irq, int dma);
-
-static int user_specified __maybe_initdata = 0;
+static int parport_pc_init_pci(int irq, int dma);
+static int parport_pc_init_superio(void);
+
+static int user_specified __devinitdata = 0;
int __init
parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
{
@@ -43,13 +34,16 @@ parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
count++;
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
- /* Probe all the likely ports. */
+ count += parport_pc_init_superio ();
+
if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x378, 0x778, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x278, 0x678, irq[0], dma[0], NULL))
count++;
+
+ /* probe for other PCI parallel devices */
count += parport_pc_init_pci (irq[0], dma[0]);
}
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index f0d1b00bf..d58f5a7a6 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -18,6 +18,7 @@
#include <linux/threads.h>
extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 15c2d11b0..77e8642ed 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -15,7 +15,9 @@
#include <asm/fixmap.h>
#include <asm/bitops.h>
#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
#include <asm/io_apic.h>
+#endif
#include <asm/apic.h>
#endif
#endif
diff --git a/include/asm-i386/softirq.h b/include/asm-i386/softirq.h
index 9964ba5bc..4fe26b2b7 100644
--- a/include/asm-i386/softirq.h
+++ b/include/asm-i386/softirq.h
@@ -4,14 +4,12 @@
#include <asm/atomic.h>
#include <asm/hardirq.h>
-extern unsigned int local_bh_count[NR_CPUS];
-
-#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
+#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif /* __ASM_SOFTIRQ_H */
diff --git a/include/asm-ia64/offsets.h b/include/asm-ia64/offsets.h
index d989cb911..72eccbc24 100644
--- a/include/asm-ia64/offsets.h
+++ b/include/asm-ia64/offsets.h
@@ -10,7 +10,7 @@
#define PF_PTRACED_BIT 4
-#define IA64_TASK_SIZE 3280 /* 0xcd0 */
+#define IA64_TASK_SIZE 2800 /* 0xaf0 */
#define IA64_PT_REGS_SIZE 400 /* 0x190 */
#define IA64_SWITCH_STACK_SIZE 560 /* 0x230 */
#define IA64_SIGINFO_SIZE 136 /* 0x88 */
@@ -19,8 +19,8 @@
#define IA64_TASK_SIGPENDING_OFFSET 16 /* 0x10 */
#define IA64_TASK_NEED_RESCHED_OFFSET 40 /* 0x28 */
#define IA64_TASK_PROCESSOR_OFFSET 108 /* 0x6c */
-#define IA64_TASK_THREAD_OFFSET 1424 /* 0x590 */
-#define IA64_TASK_THREAD_KSP_OFFSET 1424 /* 0x590 */
+#define IA64_TASK_THREAD_OFFSET 928 /* 0x3a0 */
+#define IA64_TASK_THREAD_KSP_OFFSET 928 /* 0x3a0 */
#define IA64_TASK_PID_OFFSET 188 /* 0xbc */
#define IA64_TASK_MM_OFFSET 88 /* 0x58 */
#define IA64_PT_REGS_CR_IPSR_OFFSET 0 /* 0x0 */
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 53eb9f963..2361bc06d 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -127,9 +127,10 @@ typedef union ia64_va {
#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
#define PAGE_BUG(page) do { BUG(); } while (0)
-extern __inline__ int get_order(unsigned long size)
+extern __inline__ int
+get_order (unsigned long size)
{
- double d = size - 1;
+ double d = size - 1;
long order;
__asm__ ("getf.exp %0=%1" : "=r"(order) : "f"(d));
diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h
index becc7422f..b26321422 100644
--- a/include/asm-ia64/pgalloc.h
+++ b/include/asm-ia64/pgalloc.h
@@ -8,8 +8,8 @@
* This hopefully works with any (fixed) ia-64 page-size, as defined
* in <asm/page.h> (currently 8192).
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 2000, Goutham Rao <goutham.rao@intel.com>
*/
@@ -254,4 +254,21 @@ flush_tlb_page (struct vm_area_struct *vma, unsigned long addr)
flush_tlb_range(vma->vm_mm, addr, addr + PAGE_SIZE);
}
+/*
+ * Flush the TLB entries mapping the virtually mapped linear page
+ * table corresponding to address range [START-END).
+ */
+static inline void
+flush_tlb_pgtables (struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ /*
+ * XXX fix mmap(), munmap() et al to guarantee that there are no mappings
+ * across region boundaries. --davidm 00/02/23
+ */
+ if (rgn_index(start) != rgn_index(end)) {
+ printk("flush_tlb_pgtables: can't flush across regions!!\n");
+ }
+ flush_tlb_range(mm, ia64_thash(start), ia64_thash(end));
+}
+
#endif /* _ASM_IA64_PGALLOC_H */
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 203005b5c..a941cfccf 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -294,6 +294,18 @@ extern pmd_t *ia64_bad_pagetable (void);
*/
#define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC)
+/*
+ * Return the region index for virtual address ADDRESS.
+ */
+extern __inline__ unsigned long
+rgn_index (unsigned long address)
+{
+ ia64_va a;
+
+ a.l = address;
+ return a.f.reg;
+}
+
extern __inline__ unsigned long
pgd_index (unsigned long address)
{
@@ -347,7 +359,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* execution context?).
*
*/
-#if 0
+#if 1
# define update_mmu_cache(vma,address,pte)
#else
# define update_mmu_cache(vma,address,pte) \
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 5a49bf2c0..d31d746fa 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -27,15 +27,11 @@
*/
#define TASK_SIZE 0xa000000000000000
-#ifdef CONFIG_IA32_SUPPORT
-# define TASK_UNMAPPED_BASE 0x40000000 /* XXX fix me! */
-#else
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
-#define TASK_UNMAPPED_BASE 0x2000000000000000
-#endif
+#define TASK_UNMAPPED_BASE (current->thread.map_base)
/*
* Bus types
@@ -153,7 +149,12 @@
#define IA64_THREAD_FPH_VALID (__IA64_UL(1) << 0) /* floating-point high state valid? */
#define IA64_THREAD_DBG_VALID (__IA64_UL(1) << 1) /* debug registers valid? */
-#define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* used for die_if_kernel() recursion detection */
+#define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 2) /* don't log unaligned accesses */
+#define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 3) /* generate SIGBUS on unaligned acc. */
+#define IA64_KERNEL_DEATH (__IA64_UL(1) << 63) /* see die_if_kernel()... */
+
+#define IA64_THREAD_UAC_SHIFT 2
+#define IA64_THREAD_UAC_MASK (IA64_THREAD_UAC_NOPRINT | IA64_THREAD_UAC_SIGBUS)
#ifndef __ASSEMBLY__
@@ -258,12 +259,24 @@ typedef struct {
unsigned long seg;
} mm_segment_t;
+#define SET_UNALIGN_CTL(task,value) \
+({ \
+ (task)->thread.flags |= ((value) << IA64_THREAD_UAC_SHIFT) & IA64_THREAD_UAC_MASK; \
+ 0; \
+})
+#define GET_UNALIGN_CTL(task,addr) \
+({ \
+ put_user(((task)->thread.flags & IA64_THREAD_UAC_MASK) >> IA64_THREAD_UAC_SHIFT, \
+ (int *) (addr)); \
+})
+
struct thread_struct {
__u64 ksp; /* kernel stack pointer */
unsigned long flags; /* various flags */
struct ia64_fpreg fph[96]; /* saved/loaded on demand */
__u64 dbr[IA64_NUM_DBG_REGS];
__u64 ibr[IA64_NUM_DBG_REGS];
+ __u64 map_base; /* base address for mmap() */
#ifdef CONFIG_IA32_SUPPORT
__u64 fsr; /* IA32 floating pt status reg */
__u64 fcr; /* IA32 floating pt control reg */
@@ -285,7 +298,8 @@ struct thread_struct {
0, /* flags */ \
{{{{0}}}, }, /* fph */ \
{0, }, /* dbr */ \
- {0, } /* ibr */ \
+ {0, }, /* ibr */ \
+ 0x2000000000000000 /* map_base */ \
INIT_THREAD_IA32 \
}
@@ -781,6 +795,14 @@ ia64_get_gp(void)
#define ia64_rotl(w,n) ia64_rotr((w),(64)-(n))
+extern __inline__ __u64
+ia64_thash (__u64 addr)
+{
+ __u64 result;
+ asm ("thash %0=%1" : "=r"(result) : "r" (addr));
+ return result;
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_PROCESSOR_H */
diff --git a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h
index 0559f5f8b..d3b71ccaf 100644
--- a/include/asm-ia64/siginfo.h
+++ b/include/asm-ia64/siginfo.h
@@ -54,12 +54,13 @@ typedef struct siginfo {
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
- void *_addr; /* faulting insn/memory ref. */
+ void *_addr; /* faulting insn/memory ref. */
+ int _imm; /* immediate value for "break" */
} _sigfault;
/* SIGPOLL */
struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */
int _fd;
} _sigpoll;
} _sifields;
@@ -77,6 +78,7 @@ typedef struct siginfo {
#define si_int _sifields._rt._sigval.sival_int
#define si_ptr _sifields._rt._sigval.sival_ptr
#define si_addr _sifields._sigfault._addr
+#define si_imm _sifields._sigfault._imm /* as per UNIX SysV ABI spec */
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
@@ -106,8 +108,9 @@ typedef struct siginfo {
#define ILL_PRVREG 6 /* privileged register */
#define ILL_COPROC 7 /* coprocessor error */
#define ILL_BADSTK 8 /* internal stack error */
-#define ILL_BADIADDR 9 /* Unimplemented instruction address */
-#define NSIGILL 9
+#define ILL_BADIADDR 9 /* unimplemented instruction address */
+#define __ILL_BREAK 10 /* illegal break */
+#define NSIGILL 10
/*
* SIGFPE si_codes
@@ -120,14 +123,20 @@ typedef struct siginfo {
#define FPE_FLTRES 6 /* floating point inexact result */
#define FPE_FLTINV 7 /* floating point invalid operation */
#define FPE_FLTSUB 8 /* subscript out of range */
-#define NSIGFPE 8
+#define __FPE_DECOVF 9 /* decimal overflow */
+#define __FPE_DECDIV 10 /* decimal division by zero */
+#define __FPE_DECERR 11 /* packed decimal error */
+#define __FPE_INVASC 12 /* invalid ASCII digit */
+#define __FPE_INVDEC 13 /* invalid decimal digit */
+#define NSIGFPE 13
/*
* SIGSEGV si_codes
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
-#define NSIGSEGV 2
+#define __SEGV_PSTKOVF 3 /* paragraph stack overflow */
+#define NSIGSEGV 3
/*
* SIGBUS si_codes
diff --git a/include/asm-mips/hardirq.h b/include/asm-mips/hardirq.h
index c9ffba132..68697ef74 100644
--- a/include/asm-mips/hardirq.h
+++ b/include/asm-mips/hardirq.h
@@ -1,34 +1,33 @@
-/* $Id: hardirq.h,v 1.6 2000/02/04 07:40:53 ralf Exp $
+/* $Id: hardirq.h,v 1.7 2000/02/23 00:41:38 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) 1997, 1998, 1999 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1997, 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#ifndef _ASM_HARDIRQ_H
#define _ASM_HARDIRQ_H
#include <linux/threads.h>
-
-extern unsigned int local_irq_count[NR_CPUS];
+#include <linux/irq.h>
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
#define in_interrupt() ({ int __cpu = smp_processor_id(); \
- (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
-#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+ (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
#ifndef __SMP__
-#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#define hardirq_endlock(cpu) do { } while (0)
-#define irq_enter(cpu) (local_irq_count[cpu]++)
-#define irq_exit(cpu) (local_irq_count[cpu]--)
+#define irq_enter(cpu) (local_irq_count(cpu)++)
+#define irq_exit(cpu) (local_irq_count(cpu)--)
#define synchronize_irq() barrier();
diff --git a/include/asm-mips/hw_irq.h b/include/asm-mips/hw_irq.h
new file mode 100644
index 000000000..1bf6629b4
--- /dev/null
+++ b/include/asm-mips/hw_irq.h
@@ -0,0 +1,5 @@
+/* This exists merely to satisfy <linux/irq.h>. There is
+ nothing that would go here of general interest.
+
+ Everything of consequence is in arch/alpha/kernel/irq_impl.h,
+ to be used only in arch/alpha/kernel/. */
diff --git a/include/asm-mips/parport.h b/include/asm-mips/parport.h
index 0ae99c2e9..57683df44 100644
--- a/include/asm-mips/parport.h
+++ b/include/asm-mips/parport.h
@@ -1,4 +1,4 @@
-/* $Id: parport.h,v 1.1 1999/10/09 00:01:43 ralf Exp $
+/* $Id: parport.h,v 1.2 2000/02/18 00:24:48 ralf Exp $
*
* parport.h: ia32-specific parport initialisation
*
@@ -15,19 +15,10 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
-/* If parport_cs (PCMCIA) is managing ports for us, we'll need the
- * probing routines forever; otherwise we can lose them at boot time. */
-#ifdef CONFIG_PARPORT_PC_PCMCIA
-#define __maybe_initdata
-#define __maybe_init
-#else
-#define __maybe_initdata __initdata
-#define __maybe_init __init
-#endif
+static int parport_pc_init_pci(int irq, int dma);
+static int parport_pc_init_superio(void);
-static int __maybe_init parport_pc_init_pci(int irq, int dma);
-
-static int user_specified __maybe_initdata = 0;
+static int user_specified __devinitdata = 0;
int __init
parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
{
@@ -43,13 +34,16 @@ parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
count++;
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
- /* Probe all the likely ports. */
+ count += parport_pc_init_superio ();
+
if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x378, 0x778, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x278, 0x678, irq[0], dma[0], NULL))
count++;
+
+ /* probe for other PCI parallel devices */
count += parport_pc_init_pci (irq[0], dma[0]);
}
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 90f96e492..9b909eeab 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.29 2000/02/23 00:41:38 ralf Exp $
+/* $Id: pgtable.h,v 1.30 2000/02/24 00:13:19 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
@@ -438,6 +438,7 @@ extern void __bad_pte_kernel(pmd_t *pmd);
extern int do_check_pgt_cache(int, int);
extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
extern void update_mmu_cache(struct vm_area_struct *vma,
unsigned long address, pte_t pte);
diff --git a/include/asm-mips/softirq.h b/include/asm-mips/softirq.h
index 9248125eb..bc4af8ccb 100644
--- a/include/asm-mips/softirq.h
+++ b/include/asm-mips/softirq.h
@@ -1,4 +1,4 @@
-/* $Id: softirq.h,v 1.10 2000/02/22 21:23:52 ralf Exp $
+/* $Id: softirq.h,v 1.11 2000/02/23 00:41:38 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
@@ -13,14 +13,12 @@
#include <asm/atomic.h>
#include <asm/hardirq.h>
-extern unsigned int local_bh_count[NR_CPUS];
-
-#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
+#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif /* _ASM_SOFTIRQ_H */
diff --git a/include/asm-mips64/hardirq.h b/include/asm-mips64/hardirq.h
index 3bc56d38d..7200ad062 100644
--- a/include/asm-mips64/hardirq.h
+++ b/include/asm-mips64/hardirq.h
@@ -1,4 +1,4 @@
-/* $Id: hardirq.h,v 1.3 2000/02/04 07:40:53 ralf Exp $
+/* $Id: hardirq.h,v 1.4 2000/02/23 00:41:38 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -11,24 +11,23 @@
#define _ASM_HARDIRQ_H
#include <linux/threads.h>
-
-extern unsigned int local_irq_count[NR_CPUS];
+#include <linux/irq.h>
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
#define in_interrupt() ({ int __cpu = smp_processor_id(); \
- (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
-#define in_irq() (local_irq_count[smp_processor_id()] != 0)
+ (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
#ifndef __SMP__
-#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#define hardirq_endlock(cpu) do { } while (0)
-#define irq_enter(cpu) (local_irq_count[cpu]++)
-#define irq_exit(cpu) (local_irq_count[cpu]--)
+#define irq_enter(cpu) (local_irq_count(cpu)++)
+#define irq_exit(cpu) (local_irq_count(cpu)--)
#define synchronize_irq() barrier();
diff --git a/include/asm-mips64/hw_irq.h b/include/asm-mips64/hw_irq.h
new file mode 100644
index 000000000..1bf6629b4
--- /dev/null
+++ b/include/asm-mips64/hw_irq.h
@@ -0,0 +1,5 @@
+/* This exists merely to satisfy <linux/irq.h>. There is
+ nothing that would go here of general interest.
+
+ Everything of consequence is in arch/alpha/kernel/irq_impl.h,
+ to be used only in arch/alpha/kernel/. */
diff --git a/include/asm-mips64/parport.h b/include/asm-mips64/parport.h
index 0ae99c2e9..57683df44 100644
--- a/include/asm-mips64/parport.h
+++ b/include/asm-mips64/parport.h
@@ -1,4 +1,4 @@
-/* $Id: parport.h,v 1.1 1999/10/09 00:01:43 ralf Exp $
+/* $Id: parport.h,v 1.2 2000/02/18 00:24:48 ralf Exp $
*
* parport.h: ia32-specific parport initialisation
*
@@ -15,19 +15,10 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
-/* If parport_cs (PCMCIA) is managing ports for us, we'll need the
- * probing routines forever; otherwise we can lose them at boot time. */
-#ifdef CONFIG_PARPORT_PC_PCMCIA
-#define __maybe_initdata
-#define __maybe_init
-#else
-#define __maybe_initdata __initdata
-#define __maybe_init __init
-#endif
+static int parport_pc_init_pci(int irq, int dma);
+static int parport_pc_init_superio(void);
-static int __maybe_init parport_pc_init_pci(int irq, int dma);
-
-static int user_specified __maybe_initdata = 0;
+static int user_specified __devinitdata = 0;
int __init
parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
{
@@ -43,13 +34,16 @@ parport_pc_init(int *io, int *io_hi, int *irq, int *dma)
count++;
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
} else {
- /* Probe all the likely ports. */
+ count += parport_pc_init_superio ();
+
if (parport_pc_probe_port(0x3bc, 0x7bc, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x378, 0x778, irq[0], dma[0], NULL))
count++;
if (parport_pc_probe_port(0x278, 0x678, irq[0], dma[0], NULL))
count++;
+
+ /* probe for other PCI parallel devices */
count += parport_pc_init_pci (irq[0], dma[0]);
}
diff --git a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h
index dfaff3f1e..0dc2145cf 100644
--- a/include/asm-mips64/pgtable.h
+++ b/include/asm-mips64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.11 2000/02/23 00:41:38 ralf Exp $
+/* $Id: pgtable.h,v 1.13 2000/02/27 01:03:24 kanoj 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
@@ -469,6 +469,7 @@ extern void pgd_init(unsigned long page);
extern void pmd_init(unsigned long page);
extern pgd_t swapper_pg_dir[1024];
+extern void paging_init(void);
extern void (*update_mmu_cache)(struct vm_area_struct *vma,
unsigned long address, pte_t pte);
diff --git a/include/asm-mips64/softirq.h b/include/asm-mips64/softirq.h
index 528b4f091..716cd3e17 100644
--- a/include/asm-mips64/softirq.h
+++ b/include/asm-mips64/softirq.h
@@ -1,4 +1,4 @@
-/* $Id: softirq.h,v 1.3 2000/02/22 21:23:52 ralf Exp $
+/* $Id: softirq.h,v 1.3 2000/02/23 00:41:38 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
@@ -13,14 +13,12 @@
#include <asm/atomic.h>
#include <asm/hardirq.h>
-extern unsigned int local_bh_count[NR_CPUS];
-
-#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
+#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif /* _ASM_SOFTIRQ_H */
diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h
index 6a417940b..28a47906c 100644
--- a/include/asm-ppc/hw_irq.h
+++ b/include/asm-ppc/hw_irq.h
@@ -6,30 +6,13 @@
#ifndef _PPC_HW_IRQ_H
#define _PPC_HW_IRQ_H
-#if 0
-/* Structure describing interrupts */
-struct hw_interrupt_type {
- const char * typename;
- void (*startup)(unsigned int irq);
- void (*shutdown)(unsigned int irq);
- void (*enable)(unsigned int irq);
- void (*disable)(unsigned int irq);
- void (*mask_and_ack)(unsigned int irq);
- int irq_offset;
-};
-
-struct irqdesc {
- struct irqaction *action;
- struct hw_interrupt_type *ctl;
-};
-#endif
-
struct int_control_struct
{
void (*int_cli)(void);
void (*int_sti)(void);
void (*int_restore_flags)(unsigned long);
void (*int_save_flags)(unsigned long *);
+ void (*int_set_lost)(unsigned long);
};
extern struct int_control_struct int_control;
extern unsigned long timer_interrupt_intercept;
@@ -40,12 +23,14 @@ extern void __no_use_sti(void);
extern void __no_use_cli(void);
extern void __no_use_restore_flags(unsigned long);
extern void __no_use_save_flags(unsigned long *);
+extern void __no_use_set_lost(unsigned long);
#define __cli() int_control.int_cli()
#define __sti() int_control.int_sti()
#define __save_flags(flags) int_control.int_save_flags(&flags)
#define __restore_flags(flags) int_control.int_restore_flags(flags)
#define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+#define __set_lost(irq) ({ if ((ulong)int_control.int_set_lost) int_control.int_set_lost(irq); })
extern void do_lost_interrupts(unsigned long);
extern atomic_t ppc_n_lost_interrupts;
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 21e4930de..7bb3d901d 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -38,73 +38,73 @@ extern unsigned long pci_dram_offset;
#endif /* CONFIG_APUS */
#endif
-#define readb(addr) in_8((volatile unsigned char *)(addr))
-#define writeb(b,addr) out_8((volatile unsigned char *)(addr), (b))
+#define readb(addr) in_8((volatile u8 *)(addr))
+#define writeb(b,addr) out_8((volatile u8 *)(addr), (b))
#if defined(CONFIG_APUS)
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+#define readw(addr) (*(volatile u16 *) (addr))
+#define readl(addr) (*(volatile u32 *) (addr))
+#define writew(b,addr) ((*(volatile u16 *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile u32 *) (addr)) = (b))
#else
-#define readw(addr) in_le16((volatile unsigned short *)(addr))
-#define readl(addr) in_le32((volatile unsigned *)(addr))
-#define writew(b,addr) out_le16((volatile unsigned short *)(addr),(b))
-#define writel(b,addr) out_le32((volatile unsigned *)(addr),(b))
+#define readw(addr) in_le16((volatile u16 *)(addr))
+#define readl(addr) in_le32((volatile u32 *)(addr))
+#define writew(b,addr) out_le16((volatile u16 *)(addr),(b))
+#define writel(b,addr) out_le32((volatile u32 *)(addr),(b))
#endif
-#define insb(port, buf, ns) _insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
-#define outsb(port, buf, ns) _outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
-#define insw(port, buf, ns) _insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define outsw(port, buf, ns) _outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define insl(port, buf, nl) _insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
-#define outsl(port, buf, nl) _outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define insb(port, buf, ns) _insb((u8 *)((port)+_IO_BASE), (buf), (ns))
+#define outsb(port, buf, ns) _outsb((u8 *)((port)+_IO_BASE), (buf), (ns))
+#define insw(port, buf, ns) _insw((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns) _outsw((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl) _insl((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl) _outsl((u32 *)((port)+_IO_BASE), (buf), (nl))
-#define inb(port) in_8((unsigned char *)((port)+_IO_BASE))
-#define outb(val, port) out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inb(port) in_8((u8 *)((port)+_IO_BASE))
+#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val))
#if defined(CONFIG_APUS)
-#define inw(port) in_be16((unsigned short *)((port)+_IO_BASE))
-#define outw(val, port) out_be16((unsigned short *)((port)+_IO_BASE), (val))
-#define inl(port) in_be32((unsigned *)((port)+_IO_BASE))
-#define outl(val, port) out_be32((unsigned *)((port)+_IO_BASE), (val))
+#define inw(port) in_be16((u16 *)((port)+_IO_BASE))
+#define outw(val, port) out_be16((u16 *)((port)+_IO_BASE), (val))
+#define inl(port) in_be32((u32 *)((port)+_IO_BASE))
+#define outl(val, port) out_be32((u32 *)((port)+_IO_BASE), (val))
#else
-#define inw(port) in_le16((unsigned short *)((port)+_IO_BASE))
-#define outw(val, port) out_le16((unsigned short *)((port)+_IO_BASE), (val))
-#define inl(port) in_le32((unsigned *)((port)+_IO_BASE))
-#define outl(val, port) out_le32((unsigned *)((port)+_IO_BASE), (val))
+#define inw(port) in_le16((u16 *)((port)+_IO_BASE))
+#define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val))
+#define inl(port) in_le32((u32 *)((port)+_IO_BASE))
+#define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val))
#endif
-#define inb_p(port) in_8((unsigned char *)((port)+_IO_BASE))
-#define outb_p(val, port) out_8((unsigned char *)((port)+_IO_BASE), (val))
-#define inw_p(port) in_le16((unsigned short *)((port)+_IO_BASE))
-#define outw_p(val, port) out_le16((unsigned short *)((port)+_IO_BASE), (val))
-#define inl_p(port) in_le32((unsigned *)((port)+_IO_BASE))
-#define outl_p(val, port) out_le32((unsigned *)((port)+_IO_BASE), (val))
+#define inb_p(port) in_8((u8 *)((port)+_IO_BASE))
+#define outb_p(val, port) out_8((u8 *)((port)+_IO_BASE), (val))
+#define inw_p(port) in_le16((u16 *)((port)+_IO_BASE))
+#define outw_p(val, port) out_le16((u16 *)((port)+_IO_BASE), (val))
+#define inl_p(port) in_le32((u32 *)((port)+_IO_BASE))
+#define outl_p(val, port) out_le32((u32 *)((port)+_IO_BASE), (val))
-extern void _insb(volatile unsigned char *port, void *buf, int ns);
-extern void _outsb(volatile unsigned char *port, const void *buf, int ns);
-extern void _insw(volatile unsigned short *port, void *buf, int ns);
-extern void _outsw(volatile unsigned short *port, const void *buf, int ns);
-extern void _insl(volatile unsigned long *port, void *buf, int nl);
-extern void _outsl(volatile unsigned long *port, const void *buf, int nl);
+extern void _insb(volatile u8 *port, void *buf, int ns);
+extern void _outsb(volatile u8 *port, const void *buf, int ns);
+extern void _insw(volatile u16 *port, void *buf, int ns);
+extern void _outsw(volatile u16 *port, const void *buf, int ns);
+extern void _insl(volatile u32 *port, void *buf, int nl);
+extern void _outsl(volatile u32 *port, const void *buf, int nl);
/*
* The *_ns versions below don't do byte-swapping.
*/
-#define insw_ns(port, buf, ns) _insw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define outsw_ns(port, buf, ns) _outsw_ns((unsigned short *)((port)+_IO_BASE), (buf), (ns))
-#define insl_ns(port, buf, nl) _insl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
-#define outsl_ns(port, buf, nl) _outsl_ns((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define insw_ns(port, buf, ns) _insw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define outsw_ns(port, buf, ns) _outsw_ns((u16 *)((port)+_IO_BASE), (buf), (ns))
+#define insl_ns(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
+#define outsl_ns(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
-extern void _insw_ns(volatile unsigned short *port, void *buf, int ns);
-extern void _outsw_ns(volatile unsigned short *port, const void *buf, int ns);
-extern void _insl_ns(volatile unsigned long *port, void *buf, int nl);
-extern void _outsl_ns(volatile unsigned long *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
#define IO_SPACE_LIMIT ~0
-#define memset_io(a,b,c) memset((a),(b),(c))
-#define memcpy_fromio(a,b,c) memcpy((a),(b),(c))
-#define memcpy_toio(a,b,c) memcpy((a),(b),(c))
+#define memset_io(a,b,c) memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
#ifdef __KERNEL__
/*
diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
index 009229882..867dd0bab 100644
--- a/include/asm-ppc/irq.h
+++ b/include/asm-ppc/irq.h
@@ -117,15 +117,48 @@ static __inline__ int irq_cannonicalize(int irq)
return irq;
}
-#else
+#else /* CONFIG_4xx + CONFIG_8xx */
-#ifdef CONFIG_APUS
-#define enable_irq m68k_enable_irq
-#define disable_irq m68k_disable_irq
-#include <asm-m68k/irq.h>
-#undef enable_irq
-#undef disable_irq
-#else /* CONFIG_APUS */
+#if defined(CONFIG_APUS)
+/*
+ * This structure is used to chain together the ISRs for a particular
+ * interrupt source (if it supports chaining).
+ */
+typedef struct irq_node {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+ struct irq_node *next;
+} irq_node_t;
+
+/*
+ * This structure has only 4 elements for speed reasons
+ */
+typedef struct irq_handler {
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long flags;
+ void *dev_id;
+ const char *devname;
+} irq_handler_t;
+
+/* count of spurious interrupts */
+extern volatile unsigned int num_spurious;
+
+extern int sys_request_irq(unsigned int,
+ void (*)(int, void *, struct pt_regs *),
+ unsigned long, const char *, void *);
+extern void sys_free_irq(unsigned int, void *);
+
+/*
+ * This function returns a new irq_node_t
+ */
+extern irq_node_t *new_irq_node(void);
+
+/* Number of m68k interrupts */
+#define SYS_IRQS 8
+
+#endif /* CONFIG_APUS */
/*
* this is the # irq's for all ppc arch's (pmac/chrp/prep)
@@ -133,14 +166,11 @@ static __inline__ int irq_cannonicalize(int irq)
*/
#define NR_IRQS 256
-#endif /* CONFIG_APUS */
-
#define NUM_8259_INTERRUPTS 16
#define IRQ_8259_CASCADE 16
#define openpic_to_irq(n) ((n)+NUM_8259_INTERRUPTS)
#define irq_to_openpic(n) ((n)-NUM_8259_INTERRUPTS)
-#ifndef CONFIG_APUS
/*
* This gets called from serial.c, which is now used on
* powermacs as well as prep/chrp boxes.
@@ -157,8 +187,10 @@ static __inline__ int irq_cannonicalize(int irq)
return irq;
}
}
-#endif /* !CONFIG_APUS */
#endif
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+
#endif /* _ASM_IRQ_H */
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index 5d022e02c..d543c90cc 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -62,7 +62,8 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
BUG();
/* nothing to do */
}
-extern inline void pci_dma_syng_sg(struct pci_dev *hwdev,
+
+extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
struct scatterlist *sg,
int nelems, int direction)
{
diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
index 704bd68ab..5212c5b71 100644
--- a/include/asm-ppc/processor.h
+++ b/include/asm-ppc/processor.h
@@ -692,16 +692,7 @@ void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
#endif /* ndef ASSEMBLY*/
#ifdef CONFIG_MACH_SPECIFIC
-#if defined(CONFIG_PREP)
-#define _machine _MACH_prep
-#define have_of 0
-#elif defined(CONFIG_CHRP)
-#define _machine _MACH_chrp
-#define have_of 1
-#elif defined(CONFIG_PMAC)
-#define _machine _MACH_Pmac
-#define have_of 1
-#elif defined(CONFIG_8xx)
+#if defined(CONFIG_8xx)
#define _machine _MACH_8xx
#define have_of 0
#elif defined(CONFIG_OAK)
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index d567a9975..cd4d055bb 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -66,6 +66,7 @@ extern void load_up_altivec(struct task_struct *);
extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
extern void cvt_df(double *from, float *to, unsigned long *fpscr);
extern int call_rtas(const char *, int, int, unsigned long *, ...);
+extern int abs(int);
struct device_node;
extern void note_scsi_host(struct device_node *, void *);
diff --git a/include/asm-ppc/types.h b/include/asm-ppc/types.h
index d39f91cf9..4cbcd7850 100644
--- a/include/asm-ppc/types.h
+++ b/include/asm-ppc/types.h
@@ -26,8 +26,6 @@ typedef unsigned long long __u64;
/*
* These aren't exported outside the kernel to avoid name space clashes
*/
-#ifdef __KERNEL__
-
typedef signed char s8;
typedef unsigned char u8;
@@ -40,14 +38,15 @@ typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
-#define BITS_PER_LONG 32
-
typedef struct {
u32 u[4];
} __attribute((aligned(16))) vector128;
-/* DMA addresses are 32-bits wide */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG 32
+/* DMA addresses are 32-bits wide */
typedef u32 dma_addr_t;
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/vga.h b/include/asm-ppc/vga.h
index e6a7f9a53..d7ead205f 100644
--- a/include/asm-ppc/vga.h
+++ b/include/asm-ppc/vga.h
@@ -23,12 +23,12 @@
extern inline void scr_writew(u16 val, u16 *addr)
{
- writew(val, (unsigned long)addr);
+ st_le16(addr, val);
}
extern inline u16 scr_readw(const u16 *addr)
{
- return readw((unsigned long)addr);
+ return ld_le16(addr);
}
#define VT_BUF_HAVE_MEMCPYW
diff --git a/include/asm-sparc/termbits.h b/include/asm-sparc/termbits.h
index 2d07e4e1e..657829589 100644
--- a/include/asm-sparc/termbits.h
+++ b/include/asm-sparc/termbits.h
@@ -165,10 +165,13 @@ struct termios {
#define B1152000 0x0000100d
#define B1500000 0x0000100e
#define B2000000 0x0000100f
+/* These have totally bogus values and nobody uses them
+ so far. Later on we'd have to use say 0x10000x and
+ adjust CBAUD constant and drivers accordingly.
#define B2500000 0x00001010
#define B3000000 0x00001011
#define B3500000 0x00001012
-#define B4000000 0x00001013
+#define B4000000 0x00001013 */
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index 0c137b72d..f8bdaa826 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.32 2000/02/15 10:04:54 jj Exp $ */
+/* $Id: io.h,v 1.33 2000/02/25 05:47:38 davem Exp $ */
#ifndef __SPARC64_IO_H
#define __SPARC64_IO_H
@@ -225,10 +225,8 @@ extern __inline__ void _sbus_writel(unsigned int l, unsigned long addr)
#define sbus_writew(__w, __addr) (_sbus_writew((__w), (unsigned long)(__addr)))
#define sbus_writel(__l, __addr) (_sbus_writel((__l), (unsigned long)(__addr)))
-static inline void *sbus_memset_io(void *__dst, int c, __kernel_size_t n)
+static inline void *_sbus_memset_io(unsigned long dst, int c, __kernel_size_t n)
{
- unsigned long dst = (unsigned long)__dst;
-
while(n--) {
sbus_writeb(c, dst);
dst++;
@@ -236,8 +234,11 @@ static inline void *sbus_memset_io(void *__dst, int c, __kernel_size_t n)
return (void *) dst;
}
+#define sbus_memset_io(d,c,sz) \
+ _sbus_memset_io((unsigned long)d,(int)c,(__kernel_size_t)sz)
+
static inline void *
-memset_io(void *dst, int c, __kernel_size_t n)
+_memset_io(void *dst, int c, __kernel_size_t n)
{
char *d = dst;
@@ -249,8 +250,11 @@ memset_io(void *dst, int c, __kernel_size_t n)
return dst;
}
+#define memset_io(d,c,sz) \
+ _memset_io((void *)d,(int)c,(__kernel_size_t)sz)
+
static inline void *
-memcpy_fromio(void *dst, unsigned long src, __kernel_size_t n)
+_memcpy_fromio(void *dst, unsigned long src, __kernel_size_t n)
{
char *d = dst;
@@ -263,8 +267,11 @@ memcpy_fromio(void *dst, unsigned long src, __kernel_size_t n)
return dst;
}
+#define memcpy_fromio(d,s,sz) \
+ _memcpy_fromio((void *)d,(unsigned long)s,(__kernel_size_t)sz)
+
static inline void *
-memcpy_toio(unsigned long dst, const void *src, __kernel_size_t n)
+_memcpy_toio(unsigned long dst, const void *src, __kernel_size_t n)
{
const char *s = src;
unsigned long d = dst;
@@ -277,6 +284,9 @@ memcpy_toio(unsigned long dst, const void *src, __kernel_size_t n)
return (void *)dst;
}
+#define memcpy_toio(d,s,sz) \
+ _memcpy_toio((unsigned long)d,(const void *)s,(__kernel_size_t)sz)
+
static inline int check_signature(unsigned long io_addr,
const unsigned char *signature,
int length)
diff --git a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h
index ee7d80809..1c2b889df 100644
--- a/include/asm-sparc64/siginfo.h
+++ b/include/asm-sparc64/siginfo.h
@@ -65,7 +65,7 @@ typedef struct siginfo {
/* SIGPOLL */
struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ long _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
diff --git a/include/asm-sparc64/termbits.h b/include/asm-sparc64/termbits.h
index faa32e785..330c19d06 100644
--- a/include/asm-sparc64/termbits.h
+++ b/include/asm-sparc64/termbits.h
@@ -166,10 +166,13 @@ struct termios {
#define B1152000 0x0000100d
#define B1500000 0x0000100e
#define B2000000 0x0000100f
+/* These have totally bogus values and nobody uses them
+ so far. Later on we'd have to use say 0x10000x and
+ adjust CBAUD constant and drivers accordingly.
#define B2500000 0x00001010
#define B3000000 0x00001011
#define B3500000 0x00001012
-#define B4000000 0x00001013
+#define B4000000 0x00001013 */
#define CIBAUD 0x100f0000 /* input baud rate (not used) */
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
#define CRTSCTS 0x80000000 /* flow control */
diff --git a/drivers/sound/ac97_codec.h b/include/linux/ac97_codec.h
index a614edbdb..68989d76d 100644
--- a/drivers/sound/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -1,8 +1,6 @@
#ifndef _AC97_CODEC_H_
#define _AC97_CODEC_H_
-#include "sound_config.h"
-#include "sound_calls.h"
/* AC97 1.0 */
#define AC97_RESET 0x0000 //
diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
index 90e5a3dd2..10cd77b8d 100644
--- a/include/linux/affs_fs.h
+++ b/include/linux/affs_fs.h
@@ -103,8 +103,10 @@ extern void affs_dir_truncate(struct inode *);
/* jump tables */
extern struct inode_operations affs_file_inode_operations;
-extern struct inode_operations affs_file_inode_operations_ofs;
extern struct inode_operations affs_dir_inode_operations;
+extern struct file_operations affs_file_operations;
+extern struct file_operations affs_file_operations_ofs;
+extern struct file_operations affs_dir_operations;
extern struct address_space_operations affs_symlink_aops;
extern struct address_space_operations affs_aops;
diff --git a/include/linux/bfs_fs.h b/include/linux/bfs_fs.h
index 7e7de106a..9525293cb 100644
--- a/include/linux/bfs_fs.h
+++ b/include/linux/bfs_fs.h
@@ -83,10 +83,12 @@ extern int init_bfs_fs(void);
/* file.c */
extern struct inode_operations bfs_file_inops;
+extern struct file_operations bfs_file_operations;
extern struct address_space_operations bfs_aops;
/* dir.c */
extern struct inode_operations bfs_dir_inops;
+extern struct file_operations bfs_dir_operations;
#endif /* __KERNEL__ */
#endif /* _LINUX_BFS_FS_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c035f1327..166528473 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -53,7 +53,7 @@ typedef int (merge_requests_fn) (request_queue_t *q,
int);
typedef void (request_fn_proc) (request_queue_t *q);
typedef request_queue_t * (queue_proc) (kdev_t dev);
-typedef void (make_request_fn) (int rw, struct buffer_head *bh);
+typedef int (make_request_fn) (request_queue_t *q, int rw, struct buffer_head *bh);
typedef void (plug_device_fn) (request_queue_t *q, kdev_t device);
typedef void (unplug_device_fn) (void *q);
@@ -129,7 +129,8 @@ extern wait_queue_head_t wait_for_request;
extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size);
extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size);
extern void generic_unplug_device(void * data);
-extern void generic_make_request(int rw, struct buffer_head * bh);
+extern int generic_make_request(request_queue_t *q, int rw,
+ struct buffer_head * bh);
extern request_queue_t * blk_get_queue(kdev_t dev);
/*
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index 59cd5da3c..21f5bad13 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -39,6 +39,7 @@ int coda_open(struct inode *i, struct file *f);
int coda_release(struct inode *i, struct file *f);
int coda_permission(struct inode *inode, int mask);
int coda_revalidate_inode(struct dentry *);
+int coda_notify_change(struct dentry *, struct iattr *);
/* global variables */
extern int coda_debug;
diff --git a/include/linux/dlists.h b/include/linux/dlists.h
deleted file mode 100644
index f92485e40..000000000
--- a/include/linux/dlists.h
+++ /dev/null
@@ -1,108 +0,0 @@
-#ifndef DLISTS_H
-#define DLISTS_H
-/*
- * include/linux/dlists.h - macros for double linked lists
- *
- * Copyright (C) 1997, Thomas Schoebel-Theuer,
- * <schoebel@informatik.uni-stuttgart.de>.
- */
-
-/* dlists are cyclic ringlists, so the last element cannot be tested
- * for NULL. Use the following construct for traversing cyclic lists:
- * ptr = anchor;
- * if(ptr) do {
- * ...
- * ptr = ptr->{something}_{next,prev};
- * } while(ptr != anchor);
- * The effort here is paid off with much simpler inserts/removes.
- * Examples for usage of these macros can be found in fs/ninode.c.
- * To access the last element in constant time, simply use
- * anchor->{something}_prev.
- */
-
-#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \
-static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\
-{\
- TYPE * oldfirst = *anchor;\
- if(!oldfirst) {\
- elem->NEXT = elem->PREV = *anchor = elem;\
- } else {\
- elem->PREV = oldfirst->PREV;\
- elem->NEXT = oldfirst;\
- oldfirst->PREV->NEXT = elem;\
- oldfirst->PREV = elem;\
- if(CHANGE)\
- *anchor = elem;\
- }\
-}
-
-/* insert_* is always at the first position */
-#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \
- DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV)
-
-/* append_* is always at the tail */
-#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \
- DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV)
-
-/* use this to insert _before_ oldelem somewhere in the middle of the list.
- * the list must not be empty, and oldelem must be already a member.*/
-#define DEF_INSERT_MIDDLE(NAME,TYPE) \
-static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\
-{\
- int status = (oldelem == *anchor);\
- insert_##NAME(&oldelem, elem);\
- if(status)\
- *anchor = oldelem;\
-}
-
-/* remove can be done with any element in the list */
-#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \
-static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
-{\
- TYPE * next = elem->NEXT;\
- if(next == elem) {\
- *anchor = NULL;\
- } else {\
- TYPE * prev = elem->PREV;\
- prev->NEXT = next;\
- next->PREV = prev;\
- elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\
- if(*anchor == elem)\
- *anchor = next;\
- }\
-}
-
-
-/* According to ideas from David S. Miller, here is a slightly
- * more efficient plug-in compatible version using non-cyclic lists,
- * but allowing neither backward traversals nor constant time access
- * to the last element.
- * Note that although the interface is the same, the PPREV pointer must be
- * declared doubly indirect and the test for end-of-list is different. */
-
-/* as above, this inserts always at the head */
-#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \
-static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\
-{\
- TYPE * first;\
- if((elem->NEXT = first = *anchor))\
- first->PPREV = &elem->NEXT;\
- *anchor = elem;\
- elem->PPREV = anchor;\
-}
-
-/* as above, this works with any list element */
-#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \
-static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
-{\
- TYPE * pprev;\
- if((pprev = elem->PPREV)) {\
- TYPE * next;\
- if((next = elem->NEXT))\
- next->PPREV = pprev;\
- *pprev = next;\
- elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\
- }\
-}
-
-#endif
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index f422f4e51..2ba621bc2 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -46,7 +46,7 @@ static const char cprt[] = "EFS: "EFS_VERSION" - (c) 1999 Al Smith <Al.Smith@aes
#endif
extern struct inode_operations efs_dir_inode_operations;
-extern struct inode_operations efs_file_inode_operations;
+extern struct file_operations efs_dir_operations;
extern struct address_space_operations efs_symlink_aops;
extern int init_module(void);
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 5bb7d8154..67c6fac14 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -576,17 +576,7 @@ extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
/* namei.c */
-extern void ext2_release (struct inode *, struct file *);
-extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
-extern int ext2_create (struct inode *,struct dentry *,int);
-extern int ext2_mkdir (struct inode *,struct dentry *,int);
-extern int ext2_rmdir (struct inode *,struct dentry *);
-extern int ext2_unlink (struct inode *,struct dentry *);
-extern int ext2_symlink (struct inode *,struct dentry *,const char *);
-extern int ext2_link (struct dentry *, struct inode *, struct dentry *);
-extern int ext2_mknod (struct inode *, struct dentry *, int, int);
-extern int ext2_rename (struct inode *, struct dentry *,
- struct inode *, struct dentry *);
+extern struct inode_operations ext2_dir_inode_operations;
/* super.c */
extern void ext2_error (struct super_block *, const char *, const char *, ...)
@@ -610,10 +600,11 @@ extern void ext2_truncate (struct inode *);
*/
/* dir.c */
-extern struct inode_operations ext2_dir_inode_operations;
+extern struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
+extern struct file_operations ext2_file_operations;
/* symlink.c */
extern struct inode_operations ext2_fast_symlink_inode_operations;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 2f8013318..0b55b363b 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -24,6 +24,7 @@
#define FBIOGET_CON2FBMAP 0x460F
#define FBIOPUT_CON2FBMAP 0x4610
#define FBIOBLANK 0x4611 /* arg: 0 or vesa level + 1 */
+#define FBIOGET_VBLANK _IOR('F', 0x12, struct fb_vblank)
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
@@ -211,6 +212,24 @@ struct fb_monspecs {
unsigned dpms : 1; /* supports DPMS */
};
+#define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */
+#define FB_VBLANK_HBLANKING 0x002 /* currently in a horizontal blank */
+#define FB_VBLANK_HAVE_VBLANK 0x004 /* vertical blanks can be detected */
+#define FB_VBLANK_HAVE_HBLANK 0x008 /* horizontal blanks can be detected */
+#define FB_VBLANK_HAVE_COUNT 0x010 /* global retrace counter is available */
+#define FB_VBLANK_HAVE_VCOUNT 0x020 /* the vcount field is valid */
+#define FB_VBLANK_HAVE_HCOUNT 0x040 /* the hcount field is valid */
+#define FB_VBLANK_VSYNCING 0x080 /* currently in a vsync */
+#define FB_VBLANK_HAVE_VSYNC 0x100 /* verical syncs can be detected */
+
+struct fb_vblank {
+ __u32 flags; /* FB_VBLANK flags */
+ __u32 count; /* counter of retraces since boot */
+ __u32 vcount; /* current scanline position */
+ __u32 hcount; /* current scandot position */
+ __u32 reserved[4]; /* reserved for future compatibility */
+};
+
#ifdef __KERNEL__
#if 1 /* to go away in 2.4.0 */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a64c6f9c7..e33bdfa72 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -385,6 +385,7 @@ struct inode {
unsigned long i_version;
struct semaphore i_sem;
struct inode_operations *i_op;
+ struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
wait_queue_head_t i_wait;
struct file_lock *i_flock;
@@ -668,7 +669,6 @@ struct file_operations {
};
struct inode_operations {
- struct file_operations * default_file_ops;
int (*create) (struct inode *,struct dentry *,int);
struct dentry * (*lookup) (struct inode *,struct dentry *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
@@ -684,6 +684,8 @@ struct inode_operations {
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int);
int (*revalidate) (struct dentry *);
+ int (*setattr) (struct dentry *, struct iattr *);
+ int (*getattr) (struct dentry *, struct iattr *);
};
/*
@@ -695,7 +697,6 @@ struct super_operations {
void (*write_inode) (struct inode *);
void (*put_inode) (struct inode *);
void (*delete_inode) (struct inode *);
- int (*notify_change) (struct dentry *, struct iattr *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
int (*statfs) (struct super_block *, struct statfs *, int);
@@ -796,6 +797,7 @@ extern struct block_device *bdget(dev_t);
extern void bdput(struct block_device *);
extern int blkdev_open(struct inode *, struct file *);
extern struct file_operations def_blk_fops;
+extern struct file_operations def_fifo_fops;
extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
extern int blkdev_put(struct block_device *, int);
@@ -811,9 +813,6 @@ extern const char * cdevname(kdev_t);
extern const char * kdevname(kdev_t);
extern void init_special_inode(struct inode *, umode_t, int);
-extern struct inode_operations fifo_inode_operations;
-extern struct inode_operations blkdev_inode_operations;
-
/* Invalid inode operations -- fs/bad_inode.c */
extern void make_bad_inode(struct inode *);
extern int is_bad_inode(struct inode *);
@@ -1019,11 +1018,15 @@ extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
+extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
+
+extern struct file_operations generic_ro_fops;
+
extern int vfs_readlink(struct dentry *, char *, int, const char *);
extern struct dentry *vfs_follow_link(struct dentry *, struct dentry *, unsigned, const char *);
extern int page_readlink(struct dentry *, char *, int);
extern struct dentry *page_follow_link(struct dentry *, struct dentry *, unsigned);
-struct inode_operations page_symlink_inode_operations;
+extern struct inode_operations page_symlink_inode_operations;
extern struct super_block *get_super(kdev_t);
struct super_block *get_empty_super(void);
diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h
index fcac3cd06..3509c5cb9 100644
--- a/include/linux/hdreg.h
+++ b/include/linux/hdreg.h
@@ -86,6 +86,7 @@
#define WIN_SRST 0x08 /* ATAPI soft reset command */
#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
+#define DISABLE_SEAGATE 0xFB
#define EXABYTE_ENABLE_NEST 0xF0
/* WIN_SMART sub-commands */
@@ -104,6 +105,7 @@
#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */
#define SETFEATURES_XFER 0x03 /* Set transfer mode */
+# define XFER_UDMA_7 0x47 /* 0100|0111 */
# define XFER_UDMA_6 0x46 /* 0100|0110 */
# define XFER_UDMA_5 0x45 /* 0100|0101 */
# define XFER_UDMA_4 0x44 /* 0100|0100 */
@@ -123,6 +125,7 @@
# define XFER_PIO_1 0x09 /* 0000|1001 */
# define XFER_PIO_0 0x08 /* 0000|1000 */
# define XFER_PIO_SLOW 0x00 /* 0000|0000 */
+#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */
#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */
#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */
#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */
@@ -130,9 +133,11 @@
#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */
#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */
#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */
+#define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */
#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */
#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */
#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */
+#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */
#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */
#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */
#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */
@@ -232,26 +237,11 @@ struct hd_driveid {
unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */
unsigned short eide_pio; /* min cycle time (ns), no IORDY */
unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */
-#if 0
- unsigned short words69_74[6]; /* reserved words 69-74 */
-#else
- unsigned short word69; /* reserved (word 69) */
- unsigned short word70; /* reserved (word 70) */
+ unsigned short words69_70[2]; /* reserved words 69-70 */
/* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
- unsigned short word71; /* reserved (word 71) */
- unsigned short word72; /* reserved (word 72) */
- unsigned short word73; /* reserved (word 73) */
- unsigned short word74; /* reserved (word 74) */
-#endif
+ unsigned short words71_74[4]; /* reserved words 71-74 */
unsigned short queue_depth; /* */
-#if 0
unsigned short words76_79[4]; /* reserved words 76-79 */
-#else
- unsigned short word76; /* reserved (word 76) */
- unsigned short word77; /* reserved (word 77) */
- unsigned short word78; /* reserved (word 78) */
- unsigned short word79; /* reserved (word 79) */
-#endif
unsigned short major_rev_num; /* */
unsigned short minor_rev_num; /* */
unsigned short command_set_1; /* bits 0:Smart 1:Security 2:Removable 3:PM */
@@ -266,43 +256,8 @@ struct hd_driveid {
unsigned short CurAPMvalues; /* current APM values */
unsigned short word92; /* reserved (word 92) */
unsigned short hw_config; /* hardware config */
-#if 0
- unsigned short words94_126[34];/* reserved words 94-126 */
-#else
- unsigned short word94; /* reserved (word 94) */
- unsigned short word95; /* reserved (word 95) */
- unsigned short word96; /* reserved (word 96) */
- unsigned short word97; /* reserved (word 97) */
- unsigned short word98; /* reserved (word 98) */
- unsigned short word99; /* reserved (word 99) */
- unsigned short word100; /* reserved (word 100) */
- unsigned short word101; /* reserved (word 101) */
- unsigned short word102; /* reserved (word 102) */
- unsigned short word103; /* reserved (word 103) */
- unsigned short word104; /* reserved (word 104) */
- unsigned short word105; /* reserved (word 105) */
- unsigned short word106; /* reserved (word 106) */
- unsigned short word107; /* reserved (word 107) */
- unsigned short word108; /* reserved (word 108) */
- unsigned short word109; /* reserved (word 109) */
- unsigned short word110; /* reserved (word 110) */
- unsigned short word111; /* reserved (word 111) */
- unsigned short word112; /* reserved (word 112) */
- unsigned short word113; /* reserved (word 113) */
- unsigned short word114; /* reserved (word 114) */
- unsigned short word115; /* reserved (word 115) */
- unsigned short word116; /* reserved (word 116) */
- unsigned short word117; /* reserved (word 117) */
- unsigned short word118; /* reserved (word 118) */
- unsigned short word119; /* reserved (word 119) */
- unsigned short word120; /* reserved (word 120) */
- unsigned short word121; /* reserved (word 121) */
- unsigned short word122; /* reserved (word 122) */
- unsigned short word123; /* reserved (word 123) */
- unsigned short word124; /* reserved (word 124) */
- unsigned short word125; /* reserved (word 125) */
- unsigned short word126; /* reserved (word 126) */
-#endif
+ unsigned short words94_125[33];/* reserved words 94-125 */
+ unsigned short last_lun; /* reserved (word 126) */
unsigned short word127; /* reserved (word 127) */
unsigned short dlf; /* device lock function
* 15:9 reserved
@@ -322,7 +277,8 @@ struct hd_driveid {
* 1 read-look-ahead
* 0 write cache
*/
- unsigned short reserved[126];
+ unsigned short words130_159[30];/* reserved vendor words 130-159 */
+ unsigned short words160_255[96];/* reserved words 160-255 */
};
/*
diff --git a/include/linux/hfs_fs.h b/include/linux/hfs_fs.h
index 4c9543a5d..3c3913943 100644
--- a/include/linux/hfs_fs.h
+++ b/include/linux/hfs_fs.h
@@ -234,8 +234,6 @@ extern struct hfs_cat_entry *hfs_cat_get(struct hfs_mdb *,
const struct hfs_cat_key *);
/* dir.c */
-extern hfs_rwret_t hfs_dir_read(struct file *, char *, hfs_rwarg_t,
- loff_t *);
extern int hfs_create(struct inode *, struct dentry *, int);
extern int hfs_mkdir(struct inode *, struct dentry *, int);
extern int hfs_unlink(struct inode *, struct dentry *);
@@ -249,12 +247,14 @@ extern const struct hfs_name hfs_cap_reserved2[];
extern struct inode_operations hfs_cap_ndir_inode_operations;
extern struct inode_operations hfs_cap_fdir_inode_operations;
extern struct inode_operations hfs_cap_rdir_inode_operations;
+extern struct file_operations hfs_cap_dir_operations;
extern void hfs_cap_drop_dentry(struct dentry *, const ino_t);
/* dir_dbl.c */
extern const struct hfs_name hfs_dbl_reserved1[];
extern const struct hfs_name hfs_dbl_reserved2[];
extern struct inode_operations hfs_dbl_dir_inode_operations;
+extern struct file_operations hfs_dbl_dir_operations;
extern void hfs_dbl_drop_dentry(struct dentry *, const ino_t);
/* dir_nat.c */
@@ -262,13 +262,9 @@ extern const struct hfs_name hfs_nat_reserved1[];
extern const struct hfs_name hfs_nat_reserved2[];
extern struct inode_operations hfs_nat_ndir_inode_operations;
extern struct inode_operations hfs_nat_hdir_inode_operations;
+extern struct file_operations hfs_nat_dir_operations;
extern void hfs_nat_drop_dentry(struct dentry *, const ino_t);
-/* dir_sngl.c */
-extern const struct hfs_name hfs_sngl_reserved1[];
-extern const struct hfs_name hfs_sngl_reserved2[];
-extern struct inode_operations hfs_sngl_dir_inode_operations;
-
/* file.c */
extern hfs_s32 hfs_do_read(struct inode *, struct hfs_fork *, hfs_u32,
char *, hfs_u32, int);
@@ -276,21 +272,27 @@ extern hfs_s32 hfs_do_write(struct inode *, struct hfs_fork *, hfs_u32,
const char *, hfs_u32);
extern void hfs_file_fix_mode(struct hfs_cat_entry *entry);
extern struct inode_operations hfs_file_inode_operations;
+extern struct file_operations hfs_file_operations;
/* file_cap.c */
extern struct inode_operations hfs_cap_info_inode_operations;
+extern struct file_operations hfs_cap_info_operations;
/* file_hdr.c */
extern struct inode_operations hfs_hdr_inode_operations;
+extern struct file_operations hfs_hdr_operations;
extern const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout;
extern const struct hfs_hdr_layout hfs_dbl_dir_hdr_layout;
extern const struct hfs_hdr_layout hfs_nat_hdr_layout;
extern const struct hfs_hdr_layout hfs_nat2_hdr_layout;
extern const struct hfs_hdr_layout hfs_sngl_hdr_layout;
+extern void hdr_truncate(struct inode *,size_t);
/* inode.c */
extern void hfs_put_inode(struct inode *);
extern int hfs_notify_change(struct dentry *, struct iattr *);
+extern int hfs_notify_change_cap(struct dentry *, struct iattr *);
+extern int hfs_notify_change_hdr(struct dentry *, struct iattr *);
extern struct inode *hfs_iget(struct hfs_cat_entry *, ino_t, struct dentry *);
extern void hfs_cap_ifill(struct inode *, ino_t, const int);
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 62325a43e..3672f2789 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -181,12 +181,17 @@ typedef unsigned char byte; /* used everywhere */
struct hwif_s;
typedef int (ide_ack_intr_t)(struct hwif_s *);
+#ifndef NO_DMA
+#define NO_DMA 255
+#endif
+
/*
* Structure to hold all information about the location of this port
*/
typedef struct hw_regs_s {
ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */
int irq; /* our irq number */
+ int dma; /* our dma entry */
ide_ack_intr_t *ack_intr; /* acknowledge interrupt */
void *priv; /* interface specific data */
} hw_regs_t;
@@ -356,6 +361,7 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_cmd646, ide_cy82c693, ide_4drives
} hwif_chipset_t;
+#ifdef CONFIG_BLK_DEV_IDEPCI
typedef struct ide_pci_devid_s {
unsigned short vid;
unsigned short did;
@@ -363,6 +369,7 @@ typedef struct ide_pci_devid_s {
#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0})
#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did)
+#endif /* CONFIG_BLK_DEV_IDEPCI */
typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
@@ -399,8 +406,10 @@ typedef struct hwif_s {
unsigned autodma : 1; /* automatically try to enable DMA at boot */
unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
byte channel; /* for dual-port chips: 0=primary, 1=secondary */
+#ifdef CONFIG_BLK_DEV_IDEPCI
struct pci_dev *pci_dev; /* for pci chipsets */
ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
@@ -579,7 +588,8 @@ typedef struct ide_module_s {
*/
#ifndef _IDE_C
extern ide_hwif_t ide_hwifs[]; /* master data repository */
-extern ide_module_t *ide_modules;
+extern ide_module_t *ide_modules;
+extern ide_module_t *ide_probe;
#endif
/*
@@ -851,4 +861,6 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_po
unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
#endif
+void hwif_unregister (ide_hwif_t *hwif);
+
#endif /* _IDE_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 150266ff8..4a6df60ae 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -12,6 +12,7 @@
#define IRQ_AUTODETECT 16 /* IRQ is being autodetected */
#define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */
#define IRQ_LEVEL 64 /* IRQ level triggered */
+#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */
/*
* Interrupt controller descriptor. This is all we need
@@ -25,6 +26,7 @@ struct hw_interrupt_type {
void (*disable)(unsigned int irq);
void (*ack)(unsigned int irq);
void (*end)(unsigned int irq);
+ void (*set_affinity)(unsigned int irq, unsigned int mask);
};
typedef struct hw_interrupt_type hw_irq_controller;
@@ -37,17 +39,33 @@ typedef struct hw_interrupt_type hw_irq_controller;
* Pad this out to 32 bytes for cache and indexing reasons.
*/
typedef struct {
- unsigned int status; /* IRQ status
- - IRQ_INPROGRESS, IRQ_DISABLED */
- hw_irq_controller *handler; /* never derefed in arch
- independent code */
- struct irqaction *action; /* IRQ action list */
- unsigned int depth; /* Disable depth for nested irq disables */
+ unsigned int status; /* IRQ status */
+ hw_irq_controller *handler;
+ struct irqaction *action; /* IRQ action list */
+ unsigned int depth; /* nested irq disables */
+ spinlock_t lock;
+ unsigned int __pad[3];
} ____cacheline_aligned irq_desc_t;
-#include <asm/hw_irq.h> /* the arch dependent stuff */
+extern irq_desc_t irq_desc [NR_IRQS];
+
+typedef struct {
+ unsigned int __local_irq_count;
+ unsigned int __local_bh_count;
+ atomic_t __nmi_counter;
+ unsigned int __pad[5];
+} ____cacheline_aligned irq_cpustat_t;
+
+extern irq_cpustat_t irq_stat [NR_CPUS];
-extern irq_desc_t irq_desc[NR_IRQS];
+/*
+ * Simple wrappers reducing source bloat
+ */
+#define local_irq_count(cpu) (irq_stat[(cpu)].__local_irq_count)
+#define local_bh_count(cpu) (irq_stat[(cpu)].__local_bh_count)
+#define nmi_counter(cpu) (irq_stat[(cpu)].__nmi_counter)
+
+#include <asm/hw_irq.h> /* the arch dependent stuff */
extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
extern spinlock_t irq_controller_lock;
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index d7dc3b90f..f34122fc3 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.90 2000/02/06 21:50:00 detabc Exp $
+/* $Id: isdn.h,v 1.94 2000/02/26 00:29:40 keil Exp $
*
* Main header for the Linux ISDN subsystem (linklevel).
*
@@ -21,6 +21,19 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn.h,v $
+ * Revision 1.94 2000/02/26 00:29:40 keil
+ * more softnet changes
+ *
+ * Revision 1.93 2000/02/25 11:29:17 paul
+ * changed chargetime to ulong from int (after about 20 days the "chargetime of
+ * ipppX is now 1234" message displays a negative number on alpha).
+ *
+ * Revision 1.92 2000/02/17 13:15:56 keil
+ * fix backward compatibility for 2.2
+ *
+ * Revision 1.91 2000/02/16 14:56:27 paul
+ * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers
+ *
* Revision 1.90 2000/02/06 21:50:00 detabc
* add rewriting of socket's and frame's saddr for udp-ipv4 dynip-connections.
* Include checksum-recompute of ip- and udp-header's.
@@ -444,7 +457,7 @@
#define ISDN_USAGE_EXCLUSIVE 64 /* This bit is set, if channel is exclusive */
#define ISDN_USAGE_OUTGOING 128 /* This bit is set, if channel is outgoing */
-#define ISDN_MODEM_ANZREG 24 /* Number of Modem-Registers */
+#define ISDN_MODEM_NUMREG 24 /* Number of Modem-Registers */
#define ISDN_LMSNLEN 255 /* Length of tty's Listen-MSN string */
#define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */
@@ -672,7 +685,7 @@ typedef struct isdn_net_local_s {
/* 0 = Transparent */
int huptimer; /* Timeout-counter for auto-hangup */
int charge; /* Counter for charging units */
- int chargetime; /* Timer for Charging info */
+ ulong chargetime; /* Timer for Charging info */
int hupflags; /* Flags for charge-unit-hangup: */
/* bit0: chargeint is invalid */
/* bit1: Getting charge-interval */
@@ -777,8 +790,8 @@ typedef struct isdn_audio_skb {
/* Private data of AT-command-interpreter */
typedef struct atemu {
- u_char profile[ISDN_MODEM_ANZREG]; /* Modem-Regs. Profile 0 */
- u_char mdmreg[ISDN_MODEM_ANZREG]; /* Modem-Registers */
+ u_char profile[ISDN_MODEM_NUMREG]; /* Modem-Regs. Profile 0 */
+ u_char mdmreg[ISDN_MODEM_NUMREG]; /* Modem-Registers */
char pmsn[ISDN_MSNLEN]; /* EAZ/MSNs Profile 0 */
char msn[ISDN_MSNLEN]; /* EAZ/MSN */
char plmsn[ISDN_LMSNLEN]; /* Listening MSNs Profile 0 */
@@ -985,10 +998,10 @@ typedef struct isdn_devt {
devfs_handle_t devfs_handle_isdnctrl;
devfs_handle_t devfs_handle_isdnX[ISDN_MAX_CHANNELS];
devfs_handle_t devfs_handle_isdnctrlX[ISDN_MAX_CHANNELS];
-# ifdef CONFIG_ISDN_PPP
+#ifdef CONFIG_ISDN_PPP
devfs_handle_t devfs_handle_ipppX[ISDN_MAX_CHANNELS];
-# endif
#endif
+#endif /* CONFIG_DEVFS_FS */
} isdn_dev;
extern isdn_dev *dev;
diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h
index 59da5b123..47fab8914 100644
--- a/include/linux/iso_fs.h
+++ b/include/linux/iso_fs.h
@@ -189,8 +189,8 @@ extern int isofs_bmap(struct inode *, int);
extern int init_iso9660_fs(void);
extern int isofs_lookup_grandparent(struct inode *, int);
-extern struct inode_operations isofs_file_inode_operations;
extern struct inode_operations isofs_dir_inode_operations;
+extern struct file_operations isofs_dir_operations;
extern struct address_space_operations isofs_symlink_aops;
/* The following macros are used to check for memory leaks. */
diff --git a/include/linux/list.h b/include/linux/list.h
index 656aacc2a..a3900e53c 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -104,6 +104,9 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/lists.h b/include/linux/lists.h
deleted file mode 100644
index e1163acde..000000000
--- a/include/linux/lists.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * lists.h: Simple list macros for Linux
- */
-
-#define DLNODE(ptype) \
- struct { \
- ptype * dl_prev; \
- ptype * dl_next; \
- }
-
-#define DNODE_SINGLE(node) {(node),(node)}
-#define DNODE_NULL {0,0}
-
-#define DLIST_INIT(listnam) \
- (listnam).dl_prev = &(listnam); \
- (listnam).dl_next = &(listnam);
-
-#define DLIST_NEXT(listnam) listnam.dl_next
-#define DLIST_PREV(listnam) listnam.dl_prev
-
-#define DLIST_INSERT_AFTER(node, new, listnam) do { \
- (new)->listnam.dl_prev = (node); \
- (new)->listnam.dl_next = (node)->listnam.dl_next; \
- (node)->listnam.dl_next->listnam.dl_prev = (new); \
- (node)->listnam.dl_next = (new); \
- } while (0)
-
-#define DLIST_INSERT_BEFORE(node, new, listnam) do { \
- (new)->listnam.dl_next = (node); \
- (new)->listnam.dl_prev = (node)->listnam.dl_prev; \
- (node)->listnam.dl_prev->listnam.dl_next = (new); \
- (node)->listnam.dl_prev = (new); \
- } while (0)
-
-#define DLIST_DELETE(node, listnam) do { \
- node->listnam.dl_prev->listnam.dl_next = \
- node->listnam.dl_next; \
- node->listnam.dl_next->listnam.dl_prev = \
- node->listnam.dl_prev; \
- } while (0)
-
-/*
- * queue-style operations, which have a head and tail
- */
-
-#define QUEUE_INIT(head, listnam, ptype) \
- (head)->listnam.dl_prev = (head)->listnam.dl_next = (ptype)(head);
-
-#define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam)
-#define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam)
-#define QUEUE_IS_EMPTY(head, listnam) \
- ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \
- ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head))
-
-#define QUEUE_ENTER(head, new, listnam, ptype) do { \
- (new)->listnam.dl_prev = (ptype)(head); \
- (new)->listnam.dl_next = (head)->listnam.dl_next; \
- (head)->listnam.dl_next->listnam.dl_prev = (new); \
- (head)->listnam.dl_next = (new); \
- } while (0)
-
-#define QUEUE_REMOVE(head, node, listnam) DLIST_DELETE(node, listnam)
diff --git a/include/linux/matroxfb.h b/include/linux/matroxfb.h
new file mode 100644
index 000000000..182d76b25
--- /dev/null
+++ b/include/linux/matroxfb.h
@@ -0,0 +1,32 @@
+#ifndef __LINUX_MATROXFB_H__
+#define __LINUX_MATROXFB_H__
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+struct matroxioc_output_mode {
+ __u32 output; /* which output */
+#define MATROXFB_OUTPUT_PRIMARY 0x0000
+#define MATROXFB_OUTPUT_SECONDARY 0x0001
+ __u32 mode; /* which mode */
+#define MATROXFB_OUTPUT_MODE_PAL 0x0001
+#define MATROXFB_OUTPUT_MODE_NTSC 0x0002
+#define MATROXFB_OUTPUT_MODE_MONITOR 0x0080
+};
+#define MATROXFB_SET_OUTPUT_MODE _IOW('n',0xFA,sizeof(struct matroxioc_output_mode))
+#define MATROXFB_GET_OUTPUT_MODE _IOWR('n',0xFA,sizeof(struct matroxioc_output_mode))
+
+/* bitfield */
+#define MATROXFB_OUTPUT_CONN_PRIMARY (1 << MATROXFB_OUTPUT_PRIMARY)
+#define MATROXFB_OUTPUT_CONN_SECONDARY (1 << MATROXFB_OUTPUT_SECONDARY)
+/* connect these outputs to this framebuffer */
+#define MATROXFB_SET_OUTPUT_CONNECTION _IOW('n',0xF8,sizeof(__u32))
+/* which outputs are connected to this framebuffer */
+#define MATROXFB_GET_OUTPUT_CONNECTION _IOR('n',0xF8,sizeof(__u32))
+/* which outputs are available for this framebuffer */
+#define MATROXFB_GET_AVAILABLE_OUTPUTS _IOR('n',0xF9,sizeof(__u32))
+/* which outputs exist on this framebuffer */
+#define MATROXFB_GET_ALL_OUTPUTS _IOR('n',0xFB,sizeof(__u32))
+
+#endif
+
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index c1d661460..6f63a54c4 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -89,17 +89,6 @@ struct minix_dir_entry {
#ifdef __KERNEL__
-extern struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry);
-extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
-extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
-extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
-extern int minix_unlink(struct inode * dir, struct dentry *dentry);
-extern int minix_symlink(struct inode * inode, struct dentry *dentry,
- const char * symname);
-extern int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry);
-extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev);
-extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry);
extern struct inode * minix_new_inode(const struct inode * dir, int * error);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
@@ -118,6 +107,8 @@ extern int minix_sync_file(struct file *, struct dentry *);
extern struct address_space_operations minix_aops;
extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
+extern struct file_operations minix_file_operations;
+extern struct file_operations minix_dir_operations;
extern struct dentry_operations minix_dentry_operations;
#endif /* __KERNEL__ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f42f84857..a01877f10 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -378,6 +378,8 @@ extern void show_free_areas_node(int nid);
extern void clear_page_tables(struct mm_struct *, unsigned long, int);
+extern int map_zero_setup(struct vm_area_struct *);
+
extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
@@ -393,7 +395,6 @@ extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long d
extern int pgt_cache_water[2];
extern int check_pgt_cache(void);
-extern void paging_init(void);
extern void free_area_init(unsigned long * zones_size);
extern void free_area_init_node(int nid, pg_data_t *pgdat,
unsigned long * zones_size, unsigned long zone_start_paddr);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 46e366aef..17a64200e 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -28,7 +28,8 @@ typedef struct zone_struct {
spinlock_t lock;
unsigned long offset;
unsigned long free_pages;
- int low_on_memory;
+ char low_on_memory;
+ char zone_wake_kswapd;
unsigned long pages_min, pages_low, pages_high;
/*
@@ -84,9 +85,11 @@ typedef struct pglist_data {
unsigned long node_start_mapnr;
unsigned long node_size;
int node_id;
+ struct pglist_data *node_next;
} pg_data_t;
extern int numnodes;
+extern pg_data_t *pgdat_list;
#define memclass(pgzone, tzone) (((pgzone)->zone_pgdat == (tzone)->zone_pgdat) \
&& (((pgzone) - (pgzone)->zone_pgdat->node_zones) <= \
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 54c1cbd55..de2ccffbd 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -267,6 +267,7 @@ int fat_new_dir(struct inode *inode, struct inode *parent, int is_vfat);
extern struct inode_operations fat_file_inode_operations;
extern struct inode_operations fat_file_inode_operations_1024;
extern struct inode_operations fat_file_inode_operations_readpage;
+extern struct file_operations fat_file_operations;
extern ssize_t fat_file_read(struct file *, char *, size_t, loff_t *);
extern ssize_t fat_file_write(struct file *, const char *, size_t, loff_t *);
extern void fat_truncate(struct inode *inode);
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index a9d46d35b..b028f984c 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -232,6 +232,7 @@ extern int init_ncp_fs(void);
/* linux/fs/ncpfs/dir.c */
extern struct inode_operations ncp_dir_inode_operations;
+extern struct file_operations ncp_dir_operations;
int ncp_conn_logged_in(struct super_block *);
int ncp_date_dos2unix(__u16 time, __u16 date);
void ncp_date_unix2dos(int unix_date, __u16 * time, __u16 * date);
@@ -252,6 +253,7 @@ void ncp_unlock_server(struct ncp_server *server);
/* linux/fs/ncpfs/file.c */
extern struct inode_operations ncp_file_inode_operations;
+extern struct file_operations ncp_file_operations;
int ncp_make_open(struct inode *, int);
/* linux/fs/ncpfs/mmap.c */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4c002a7cb..2c7103040 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -478,26 +478,6 @@ extern __inline__ int netif_running(struct net_device *dev)
return test_bit(__LINK_STATE_START, &dev->state);
}
-/* Hot-plugging. */
-extern __inline__ int netif_device_present(struct net_device *dev)
-{
- return test_bit(__LINK_STATE_PRESENT, &dev->state);
-}
-
-extern __inline__ void netif_device_detach(struct net_device *dev)
-{
- if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
- netif_running(dev))
- netif_stop_queue(dev);
-}
-
-extern __inline__ void netif_device_attach(struct net_device *dev)
-{
- if (test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
- netif_running(dev))
- netif_wake_queue(dev);
-}
-
/* Use this variant when it is known for sure that it
* is executing from interrupt context.
*/
@@ -553,6 +533,35 @@ extern __inline__ void dev_put(struct net_device *dev)
#define __dev_put(dev) atomic_dec(&(dev)->refcnt)
#define dev_hold(dev) atomic_inc(&(dev)->refcnt)
+/* Hot-plugging. */
+extern __inline__ int netif_device_present(struct net_device *dev)
+{
+ return test_bit(__LINK_STATE_PRESENT, &dev->state);
+}
+
+extern __inline__ void netif_device_detach(struct net_device *dev)
+{
+ if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) &&
+ netif_running(dev)) {
+ netif_stop_queue(dev);
+ if (dev->tx_timeout &&
+ del_timer(&dev->watchdog_timer))
+ __dev_put(dev);
+ }
+}
+
+extern __inline__ void netif_device_attach(struct net_device *dev)
+{
+ if (test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) &&
+ netif_running(dev)) {
+ netif_wake_queue(dev);
+ if (dev->tx_timeout) {
+ dev->watchdog_timer.expires = jiffies + dev->watchdog_timeo;
+ add_timer(&dev->watchdog_timer);
+ dev_hold(dev);
+ }
+ }
+}
/* These functions live elsewhere (drivers/net/net_init.c, but related) */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 26fb2de7f..3b1ae1764 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -185,17 +185,20 @@ extern int nfs_revalidate(struct dentry *);
extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
extern int __nfs_revalidate_inode(struct nfs_server *, struct dentry *);
+extern int nfs_notify_change(struct dentry *, struct iattr *);
/*
* linux/fs/nfs/file.c
*/
extern struct inode_operations nfs_file_inode_operations;
+extern struct file_operations nfs_file_operations;
extern struct address_space_operations nfs_file_aops;
/*
* linux/fs/nfs/dir.c
*/
extern struct inode_operations nfs_dir_inode_operations;
+extern struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations;
extern void nfs_flush_dircache(struct inode *);
extern void nfs_free_dircache(struct inode *);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index eda945b6c..d32ff4828 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -285,6 +285,7 @@
#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/list.h>
+#include <linux/errno.h>
/* This defines the direction arg to the DMA mapping routines. */
#define PCI_DMA_BIDIRECTIONAL 0
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3927b11f9..b7911143f 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1022,6 +1022,9 @@
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+#define PCI_VENDOR_ID_3WARE 0x13C1
+#define PCI_DEVICE_ID_3WARE_1000 0x1000
+
#define PCI_VENDOR_ID_LAVA 0x1407
#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
@@ -1095,8 +1098,8 @@
#define PCI_DEVICE_ID_S3_ViRGE_MXPMV 0x8c03
#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
-#define PCI_VENDOR_ID_DCI 0x6666
-#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
+#define PCI_VENDOR_ID_DCI 0x6666
+#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
#define PCI_VENDOR_ID_GENROCO 0x5555
#define PCI_DEVICE_ID_GENROCO_HFP832 0x0003
@@ -1156,6 +1159,7 @@
#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190
#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191
#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192
+#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601
#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4
#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5
#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 3f73f489f..4d0a950a9 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -101,6 +101,7 @@ struct pm_dev
unsigned long flags;
int state;
+ int prev_state;
struct list_head entry;
};
@@ -129,9 +130,14 @@ void pm_unregister(struct pm_dev *dev);
void pm_unregister_all(pm_callback callback);
/*
+ * Send a request to a single device
+ */
+int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+/*
* Send a request to all devices
*/
-int pm_send_request(pm_request_t rqst, void *data);
+int pm_send_all(pm_request_t rqst, void *data);
/*
* Find a device
@@ -156,7 +162,12 @@ extern inline void pm_unregister(struct pm_dev *dev) {}
extern inline void pm_unregister_all(pm_callback callback) {}
-extern inline int pm_send_request(pm_request_t rqst, void *data)
+extern inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+ return 0;
+}
+
+extern inline int pm_send_all(pm_request_t rqst, void *data)
{
return 0;
}
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index d8ae9689c..ca7a8cd8b 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -10,4 +10,10 @@
#define PR_GET_DUMPABLE 3
#define PR_SET_DUMPABLE 4
+/* Get/set unaligned access control bits (if meaningful) */
+#define PR_GET_UNALIGN 5
+#define PR_SET_UNALIGN 6
+# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */
+# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 21349eb40..f5927109a 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -59,7 +59,8 @@ struct proc_dir_entry {
uid_t uid;
gid_t gid;
unsigned long size;
- struct inode_operations * ops;
+ struct inode_operations * proc_iops;
+ struct file_operations * proc_fops;
get_info_t *get_info;
struct module *owner;
struct proc_dir_entry *next, *parent, *subdir;
@@ -80,7 +81,7 @@ extern struct proc_dir_entry *proc_root_fs;
extern struct proc_dir_entry *proc_net;
extern struct proc_dir_entry *proc_bus;
extern struct proc_dir_entry *proc_root_driver;
-extern struct proc_dir_entry proc_root_kcore;
+extern struct proc_dir_entry *proc_root_kcore;
extern void proc_root_init(void);
extern void proc_misc_init(void);
@@ -112,10 +113,9 @@ extern int proc_match(int, const char *,struct proc_dir_entry *);
extern int proc_readdir(struct file *, void *, filldir_t);
extern struct dentry *proc_lookup(struct inode *, struct dentry *);
-extern struct inode_operations proc_sys_inode_operations;
-extern struct inode_operations proc_kcore_inode_operations;
-extern struct inode_operations proc_kmsg_inode_operations;
-extern struct inode_operations proc_ppc_htab_inode_operations;
+extern struct file_operations proc_kcore_operations;
+extern struct file_operations proc_kmsg_operations;
+extern struct file_operations ppc_htab_operations;
/*
* proc_tty.c
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index d831875bb..4e68ee5a6 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -108,6 +108,8 @@ extern int init_qnx4_fs(void);
extern int qnx4_create(struct inode *dir, struct dentry *dentry, int mode);
extern struct inode_operations qnx4_file_inode_operations;
extern struct inode_operations qnx4_dir_inode_operations;
+extern struct file_operations qnx4_file_operations;
+extern struct file_operations qnx4_dir_operations;
extern int qnx4_is_free(struct super_block *sb, long block);
extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy);
extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode);
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 9e457818f..e0fdda3fa 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -75,6 +75,8 @@ extern dev_mapping_t mddev_map [MAX_MD_DEVS];
extern inline mddev_t * kdev_to_mddev (kdev_t dev)
{
+ if (MAJOR(dev) != MD_MAJOR)
+ BUG();
return mddev_map[MINOR(dev)].mddev;
}
@@ -213,7 +215,7 @@ struct mdk_personality_s
char *name;
int (*map)(mddev_t *mddev, kdev_t dev, kdev_t *rdev,
unsigned long *rsector, unsigned long size);
- int (*make_request)(mddev_t *mddev, int rw, struct buffer_head * bh);
+ int (*make_request)(request_queue_t *q, mddev_t *mddev, int rw, struct buffer_head * bh);
void (*end_request)(struct buffer_head * bh, int uptodate);
int (*run)(mddev_t *mddev);
int (*stop)(mddev_t *mddev);
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index 52c3d7f33..d11573ca5 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -101,10 +101,12 @@ int smb_mmap(struct file *, struct vm_area_struct *);
/* linux/fs/smbfs/file.c */
extern struct inode_operations smb_file_inode_operations;
+extern struct file_operations smb_file_operations;
extern struct address_space_operations smb_file_aops;
/* linux/fs/smbfs/dir.c */
extern struct inode_operations smb_dir_inode_operations;
+extern struct file_operations smb_dir_operations;
void smb_renew_times(struct dentry *);
/* linux/fs/smbfs/ioctl.c */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e7c710646..1d91cf216 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -21,11 +21,11 @@
****************************************************************
*/
-#include <linux/lists.h>
-
#ifndef _LINUX_SYSCTL_H
#define _LINUX_SYSCTL_H
+#include <linux/list.h>
+
#define CTL_MAXNAME 10
struct __sysctl_args {
@@ -664,7 +664,7 @@ struct ctl_table
struct ctl_table_header
{
ctl_table *ctl_table;
- DLNODE(struct ctl_table_header) ctl_entry;
+ struct list_head ctl_entry;
};
struct ctl_table_header * register_sysctl_table(ctl_table * table,
diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h
index 4f65ba7dd..9e177c3d4 100644
--- a/include/linux/sysv_fs.h
+++ b/include/linux/sysv_fs.h
@@ -367,16 +367,6 @@ sv_bread (struct super_block *sb, kdev_t dev, unsigned int block)
* Function prototypes
*/
-extern struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry);
-extern int sysv_create(struct inode * dir, struct dentry * dentry, int mode);
-extern int sysv_mkdir(struct inode * dir, struct dentry * dentry, int mode);
-extern int sysv_rmdir(struct inode * dir, struct dentry * dentry);
-extern int sysv_unlink(struct inode * dir, struct dentry * dentry);
-extern int sysv_symlink(struct inode * inode, struct dentry * dentry, const char * symname);
-extern int sysv_link(struct dentry * old_dentry, struct inode * dir, struct dentry * dentry);
-extern int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev);
-extern int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry);
extern struct inode * sysv_new_inode(const struct inode * dir);
extern void sysv_free_inode(struct inode * inode);
extern unsigned long sysv_count_free_inodes(struct super_block *sb);
@@ -391,9 +381,13 @@ extern int init_sysv_fs(void);
extern void sysv_write_inode(struct inode *);
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *);
+extern int sysv_notify_change(struct dentry *, struct iattr *);
extern struct inode_operations sysv_file_inode_operations;
+extern struct inode_operations sysv_symlink_inode_operations;
extern struct inode_operations sysv_dir_inode_operations;
+extern struct file_operations sysv_file_operations;
+extern struct file_operations sysv_dir_operations;
extern struct address_space_operations sysv_aops;
#endif /* __KERNEL__ */
diff --git a/include/linux/timer.h b/include/linux/timer.h
index d159222b7..f9e7efdaa 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -20,7 +20,6 @@
#define GSCD_TIMER 9 /* Goldstar CDROM */
#define COMTROL_TIMER 10 /* Comtrol serial */
#define DIGI_TIMER 11 /* Digi serial */
-#define GDTH_TIMER 12 /* Ugh - gdth scsi driver */
#define COPRO_TIMER 31 /* 387 timeout for buggy hardware (boot only) */
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 83a6a69e7..d7c14cd74 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -504,9 +504,6 @@ struct ufs_inode {
#ifdef __KERNEL__
-/* acl.c */
-extern int ufs_permission (struct inode *, int);
-
/* balloc.c */
extern void ufs_free_fragments (struct inode *, unsigned, unsigned);
extern void ufs_free_blocks (struct inode *, unsigned, unsigned);
@@ -518,7 +515,6 @@ extern void ufs_put_cylinder (struct super_block *, unsigned);
/* dir.c */
extern struct inode_operations ufs_dir_inode_operations;
-extern struct file_operations ufs_dir_operations;
extern int ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, struct buffer_head *, unsigned long);
/* file.c */
@@ -543,18 +539,9 @@ extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
/* namei.c */
-extern struct dentry *ufs_lookup (struct inode *, struct dentry *);
-extern int ufs_mkdir(struct inode *, struct dentry *, int);
-extern int ufs_rmdir (struct inode *, struct dentry *);
-extern int ufs_unlink (struct inode *, struct dentry *);
-extern int ufs_create (struct inode *, struct dentry *, int);
-extern int ufs_rename (struct inode *, struct dentry *, struct inode *, struct dentry *);
-extern int ufs_mknod (struct inode *, struct dentry *, int, int);
-extern int ufs_symlink (struct inode *, struct dentry *, const char *);
-extern int ufs_link (struct dentry *, struct inode *, struct dentry *);
+extern struct file_operations ufs_dir_operations;
/* super.c */
-extern struct super_operations ufs_super_ops;
extern struct file_system_type ufs_fs_type;
extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
diff --git a/include/linux/umsdos_fs.h b/include/linux/umsdos_fs.h
index 1e7a0bead..6f113d28c 100644
--- a/include/linux/umsdos_fs.h
+++ b/include/linux/umsdos_fs.h
@@ -174,6 +174,9 @@ struct umsdos_ioctl {
#endif
extern struct inode_operations umsdos_dir_inode_operations;
+extern struct inode_operations umsdos_rdir_inode_operations;
+extern struct file_operations umsdos_dir_operations;
+extern struct file_operations umsdos_rdir_operations;
extern int init_umsdos_fs (void);
#include <linux/umsdos_fs.p>
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 86bd08715..6d8f5dae6 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -4,6 +4,7 @@
#define WNOHANG 0x00000001
#define WUNTRACED 0x00000002
+#define __WALL 0x40000000
#define __WCLONE 0x80000000
#ifdef __KERNEL__
diff --git a/include/net/atmclip.h b/include/net/atmclip.h
index edcae7c37..a568dd753 100644
--- a/include/net/atmclip.h
+++ b/include/net/atmclip.h
@@ -1,6 +1,6 @@
/* net/atm/atmarp.h - RFC1577 ATM ARP */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#ifndef _ATMCLIP_H
@@ -11,6 +11,7 @@
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/atmarp.h>
+#include <linux/spinlock.h>
#include <net/neighbour.h>
@@ -22,6 +23,7 @@ struct clip_vcc {
struct atm_vcc *vcc; /* VCC descriptor */
struct atmarp_entry *entry; /* ATMARP table entry, NULL if IP addr.
isn't known yet */
+ int xoff; /* 1 if send buffer is full */
unsigned char encap; /* 0: NULL, 1: LLC/SNAP */
unsigned long last_use; /* last send or receive operation */
unsigned long idle_timeout; /* keep open idle for so many jiffies*/
@@ -48,8 +50,9 @@ struct atmarp_entry {
struct clip_priv {
char name[8]; /* interface name */
int number; /* for convenience ... */
+ spinlock_t xoff_lock; /* ensures that pop is atomic (SMP) */
struct net_device_stats stats;
- struct net_device *next; /* next CLIP interface */
+ struct net_device *next; /* next CLIP interface */
};
diff --git a/init/main.c b/init/main.c
index 5ae3597e4..458143ffb 100644
--- a/init/main.c
+++ b/init/main.c
@@ -490,7 +490,6 @@ asmlinkage void __init start_kernel(void)
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
- paging_init();
trap_init();
init_IRQ();
sched_init();
diff --git a/ipc/shm.c b/ipc/shm.c
index 508b6a3c9..9c326c799 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -11,6 +11,7 @@
* HIGHMEM support, Ingo Molnar <mingo@redhat.com>
* avoid vmalloc and make shmmax, shmall, shmmni sysctl'able,
* Christoph Rohland <hans-christoph.rohland@sap.com>
+ * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
*/
#include <linux/config.h>
@@ -70,6 +71,13 @@ static int shm_swapout(struct page *, struct file *);
static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
#endif
+static void zshm_swap (int prio, int gfp_mask, zone_t *zone);
+static void zmap_unuse(swp_entry_t entry, struct page *page);
+static void shmzero_open(struct vm_area_struct *shmd);
+static void shmzero_close(struct vm_area_struct *shmd);
+static int zero_id;
+static struct shmid_kernel zshmid_kernel;
+
size_t shm_ctlmax = SHMMAX;
int shm_ctlall = SHMALL;
int shm_ctlmni = SHMMNI;
@@ -103,6 +111,8 @@ void __init shm_init (void)
#ifdef CONFIG_PROC_FS
create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
#endif
+ zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, shm_ctlmni);
+ shm_unlock(zero_id);
return;
}
@@ -179,6 +189,26 @@ static int shm_revalidate(struct shmid_kernel* shp, int shmid, int pagecount, in
return 0;
}
+static inline struct shmid_kernel *newseg_alloc(int numpages)
+{
+ struct shmid_kernel *shp;
+
+ shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
+ if (!shp)
+ return 0;
+
+ shp->shm_dir = shm_alloc (numpages);
+ if (!shp->shm_dir) {
+ kfree(shp);
+ return 0;
+ }
+ shp->shm_npages = numpages;
+ shp->attaches = NULL;
+ shp->shm_nattch = 0;
+ init_MUTEX(&shp->sem);
+ return(shp);
+}
+
static int newseg (key_t key, int shmflg, size_t size)
{
struct shmid_kernel *shp;
@@ -193,15 +223,8 @@ static int newseg (key_t key, int shmflg, size_t size)
if (shm_tot + numpages >= shm_ctlall)
return -ENOSPC;
- shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
- if (!shp)
- return -ENOMEM;
-
- shp->shm_dir = shm_alloc (numpages);
- if (!shp->shm_dir) {
- kfree(shp);
+ if (!(shp = newseg_alloc(numpages)))
return -ENOMEM;
- }
id = ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
if(id == -1) {
shm_free(shp->shm_dir,numpages);
@@ -212,13 +235,10 @@ static int newseg (key_t key, int shmflg, size_t size)
shp->shm_perm.mode = (shmflg & S_IRWXUGO);
shp->shm_segsz = size;
shp->shm_cpid = current->pid;
- shp->attaches = NULL;
- shp->shm_lpid = shp->shm_nattch = 0;
+ shp->shm_lpid = 0;
shp->shm_atime = shp->shm_dtime = 0;
shp->shm_ctime = CURRENT_TIME;
- shp->shm_npages = numpages;
shp->id = shm_buildid(id,shp->shm_perm.seq);
- init_MUTEX(&shp->sem);
shm_tot += numpages;
shm_unlock(id);
@@ -255,6 +275,35 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
return err;
}
+static void killseg_core(struct shmid_kernel *shp, int doacc)
+{
+ int i, numpages, rss, swp;
+
+ numpages = shp->shm_npages;
+ for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
+ pte_t pte;
+ pte = SHM_ENTRY (shp,i);
+ if (pte_none(pte))
+ continue;
+ if (pte_present(pte)) {
+ __free_page (pte_page(pte));
+ rss++;
+ } else {
+ swap_free(pte_to_swp_entry(pte));
+ swp++;
+ }
+ }
+ shm_free (shp->shm_dir, numpages);
+ kfree(shp);
+ if (doacc) {
+ shm_lockall();
+ shm_rss -= rss;
+ shm_swp -= swp;
+ shm_tot -= numpages;
+ shm_unlockall();
+ }
+}
+
/*
* Only called after testing nattch and SHM_DEST.
* Here pages, pgtable and shmid_kernel are freed.
@@ -262,8 +311,6 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
static void killseg (int shmid)
{
struct shmid_kernel *shp;
- int i, numpages;
- int rss, swp;
down(&shm_ids.sem);
shp = shm_lock(shmid);
@@ -284,28 +331,8 @@ out_up:
BUG();
shm_unlock(shmid);
up(&shm_ids.sem);
+ killseg_core(shp, 1);
- numpages = shp->shm_npages;
- for (i = 0, rss = 0, swp = 0; i < numpages ; i++) {
- pte_t pte;
- pte = SHM_ENTRY (shp,i);
- if (pte_none(pte))
- continue;
- if (pte_present(pte)) {
- __free_page (pte_page(pte));
- rss++;
- } else {
- swap_free(pte_to_swp_entry(pte));
- swp++;
- }
- }
- shm_free (shp->shm_dir, numpages);
- kfree(shp);
- shm_lockall();
- shm_rss -= rss;
- shm_swp -= swp;
- shm_tot -= numpages;
- shm_unlockall();
return;
}
@@ -458,6 +485,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
+ if (shp == &zshmid_kernel) {
+ shm_unlock(shmid);
+ return -EINVAL;
+ }
if(cmd==SHM_STAT) {
err = -EINVAL;
if (shmid > shm_ids.max_id)
@@ -498,6 +529,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
+ if (shp == &zshmid_kernel) {
+ shm_unlock(shmid);
+ return -EINVAL;
+ }
err=-EIDRM;
if(shm_checkid(shp,shmid))
goto out_unlock;
@@ -532,6 +567,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
err=-EINVAL;
if(shp==NULL)
goto out_up;
+ if (shp == &zshmid_kernel)
+ goto out_unlock_up;
err=-EIDRM;
if(shm_checkid(shp,shmid))
goto out_unlock_up;
@@ -653,6 +690,8 @@ asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shp = shm_lock(shmid);
if (!shp)
goto out_up;
+ if (shp == &zshmid_kernel)
+ goto out_unlock_up;
err = -EACCES;
if (ipcperms(&shp->shm_perm, flg))
@@ -835,10 +874,12 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
struct shmid_kernel *shp;
unsigned int idx;
struct page * page;
+ int is_shmzero;
shp = (struct shmid_kernel *) shmd->vm_private_data;
idx = (address - shmd->vm_start) >> PAGE_SHIFT;
idx += shmd->vm_pgoff;
+ is_shmzero = (shp->id == zero_id);
/*
* A shared mapping past the last page of the file is an error
@@ -850,7 +891,7 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
return NULL;
}
down(&shp->sem);
- if(shp != shm_lock(shp->id))
+ if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
BUG();
pte = SHM_ENTRY(shp,idx);
@@ -864,7 +905,7 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
if (!page)
goto oom;
clear_highpage(page);
- if(shp != shm_lock(shp->id))
+ if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
BUG();
} else {
swp_entry_t entry = pte_to_swp_entry(pte);
@@ -882,11 +923,11 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
delete_from_swap_cache(page);
page = replace_with_highmem(page);
swap_free(entry);
- if(shp != shm_lock(shp->id))
+ if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
BUG();
- shm_swp--;
+ if (is_shmzero) shm_swp--;
}
- shm_rss++;
+ if (is_shmzero) shm_rss++;
pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
SHM_ENTRY(shp, idx) = pte;
} else
@@ -904,6 +945,65 @@ oom:
return NOPAGE_OOM;
}
+#define OKAY 0
+#define RETRY 1
+#define FAILED 2
+
+static int shm_swap_core(struct shmid_kernel *shp, unsigned long idx, swp_entry_t swap_entry, zone_t *zone, int *counter, struct page **outpage)
+{
+ pte_t page;
+ struct page *page_map;
+
+ page = SHM_ENTRY(shp, idx);
+ if (!pte_present(page))
+ return RETRY;
+ page_map = pte_page(page);
+ if (zone && (!memclass(page_map->zone, zone)))
+ return RETRY;
+ if (shp->id != zero_id) swap_attempts++;
+
+ if (--counter < 0) /* failed */
+ return FAILED;
+ if (page_count(page_map) != 1)
+ return RETRY;
+
+ if (!(page_map = prepare_highmem_swapout(page_map)))
+ return FAILED;
+ SHM_ENTRY (shp, idx) = swp_entry_to_pte(swap_entry);
+
+ /* add the locked page to the swap cache before allowing
+ the swapin path to run lookup_swap_cache(). This avoids
+ reading a not yet uptodate block from disk.
+ NOTE: we just accounted the swap space reference for this
+ swap cache page at __get_swap_page() time. */
+ add_to_swap_cache(*outpage = page_map, swap_entry);
+ return OKAY;
+}
+
+static void shm_swap_postop(struct page *page)
+{
+ lock_kernel();
+ rw_swap_page(WRITE, page, 0);
+ unlock_kernel();
+ __free_page(page);
+}
+
+static int shm_swap_preop(swp_entry_t *swap_entry)
+{
+ lock_kernel();
+ /* subtle: preload the swap count for the swap cache. We can't
+ increase the count inside the critical section as we can't release
+ the shm_lock there. And we can't acquire the big lock with the
+ shm_lock held (otherwise we would deadlock too easily). */
+ *swap_entry = __get_swap_page(2);
+ if (!(*swap_entry).val) {
+ unlock_kernel();
+ return 1;
+ }
+ unlock_kernel();
+ return 0;
+}
+
/*
* Goes through counter = (shm_rss >> prio) present shm pages.
*/
@@ -912,28 +1012,19 @@ static unsigned long swap_idx = 0; /* next to swap */
int shm_swap (int prio, int gfp_mask, zone_t *zone)
{
- pte_t page;
struct shmid_kernel *shp;
swp_entry_t swap_entry;
unsigned long id, idx;
int loop = 0;
int counter;
struct page * page_map;
-
+
+ zshm_swap(prio, gfp_mask, zone);
counter = shm_rss >> prio;
if (!counter)
return 0;
- lock_kernel();
- /* subtle: preload the swap count for the swap cache. We can't
- increase the count inside the critical section as we can't release
- the shm_lock there. And we can't acquire the big lock with the
- shm_lock held (otherwise we would deadlock too easily). */
- swap_entry = __get_swap_page(2);
- if (!swap_entry.val) {
- unlock_kernel();
+ if (shm_swap_preop(&swap_entry))
return 0;
- }
- unlock_kernel();
shm_lockall();
check_id:
@@ -943,8 +1034,12 @@ next_id:
swap_idx = 0;
if (++swap_id > shm_ids.max_id) {
swap_id = 0;
- if (loop)
- goto failed;
+ if (loop) {
+failed:
+ shm_unlockall();
+ __swap_free(swap_entry, 2);
+ return 0;
+ }
loop = 1;
}
goto check_id;
@@ -956,43 +1051,16 @@ check_table:
if (idx >= shp->shm_npages)
goto next_id;
- page = SHM_ENTRY(shp, idx);
- if (!pte_present(page))
- goto check_table;
- page_map = pte_page(page);
- if (zone && (!memclass(page_map->zone, zone)))
- goto check_table;
- swap_attempts++;
-
- if (--counter < 0) { /* failed */
-failed:
- shm_unlockall();
- __swap_free(swap_entry, 2);
- return 0;
+ switch (shm_swap_core(shp, idx, swap_entry, zone, &counter, &page_map)) {
+ case RETRY: goto check_table;
+ case FAILED: goto failed;
}
- if (page_count(page_map) != 1)
- goto check_table;
-
- if (!(page_map = prepare_highmem_swapout(page_map)))
- goto failed;
- SHM_ENTRY (shp, idx) = swp_entry_to_pte(swap_entry);
swap_successes++;
shm_swp++;
shm_rss--;
-
- /* add the locked page to the swap cache before allowing
- the swapin path to run lookup_swap_cache(). This avoids
- reading a not yet uptodate block from disk.
- NOTE: we just accounted the swap space reference for this
- swap cache page at __get_swap_page() time. */
- add_to_swap_cache(page_map, swap_entry);
shm_unlockall();
- lock_kernel();
- rw_swap_page(WRITE, page_map, 0);
- unlock_kernel();
-
- __free_page(page_map);
+ shm_swap_postop(page_map);
return 1;
}
@@ -1014,31 +1082,41 @@ static void shm_unuse_page(struct shmid_kernel *shp, unsigned long idx,
swap_free(entry);
}
+static int shm_unuse_core(struct shmid_kernel *shp, swp_entry_t entry, struct page *page)
+{
+ int n;
+
+ for (n = 0; n < shp->shm_npages; n++) {
+ if (pte_none(SHM_ENTRY(shp,n)))
+ continue;
+ if (pte_present(SHM_ENTRY(shp,n)))
+ continue;
+ if (pte_to_swp_entry(SHM_ENTRY(shp,n)).val == entry.val) {
+ shm_unuse_page(shp, n, entry, page);
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
* unuse_shm() search for an eventually swapped out shm page.
*/
void shm_unuse(swp_entry_t entry, struct page *page)
{
- int i, n;
+ int i;
shm_lockall();
for (i = 0; i <= shm_ids.max_id; i++) {
struct shmid_kernel *shp = shm_get(i);
if(shp==NULL)
continue;
- for (n = 0; n < shp->shm_npages; n++) {
- if (pte_none(SHM_ENTRY(shp,n)))
- continue;
- if (pte_present(SHM_ENTRY(shp,n)))
- continue;
- if (pte_to_swp_entry(SHM_ENTRY(shp,n)).val == entry.val) {
- shm_unuse_page(shp, n, entry, page);
- goto out;
- }
- }
+ if (shm_unuse_core(shp, entry, page))
+ goto out;
}
out:
shm_unlockall();
+ zmap_unuse(entry, page);
}
#ifdef CONFIG_PROC_FS
@@ -1053,6 +1131,10 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
for(i = 0; i <= shm_ids.max_id; i++) {
struct shmid_kernel* shp = shm_lock(i);
+ if (shp == &zshmid_kernel) {
+ shm_unlock(i);
+ continue;
+ }
if(shp!=NULL) {
#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
@@ -1100,3 +1182,138 @@ done:
return len;
}
#endif
+
+static struct shmid_kernel *zmap_list = 0;
+static spinlock_t zmap_list_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long zswap_idx = 0; /* next to swap */
+static struct shmid_kernel *zswap_shp = 0;
+
+static struct vm_operations_struct shmzero_vm_ops = {
+ open: shmzero_open,
+ close: shmzero_close,
+ nopage: shm_nopage,
+ swapout: shm_swapout,
+};
+
+int map_zero_setup(struct vm_area_struct *vma)
+{
+ struct shmid_kernel *shp;
+
+ if (!(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE)))
+ return -ENOMEM;
+ shp->id = zero_id; /* hack for shm_lock et al */
+ vma->vm_private_data = shp;
+ vma->vm_ops = &shmzero_vm_ops;
+ shmzero_open(vma);
+ spin_lock(&zmap_list_lock);
+ shp->attaches = (struct vm_area_struct *)zmap_list;
+ zmap_list = shp;
+ spin_unlock(&zmap_list_lock);
+ return 0;
+}
+
+static void shmzero_open(struct vm_area_struct *shmd)
+{
+ struct shmid_kernel *shp;
+
+ shp = (struct shmid_kernel *) shmd->vm_private_data;
+ down(&shp->sem);
+ shp->shm_nattch++;
+ up(&shp->sem);
+}
+
+static void shmzero_close(struct vm_area_struct *shmd)
+{
+ int done = 0;
+ struct shmid_kernel *shp, *prev, *cur;
+
+ shp = (struct shmid_kernel *) shmd->vm_private_data;
+ down(&shp->sem);
+ if (--shp->shm_nattch == 0)
+ done = 1;
+ up(&shp->sem);
+ if (done) {
+ spin_lock(&zmap_list_lock);
+ if (shp == zswap_shp)
+ zswap_shp = (struct shmid_kernel *)(shp->attaches);
+ if (shp == zmap_list)
+ zmap_list = (struct shmid_kernel *)(shp->attaches);
+ else {
+ prev = zmap_list;
+ cur = (struct shmid_kernel *)(prev->attaches);
+ while (cur != shp) {
+ prev = cur;
+ cur = (struct shmid_kernel *)(prev->attaches);
+ }
+ prev->attaches = (struct vm_area_struct *)(shp->attaches);
+ }
+ spin_unlock(&zmap_list_lock);
+ killseg_core(shp, 0);
+ }
+}
+
+static void zmap_unuse(swp_entry_t entry, struct page *page)
+{
+ struct shmid_kernel *shp;
+
+ spin_lock(&zmap_list_lock);
+ shp = zmap_list;
+ while (shp) {
+ if (shm_unuse_core(shp, entry, page))
+ break;
+ shp = (struct shmid_kernel *)shp->attaches;
+ }
+ spin_unlock(&zmap_list_lock);
+}
+
+static void zshm_swap (int prio, int gfp_mask, zone_t *zone)
+{
+ struct shmid_kernel *shp;
+ swp_entry_t swap_entry;
+ unsigned long idx;
+ int loop = 0;
+ int counter;
+ struct page * page_map;
+
+ counter = 10; /* maybe we should use zshm_rss */
+ if (!counter)
+ return;
+next:
+ if (shm_swap_preop(&swap_entry))
+ return;
+
+ spin_lock(&zmap_list_lock);
+ if (zmap_list == 0)
+ goto failed;
+next_id:
+ if ((shp = zswap_shp) == 0) {
+ if (loop) {
+failed:
+ spin_unlock(&zmap_list_lock);
+ __swap_free(swap_entry, 2);
+ return;
+ }
+ zswap_shp = shp = zmap_list;
+ zswap_idx = 0;
+ loop = 1;
+ }
+
+check_table:
+ idx = zswap_idx++;
+ if (idx >= shp->shm_npages) {
+ zswap_shp = (struct shmid_kernel *)(zswap_shp->attaches);
+ zswap_idx = 0;
+ goto next_id;
+ }
+
+ switch (shm_swap_core(shp, idx, swap_entry, zone, &counter, &page_map)) {
+ case RETRY: goto check_table;
+ case FAILED: goto failed;
+ }
+ spin_unlock(&zmap_list_lock);
+
+ shm_swap_postop(page_map);
+ if (counter)
+ goto next;
+ return;
+}
diff --git a/ipc/util.c b/ipc/util.c
index b5b5431d8..1c929256a 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -317,4 +317,9 @@ void shm_unuse(swp_entry_t entry, struct page *page)
{
}
+int map_zero_setup(struct vm_area_struct *vma)
+{
+ return -EINVAL;
+}
+
#endif /* CONFIG_SYSVIPC */
diff --git a/kernel/exit.c b/kernel/exit.c
index 65d72df43..9dd09f050 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -445,7 +445,7 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
DECLARE_WAITQUEUE(wait, current);
struct task_struct *p;
- if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
+ if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(&current->wait_chldexit,&wait);
@@ -464,8 +464,13 @@ repeat:
if (p->pgrp != -pid)
continue;
}
- /* wait for cloned processes iff the __WCLONE flag is set */
- if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ /* Wait for all children (clone and not) if __WALL is set;
+ * otherwise, wait for clone children *only* if __WCLONE is
+ * set; otherwise, wait for non-clone children *only*. (Note:
+ * A "clone" child here is one that reports to its parent
+ * using a signal other than SIGCHLD.) */
+ if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+ && !(options & __WALL))
continue;
flag = 1;
switch (p->state) {
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 79525ce16..06de40312 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -159,6 +159,8 @@ EXPORT_SYMBOL(__mark_inode_dirty);
EXPORT_SYMBOL(free_kiovec);
EXPORT_SYMBOL(brw_kiovec);
EXPORT_SYMBOL(alloc_kiovec);
+EXPORT_SYMBOL(expand_kiobuf);
+EXPORT_SYMBOL(unmap_kiobuf);
EXPORT_SYMBOL(get_empty_filp);
EXPORT_SYMBOL(init_private_file);
EXPORT_SYMBOL(filp_open);
@@ -196,6 +198,7 @@ EXPORT_SYMBOL(generic_file_read);
EXPORT_SYMBOL(do_generic_file_read);
EXPORT_SYMBOL(generic_file_write);
EXPORT_SYMBOL(generic_file_mmap);
+EXPORT_SYMBOL(generic_ro_fops);
EXPORT_SYMBOL(generic_buffer_fdatasync);
EXPORT_SYMBOL(page_hash_bits);
EXPORT_SYMBOL(page_hash_table);
@@ -216,6 +219,7 @@ EXPORT_SYMBOL(get_unused_fd);
EXPORT_SYMBOL(vfs_rmdir);
EXPORT_SYMBOL(vfs_unlink);
EXPORT_SYMBOL(vfs_rename);
+EXPORT_SYMBOL(generic_read_dir);
EXPORT_SYMBOL(__pollwait);
EXPORT_SYMBOL(ROOT_DEV);
EXPORT_SYMBOL(__find_get_page);
diff --git a/kernel/pm.c b/kernel/pm.c
index c35620402..b2f60d65f 100644
--- a/kernel/pm.c
+++ b/kernel/pm.c
@@ -87,21 +87,27 @@ void pm_unregister_all(pm_callback callback)
}
/*
- * Send request to an individual device
+ * Send request to a single device
*/
-static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
{
int status = 0;
- int next_state;
+ int prev_state, next_state;
switch (rqst) {
case PM_SUSPEND:
case PM_RESUME:
+ prev_state = dev->state;
next_state = (int) data;
- if (dev->state != next_state) {
+ if (prev_state != next_state) {
if (dev->callback)
status = (*dev->callback)(dev, rqst, data);
- if (!status)
+ if (!status) {
dev->state = next_state;
+ dev->prev_state = prev_state;
+ }
+ }
+ else {
+ dev->prev_state = prev_state;
}
break;
default:
@@ -115,13 +121,19 @@ static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
/*
* Undo incomplete request
*/
-static void pm_undo_request(struct pm_dev *last, pm_request_t undo, void *data)
+static void pm_undo_all(struct pm_dev *last)
{
struct list_head *entry = last->entry.prev;
while (entry != &pm_devs) {
struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->callback)
- pm_send(dev, undo, data);
+ if (dev->state != dev->prev_state) {
+ /* previous state was zero (running) resume or
+ * previous state was non-zero (suspended) suspend
+ */
+ pm_request_t undo = (dev->prev_state
+ ? PM_SUSPEND:PM_RESUME);
+ pm_send(dev, undo, (void*) dev->prev_state);
+ }
entry = entry->prev;
}
}
@@ -129,7 +141,7 @@ static void pm_undo_request(struct pm_dev *last, pm_request_t undo, void *data)
/*
* Send a request to all devices
*/
-int pm_send_request(pm_request_t rqst, void *data)
+int pm_send_all(pm_request_t rqst, void *data)
{
struct list_head *entry = pm_devs.next;
while (entry != &pm_devs) {
@@ -137,9 +149,11 @@ int pm_send_request(pm_request_t rqst, void *data)
if (dev->callback) {
int status = pm_send(dev, rqst, data);
if (status) {
- /* resume devices on failed suspend request */
+ /* return devices to previous state on
+ * failed suspend request
+ */
if (rqst == PM_SUSPEND)
- pm_undo_request(dev, PM_RESUME, 0);
+ pm_undo_all(dev);
return status;
}
}
@@ -166,6 +180,7 @@ struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
EXPORT_SYMBOL(pm_register);
EXPORT_SYMBOL(pm_unregister);
EXPORT_SYMBOL(pm_unregister_all);
-EXPORT_SYMBOL(pm_send_request);
+EXPORT_SYMBOL(pm_send);
+EXPORT_SYMBOL(pm_send_all);
EXPORT_SYMBOL(pm_find);
EXPORT_SYMBOL(pm_active);
diff --git a/kernel/sched.c b/kernel/sched.c
index 1ccc6826c..bec8a4494 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -497,17 +497,15 @@ repeat_schedule:
c = -1000;
if (prev->state == TASK_RUNNING)
goto still_running;
-still_running_back:
- tmp = runqueue_head.next;
- while (tmp != &runqueue_head) {
+still_running_back:
+ list_for_each(tmp, &runqueue_head) {
p = list_entry(tmp, struct task_struct, run_list);
if (can_schedule(p)) {
int weight = goodness(p, this_cpu, prev->active_mm);
if (weight > c)
c = weight, next = p;
}
- tmp = tmp->next;
}
/* Do we need to re-calculate counters? */
@@ -658,13 +656,10 @@ static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, con
if (!head->next || !head->prev)
WQ_BUG();
#endif
- tmp = head->next;
- while (tmp != head) {
+ list_for_each(tmp, head) {
unsigned int state;
wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
- tmp = tmp->next;
-
#if WAITQUEUE_DEBUG
CHECK_MAGIC(curr->__magic);
#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index e3f7c5e2b..550df4db9 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -226,8 +226,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, int cmd, void * arg)
default:
unlock_kernel();
return -EINVAL;
- break;
- };
+ }
unlock_kernel();
return 0;
}
@@ -1049,6 +1048,22 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
}
current->dumpable = arg2;
break;
+ case PR_SET_UNALIGN:
+#ifdef SET_UNALIGN_CTL
+ error = SET_UNALIGN_CTL(current, arg2);
+#else
+ error = -EINVAL;
+#endif
+ break;
+
+ case PR_GET_UNALIGN:
+#ifdef GET_UNALIGN_CTL
+ error = GET_UNALIGN_CTL(current, arg2);
+#else
+ error = -EINVAL;
+#endif
+ break;
+
default:
error = -EINVAL;
break;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9a6a7a74d..efcda3de4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -12,6 +12,8 @@
* Horn.
* Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer.
* Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer.
+ * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill
+ * Wendling.
*/
#include <linux/config.h>
@@ -86,8 +88,7 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
static ctl_table root_table[];
-static struct ctl_table_header root_table_header =
- {root_table, DNODE_SINGLE(&root_table_header)};
+static LIST_HEAD(root_table_header);
static ctl_table kern_table[];
static ctl_table vm_table[];
@@ -115,23 +116,9 @@ struct file_operations proc_sys_file_operations =
write: proc_writesys,
};
-struct inode_operations proc_sys_inode_operations =
+static struct inode_operations proc_sys_inode_operations =
{
- &proc_sys_file_operations,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- proc_sys_permission, /* permission */
- NULL /* revalidate */
+ permission: proc_sys_permission,
};
extern struct proc_dir_entry *proc_sys_root;
@@ -305,21 +292,23 @@ static ctl_table dev_table[] = {
{0}
};
+extern void init_irq_proc (void);
void __init sysctl_init(void)
{
#ifdef CONFIG_PROC_FS
register_proc_table(root_table, proc_sys_root);
+ init_irq_proc();
#endif
-}
+}
int do_sysctl (int *name, int nlen,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
int error;
- struct ctl_table_header *tmp;
+ struct list_head *tmp;
void *context;
if (nlen == 0 || nlen >= CTL_MAXNAME)
@@ -333,17 +322,17 @@ int do_sysctl (int *name, int nlen,
if(get_user(old_len, oldlenp))
return -EFAULT;
}
- tmp = &root_table_header;
- do {
+ list_for_each(tmp, &root_table_header) {
+ struct ctl_table_header *head =
+ list_entry(tmp, struct ctl_table_header, ctl_entry);
context = NULL;
error = parse_table(name, nlen, oldval, oldlenp,
- newval, newlen, tmp->ctl_table, &context);
+ newval, newlen, head->ctl_table, &context);
if (context)
kfree(context);
if (error != -ENOTDIR)
return error;
- tmp = tmp->DLIST_NEXT(ctl_entry);
- } while (tmp != &root_table_header);
+ }
return -ENOTDIR;
}
@@ -438,7 +427,7 @@ repeat:
newval, newlen, context);
return error;
}
- };
+ }
return -ENOTDIR;
}
@@ -495,14 +484,15 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
int insert_at_head)
{
struct ctl_table_header *tmp;
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
if (!tmp)
return 0;
- *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
+ tmp->ctl_table = table;
+ INIT_LIST_HEAD(&tmp->ctl_entry);
if (insert_at_head)
- DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
+ list_add(&tmp->ctl_entry, &root_table_header);
else
- DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
+ list_add_tail(&tmp->ctl_entry, &root_table_header);
#ifdef CONFIG_PROC_FS
register_proc_table(table, proc_sys_root);
#endif
@@ -514,7 +504,7 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
*/
void unregister_sysctl_table(struct ctl_table_header * header)
{
- DLIST_DELETE(header, ctl_entry);
+ list_del(&header->ctl_entry);
#ifdef CONFIG_PROC_FS
unregister_proc_table(header->ctl_table, proc_sys_root);
#endif
@@ -565,9 +555,10 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
if (!de)
continue;
de->data = (void *) table;
- if (table->proc_handler)
- de->ops = &proc_sys_inode_operations;
-
+ if (table->proc_handler) {
+ de->proc_fops = &proc_sys_file_operations;
+ de->proc_iops = &proc_sys_inode_operations;
+ }
}
table->de = de;
if (de->mode & S_IFDIR)
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 43ade5c96..7a6d9db09 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -82,7 +82,7 @@ static void __init reserve_bootmem_core(bootmem_data_t *bdata, unsigned long add
BUG();
for (i = sidx; i < eidx; i++)
if (test_and_set_bit(i, bdata->node_bootmem_map))
- BUG();
+ printk("hm, page %08lx reserved twice.\n", i*PAGE_SIZE);
}
static void __init free_bootmem_core(bootmem_data_t *bdata, unsigned long addr, unsigned long size)
diff --git a/mm/filemap.c b/mm/filemap.c
index 749e14250..6756c70a0 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1321,8 +1321,7 @@ struct page * filemap_nopage(struct vm_area_struct * area,
* of the file is an error and results in a SIGBUS, while a
* private mapping just maps in a zero page.
*/
- if ((pgoff >= size) &&
- (area->vm_flags & VM_SHARED) && (area->vm_mm == current->mm))
+ if ((pgoff >= size) && (area->vm_mm == current->mm))
return NULL;
/*
@@ -1431,33 +1430,6 @@ page_not_uptodate:
return NULL;
}
-/*
- * Tries to write a shared mapped page to its backing store. May return -EIO
- * if the disk is full.
- */
-static inline int do_write_page(struct inode * inode, struct file * file,
- struct page * page, unsigned long index)
-{
- int retval;
- int (*writepage) (struct dentry *, struct page *);
-
- /* refuse to extend file size.. */
- if (S_ISREG(inode->i_mode)) {
- unsigned long size_idx = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- /* Ho humm.. We should have tested for this earlier */
- if (size_idx <= index)
- return -EIO;
- }
- writepage = inode->i_mapping->a_ops->writepage;
- lock_page(page);
-
- retval = writepage(file->f_dentry, page);
-
- UnlockPage(page);
- return retval;
-}
-
static int filemap_write_page(struct file *file,
unsigned long index,
struct page * page,
@@ -1476,7 +1448,9 @@ static int filemap_write_page(struct file *file,
* vma/file is guaranteed to exist in the unmap/sync cases because
* mmap_sem is held.
*/
- result = do_write_page(inode, file, page, index);
+ lock_page(page);
+ result = inode->i_mapping->a_ops->writepage(dentry, page);
+ UnlockPage(page);
return result;
}
diff --git a/mm/memory.c b/mm/memory.c
index b4bf6ed36..aab598aed 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -418,7 +418,7 @@ static struct page * follow_page(unsigned long address)
struct page * get_page_map(struct page *page, unsigned long vaddr)
{
- if (MAP_NR(page) >= max_mapnr)
+ if (MAP_NR(vaddr) >= max_mapnr)
return 0;
if (page == ZERO_PAGE(vaddr))
return 0;
@@ -712,6 +712,19 @@ int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long
}
/*
+ * Establish a new mapping:
+ * - flush the old one
+ * - update the page tables
+ * - inform the TLB about the new one
+ */
+static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry)
+{
+ flush_tlb_page(vma, address);
+ set_pte(page_table, entry);
+ update_mmu_cache(vma, address, entry);
+}
+
+/*
* This routine handles present pages, when users try to write
* to a shared page. It is done by copying the page to a new address
* and decrementing the shared-page counter for the old page.
@@ -769,8 +782,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
/* FallThrough */
case 1:
flush_cache_page(vma, address);
- set_pte(page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
- flush_tlb_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
spin_unlock(&tsk->mm->page_table_lock);
return 1;
}
@@ -793,8 +805,7 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
copy_cow_page(old_page, new_page, address);
flush_page_to_ram(new_page);
flush_cache_page(vma, address);
- set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
- flush_tlb_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
/* Free the old page.. */
new_page = old_page;
@@ -862,6 +873,8 @@ void vmtruncate(struct inode * inode, loff_t offset)
struct vm_area_struct * mpnt;
struct address_space *mapping = inode->i_mapping;
+ if (inode->i_size < offset)
+ goto out;
inode->i_size = offset;
truncate_inode_pages(mapping, offset);
spin_lock(&mapping->i_shared_lock);
@@ -906,6 +919,9 @@ void vmtruncate(struct inode * inode, loff_t offset)
} while ((mpnt = mpnt->vm_next_share) != NULL);
out_unlock:
spin_unlock(&mapping->i_shared_lock);
+out:
+ /* this should go into ->truncate */
+ inode->i_size = offset;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
}
@@ -1120,9 +1136,7 @@ static inline int handle_pte_fault(struct task_struct *tsk,
entry = pte_mkdirty(entry);
}
entry = pte_mkyoung(entry);
- set_pte(pte, entry);
- flush_tlb_page(vma, address);
- update_mmu_cache(vma, address, entry);
+ establish_pte(vma, address, pte, entry);
}
spin_unlock(&tsk->mm->page_table_lock);
return 1;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index efdbb98f1..1b61ebd17 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -27,6 +27,7 @@
int nr_swap_pages = 0;
int nr_lru_pages;
LIST_HEAD(lru_cache);
+pg_data_t *pgdat_list = (pg_data_t *)0;
static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
static int zone_balance_ratio[MAX_NR_ZONES] = { 128, 128, 128, };
@@ -264,24 +265,23 @@ struct page * __alloc_pages (zonelist_t *zonelist, unsigned long order)
{
if (z->low_on_memory)
z->low_on_memory = 0;
+ z->zone_wake_kswapd = 0;
}
else
{
extern wait_queue_head_t kswapd_wait;
- if (z->low_on_memory)
- goto balance;
-
- if (free <= z->pages_low)
- {
+ if (free <= z->pages_low) {
+ z->zone_wake_kswapd = 1;
wake_up_interruptible(&kswapd_wait);
+ } else
+ z->zone_wake_kswapd = 0;
- if (free <= z->pages_min)
- {
- z->low_on_memory = 1;
- goto balance;
- }
- }
+ if (free <= z->pages_min)
+ z->low_on_memory = 1;
+
+ if (z->low_on_memory)
+ goto balance;
}
}
/*
@@ -482,6 +482,9 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
unsigned long totalpages, offset;
unsigned int cumulative = 0;
+ pgdat->node_next = pgdat_list;
+ pgdat_list = pgdat;
+
totalpages = 0;
for (i = 0; i < MAX_NR_ZONES; i++) {
unsigned long size = zones_size[i];
@@ -560,6 +563,7 @@ void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
zone->pages_low = mask*2;
zone->pages_high = mask*3;
zone->low_on_memory = 0;
+ zone->zone_wake_kswapd = 0;
zone->zone_mem_map = mem_map + offset;
zone->zone_start_mapnr = offset;
zone->zone_start_paddr = zone_start_paddr;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 02cf78030..fa687b7e0 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -8,6 +8,7 @@
* Removed kswapd_ctl limits, and swap out as many pages as needed
* to bring the system back to freepages.high: 2.4.97, Rik van Riel.
* Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $
+ * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com).
*/
#include <linux/slab.h>
@@ -468,7 +469,10 @@ DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
*/
int kswapd(void *unused)
{
+ int i;
struct task_struct *tsk = current;
+ pg_data_t *pgdat;
+ zone_t *zone;
tsk->session = 1;
tsk->pgrp = 1;
@@ -496,12 +500,17 @@ int kswapd(void *unused)
* up on a more timely basis.
*/
do {
- /* kswapd is critical to provide GFP_ATOMIC
- allocations (not GFP_HIGHMEM ones). */
- if (nr_free_pages() - nr_free_highpages() >= freepages.high)
- break;
- if (!do_try_to_free_pages(GFP_KSWAPD, 0))
- break;
+ pgdat = pgdat_list;
+ while (pgdat) {
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ zone = pgdat->node_zones + i;
+ if ((!zone->size) ||
+ (!zone->zone_wake_kswapd))
+ continue;
+ do_try_to_free_pages(GFP_KSWAPD, zone);
+ }
+ pgdat = pgdat->node_next;
+ }
run_task_queue(&tq_disk);
} while (!tsk->need_resched);
tsk->state = TASK_INTERRUPTIBLE;
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 43cf3d9a2..98d51c094 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -73,6 +73,7 @@ static void link_vcc(struct clip_vcc *clip_vcc,struct atmarp_entry *entry)
DPRINTK("link_vcc %p to entry %p (neigh %p)\n",clip_vcc,entry,
entry->neigh);
clip_vcc->entry = entry;
+ clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */
clip_vcc->next = entry->vccs;
entry->vccs = clip_vcc;
entry->neigh->used = jiffies;
@@ -95,6 +96,8 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
*walk = clip_vcc->next; /* atomic */
clip_vcc->entry = NULL;
+ if (clip_vcc->xoff)
+ netif_wake_queue(entry->neigh->dev);
if (entry->vccs) return;
entry->expires = jiffies-1;
/* force resolution or expiration */
@@ -218,13 +221,27 @@ void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
}
+/*
+ * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that
+ * clip_pop is atomic with respect to the critical section in clip_start_xmit.
+ */
+
+
static void clip_pop(struct atm_vcc *vcc,struct sk_buff *skb)
{
+ struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
+ int old;
+
DPRINTK("clip_pop(vcc %p)\n",vcc);
- CLIP_VCC(vcc)->old_pop(vcc,skb);
+ clip_vcc->old_pop(vcc,skb);
/* skb->dev == NULL in outbound ARP packets */
- if (atm_may_send(vcc,0) && skb->dev)
- netif_wake_queue(skb->dev);
+ if (!skb->dev) return;
+ spin_lock(&PRIV(skb->dev)->xoff_lock);
+ if (atm_may_send(vcc,0)) {
+ old = xchg(&clip_vcc->xoff,0);
+ if (old) netif_wake_queue(skb->dev);
+ }
+ spin_unlock(&PRIV(skb->dev)->xoff_lock);
}
@@ -354,8 +371,10 @@ int clip_encap(struct atm_vcc *vcc,int mode)
static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
{
+ struct clip_priv *clip_priv = PRIV(dev);
struct atmarp_entry *entry;
struct atm_vcc *vcc;
+ int old;
DPRINTK("clip_start_xmit (skb %p)\n",skb);
if (!skb->dst) {
@@ -368,7 +387,7 @@ static int clip_start_xmit(struct sk_buff *skb,struct net_device *dev)
skb->dst->neighbour = clip_find_neighbour(skb->dst,1);
if (!skb->dst->neighbour) {
dev_kfree_skb(skb); /* lost that one */
- PRIV(dev)->stats.tx_dropped++;
+ clip_priv->stats.tx_dropped++;
return 0;
}
#endif
@@ -386,7 +405,7 @@ return 0;
skb_queue_tail(&entry->neigh->arp_queue,skb);
else {
dev_kfree_skb(skb);
- PRIV(dev)->stats.tx_dropped++;
+ clip_priv->stats.tx_dropped++;
}
return 0;
}
@@ -401,15 +420,33 @@ return 0;
((u16 *) here)[3] = skb->protocol;
}
atomic_add(skb->truesize,&vcc->tx_inuse);
- if (!atm_may_send(vcc,0))
- netif_stop_queue(dev);
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = vcc->atm_options;
entry->vccs->last_use = jiffies;
DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
- PRIV(dev)->stats.tx_packets++;
- PRIV(dev)->stats.tx_bytes += skb->len;
+ old = xchg(&entry->vccs->xoff,1); /* assume XOFF ... */
+ if (old) {
+ printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
+ return 0;
+ }
+ clip_priv->stats.tx_packets++;
+ clip_priv->stats.tx_bytes += skb->len;
(void) vcc->dev->ops->send(vcc,skb);
+ if (atm_may_send(vcc,0)) {
+ entry->vccs->xoff = 0;
+ return 0;
+ }
+ if (old) return 0;
+ spin_lock(&clip_priv->xoff_lock);
+ netif_stop_queue(dev); /* XOFF -> throttle immediately */
+ barrier();
+ if (!entry->vccs->xoff)
+ netif_start_queue(dev);
+ /* Oh, we just raced with clip_pop. netif_start_queue should be
+ good enough, because nothing should really be asleep because
+ of the brief netif_stop_queue. If this isn't true or if it
+ changes, use netif_wake_queue instead. */
+ spin_unlock(&clip_priv->xoff_lock);
return 0;
}
@@ -434,6 +471,7 @@ int clip_mkip(struct atm_vcc *vcc,int timeout)
clip_vcc->vcc = vcc;
vcc->user_back = clip_vcc;
clip_vcc->entry = NULL;
+ clip_vcc->xoff = 0;
clip_vcc->encap = 1;
clip_vcc->last_use = jiffies;
clip_vcc->idle_timeout = timeout*HZ;
@@ -523,7 +561,7 @@ static int clip_init(struct net_device *dev)
dev->hard_header_len = RFC1483LLC_LEN;
dev->mtu = RFC1626_MTU;
dev->addr_len = 0;
- dev->tx_queue_len = 100; /* "normal" queue */
+ dev->tx_queue_len = 100; /* "normal" queue (packets) */
/* When using a "real" qdisc, the qdisc determines the queue */
/* length. tx_queue_len is only used for the default case, */
/* without any more elaborate queuing. 100 is a reasonable */
@@ -538,6 +576,7 @@ static int clip_init(struct net_device *dev)
int clip_create(int number)
{
struct net_device *dev;
+ struct clip_priv *clip_priv;
int error;
if (number != -1) {
@@ -554,16 +593,18 @@ int clip_create(int number)
GFP_KERNEL);
if (!dev) return -ENOMEM;
memset(dev,0,sizeof(struct net_device)+sizeof(struct clip_priv));
- dev->name = PRIV(dev)->name;
+ clip_priv = PRIV(dev);
+ dev->name = clip_priv->name;
sprintf(dev->name,"atm%d",number);
dev->init = clip_init;
- PRIV(dev)->number = number;
+ spin_lock_init(&clip_priv->xoff_lock);
+ clip_priv->number = number;
error = register_netdev(dev);
if (error) {
kfree(dev);
return error;
}
- PRIV(dev)->next = clip_devs;
+ clip_priv->next = clip_devs;
clip_devs = dev;
DPRINTK("registered (net:%s)\n",dev->name);
return number;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 5b0e9138f..8c6d8d4af 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -184,9 +184,7 @@ lec_open(struct net_device *dev)
{
struct lec_priv *priv = (struct lec_priv *)dev->priv;
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = 1;
+ netif_start_queue(dev);
memset(&priv->stats,0,sizeof(struct net_device_stats));
return 0;
@@ -214,165 +212,148 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
if (!priv->lecd) {
printk("%s:No lecd attached\n",dev->name);
priv->stats.tx_errors++;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
return -EUNATCH;
}
- if (dev->tbusy) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- printk("%s: transmit timed out\n", dev->name);
- dev->tbusy = 0;
- }
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
-
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n",
- dev->name);
- } else {
- DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
- (long)skb->head, (long)skb->data, (long)skb->tail,
- (long)skb->end);
+ DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
+ (long)skb->head, (long)skb->data, (long)skb->tail,
+ (long)skb->end);
#ifdef CONFIG_BRIDGE
- if (skb->pkt_bridged == IS_BRIDGED)
- handle_bridge(skb, dev);
+ if (skb->pkt_bridged == IS_BRIDGED)
+ handle_bridge(skb, dev);
#endif /* CONFIG_BRIDGE */
- /* Make sure we have room for lec_id */
- if (skb_headroom(skb) < 2) {
+ /* Make sure we have room for lec_id */
+ if (skb_headroom(skb) < 2) {
- DPRINTK("lec_send_packet: reallocating skb\n");
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
- skb_push(skb, 2);
+ DPRINTK("lec_send_packet: reallocating skb\n");
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL) return 0;
+ skb = skb2;
+ }
+ skb_push(skb, 2);
- /* Put le header to place, works for TokenRing too */
- lec_h = (struct lecdatahdr_8023*)skb->data;
- lec_h->le_header = htons(priv->lecid);
+ /* Put le header to place, works for TokenRing too */
+ lec_h = (struct lecdatahdr_8023*)skb->data;
+ lec_h->le_header = htons(priv->lecid);
#ifdef CONFIG_TR
- /* Ugly. Use this to realign Token Ring packets for
- * e.g. PCA-200E driver. */
- if (priv->is_trdev) {
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
+ /* Ugly. Use this to realign Token Ring packets for
+ * e.g. PCA-200E driver. */
+ if (priv->is_trdev) {
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL) return 0;
+ skb = skb2;
+ }
#endif
#if DUMP_PACKETS > 0
- printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
- skb->len, priv->lecid);
+ printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
+ skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
- for(i=0;i<skb->len && i <99;i++) {
- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
- }
+ for(i=0;i<skb->len && i <99;i++) {
+ sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
+ }
#elif DUMP_PACKETS >= 1
- for(i=0;i<skb->len && i < 30;i++) {
- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
- }
+ for(i=0;i<skb->len && i < 30;i++) {
+ sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
+ }
#endif /* DUMP_PACKETS >= 1 */
- if (i==skb->len)
- printk("%s\n",buf);
- else
- printk("%s...\n",buf);
+ if (i==skb->len)
+ printk("%s\n",buf);
+ else
+ printk("%s...\n",buf);
#endif /* DUMP_PACKETS > 0 */
- /* Minimum ethernet-frame size */
- if (skb->len <62) {
- if (skb->truesize < 62) {
- printk("%s:data packet %d / %d\n",
- dev->name,
- skb->len,skb->truesize);
- nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
- memcpy(nb,skb->data,skb->len);
- kfree(skb->head);
- skb->head = skb->data = nb;
- skb->tail = nb+62;
- skb->end = nb+64;
- skb->len=62;
- skb->truesize = 64;
- } else {
- skb->len = 62;
- }
+ /* Minimum ethernet-frame size */
+ if (skb->len <62) {
+ if (skb->truesize < 62) {
+ printk("%s:data packet %d / %d\n",
+ dev->name,
+ skb->len,skb->truesize);
+ nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+ memcpy(nb,skb->data,skb->len);
+ kfree(skb->head);
+ skb->head = skb->data = nb;
+ skb->tail = nb+62;
+ skb->end = nb+64;
+ skb->len=62;
+ skb->truesize = 64;
+ } else {
+ skb->len = 62;
}
-
- /* Send to right vcc */
- is_rdesc = 0;
- dst = lec_h->h_dest;
+ }
+
+ /* Send to right vcc */
+ is_rdesc = 0;
+ dst = lec_h->h_dest;
#ifdef CONFIG_TR
- if (priv->is_trdev) {
- dst = get_tr_dst(skb->data+2, rdesc);
- if (dst == NULL) {
- dst = rdesc;
- is_rdesc = 1;
- }
+ if (priv->is_trdev) {
+ dst = get_tr_dst(skb->data+2, rdesc);
+ if (dst == NULL) {
+ dst = rdesc;
+ is_rdesc = 1;
}
+ }
#endif
- entry = NULL;
- send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
- DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
- send_vcc, send_vcc?send_vcc->flags:0, entry);
- if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
- if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
- DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
- skb_queue_tail(&entry->tx_wait, skb);
- } else {
- DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name);
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
- priv->stats.tx_dropped++;
- dev_kfree_skb(skb);
- }
- dev->tbusy=0;
- return 0;
+ entry = NULL;
+ send_vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
+ DPRINTK("%s:send_vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
+ send_vcc, send_vcc?send_vcc->flags:0, entry);
+ if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) {
+ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
+ DPRINTK("%s:lec_send_packet: queuing packet, ", dev->name);
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+ skb_queue_tail(&entry->tx_wait, skb);
+ } else {
+ DPRINTK("%s:lec_send_packet: tx queue full or no arp entry, dropping, ", dev->name);
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+ priv->stats.tx_dropped++;
+ dev_kfree_skb(skb);
}
+ return 0;
+ }
#if DUMP_PACKETS > 0
- printk("%s:sending to vpi:%d vci:%d\n", dev->name,
- send_vcc->vpi, send_vcc->vci);
+ printk("%s:sending to vpi:%d vci:%d\n", dev->name,
+ send_vcc->vpi, send_vcc->vci);
#endif /* DUMP_PACKETS > 0 */
- while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
- DPRINTK("lec.c: emptying tx queue, ");
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
- ATM_SKB(skb2)->vcc = send_vcc;
- atomic_add(skb2->truesize, &send_vcc->tx_inuse);
- ATM_SKB(skb2)->iovcnt = 0;
- ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
- DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
- send_vcc->vpi, send_vcc->vci);
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb2->len;
- send_vcc->dev->ops->send(send_vcc, skb2);
- }
-
- ATM_SKB(skb)->vcc = send_vcc;
- atomic_add(skb->truesize, &send_vcc->tx_inuse);
- ATM_SKB(skb)->iovcnt = 0;
- ATM_SKB(skb)->atm_options = send_vcc->atm_options;
+ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
+ DPRINTK("lec.c: emptying tx queue, ");
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+ ATM_SKB(skb2)->vcc = send_vcc;
+ atomic_add(skb2->truesize, &send_vcc->tx_inuse);
+ ATM_SKB(skb2)->iovcnt = 0;
+ ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
+ DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
+ send_vcc->vpi, send_vcc->vci);
priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
- send_vcc->dev->ops->send(send_vcc, skb);
+ priv->stats.tx_bytes += skb2->len;
+ send_vcc->dev->ops->send(send_vcc, skb2);
}
+
+ ATM_SKB(skb)->vcc = send_vcc;
+ atomic_add(skb->truesize, &send_vcc->tx_inuse);
+ ATM_SKB(skb)->iovcnt = 0;
+ ATM_SKB(skb)->atm_options = send_vcc->atm_options;
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ send_vcc->dev->ops->send(send_vcc, skb);
+
+#if 0
/* Should we wait for card's device driver to notify us? */
dev->tbusy=0;
-
+#endif
return 0;
}
@@ -380,8 +361,7 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
static int
lec_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
return 0;
}
@@ -530,9 +510,7 @@ lec_atm_close(struct atm_vcc *vcc)
priv->lecd = NULL;
/* Do something needful? */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
lec_arp_destroy(priv);
if (skb_peek(&vcc->recvq))
@@ -698,7 +676,7 @@ lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */
!priv->is_proxy && /* Proxy wants all the packets */
- memcmp(dst, dev->dev_addr, sizeof(dev->dev_addr))) {
+ memcmp(dst, dev->dev_addr, dev->addr_len)) {
dev_kfree_skb(skb);
return;
}
@@ -814,8 +792,7 @@ lecd_attach(struct atm_vcc *vcc, int arg)
priv->path_switching_delay = (6*HZ);
if (dev_lec[i]->flags & IFF_UP) {
- dev_lec[i]->tbusy = 0;
- dev_lec[i]->start = 1;
+ netif_start_queue(dev_lec[i]);
}
MOD_INC_USE_COUNT;
return i;
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index c779b18eb..bb6eddfe6 100644
--- a/net/atm/mpoa_proc.c
+++ b/net/atm/mpoa_proc.c
@@ -45,13 +45,6 @@ static struct file_operations mpc_file_operations = {
write: proc_mpc_write,
};
-/*
- * Define allowed INODE OPERATIONS
- */
-static struct inode_operations mpc_inode_operations = {
- &mpc_file_operations,
-};
-
static int print_header(char *buff,struct mpoa_client *mpc){
if(mpc != NULL){
return sprintf(buff,"\nInterface %d:\n\n",mpc->dev_num);
@@ -330,7 +323,7 @@ int mpc_proc_init(void)
printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
return -ENOMEM;
}
- p->ops = &mpc_inode_operations;
+ p->proc_fops = &mpc_file_operations;
return 0;
}
diff --git a/net/atm/proc.c b/net/atm/proc.c
index b67ae428a..904dc43ba 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -63,15 +63,6 @@ static struct file_operations proc_spec_atm_operations = {
read: proc_spec_atm_read,
};
-static struct inode_operations proc_dev_atm_inode_operations = {
- &proc_dev_atm_operations, /* default ATM directory file-ops */
-};
-
-static struct inode_operations proc_spec_atm_inode_operations = {
- &proc_spec_atm_operations, /* default ATM directory file-ops */
-};
-
-
static void add_stats(char *buf,const char *aal,
const struct atm_aal_stats *stats)
{
@@ -563,7 +554,7 @@ int atm_proc_dev_register(struct atm_dev *dev)
if (!dev->proc_entry)
goto fail0;
dev->proc_entry->data = dev;
- dev->proc_entry->ops = &proc_dev_atm_inode_operations;
+ dev->proc_entry->proc_fops = &proc_dev_atm_operations;
return 0;
kfree(dev->proc_entry);
fail0:
@@ -584,7 +575,7 @@ void atm_proc_dev_deregister(struct atm_dev *dev)
name = create_proc_entry(#name,0,atm_proc_root); \
if (!name) goto cleanup; \
name->data = atm_##name##_info; \
- name->ops = &proc_spec_atm_inode_operations
+ name->proc_fops = &proc_spec_atm_operations
int __init atm_proc_init(void)
diff --git a/net/atm/raw.c b/net/atm/raw.c
index 0db4aabb6..355382502 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -1,6 +1,6 @@
/* net/atm/raw.c - Raw AAL0 and AAL5 transports */
-/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
#include <linux/module.h>
@@ -38,7 +38,7 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
{
DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
wake_up(&vcc->wsleep);
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index de14e83a8..d2fac6697 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_device.c,v 1.1 2000/02/18 16:47:11 davem Exp $
+ * $Id: br_device.c,v 1.2 2000/02/24 19:48:06 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -116,12 +116,10 @@ static int br_dev_stop(struct net_device *dev)
return 0;
}
-#ifdef CONFIG_NET_FASTROUTE
static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
{
return -1;
}
-#endif
void br_dev_setup(struct net_device *dev)
{
@@ -133,9 +131,7 @@ void br_dev_setup(struct net_device *dev)
dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list;
dev->stop = br_dev_stop;
-#ifdef CONFIG_NET_FASTROUTE
dev->accept_fastpath = br_dev_accept_fastpath;
-#endif
-
dev->tx_queue_len = 0;
+ dev->set_mac_address = NULL;
}
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 2ca3c7fdd..be9d1867a 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.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_fdb.c,v 1.4 2000/02/24 06:16:45 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,9 +14,9 @@
*/
#include <linux/kernel.h>
+#include <linux/spinlock.h>
#include <linux/if_bridge.h>
#include <asm/atomic.h>
-#include <asm/spinlock.h>
#include <asm/uaccess.h>
#include "br_private.h"
@@ -216,6 +216,7 @@ int br_fdb_get_entries(struct net_bridge *br,
struct __fdb_entry ent;
int err;
struct net_bridge_fdb_entry *g;
+ struct net_bridge_fdb_entry **pp;
if (has_expired(br, f)) {
f = f->next_hash;
@@ -236,13 +237,13 @@ int br_fdb_get_entries(struct net_bridge *br,
read_lock_bh(&br->hash_lock);
g = f->next_hash;
+ pp = f->pprev_hash;
br_fdb_put(f);
if (err)
goto out_fault;
- if (f->next_hash == NULL &&
- f->pprev_hash == NULL)
+ if (g == NULL && pp == NULL)
goto out_disappeared;
num++;
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index e33850fd2..10e744a2f 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_forward.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_forward.c,v 1.2 2000/02/21 15:51:33 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index cbba5296d..dc77c5ffd 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.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_if.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index e3175dac9..e6fa6b379 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_input.c,v 1.3 2000/02/24 19:48:06 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,21 +23,15 @@ unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
- if (br->dev.flags & IFF_UP) {
- br->statistics.rx_packets++;
- br->statistics.rx_bytes += skb->len;
-
- skb->dev = &br->dev;
- skb->pkt_type = PACKET_HOST;
- skb->mac.raw = skb->data;
- skb_pull(skb, skb->nh.raw - skb->data);
- skb->protocol = eth_type_trans(skb, &br->dev);
- netif_rx(skb);
-
- return;
- }
-
- kfree_skb(skb);
+ br->statistics.rx_packets++;
+ br->statistics.rx_bytes += skb->len;
+
+ skb->dev = &br->dev;
+ skb->pkt_type = PACKET_HOST;
+ skb->mac.raw = skb->data;
+ skb_pull(skb, skb->nh.raw - skb->data);
+ skb->protocol = eth_type_trans(skb, &br->dev);
+ netif_rx(skb);
}
static void __br_handle_frame(struct sk_buff *skb)
@@ -46,17 +40,44 @@ static void __br_handle_frame(struct sk_buff *skb)
unsigned char *dest;
struct net_bridge_fdb_entry *dst;
struct net_bridge_port *p;
+ int passedup;
skb->nh.raw = skb->mac.raw;
dest = skb->mac.ethernet->h_dest;
p = skb->dev->br_port;
br = p->br;
+ passedup = 0;
+
+ if (!(br->dev.flags & IFF_UP) ||
+ p->state == BR_STATE_DISABLED)
+ goto freeandout;
+
+ if (br->dev.flags & IFF_PROMISC) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ passedup = 1;
+ br_pass_frame_up(br, skb2);
+ }
+ }
- if (p->state == BR_STATE_DISABLED ||
- skb->mac.ethernet->h_source[0] & 1)
+ if (skb->mac.ethernet->h_source[0] & 1)
goto freeandout;
+ if (!passedup &&
+ (dest[0] & 1) &&
+ (br->dev.flags & IFF_ALLMULTI || br->dev.mc_list != NULL)) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (skb2) {
+ passedup = 1;
+ br_pass_frame_up(br, skb2);
+ }
+ }
+
if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0))
goto handle_special_frame;
@@ -71,14 +92,16 @@ static void __br_handle_frame(struct sk_buff *skb)
if (dest[0] & 1) {
br_flood(br, skb, 1);
- br_pass_frame_up(br, skb);
+ if (!passedup)
+ br_pass_frame_up(br, skb);
return;
}
dst = br_fdb_get(br, dest);
if (dst != NULL && dst->is_local) {
- br_pass_frame_up(br, skb);
+ if (!passedup)
+ br_pass_frame_up(br, skb);
br_fdb_put(dst);
return;
}
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 8830cd747..dad96fb99 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.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_ioctl.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 8a109d7c3..6ed309b75 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_notify.c,v 1.1 2000/02/18 16:47:12 davem Exp $
+ * $Id: br_notify.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index a35d03f20..db5c18733 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ * $Id: br_stp.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 345792f83..71e51ffb2 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_bpdu.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ * $Id: br_stp_bpdu.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index bbffc4126..263ac21af 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_if.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ * $Id: br_stp_if.c,v 1.2 2000/02/21 15:51:34 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index ca4e6e568..c530f14f8 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_timer.c,v 1.1 2000/02/18 16:47:13 davem Exp $
+ * $Id: br_stp_timer.c,v 1.2 2000/02/21 15:51:35 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/core/dev.c b/net/core/dev.c
index d2ed4f523..638ab6432 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -933,20 +933,19 @@ void net_call_rx_atomic(void (*fn)(void))
void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
#endif
-#define HANDLE_BRIDGE(SKB, PT_PREV) \
-do { \
- if ((SKB)->dev->br_port != NULL && \
- br_handle_frame_hook != NULL) { \
- if (PT_PREV) \
- if (!(PT_PREV->data)) \
- deliver_to_old_ones(PT_PREV, SKB, 1); \
- else \
- pt_prev->func(SKB, SKB->dev, PT_PREV); \
- \
- br_handle_frame_hook(SKB); \
- continue; \
- } \
-} while(0)
+static void __inline__ handle_bridge(struct sk_buff *skb,
+ struct packet_type *pt_prev)
+{
+ if (pt_prev)
+ deliver_to_old_ones(pt_prev, skb, 0);
+ else {
+ atomic_inc(&skb->users);
+ pt_prev->func(skb, skb->dev, pt_prev);
+ }
+
+ br_handle_frame_hook(skb);
+}
+
static void net_rx_action(struct softirq_action *h)
{
@@ -999,7 +998,11 @@ static void net_rx_action(struct softirq_action *h)
}
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
- HANDLE_BRIDGE(skb, pt_prev);
+ if (skb->dev->br_port != NULL &&
+ br_handle_frame_hook != NULL) {
+ handle_bridge(skb, pt_prev);
+ continue;
+ }
#endif
for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
@@ -1856,6 +1859,14 @@ int register_netdevice(struct net_device *dev)
*dp = dev;
dev_hold(dev);
write_unlock_bh(&dev_base_lock);
+
+ /*
+ * Default initial state at registry is that the
+ * device is present.
+ */
+
+ set_bit(__LINK_STATE_PRESENT, &dev->state);
+
return 0;
}
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 1b16e7734..04728d5d8 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1837,7 +1837,8 @@ static int dn_sendmsg(struct socket *sock, struct msghdr *msg, int size,
scp->persist_fxn = dn_nsp_xmit_timeout;
while(sent < size) {
- if ((err = sock_error(sk) != 0))
+ err = sock_error(sk);
+ if (err)
goto out;
if (signal_pending(current)) {
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index b7512a1c9..b848151a9 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.107 2000/02/18 16:47:20 davem Exp $
+ * Version: $Id: af_inet.c,v 1.108 2000/02/21 16:25:59 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -135,7 +135,9 @@ extern int dlci_ioctl(unsigned int, void*);
int (*dlci_ioctl_hook)(unsigned int, void *) = NULL;
#endif
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
int (*br_ioctl_hook)(unsigned long) = NULL;
+#endif
/* New destruction routine */
@@ -837,13 +839,14 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return(devinet_ioctl(cmd,(void *) arg));
case SIOCGIFBR:
case SIOCSIFBR:
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#ifdef CONFIG_KMOD
if (br_ioctl_hook == NULL)
request_module("bridge");
#endif
if (br_ioctl_hook != NULL)
return br_ioctl_hook(arg);
-
+#endif
return -ENOPKG;
case SIOCADDDLCI:
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 3aad90680..c93da55f9 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -8,7 +8,7 @@
* the older version didn't come out right using gcc 2.5.8, the newer one
* seems to fall out with gcc 2.6.2.
*
- * Version: $Id: igmp.c,v 1.37 2000/02/09 11:16:40 davem Exp $
+ * Version: $Id: igmp.c,v 1.38 2000/02/27 01:20:02 davem Exp $
*
* Authors:
* Alan Cox <Alan.Cox@linux.org>
@@ -93,6 +93,7 @@
#include <net/route.h>
#include <net/sock.h>
#include <net/checksum.h>
+#include <linux/netfilter_ipv4.h>
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
@@ -185,6 +186,11 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
+static inline int igmp_send_report2(struct sk_buff *skb)
+{
+ return skb->dst->output(skb);
+}
+
static int igmp_send_report(struct net_device *dev, u32 group, int type)
{
struct sk_buff *skb;
@@ -242,7 +248,8 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
ih->group=group;
ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
- return skb->dst->output(skb);
+ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+ igmp_send_report2);
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index bcdd71354..454e81fea 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1,5 +1,5 @@
/*
- * $Id: ipconfig.c,v 1.26 2000/01/29 07:42:08 davem Exp $
+ * $Id: ipconfig.c,v 1.27 2000/02/21 15:51:41 davem Exp $
*
* Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
* information to configure own IP address and routes.
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 37ab925bf..887aaa519 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.121 2000/02/08 21:27:19 davem Exp $
+ * Version: $Id: tcp_output.c,v 1.122 2000/02/21 15:51:41 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index b53f8a8cf..ac70091af 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -6,7 +6,7 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Jun 6 21:00:56 1999
- * Modified at: Tue Jan 4 14:12:06 2000
+ * Modified at: Wed Feb 23 00:09:02 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c and previous IrCOMM work by Takahide Higuchi
*
@@ -1079,6 +1079,9 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
"(), CTS tx start...\n");
tty->hw_stopped = 0;
+ /* Wake up processes blocked on open */
+ wake_up_interruptible(&self->open_wait);
+
queue_task(&self->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
diff --git a/net/netsyms.c b/net/netsyms.c
index fbb07ab5a..d03c0a1b1 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -507,9 +507,6 @@ EXPORT_SYMBOL(dev_load);
#endif
EXPORT_SYMBOL(dev_ioctl);
EXPORT_SYMBOL(dev_queue_xmit);
-#ifdef CONFIG_NET_FASTROUTE
-EXPORT_SYMBOL(dev_fastroute_stat);
-#endif
#ifdef CONFIG_NET_HW_FLOWCONTROL
EXPORT_SYMBOL(netdev_register_fc);
EXPORT_SYMBOL(netdev_unregister_fc);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 46439faa3..3a9d20e9c 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -5,7 +5,7 @@
*
* PACKET - implements raw packet sockets.
*
- * Version: $Id: af_packet.c,v 1.31 2000/02/18 16:47:23 davem Exp $
+ * Version: $Id: af_packet.c,v 1.32 2000/02/21 16:25:55 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1438,12 +1438,14 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
case SIOCGIFBR:
case SIOCSIFBR:
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
#ifdef CONFIG_KMOD
if (br_ioctl_hook == NULL)
request_module("bridge");
#endif
if (br_ioctl_hook != NULL)
return br_ioctl_hook(arg);
+#endif
return -ENOPKG;
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index e81541cea..a3b25f2a7 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -6,6 +6,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/skbuff.h>
+#include <linux/interrupt.h>
#include <linux/atmdev.h>
#include <linux/atmclip.h>
#include <linux/netdevice.h>
@@ -20,7 +21,7 @@ extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
__inline__ in socket.c */
-#if 1 /* control */
+#if 0 /* control */
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
#else
#define DPRINTK(format,args...)
@@ -64,6 +65,7 @@ struct atm_flow_data {
struct tcf_proto *filter_list;
struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* chaining */
+ struct atm_qdisc_data *parent; /* parent qdisc */
struct socket *sock; /* for closing */
u32 classid; /* x:y type ID */
int ref; /* reference count */
@@ -79,6 +81,7 @@ struct atm_qdisc_data {
struct atm_flow_data link; /* unclassified skbs go here */
struct atm_flow_data *flows; /* NB: "link" is also on this
list */
+ struct tasklet_struct task; /* requeue tasklet */
};
@@ -153,6 +156,18 @@ static unsigned long atm_tc_bind_filter(struct Qdisc *sch,
}
+static void destroy_filters(struct atm_flow_data *flow)
+{
+ struct tcf_proto *filter;
+
+ while ((filter = flow->filter_list)) {
+ DPRINTK("destroy_filters: destroying filter %p\n",filter);
+ flow->filter_list = filter->next;
+ filter->ops->destroy(filter);
+ }
+}
+
+
/*
* atm_tc_put handles all destructions, including the ones that are explicitly
* requested (atm_tc_destroy, etc.). The assumption here is that we never drop
@@ -164,7 +179,6 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow = (struct atm_flow_data *) cl;
struct atm_flow_data **prev;
- struct tcf_proto *filter;
DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
if (--flow->ref) return;
@@ -178,14 +192,10 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
*prev = flow->next;
DPRINTK("atm_tc_put: qdisc %p\n",flow->q);
qdisc_destroy(flow->q);
- while ((filter = flow->filter_list)) {
- DPRINTK("atm_tc_put: destroying filter %p\n",filter);
- flow->filter_list = filter->next;
- DPRINTK("atm_tc_put: filter %p\n",filter);
- filter->ops->destroy(filter);
- }
+ destroy_filters(flow);
if (flow->sock) {
- DPRINTK("atm_tc_put: f_count %d\n",file_count(flow->sock->file));
+ DPRINTK("atm_tc_put: f_count %d\n",
+ file_count(flow->sock->file));
flow->vcc->pop = flow->old_pop;
sockfd_put(flow->sock);
}
@@ -200,8 +210,11 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
static void sch_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb)
{
+ struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
+
+ D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n",vcc,skb,p);
VCC2FLOW(vcc)->old_pop(vcc,skb);
- mark_bh(NET_BH); /* may allow to send more */
+ tasklet_schedule(&p->task);
}
@@ -302,6 +315,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
flow->vcc->user_back = flow;
DPRINTK("atm_tc_change: vcc %p\n",flow->vcc);
flow->old_pop = flow->vcc->pop;
+ flow->parent = p;
flow->vcc->pop = sch_atm_pop;
flow->classid = classid;
flow->ref = 1;
@@ -440,21 +454,31 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
}
-static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
+/*
+ * Dequeue packets and send them over ATM. Note that we quite deliberately
+ * avoid checking net_device's flow control here, simply because sch_atm
+ * uses its own channels, which have nothing to do with any CLIP/LANE/or
+ * non-ATM interfaces.
+ */
+
+
+static void sch_atm_dequeue(unsigned long data)
{
+ struct Qdisc *sch = (struct Qdisc *) data;
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
struct sk_buff *skb;
- D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n",sch,p);
for (flow = p->link.next; flow; flow = flow->next)
/*
* If traffic is properly shaped, this won't generate nasty
- * little bursts. Otherwise, it may ... @@@
+ * little bursts. Otherwise, it may ... (but that's okay)
*/
while ((skb = flow->q->dequeue(flow->q))) {
if (!atm_may_send(flow->vcc,skb->truesize)) {
- flow->q->ops->requeue(skb,flow->q);
+ if (flow->q->ops->requeue(skb,flow->q))
+ sch->q.qlen--;
break;
}
sch->q.qlen--;
@@ -469,7 +493,7 @@ static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
if (!new) continue;
skb = new;
}
- D2PRINTK("atm_tc_dequeue: ip %p, data %p\n",
+ D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
skb->nh.iph,skb->data);
ATM_SKB(skb)->vcc = flow->vcc;
memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
@@ -479,6 +503,16 @@ static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
/* atm.atm_options are already set by atm_tc_enqueue */
(void) flow->vcc->dev->ops->send(flow->vcc,skb);
}
+}
+
+
+static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
+{
+ struct atm_qdisc_data *p = PRIV(sch);
+ struct sk_buff *skb;
+
+ D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ tasklet_schedule(&p->task);
skb = p->link.q->dequeue(p->link.q);
if (skb) sch->q.qlen--;
return skb;
@@ -530,6 +564,7 @@ static int atm_tc_init(struct Qdisc *sch,struct rtattr *opt)
p->link.classid = sch->handle;
p->link.ref = 1;
p->link.next = NULL;
+ tasklet_init(&p->task,sch_atm_dequeue,(unsigned long) sch);
MOD_INC_USE_COUNT;
return 0;
}
@@ -554,6 +589,7 @@ static void atm_tc_destroy(struct Qdisc *sch)
DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p);
/* races ? */
while ((flow = p->flows)) {
+ destroy_filters(flow);
if (flow->ref > 1)
printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
flow->ref);
@@ -565,6 +601,7 @@ static void atm_tc_destroy(struct Qdisc *sch)
break;
}
}
+ tasklet_kill(&p->task);
MOD_DEC_USE_COUNT;
}
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 0b741fa4e..bb6b3a291 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -878,7 +878,7 @@ cbq_dequeue_prio(struct Qdisc *sch, int prio)
/* Start round */
do {
- struct cbq_class *borrow = NULL;
+ struct cbq_class *borrow = cl;
if (cl->q->q.qlen &&
(borrow = cbq_under_limit(cl)) == NULL)
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 1c1a48582..76f2fc394 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -278,10 +278,16 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
static int dsmark_requeue(struct sk_buff *skb,struct Qdisc *sch)
{
+ int ret;
struct dsmark_qdisc_data *p = PRIV(sch);
D2PRINTK("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
- return p->q->ops->requeue(skb,p->q);
+ if ((ret = p->q->ops->requeue(skb, p->q)) == 0) {
+ sch->q.qlen++;
+ return 0;
+ }
+ sch->stats.drops++;
+ return ret;
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index cb8419990..39d7781d0 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -95,25 +95,11 @@ static struct file_operations router_fops =
static struct inode_operations router_inode =
{
- &router_fops,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- router_proc_perms, /* permission */
- NULL /* revalidate */
+ permission: router_proc_perms,
};
/*
- * /proc/net/router/<device> file and inode operations
+ * /proc/net/router/<device> file operations
*/
static struct file_operations wandev_fops =
@@ -122,25 +108,6 @@ static struct file_operations wandev_fops =
ioctl: wanrouter_ioctl,
};
-static struct inode_operations wandev_inode =
-{
- &wandev_fops,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* truncate */
- router_proc_perms, /* permission */
- NULL /* revalidate */
-};
-
/*
* /proc/net/router
*/
@@ -175,12 +142,14 @@ int __init wanrouter_proc_init (void)
p = create_proc_entry("config",0,proc_router);
if (!p)
goto fail_config;
- p->ops = &router_inode;
+ p->proc_fops = &router_fops;
+ p->proc_iops = &router_inode;
p->get_info = config_get_info;
p = create_proc_entry("status",0,proc_router);
if (!p)
goto fail_stat;
- p->ops = &router_inode;
+ p->proc_fops = &router_fops;
+ p->proc_iops = &router_inode;
p->get_info = status_get_info;
return 0;
fail_stat:
@@ -214,7 +183,8 @@ int wanrouter_proc_add (wan_device_t* wandev)
wandev->dent = create_proc_entry(wandev->name, 0, proc_router);
if (!wandev->dent)
return -ENOMEM;
- wandev->dent->ops = &wandev_inode;
+ wandev->dent->proc_fops = &wandev_fops;
+ wandev->dent->proc_iops = &router_inode;
wandev->dent->get_info = wandev_get_info;
wandev->dent->data = wandev;
return 0;