summaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
parent7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff)
Merge with 2.3.48.
Diffstat (limited to 'drivers')
-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.buddha210
-rw-r--r--drivers/block/README.fd222
-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/ac97_codec.h161
-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
273 files changed, 27617 insertions, 14066 deletions
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.buddha b/drivers/block/README.buddha
deleted file mode 100644
index d3b7bc73f..000000000
--- a/drivers/block/README.buddha
+++ /dev/null
@@ -1,210 +0,0 @@
-
-The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by
-Geert Uytterhoeven based on the following specifications:
-
-------------------------------------------------------------------------
-
-Register map of the Buddha IDE controller and the
-Buddha-part of the Catweasel Zorro-II version
-
-The Autoconfiguration has been implemented just as Commodore
-described in their manuals, no tricks have been used (for
-example leaving some address lines out of the equations...).
-If you want to configure the board yourself (for example let
-a Linux kernel configure the card), look at the Commodore
-Docs. Reading the nibbles should give this information:
-
-Vendor number: 4626 ($1212)
-product number: 0 (42 for Catweasel Z-II)
-Serial number: 0
-Rom-vector: $1000
-
-The card should be a Z-II board, size 64K, not for freemem
-list, Rom-Vektor is valid, no second Autoconfig-board on the
-same card, no space preferrence, supports "Shutup_forever".
-
-Setting the base address should be done in two steps, just
-as the Amiga Kickstart does: The lower nibble of the 8-Bit
-address is written to $4a, then the whole Byte is written to
-$48, while it doesn't matter how often you're writing to $4a
-as long as $48 is not touched. After $48 has been written,
-the whole card disappears from $e8 and is mapped to the new
-addrress just written. Make shure $4a is written befor $48,
-otherwise your chance is only 1:16 to find the board :-).
-
-The local memory-map is even active when mapped to $e8:
-
-$0-$7e Autokonfig-space, see Z-II docs.
-
-$80-$7fd reserved
-
-$7fe Speed-select Register: Read & Write
- (description see further down)
-
-$800-$8ff IDE-Select 0 (Port 0, Register set 0)
-
-$900-$9ff IDE-Select 1 (Port 0, Register set 1)
-
-$a00-$aff IDE-Select 2 (Port 1, Register set 0)
-
-$b00-$bff IDE-Select 3 (Port 1, Register set 1)
-
-$c00-$cff IDE-Select 4 (Port 2, Register set 0,
- Catweasel only!)
-
-$d00-$dff IDE-Select 5 (Port 3, Register set 1,
- Catweasel only!)
-
-$e00-$eff local expansion port, on Catweasel Z-II the
- Catweasel registers are also mapped here.
- Never touch, use multidisk.device!
-
-$f00 read only, Byte-access: Bit 7 shows the
- level of the IRQ-line of IDE port 0.
-
-$f01-$f3f mirror of $f00
-
-$f40 read only, Byte-access: Bit 7 shows the
- level of the IRQ-line of IDE port 1.
-
-$f41-$f7f mirror of $f40
-
-$f80 read only, Byte-access: Bit 7 shows the
- level of the IRQ-line of IDE port 2.
- (Catweasel only!)
-
-$f81-$fbf mirror of $f80
-
-$fc0 write-only: Writing any value to this
- register enables IRQs to be passed from the
- IDE ports to the Zorro bus. This mechanism
- has been implemented to be compatible with
- harddisks that are either defective or have
- a buggy firmware and pull the IRQ line up
- while starting up. If interrupts would
- always be passed to the bus, the computer
- might not start up. Once enabled, this flag
- can not be disabled again. The level of the
- flag can not be determined by software
- (what for? Write to me if it's necessary!).
-
-$fc1-$fff mirror of $fc0
-
-$1000-$ffff Buddha-Rom with offset $1000 in the rom
- chip. The addresses $0 to $fff of the rom
- chip cannot be read. Rom is Byte-wide and
- mapped to even addresses.
-
-The IDE ports issue an INT2. You can read the level of the
-IRQ-lines of the IDE-ports by reading from the three (two
-for Buddha-only) registers $f00, $f40 and $f80. This way
-more than one I/O request can be handled and you can easily
-determine what driver has to serve the INT2. Buddha and
-Catweasel expansion boards can issue an INT6. A seperate
-memory map is available for the I/O module and the sysop's
-I/O module.
-
-The IDE ports are fed by the address lines A2 to A4, just as
-the Amiga 1200 and Amiga 4000 IDE ports are. This way
-existing drivers can be easily ported to Buddha. A move.l
-polls two words out of the same address of IDE port since
-every word is mirrored once. movem is not possible, but
-it's not necessary either, because you can only speedup
-68000 systems with this technique. A 68020 system with
-fastmem is faster with move.l.
-
-If you're using the mirrored registers of the IDE-ports with
-A6=1, the Buddha doesn't care about the speed that you have
-selected in the speed register (see further down). With
-A6=1 (for example $840 for port 0, register set 0), a 780ns
-access is being made. These registers should be used for a
-command access to the harddisk/CD-Rom, since command
-accesses are Byte-wide and have to be made slower according
-to the ATA-X3T9 manual.
-
-Now for the speed-register: The register is byte-wide, and
-only the upper three bits are used (Bits 7 to 5). Bit 4
-must always be set to 1 to be compatible with later Buddha
-versions (if I'll ever update this one). I presume that
-I'll never use the lower four bits, but they have to be set
-to 1 by definition.
- The values in this table have to be shifted 5 bits to the
-left and or'd with $1f (this sets the lower 5 bits).
-
-All the timings have in common: Select and IOR/IOW rise at
-the same time. IOR and IOW have a propagation delay of
-about 30ns to the clocks on the Zorro bus, that's why the
-values are no multiple of 71. One clock-cycle is 71ns long
-(exactly 70,5 at 14,18 Mhz on PAL systems).
-
-value 0 (Default after reset)
-
-497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles)
-(same timing as the Amiga 1200 does on it's IDE port without
-accelerator card)
-
-value 1
-
-639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles)
-
-value 2
-
-781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles)
-
-value 3
-
-355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
-
-value 4
-
-355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles)
-
-value 5
-
-355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles)
-
-value 6
-
-1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles)
-
-value 7
-
-355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle)
-
-When accessing IDE registers with A6=1 (for example $84x),
-the timing will always be mode 0 8-bit compatible, no matter
-what you have selected in the speed register:
-
-781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive.
-
-All the timings with a very short select-signal (the 355ns
-fast accesses) depend on the accelerator card used in the
-system: Sometimes two more clock cycles are inserted by the
-bus interface, making the whole access 497ns long. This
-doesn't affect the reliability of the controller nor the
-performance of the card, since this doesn't happen very
-often.
-
-All the timings are calculated and only confirmed by
-measurements that allowed me to count the clock cycles. If
-the system is clocked by an oscillator other than 28,37516
-Mhz (for example the NTSC-frequency 28,63636 Mhz), each
-clock cycle is shortened to a bit less than 70ns (not worth
-mentioning). You could think of a small performance boost
-by overclocking the system, but you would either need a
-multisync monitor, or a graphics card, and your internal
-diskdrive would go crazy, that's why you shouldn't tune your
-Amiga this way.
-
-Giving you the possibility to write software that is
-compatible with both the Buddha and the Catweasel Z-II, The
-Buddha acts just like a Catweasel Z-II with no device
-connected to the third IDE-port. The IRQ-register $f80
-always shows a "no IRQ here" on the Buddha, and accesses to
-the third IDE port are going into data's Nirwana on the
-Buddha.
-
- Jens Schönfeld february 19th, 1997
- updated may 27th, 1997
- eMail: sysop@nostlgic.tng.oche.de
-
diff --git a/drivers/block/README.fd b/drivers/block/README.fd
deleted file mode 100644
index 38f0b85a5..000000000
--- a/drivers/block/README.fd
+++ /dev/null
@@ -1,222 +0,0 @@
-This Readme file describes the floppy driver.
-
-FAQ list:
-=========
-
- A FAQ list may be found in the fdutils package (see below), and also
-at http://fdutils.linux.lu/FAQ.html
-
-
-LILO configuration options (Thinkpad users, read this)
-======================================================
-
- The floppy driver is configured using the 'floppy=' option in
-lilo. This option can be typed at the boot prompt, or entered in the
-lilo configuration file.
- Example: If your kernel is called linux-2.2.13, type the following line
-at the lilo boot prompt (if you have a thinkpad):
- linux-2.2.13 floppy=thinkpad
-You may also enter the following line in /etc/lilo.conf, in the description
-of linux-2.2.13:
- append = "floppy=thinkpad"
-
- Several floppy related options may be given, example:
- linux-2.2.13 floppy=daring floppy=two_fdc
- append = "floppy=daring floppy=two_fdc"
-
- If you give options both in the lilo config file and on the boot
-prompt, the option strings of both places are concatenated, the boot
-prompt options coming last. That's why there are also options to
-restore the default behavior.
-
- If you use the floppy driver as a module, use the following syntax:
- insmod floppy <options>
-
-Example:
- insmod floppy daring two_fdc
-
- Some versions of insmod are buggy in one way or another. If you have
-any problems (options not being passed correctly, segfaults during
-insmod), first check whether there is a more recent version.
-
- The floppy related options include:
-
- floppy=asus_pci
- Sets the bit mask to allow only units 0 and 1. (default)
-
- floppy=daring
- Tells the floppy driver that you have a well behaved floppy controller.
- This allows more efficient and smoother operation, but may fail on
- certain controllers. This may speed up certain operations.
-
- floppy=0,daring
- Tells the floppy driver that your floppy controller should be used
- with caution.
-
- floppy=one_fdc
- Tells the floppy driver that you have only one floppy controller.
- (default)
-
- floppy=two_fdc
- floppy=<address>,two_fdc
- Tells the floppy driver that you have two floppy controllers.
- The second floppy controller is assumed to be at <address>.
- This option is not needed if the second controller is at address
- 0x370, and if you use the 'cmos' option.
-
- floppy=thinkpad
- Tells the floppy driver that you have a Thinkpad. Thinkpads use an
- inverted convention for the disk change line.
-
- floppy=0,thinkpad
- Tells the floppy driver that you don't have a Thinkpad.
-
- floppy=omnibook
- floppy=nodma
- Tells the floppy driver not to use Dma for data transfers.
- This is needed on HP Omnibooks, which don't have a workable
- DMA channel for the floppy driver. This option is also useful
- if you frequently get "Unable to allocate DMA memory" messages.
- Indeed, dma memory needs to be continuous in physical memory,
- and is thus harder to find, whereas non-dma buffers may be
- allocated in virtual memory. However, I advise against this if
- you have an FDC without a FIFO (8272A or 82072). 82072A and
- later are OK. You also need at least a 486 to use nodma.
- If you use nodma mode, I suggest you also set the FIFO
- threshold to 10 or lower, in order to limit the number of data
- transfer interrupts.
-
- If you have a FIFO-able FDC, the floppy driver automatically
- falls back on non DMA mode if no DMA-able memory can be found.
- If you want to avoid this, explicitely ask for 'yesdma'.
-
- floppy=yesdma
- Tells the floppy driver that a workable DMA channel is available.
- (default)
-
- floppy=nofifo
- Disables the FIFO entirely. This is needed if you get "Bus
- master arbitration error" messages from your Ethernet card (or
- from other devices) while accessing the floppy.
-
- floppy=fifo
- Enables the FIFO. (default)
-
- floppy=<threshold>,fifo_depth
- Sets the FIFO threshold. This is mostly relevant in DMA
- mode. If this is higher, the floppy driver tolerates more
- interrupt latency, but it triggers more interrupts (i.e. it
- imposes more load on the rest of the system). If this is
- lower, the interrupt latency should be lower too (faster
- processor). The benefit of a lower threshold is less
- interrupts.
- To tune the fifo threshold, switch on over/underrun messages
- using 'floppycontrol --messages'. Then access a floppy
- disk. If you get a huge amount of "Over/Underrun - retrying"
- messages, then the fifo threshold is too low. Try with a
- higher value, until you only get an occasional Over/Underrun.
- It is a good idea to compile the floppy driver as a module
- when doing this tuning. Indeed, it allows to try different
- fifo values without rebooting the machine for each test. Note
- that you need to do 'floppycontrol --messages' every time you
- re-insert the module.
- Usually, tuning the fifo threshold should not be needed, as
- the default (0xa) is reasonable.
-
- floppy=<drive>,<type>,cmos
- Sets the CMOS type of <drive> to <type>. This is mandatory if
- you have more than two floppy drives (only two can be
- described in the physical CMOS), or if your BIOS uses
- non-standard CMOS types. The CMOS types are:
- 0 - Use the value of the physical CMOS
- 1 - 5 1/4 DD
- 2 - 5 1/4 HD
- 3 - 3 1/2 DD
- 4 - 3 1/2 HD
- 5 - 3 1/2 ED
- 6 - 3 1/2 ED
- 16 - unknown or not installed
- (Note: there are two valid types for ED drives. This is because 5 was
- initially chosen to represent floppy *tapes*, and 6 for ED drives.
- AMI ignored this, and used 5 for ED drives. That's why the floppy
- driver handles both.)
-
- floppy=unexpected_interrupts
- Print a warning message when an unexpected interrupt is received.
- (default)
-
- floppy=no_unexpected_interrupts
- floppy=L40SX
- Don't print a message when an unexpected interrupt is received. This
- is needed on IBM L40SX laptops in certain video modes. (There seems
- to be an interaction between video and floppy. The unexpected
- interrupts affect only performance, and can be safely ignored.)
-
- floppy=broken_dcl
- Don't use the disk change line, but assume that the disk was
- changed whenever the device node is reopened. Needed on some
- boxes where the disk change line is broken or unsupported.
- This should be regarded as a stopgap measure, indeed it makes
- floppy operation less efficient due to unneeded cache
- flushings, and slightly more unreliable. Please verify your
- cable, connection and jumper settings if you have any DCL
- problems. However, some older drives, and also some laptops
- are known not to have a DCL.
-
- floppy=debug
- Print debugging messages.
-
- floppy=messages
- Print informational messages for some operations (disk change
- notifications, warnings about over and underruns, and about
- autodetection).
-
- floppy=silent_dcl_clear
- Uses a less noisy way to clear the disk change line (which
- doesn't involve seeks). Implied by 'daring' option.
-
- floppy=<nr>,irq
- Sets the floppy IRQ to <nr> instead of 6.
-
- floppy=<nr>,dma
- Sets the floppy DMA channel to <nr> instead of 2.
-
- floppy=slow
- Use PS/2 stepping rate:
- " PS/2 floppies have much slower step rates than regular floppies.
- It's been recommended that take about 1/4 of the default speed
- in some more extreme cases."
-
-
-
-Supporting utilities and additional documentation:
-==================================================
-
- Additional parameters of the floppy driver can be configured at
-runtime. Utilities which do this can be found in the fdutils package.
-This package also contains a new version of mtools which allows to
-access high capacity disks (up to 1992K on a high density 3 1/2 disk!).
-It also contains additional documentation about the floppy driver.
-
-The latest version can be found at fdutils homepage:
- http://fdutils.linux.lu
-
-The fdutils-5.3 release can be found at:
- http://fdutils.linux.lu/fdutils-5.3.src.tar.gz
- http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz
- ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz
- ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz
-
-Reporting problems about the floppy driver
-==========================================
-
- If you have a question or a bug report about the floppy driver, mail
-me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use
-comp.os.linux.hardware. As the volume in these groups is rather high,
-be sure to include the word "floppy" (or "FLOPPY") in the subject
-line. If the reported problem happens when mounting floppy disks, be
-sure to mention also the type of the filesystem in the subject line.
-
- Be sure to read the FAQ before mailing/posting any bug reports!
-
- Alain
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/ac97_codec.h b/drivers/sound/ac97_codec.h
deleted file mode 100644
index a614edbdb..000000000
--- a/drivers/sound/ac97_codec.h
+++ /dev/null
@@ -1,161 +0,0 @@
-#ifndef _AC97_CODEC_H_
-#define _AC97_CODEC_H_
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-/* AC97 1.0 */
-#define AC97_RESET 0x0000 //
-#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out
-#define AC97_HEADPHONE_VOL 0x0004 //
-#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output
-#define AC97_MASTER_TONE 0x0008 //
-#define AC97_PCBEEP_VOL 0x000a // none
-#define AC97_PHONE_VOL 0x000c // TAD Input (mono)
-#define AC97_MIC_VOL 0x000e // MIC Input (mono)
-#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo)
-#define AC97_CD_VOL 0x0012 // CD Input (stereo)
-#define AC97_VIDEO_VOL 0x0014 // none
-#define AC97_AUX_VOL 0x0016 // Aux Input (stereo)
-#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo)
-#define AC97_RECORD_SELECT 0x001a //
-#define AC97_RECORD_GAIN 0x001c
-#define AC97_RECORD_GAIN_MIC 0x001e
-#define AC97_GENERAL_PURPOSE 0x0020
-#define AC97_3D_CONTROL 0x0022
-#define AC97_MODEM_RATE 0x0024
-#define AC97_POWER_CONTROL 0x0026
-
-/* AC'97 2.0 */
-#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */
-#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */
-#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */
-#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */
-#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_DAC_RATE 0x0032 /* PCM LR DAC Rate */
-#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */
-#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */
-#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */
-#define AC97_RESERVED_3A 0x003A /* Reserved */
-
-/* range 0x3c-0x58 - MODEM */
-
-/* registers 0x005a - 0x007a are vendor reserved */
-
-#define AC97_VENDOR_ID1 0x007c
-#define AC97_VENDOR_ID2 0x007e
-
-/* volume control bit defines */
-#define AC97_MUTE 0x8000
-#define AC97_MICBOOST 0x0040
-#define AC97_LEFTVOL 0x3f00
-#define AC97_RIGHTVOL 0x003f
-
-/* record mux defines */
-#define AC97_RECMUX_MIC 0x0000
-#define AC97_RECMUX_CD 0x0101
-#define AC97_RECMUX_VIDEO 0x0202 /* not used */
-#define AC97_RECMUX_AUX 0x0303
-#define AC97_RECMUX_LINE 0x0404
-#define AC97_RECMUX_STEREO_MIX 0x0505
-#define AC97_RECMUX_MONO_MIX 0x0606
-#define AC97_RECMUX_PHONE 0x0707
-
-
-/* general purpose register bit defines */
-#define AC97_GP_LPBK 0x0080 /* Loopback mode */
-#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */
-#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */
-#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */
-#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */
-#define AC97_GP_LD 0x1000 /* Loudness 1=on */
-#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */
-#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */
-#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
-
-
-/* powerdown control and status bit defines */
-
-/* status */
-#define AC97_PWR_MDM 0x0010 /* Modem section ready */
-#define AC97_PWR_REF 0x0008 /* Vref nominal */
-#define AC97_PWR_ANL 0x0004 /* Analog section ready */
-#define AC97_PWR_DAC 0x0002 /* DAC section ready */
-#define AC97_PWR_ADC 0x0001 /* ADC section ready */
-
-/* control */
-#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */
-#define AC97_PWR_PR1 0x0200 /* DAC powerdown */
-#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */
-#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */
-#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */
-#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */
-#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */
-#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */
-
-/* useful power states */
-#define AC97_PWR_D0 0x0000 /* everything on */
-#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
-#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */
-
-/* Total number of defined registers. */
-#define AC97_REG_CNT 64
-
-
-/* OSS interface to the ac97s.. */
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
- SOUND_MASK_LINE|SOUND_MASK_CD|\
- SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\
- SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
- SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
- SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
- SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD|SOUND_MASK_VIDEO|\
- SOUND_MASK_LINE1| SOUND_MASK_LINE|\
- SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
-
-struct ac97_codec {
- /* AC97 controller connected with */
- void *private_data;
-
- char *name;
- int id;
- int dev_mixer;
-
- /* codec specific init/reset routines, used mainly for 4 or 6 channel support */
- int (*codec_init) (struct ac97_codec *codec);
-
- /* controller specific lower leverl ac97 accessing routines */
- u16 (*codec_read) (struct ac97_codec *codec, u8 reg);
- void (*codec_write) (struct ac97_codec *codec, u8 reg, u16 val);
-
- /* OSS mixer masks */
- int modcnt;
- int supported_mixers;
- int stereo_mixers;
- int record_sources;
-
- /* OSS mixer interface */
- int (*read_mixer) (struct ac97_codec *codec, int oss_channel);
- void (*write_mixer)(struct ac97_codec *codec, int oss_channel,
- unsigned int left, unsigned int right);
- int (*recmask_io) (struct ac97_codec *codec, int rw, int mask);
- int (*mixer_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
-
- /* saved OSS mixer states */
- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
-};
-
-extern int ac97_read_proc (char *page_out, char **start, off_t off,
- int count, int *eof, void *data);
-extern int ac97_probe_codec(struct ac97_codec *);
-
-#endif /* _AC97_CODEC_H_ */
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;