summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
commit1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch)
tree357efc7b93f8f5102110d20d293f41360ec212fc /drivers
parentaea27b2e18d69af87e673972246e66657b4fa274 (diff)
Merge with Linux 2.3.21.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile9
-rw-r--r--drivers/acorn/block/Config.in10
-rw-r--r--drivers/acorn/scsi/Config.in24
-rw-r--r--drivers/atm/Config.in74
-rw-r--r--drivers/block/Config.in330
-rw-r--r--drivers/block/Makefile8
-rw-r--r--drivers/block/cmos-probe.c78
-rw-r--r--drivers/block/cpqarray.c4
-rw-r--r--drivers/block/ide-disk.c144
-rw-r--r--drivers/block/ide-dma.c12
-rw-r--r--drivers/block/ide-floppy.c2
-rw-r--r--drivers/block/ide-geometry.c225
-rw-r--r--drivers/block/ide-pci.c2
-rw-r--r--drivers/block/ide-pmac.c121
-rw-r--r--drivers/block/ide.c146
-rw-r--r--drivers/block/pdc202xx.c10
-rw-r--r--drivers/char/adbmouse.c2
-rw-r--r--drivers/char/busmouse.c7
-rw-r--r--drivers/char/console.c2
-rw-r--r--drivers/char/defkeymap.c3
-rw-r--r--drivers/char/dn_keyb.c2
-rw-r--r--drivers/char/drm/fops.c2
-rw-r--r--drivers/char/ftape/Config.in26
-rw-r--r--drivers/char/joystick/Config.in22
-rw-r--r--drivers/char/keyboard.c1
-rw-r--r--drivers/char/mem.c13
-rw-r--r--drivers/char/misc.c6
-rw-r--r--drivers/char/n_hdlc.c97
-rw-r--r--drivers/char/n_tty.c5
-rw-r--r--drivers/char/pc110pad.c19
-rw-r--r--drivers/char/pc_keyb.c32
-rw-r--r--drivers/char/pms.c29
-rw-r--r--drivers/char/ppdev.c36
-rw-r--r--drivers/char/ppdev.h7
-rw-r--r--drivers/char/qpmouse.c2
-rw-r--r--drivers/char/tty_io.c60
-rw-r--r--drivers/fc4/Config.in32
-rw-r--r--drivers/macintosh/Makefile40
-rw-r--r--drivers/macintosh/adb.c144
-rw-r--r--drivers/macintosh/mac_keyb.c40
-rw-r--r--drivers/macintosh/macio-adb.c39
-rw-r--r--drivers/macintosh/macserial.c53
-rw-r--r--drivers/macintosh/macserial.h1
-rw-r--r--drivers/macintosh/mediabay.c102
-rw-r--r--drivers/macintosh/via-cuda.c149
-rw-r--r--drivers/macintosh/via-pmu.c668
-rw-r--r--drivers/misc/Config.in9
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/acpi.c219
-rw-r--r--drivers/misc/piix4_acpi.c214
-rw-r--r--drivers/net/Config.in398
-rw-r--r--drivers/net/Makefile229
-rw-r--r--drivers/net/Space.c45
-rw-r--r--drivers/net/arcnet.c2
-rw-r--r--drivers/net/ncr885_debug.h54
-rw-r--r--drivers/net/ncr885e.c1458
-rw-r--r--drivers/net/ncr885e.h367
-rw-r--r--drivers/net/pcmcia/ray_cs.c372
-rw-r--r--drivers/net/pcmcia/ray_cs.h9
-rw-r--r--drivers/net/pcmcia/rayctl.h19
-rw-r--r--drivers/net/sgiseeq.c30
-rw-r--r--drivers/net/sgiseeq.h24
-rw-r--r--drivers/net/sk_mca.c1
-rw-r--r--drivers/net/tokenring/.cvsignore2
-rw-r--r--drivers/net/tokenring/Config.in15
-rw-r--r--drivers/net/tokenring/Makefile51
-rw-r--r--drivers/net/tokenring/ibmtr.c (renamed from drivers/net/ibmtr.c)48
-rw-r--r--drivers/net/tokenring/ibmtr.h (renamed from drivers/net/ibmtr.h)2
-rw-r--r--drivers/net/tokenring/olympic.c (renamed from drivers/net/olympic.c)0
-rw-r--r--drivers/net/tokenring/olympic.h (renamed from drivers/net/olympic.h)0
-rw-r--r--drivers/net/tokenring/sktr.c (renamed from drivers/net/sktr.c)168
-rw-r--r--drivers/net/tokenring/sktr.h (renamed from drivers/net/sktr.h)7
-rw-r--r--drivers/net/tokenring/sktr_firmware.h (renamed from drivers/net/sktr_firmware.h)0
-rw-r--r--drivers/net/wan/.cvsignore2
-rw-r--r--drivers/net/wan/Config.in64
-rw-r--r--drivers/net/wan/Makefile181
-rw-r--r--drivers/net/wan/cosa.c (renamed from drivers/net/cosa.c)0
-rw-r--r--drivers/net/wan/cosa.h (renamed from drivers/net/cosa.h)0
-rw-r--r--drivers/net/wan/cycx_drv.c (renamed from drivers/net/cycx_drv.c)0
-rw-r--r--drivers/net/wan/cycx_main.c (renamed from drivers/net/cycx_main.c)0
-rw-r--r--drivers/net/wan/cycx_x25.c (renamed from drivers/net/cycx_x25.c)0
-rw-r--r--drivers/net/wan/dlci.c (renamed from drivers/net/dlci.c)0
-rw-r--r--drivers/net/wan/hostess_sv11.c (renamed from drivers/net/hostess_sv11.c)2
-rw-r--r--drivers/net/wan/lapbether.c (renamed from drivers/net/lapbether.c)0
-rw-r--r--drivers/net/wan/sbni.c1533
-rw-r--r--drivers/net/wan/sbni.h194
-rw-r--r--drivers/net/wan/sdla.c (renamed from drivers/net/sdla.c)0
-rw-r--r--drivers/net/wan/sdla_fr.c (renamed from drivers/net/sdla_fr.c)0
-rw-r--r--drivers/net/wan/sdla_ppp.c (renamed from drivers/net/sdla_ppp.c)0
-rw-r--r--drivers/net/wan/sdla_x25.c (renamed from drivers/net/sdla_x25.c)0
-rw-r--r--drivers/net/wan/sdladrv.c (renamed from drivers/net/sdladrv.c)1
-rw-r--r--drivers/net/wan/sdlamain.c (renamed from drivers/net/sdlamain.c)1
-rw-r--r--drivers/net/wan/sealevel.c (renamed from drivers/net/sealevel.c)2
-rw-r--r--drivers/net/wan/syncppp.c (renamed from drivers/net/syncppp.c)0
-rw-r--r--drivers/net/wan/syncppp.h (renamed from drivers/net/syncppp.h)0
-rw-r--r--drivers/net/wan/x25_asy.c (renamed from drivers/net/x25_asy.c)0
-rw-r--r--drivers/net/wan/x25_asy.h (renamed from drivers/net/x25_asy.h)0
-rw-r--r--drivers/net/wan/z85230.c (renamed from drivers/net/z85230.c)0
-rw-r--r--drivers/net/wan/z85230.h (renamed from drivers/net/z85230.h)0
-rw-r--r--drivers/parport/ieee1284.c39
-rw-r--r--drivers/parport/ieee1284_ops.c15
-rw-r--r--drivers/parport/init.c4
-rw-r--r--drivers/parport/parport_pc.c137
-rw-r--r--drivers/parport/share.c8
-rw-r--r--drivers/pci/Makefile6
-rw-r--r--drivers/pci/devlist.h4
-rw-r--r--drivers/pci/helper.c69
-rw-r--r--drivers/pci/pci.c93
-rw-r--r--drivers/pci/quirks.c4
-rw-r--r--drivers/pci/setup.c10
-rw-r--r--drivers/pnp/Config.in2
-rw-r--r--drivers/sbus/char/pcikbd.c2
-rw-r--r--drivers/sbus/char/sunkbd.c2
-rw-r--r--drivers/sbus/char/sunmouse.c4
-rw-r--r--drivers/sbus/char/uctrl.c2
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx30
-rw-r--r--drivers/scsi/ChangeLog.sym53c8xx129
-rw-r--r--drivers/scsi/Makefile19
-rw-r--r--drivers/scsi/README.aic7xxx24
-rw-r--r--drivers/scsi/README.ncr53c8xx416
-rw-r--r--drivers/scsi/aic7xxx.c272
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/imm.c9
-rw-r--r--drivers/scsi/ncr53c8xx.c412
-rw-r--r--drivers/scsi/scsi_ioctl.c66
-rw-r--r--drivers/scsi/sg.c121
-rw-r--r--drivers/scsi/sim710.c1605
-rw-r--r--drivers/scsi/sim710.h845
-rw-r--r--drivers/scsi/sim710.scr554
-rw-r--r--drivers/scsi/sim710_d.h2360
-rw-r--r--drivers/scsi/sim710_u.h67
-rw-r--r--drivers/scsi/sym53c8xx.c4503
-rw-r--r--drivers/scsi/sym53c8xx.h2
-rw-r--r--drivers/scsi/sym53c8xx_defs.h401
-rw-r--r--drivers/sgi/char/shmiq.c4
-rw-r--r--drivers/sound/esssolo1.c29
-rw-r--r--drivers/usb/Config.in58
-rw-r--r--drivers/usb/Makefile9
-rw-r--r--drivers/usb/README.ohci12
-rw-r--r--drivers/usb/README.serial35
-rw-r--r--drivers/usb/acm.c235
-rw-r--r--drivers/usb/audio.c3522
-rw-r--r--drivers/usb/audio.h116
-rw-r--r--drivers/usb/cpia.c1216
-rw-r--r--drivers/usb/cpia.h90
-rw-r--r--drivers/usb/ezusb.c157
-rw-r--r--drivers/usb/ezusb.h25
-rw-r--r--drivers/usb/hp_scanner.c4
-rw-r--r--drivers/usb/hub.c10
-rw-r--r--drivers/usb/inits.h3
-rw-r--r--drivers/usb/keyboard.c2
-rw-r--r--drivers/usb/keymap.c4
-rw-r--r--drivers/usb/maps/usb.map16
-rw-r--r--drivers/usb/mouse.c2
-rw-r--r--drivers/usb/ohci-debug.c5
-rw-r--r--drivers/usb/ohci-hcd.c10
-rw-r--r--drivers/usb/ohci-hcd.h2
-rw-r--r--drivers/usb/ohci.c350
-rw-r--r--drivers/usb/ohci.h43
-rw-r--r--drivers/usb/printer.c21
-rw-r--r--drivers/usb/proc_usb.c234
-rw-r--r--drivers/usb/serial.c691
-rw-r--r--drivers/usb/uhci.c71
-rw-r--r--drivers/usb/uhci.h4
-rw-r--r--drivers/usb/usb-core.c18
-rw-r--r--drivers/usb/usb.c119
-rw-r--r--drivers/usb/usb.h50
-rw-r--r--drivers/usb/usb_scsi.c24
-rw-r--r--drivers/usb/usb_scsi_debug.c1
-rw-r--r--drivers/usb/uss720.c25
-rw-r--r--drivers/video/Config.in656
-rw-r--r--drivers/video/Makefile8
-rw-r--r--drivers/video/amifb.c1
-rw-r--r--drivers/video/aty.h13
-rw-r--r--drivers/video/atyfb.c216
-rw-r--r--drivers/video/chipsfb.c40
-rw-r--r--drivers/video/controlfb.c50
-rw-r--r--drivers/video/fbcon-afb.c10
-rw-r--r--drivers/video/fbcon-cfb16.c75
-rw-r--r--drivers/video/fbcon-cfb2.c24
-rw-r--r--drivers/video/fbcon-cfb24.c45
-rw-r--r--drivers/video/fbcon-cfb32.c114
-rw-r--r--drivers/video/fbcon-cfb4.c24
-rw-r--r--drivers/video/fbcon-cfb8.c44
-rw-r--r--drivers/video/fbcon-ilbm.c10
-rw-r--r--drivers/video/fbcon-iplan2p2.c8
-rw-r--r--drivers/video/fbcon-iplan2p4.c8
-rw-r--r--drivers/video/fbcon-iplan2p8.c2
-rw-r--r--drivers/video/fbcon-mac.c12
-rw-r--r--drivers/video/fbcon-mfb.c30
-rw-r--r--drivers/video/fbcon.c54
-rw-r--r--drivers/video/fbmem.c10
-rw-r--r--drivers/video/imsttfb.c31
-rw-r--r--drivers/video/modedb.c2
-rw-r--r--drivers/video/platinumfb.c147
-rw-r--r--drivers/video/sbusfb.c6
-rw-r--r--drivers/video/tdfxfb.c1891
-rw-r--r--drivers/video/valkyriefb.c8
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/vga_font.c1
-rw-r--r--drivers/video/virgefb.c2
201 files changed, 25414 insertions, 6157 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 1a74fa394..b31d2beb4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -11,7 +11,7 @@ SUB_DIRS := block char net parport sound misc
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
macintosh video dio zorro fc4 usb \
- nubus tc ap1000 atm
+ nubus tc ap1000 atm pcmcia
ifdef CONFIG_DIO
SUB_DIRS += dio
@@ -22,8 +22,12 @@ ifdef CONFIG_PCI
SUB_DIRS += pci
endif
-ifdef CONFIG_PCMCIA
+ifeq ($(CONFIG_PCMCIA),y)
SUB_DIRS += pcmcia
+else
+ ifeq ($(CONFIG_PCMCIA),m)
+ MOD_SUB_DIRS += pcmcia
+ endif
endif
ifdef CONFIG_SBUS
@@ -117,7 +121,6 @@ endif
ifeq ($(CONFIG_AP1000),y)
SUB_DIRS += ap1000
-ALL_SUB_DIRS += ap1000
endif
ifeq ($(CONFIG_FC4),y)
diff --git a/drivers/acorn/block/Config.in b/drivers/acorn/block/Config.in
index 6ed6cf6a3..be2d2432f 100644
--- a/drivers/acorn/block/Config.in
+++ b/drivers/acorn/block/Config.in
@@ -5,11 +5,11 @@ mainmenu_option next_comment
comment 'Acorn-specific block devices'
if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
- tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
- tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
- if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
- bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
- fi
+ tristate 'Old Archimedes floppy (1772) support' CONFIG_BLK_DEV_FD1772
+ tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM
+ if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then
+ bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT
+ fi
fi
endmenu
diff --git a/drivers/acorn/scsi/Config.in b/drivers/acorn/scsi/Config.in
index 68d4f920b..28030bc32 100644
--- a/drivers/acorn/scsi/Config.in
+++ b/drivers/acorn/scsi/Config.in
@@ -3,21 +3,21 @@
#
dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 $CONFIG_SCSI
if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then
- bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
- bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
+ bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+ bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'ARXE SCSI support (Experimental)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
- dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
- dep_tristate 'EESOX support (Experimental)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
- dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
+ dep_tristate 'ARXE SCSI support (EXPERIMENTAL)' CONFIG_SCSI_ARXESCSI $CONFIG_SCSI
+ dep_tristate 'CumanaSCSI II support (EXPERIMENTAL)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI
+ dep_tristate 'EESOX support (EXPERIMENTAL)' CONFIG_SCSI_EESOXSCSI $CONFIG_SCSI
+ dep_tristate 'PowerTec support (EXPERIMENTAL)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI
- comment 'The following drivers are not fully supported'
+ comment 'The following drivers are not fully supported'
- dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
- if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
- dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
- fi
- dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
+ dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI
+ if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then
+ dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI
+ fi
+ dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI
fi
diff --git a/drivers/atm/Config.in b/drivers/atm/Config.in
index af401ed29..c0112f839 100644
--- a/drivers/atm/Config.in
+++ b/drivers/atm/Config.in
@@ -4,44 +4,44 @@
mainmenu_option next_comment
comment 'ATM drivers'
if [ "$CONFIG_INET" = "y" ]; then
- tristate 'ATM over TCP' CONFIG_ATM_TCP y
+ tristate 'ATM over TCP' CONFIG_ATM_TCP
fi
if [ "$CONFIG_PCI" = "y" ]; then
- tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI y
- if [ ! "$CONFIG_ATM_ENI" = "n" ]; then
- bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG n
- bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST n
- if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then
- bool ' Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W n
- bool ' Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W y
- bool ' Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W n
- bool ' Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W n
- bool ' Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W n
- bool ' Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W n
- bool ' Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W y
- bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W n
- fi
- fi
- tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM y
- if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then
- bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG n
- bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS y
- fi
-# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y
-# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
-# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
-# fi
- tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR
- if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
- bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI
- fi
- tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
- if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
- bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
- fi
- tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON y
- if [ "$CONFIG_ATM_HORIZON" != "n" ]; then
- bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
- fi
+ tristate 'Efficient Networks ENI155P' CONFIG_ATM_ENI
+ if [ ! "$CONFIG_ATM_ENI" = "n" ]; then
+ bool ' Enable extended debugging' CONFIG_ATM_ENI_DEBUG
+ bool ' Fine-tune burst settings' CONFIG_ATM_ENI_TUNE_BURST
+ if [ "$CONFIG_ATM_ENI_TUNE_BURST" = "y" ]; then
+ bool ' Enable 16W TX bursts (discouraged)' CONFIG_ATM_ENI_BURST_TX_16W
+ bool ' Enable 8W TX bursts (recommended)' CONFIG_ATM_ENI_BURST_TX_8W
+ bool ' Enable 4W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_4W
+ bool ' Enable 2W TX bursts (optional)' CONFIG_ATM_ENI_BURST_TX_2W
+ bool ' Enable 16W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_16W
+ bool ' Enable 8W RX bursts (discouraged)' CONFIG_ATM_ENI_BURST_RX_8W
+ bool ' Enable 4W RX bursts (recommended)' CONFIG_ATM_ENI_BURST_RX_4W
+ bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W
+ fi
+ fi
+ tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM
+ if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then
+ bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG
+ bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS
+ fi
+# bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y
+# if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then
+# bool ' Enable extended debugging' CONFIG_ATM_TNETA1570_DEBUG n
+# fi
+ tristate 'IDT 77201 (NICStAR)' CONFIG_ATM_NICSTAR
+ if [ "$CONFIG_ATM_NICSTAR" != "n" ]; then
+ bool ' Use suni PHY driver' CONFIG_ATM_NICSTAR_USE_SUNI
+ fi
+ tristate 'Madge Ambassador (Collage PCI 155 Server)' CONFIG_ATM_AMBASSADOR
+ if [ "$CONFIG_ATM_AMBASSADOR" != "n" ]; then
+ bool ' Enable debugging messages' CONFIG_ATM_AMBASSADOR_DEBUG
+ fi
+ tristate 'Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)' CONFIG_ATM_HORIZON
+ if [ "$CONFIG_ATM_HORIZON" != "n" ]; then
+ bool ' Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
+ fi
fi
endmenu
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 7c00c4dd2..c23b8d094 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -6,198 +6,200 @@ comment 'Block devices'
tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
if [ "$CONFIG_AMIGA" = "y" ]; then
- tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
+ tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
fi
if [ "$CONFIG_ATARI" = "y" ]; then
- tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
+ tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
fi
if [ "$CONFIG_MAC" = "y" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
- fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
+ fi
fi
tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
comment 'Please see Documentation/ide.txt for help/info on IDE drives'
if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then
- bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
+ bool 'Old hard disk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY
else
- bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
- dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
- if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
- bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
- fi
- dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
- if [ "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
- bool ' Include CD-Changer Reporting' CONFIG_IDECD_SLOTS
- fi
- dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
- dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
- dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
- if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
- bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
- if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
- bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
- fi
- if [ "$CONFIG_PCI" = "y" ]; then
- 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 ' 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
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' IDEDMA_NEW_DRIVE_LISTINGS
- define_bool IDEDMA_PCI_EXPERIMENTAL y
- else
- define_bool IDEDMA_PCI_EXPERIMENTAL n
- fi
- fi
- bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
- bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
- if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
- fi
- bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
- bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
- fi
- bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X
- if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then
- bool ' HPT34X DMA support (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
- fi
- bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
- if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
- bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
- fi
- fi
- if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
- fi
- if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
- bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
- if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
- "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
- bool ' Special UDMA Feature (EXPERIMENTAL)' PDC202XX_FORCE_BURST_BIT
- bool ' Special Mode Feature (DANGEROUS)' PDC202XX_FORCE_MASTER_MODE
- fi
- fi
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
- fi
- if [ "$IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
- bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
- if [ "$CONFIG_X86" = "y" ]; then
- bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
- fi
- fi
+ bool ' Use old disk-only driver on primary interface' CONFIG_BLK_DEV_HD_IDE
+ dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE
+ if [ "$CONFIG_BLK_DEV_IDEDISK" != "n" ]; then
+ bool ' Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE
+ fi
+ dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
+ dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE
+ dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
+ comment 'IDE chipset support/bugfixes'
+ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then
+ bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
+ if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then
+ bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED
fi
- if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
- bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+ if [ "$CONFIG_PCI" = "y" ]; then
+ 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 ' 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
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Good-Bad DMA Model-Firmware (EXPERIMENTAL)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+ define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL y
+ else
+ define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n
+ fi
+ 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" ]; then
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' ALI M15x3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
+ fi
+ bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646
+ bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693
+ fi
+ 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 (DANGEROUS)' CONFIG_BLK_DEV_HPT34X_DMA
+ fi
+ bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366
+ fi
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a \
+ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+ bool ' PIIXn Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TUNING
+ fi
+ fi
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+ bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+ fi
+ if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+ bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX
+ if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
+ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then
+ bool ' Special UDMA Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_BURST_BIT
+ bool ' Special Mode Feature (DANGEROUS)' CONFIG_PDC202XX_FORCE_MASTER_MODE
+ fi
+ fi
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513
+ fi
+ if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then
+ bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
+ fi
+ fi
+ fi
+ if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
+ bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+ fi
fi
- fi
- if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
- bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
- if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
- bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
- if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
- bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
- fi
- fi
- fi
- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE
- if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then
- bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS
- if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
- bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO
- fi
- fi
- bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE
- fi
- if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
- "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
- "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
- define_bool CONFIG_BLK_DEV_IDEDMA y
- if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
- "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
- "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
- define_bool CONFIG_IDEDMA_AUTO y
+ if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+ bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+ if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
+ bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
+ if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
+ bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
+ fi
+ fi
fi
- fi
- bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
- if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
- comment 'Note: most of these also require special kernel boot parameters'
- bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
- bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
- bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
- bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
- if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
- "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ bool ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE
+ if [ "$CONFIG_BLK_DEV_IDE_ICSIDE" = "y" ]; then
+ bool ' ICS DMA support' CONFIG_BLK_DEV_IDEDMA_ICS
+ if [ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+ bool ' Use ICS DMA by default' CONFIG_IDEDMA_ICS_AUTO
+ fi
+ fi
+ bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE
fi
- bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
- bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
- fi
- if [ "$CONFIG_AMIGA" = "y" ]; then
- bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
+ if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" -o \
+ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
+ "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
+ define_bool CONFIG_BLK_DEV_IDEDMA y
+ if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
+ "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
+ "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
+ define_bool CONFIG_IDEDMA_AUTO y
+ fi
fi
- fi
- if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA
- fi
- if [ "$CONFIG_ATARI" = "y" ]; then
- bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
- fi
- if [ "$CONFIG_MAC" = "y" ]; then
- bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
- fi
- fi
+ bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
+ if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
+ comment 'Note: most of these also require special kernel boot parameters'
+ bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+ bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+ bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+ bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+ if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a \
+ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+ fi
+ bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
+ bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE
+ fi
+ fi
+ if [ "$CONFIG_ZORRO" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Buddha/Catweasel IDE interface support (EXPERIMENTAL)' CONFIG_BLK_DEV_BUDDHA
+ fi
+ if [ "$CONFIG_ATARI" = "y" ]; then
+ bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE
+ fi
+ if [ "$CONFIG_MAC" = "y" ]; then
+ bool ' Macintosh Quadra/Powerbook IDE interface support' CONFIG_BLK_DEV_MAC_IDE
+ fi
+ fi
fi
if [ "$CONFIG_MCA" = "y" ]; then
- tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+ tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
fi
if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+ tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
fi
if [ "$CONFIG_ATARI" = "y" ]; then
- tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
- if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
- comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
- bool 'Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
- dep_tristate 'Atari SLM laser printer support' CONFIG_ATARI_SLM $CONFIG_ATARI_ACSI
- fi
-fi
-tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+ tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
+ if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+ comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
+ bool ' Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
+ tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM
+ fi
+fi
+if [ "$CONFIG_PCI" = "y" ]; then
+ tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
+fi
comment 'Additional Block Devices'
tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
if [ "$CONFIG_NET" = "y" ]; then
- tristate 'Network block device support' CONFIG_BLK_DEV_NBD
+ tristate 'Network block device support' CONFIG_BLK_DEV_NBD
fi
bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
- tristate ' Linear (append) mode' CONFIG_MD_LINEAR
- tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED
- tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
- tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+ tristate ' Linear (append) mode' CONFIG_MD_LINEAR
+ tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED
+ tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
+ tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5
fi
if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
- bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
+ bool ' Boot support (linear, striped)' CONFIG_MD_BOOT
fi
tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
- bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
+ bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
fi
tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
@@ -205,14 +207,14 @@ tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
# PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option
# controls the choices given to the user ...
-if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ] ; then
+if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ]; then
define_bool CONFIG_PARIDE_PARPORT y
else
define_bool CONFIG_PARIDE_PARPORT m
fi
dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT
if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
- source drivers/block/paride/Config.in
+ source drivers/block/paride/Config.in
fi
if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
@@ -226,15 +228,15 @@ if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
"$CONFIG_BLK_DEV_PIIX" = "y" -o \
"$CONFIG_BLK_DEV_SIS5513" = "y" -o \
"$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
- define_bool CONFIG_BLK_DEV_IDE_MODES y
+ define_bool CONFIG_BLK_DEV_IDE_MODES y
else
- define_bool CONFIG_BLK_DEV_IDE_MODES n
+ define_bool CONFIG_BLK_DEV_IDE_MODES n
fi
if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
- define_bool CONFIG_BLK_DEV_HD y
+ define_bool CONFIG_BLK_DEV_HD y
else
- define_bool CONFIG_BLK_DEV_HD n
+ define_bool CONFIG_BLK_DEV_HD n
fi
endmenu
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index abc2242dc..8519318d9 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -20,7 +20,7 @@ ALL_SUB_DIRS := $(SUB_DIRS) paride
L_TARGET := block.a
-L_OBJS := genhd.o cmos-probe.o
+L_OBJS := genhd.o ide-geometry.o
M_OBJS :=
MOD_LIST_NAME := BLOCK_MODULES
LX_OBJS := ll_rw_blk.o blkpg.o
@@ -248,7 +248,7 @@ ifeq ($(CONFIG_BLK_DEV_IDE),y)
else
ifeq ($(CONFIG_BLK_DEV_IDE),m)
MIX_OBJS += ide.o $(IDE_OBJS)
- M_OBJS += ide-mod.o ide-probe.o
+ M_OBJS += ide-mod.o ide-probe-mod.o
endif
endif
@@ -376,3 +376,7 @@ include $(TOPDIR)/Rules.make
ide-mod.o: ide.o $(IDE_OBJS)
$(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS)
+
+ide-probe-mod.o: ide-probe.o ide-geometry.o
+ $(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o
+
diff --git a/drivers/block/cmos-probe.c b/drivers/block/cmos-probe.c
deleted file mode 100644
index f0147d5e3..000000000
--- a/drivers/block/cmos-probe.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * linux/drivers/block/cmos-probe.c Version 1.00 August 16, 1999
- *
- * Copyright (C) 1994-1999 Linus Torvalds & authors (see below)
- */
-
-#undef REALLY_SLOW_IO /* most systems can safely undef this */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/malloc.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/*
- * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
- * controller that is BIOS compatible with ST-506, and thus showing up in our
- * BIOS table, but not register compatible, and therefore not present in CMOS.
- *
- * Furthermore, we will assume that our ST-506 drives <if any> are the primary
- * drives in the system -- the ones reflected as drive 1 or 2. The first
- * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
- * nibble. This will be either a 4 bit drive type or 0xf indicating use byte
- * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
- * means we have an AT controller hard disk for that drive.
- *
- * Of course, there is no guarantee that either drive is actually on the
- * "primary" IDE interface, but we don't bother trying to sort that out here.
- * If a drive is not actually on the primary interface, then these parameters
- * will be ignored. This results in the user having to supply the logical
- * drive geometry as a boot parameter for each drive not on the primary i/f.
- *
- * The only "perfect" way to handle this would be to modify the setup.[cS] code
- * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
- * for us during initialization. I have the necessary docs -- any takers? -ml
- */
-void probe_cmos_for_drives (ide_hwif_t *hwif)
-{
-#ifdef __i386__
- extern struct drive_info_struct drive_info;
- byte cmos_disks, *BIOS = (byte *) &drive_info;
- int unit;
-
-#ifdef CONFIG_BLK_DEV_PDC4030
- if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
- return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
- outb_p(0x12,0x70); /* specify CMOS address 0x12 */
- cmos_disks = inb_p(0x71); /* read the data from 0x12 */
- /* Extract drive geometry from CMOS+BIOS if not already setup */
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
- if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present && !drive->nobios) {
- drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
- drive->head = drive->bios_head = *(BIOS+2);
- drive->sect = drive->bios_sect = *(BIOS+14);
- drive->ctl = *(BIOS+8);
- drive->present = 1;
- }
- BIOS += 16;
- }
-#endif
-}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 1b2be20dd..579fbc13a 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -212,6 +212,7 @@ struct file_operations ida_fops = {
*/
static void ida_procinit(int i)
{
+#ifdef CONFIG_PROC_FS
struct proc_dir_entry *pd;
if (proc_array == NULL) {
@@ -224,6 +225,7 @@ static void ida_procinit(int i)
if (!pd) return;
pd->read_proc = ida_proc_get_info;
pd->data = hba[i];
+#endif
}
/*
@@ -356,7 +358,9 @@ void cleanup_module(void)
}
}
}
+#ifdef CONFIG_PROC_FS
remove_proc_entry("array", &proc_root);
+#endif
kfree(ida);
kfree(ida_sizes);
kfree(ida_hardsizes);
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index 2ea7d5b51..d2941a1ab 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -94,42 +94,40 @@ static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsign
*
* Returns: 1 if lba_capacity looks sensible
* 0 otherwise
+ *
+ * It is called only once for each drive.
*/
static int lba_capacity_is_ok (struct hd_driveid *id)
{
- unsigned long lba_sects = id->lba_capacity;
- unsigned long chs_sects = id->cyls * id->heads * id->sectors;
- unsigned long _10_percent = chs_sects / 10;
+ unsigned long lba_sects, chs_sects, head, tail;
/*
- * very large drives (8GB+) may lie about the number of cylinders
- * This is a split test for drives 8 Gig and Bigger only.
+ * The ATA spec tells large drives to return
+ * C/H/S = 16383/16/63 independent of their size.
+ * Some drives can be jumpered to use 15 heads instead of 16.
*/
- if ((id->lba_capacity >= 16514064) && (id->cyls == 0x3fff) &&
- (id->heads == 16) && (id->sectors == 63)) {
- id->cyls = lba_sects / (16 * 63); /* correct cyls */
- return 1; /* lba_capacity is our only option */
- }
- /*
- * ... and at least one TLA VBC has POS instead of brain and can't
- * tell 16 from 15.
- */
- if ((id->lba_capacity >= 15481935) && (id->cyls == 0x3fff) &&
- (id->heads == 15) && (id->sectors == 63)) {
- id->cyls = lba_sects / (15 * 63); /* correct cyls */
- return 1; /* lba_capacity is our only option */
- }
- /* perform a rough sanity check on lba_sects: within 10% is "okay" */
- if ((lba_sects - chs_sects) < _10_percent) {
- return 1; /* lba_capacity is good */
- }
+ if (id->cyls == 16383 && id->sectors == 63 &&
+ (id->heads == 15 || id->heads == 16) &&
+ id->lba_capacity >= 16383*63*id->heads)
+ return 1;
+
+ lba_sects = id->lba_capacity;
+ chs_sects = id->cyls * id->heads * id->sectors;
+
+ /* perform a rough sanity check on lba_sects: within 10% is OK */
+ if ((lba_sects - chs_sects) < chs_sects/10)
+ return 1;
+
/* some drives have the word order reversed */
- lba_sects = (lba_sects << 16) | (lba_sects >> 16);
- if ((lba_sects - chs_sects) < _10_percent) {
- id->lba_capacity = lba_sects; /* fix it */
+ head = ((lba_sects >> 16) & 0xffff);
+ tail = (lba_sects & 0xffff);
+ lba_sects = (head | (tail << 16));
+ if ((lba_sects - chs_sects) < chs_sects/10) {
+ id->lba_capacity = lba_sects;
return 1; /* lba_capacity is (now) good */
}
- return 0; /* lba_capacity value is bad */
+
+ return 0; /* lba_capacity value may be bad */
}
/*
@@ -450,24 +448,28 @@ static int idedisk_media_change (ide_drive_t *drive)
}
/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
*/
-static unsigned long idedisk_capacity (ide_drive_t *drive)
+static void init_idedisk_capacity (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
unsigned long capacity = drive->cyl * drive->head * drive->sect;
drive->select.b.lba = 0;
+
/* Determine capacity, and use LBA if the drive properly supports it */
- if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
- if (id->lba_capacity >= capacity) {
- drive->cyl = id->lba_capacity / (drive->head * drive->sect);
- capacity = id->lba_capacity;
- drive->select.b.lba = 1;
- }
+ if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ capacity = id->lba_capacity;
+ drive->cyl = capacity / (drive->head * drive->sect);
+ drive->select.b.lba = 1;
}
- return (capacity - drive->sect0);
+ drive->capacity = capacity;
+}
+
+static unsigned long idedisk_capacity (ide_drive_t *drive)
+{
+ return (drive->capacity - drive->sect0);
}
static void idedisk_special (ide_drive_t *drive)
@@ -628,7 +630,7 @@ static void idedisk_add_settings(ide_drive_t *drive)
int major = HWIF(drive)->major;
int minor = drive->select.b.unit << PARTN_BITS;
- ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 65535, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL);
@@ -679,7 +681,7 @@ static int idedisk_cleanup (ide_drive_t *drive)
static void idedisk_setup (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- unsigned long capacity, check;
+ unsigned long capacity;
idedisk_add_settings(drive);
@@ -705,66 +707,33 @@ static void idedisk_setup (ide_drive_t *drive)
drive->head = drive->bios_head = id->heads;
drive->sect = drive->bios_sect = id->sectors;
}
+
/* Handle logical geometry translation by the drive */
if ((id->field_valid & 1) && id->cur_cyls &&
id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
- /*
- * Extract the physical drive geometry for our use.
- * Note that we purposely do *not* update the bios info.
- * This way, programs that use it (like fdisk) will
- * still have the same logical view as the BIOS does,
- * which keeps the partition table from being screwed.
- *
- * An exception to this is the cylinder count,
- * which we reexamine later on to correct for 1024 limitations.
- */
drive->cyl = id->cur_cyls;
drive->head = id->cur_heads;
drive->sect = id->cur_sectors;
-
- /* check for word-swapped "capacity" field in id information */
- capacity = drive->cyl * drive->head * drive->sect;
- check = (id->cur_capacity0 << 16) | id->cur_capacity1;
- if (check == capacity) { /* was it swapped? */
- /* yes, bring it into little-endian order: */
- id->cur_capacity0 = (capacity >> 0) & 0xffff;
- id->cur_capacity1 = (capacity >> 16) & 0xffff;
- }
}
+
/* Use physical geometry if what we have still makes no sense */
- if ((!drive->head || drive->head > 16) &&
- id->heads && id->heads <= 16) {
- if ((id->lba_capacity > 16514064) || (id->cyls == 0x3fff)) {
- id->cyls = ((int)(id->lba_capacity/(id->heads * id->sectors)));
- }
- drive->cyl = id->cur_cyls = id->cyls;
- drive->head = id->cur_heads = id->heads;
- drive->sect = id->cur_sectors = id->sectors;
+ if (drive->head > 16 && id->heads && id->heads <= 16) {
+ drive->cyl = id->cyls;
+ drive->head = id->heads;
+ drive->sect = id->sectors;
}
/* calculate drive capacity, and select LBA if possible */
- capacity = idedisk_capacity (drive);
+ init_idedisk_capacity (drive);
/*
* if possible, give fdisk access to more of the drive,
* by correcting bios_cyls:
*/
+ capacity = idedisk_capacity (drive);
if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
- (!drive->forced_geom) && drive->bios_sect && drive->bios_head) {
+ (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
-#ifdef DEBUG
- printk("Fixing Geometry :: CHS=%d/%d/%d to CHS=%d/%d/%d\n",
- drive->id->cur_cyls,
- drive->id->cur_heads,
- drive->id->cur_sectors,
- drive->bios_cyl,
- drive->bios_head,
- drive->bios_sect);
-#endif
- drive->id->cur_cyls = drive->bios_cyl;
- drive->id->cur_heads = drive->bios_head;
- drive->id->cur_sectors = drive->bios_sect;
- }
#if 0 /* done instead for entire identify block in arch/ide.h stuff */
/* fix byte-ordering of buffer size field */
@@ -791,19 +760,6 @@ static void idedisk_setup (ide_drive_t *drive)
}
printk("\n");
- if (drive->select.b.lba) {
- if (*(int *)&id->cur_capacity0 < id->lba_capacity) {
-#ifdef DEBUG
- printk(" CurSects=%d, LBASects=%d, ",
- *(int *)&id->cur_capacity0, id->lba_capacity);
-#endif
- *(int *)&id->cur_capacity0 = id->lba_capacity;
-#ifdef DEBUG
- printk( "Fixed CurSects=%d\n", *(int *)&id->cur_capacity0);
-#endif
- }
- }
-
drive->mult_count = 0;
if (id->max_multsect) {
#ifdef CONFIG_IDEDISK_MULTI_MODE
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index cd631c621..d3c657516 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -91,7 +91,7 @@
#include <asm/io.h>
#include <asm/irq.h>
-#ifdef IDEDMA_NEW_DRIVE_LISTINGS
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
struct drive_list_entry {
char * id_model;
@@ -130,7 +130,7 @@ int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
return 0;
}
-#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
/*
* good_dma_drives() lists the model names (from "hdparm -i")
@@ -162,7 +162,7 @@ const char *bad_dma_drives[] = {"WDC AC11000H",
"WDC AC31600H",
NULL};
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
/*
* Our Physical Region Descriptor (PRD) table should be large enough
@@ -314,7 +314,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
{
struct hd_driveid *id = drive->id;
-#ifdef IDEDMA_NEW_DRIVE_LISTINGS
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
if (good_bad) {
return in_drive_list(id, drive_whitelist);
} else {
@@ -323,7 +323,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
return(blacklist);
}
-#else /* !IDEDMA_NEW_DRIVE_LISTINGS */
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
const char **list;
if (good_bad) {
@@ -344,7 +344,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad)
}
}
}
-#endif /* IDEDMA_NEW_DRIVE_LISTINGS */
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
return 0;
}
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index 66b71b3a2..f1c8baef8 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1498,7 +1498,7 @@ static void idefloppy_add_settings(ide_drive_t *drive)
int major = HWIF(drive)->major;
int minor = drive->select.b.unit << PARTN_BITS;
- ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c
new file mode 100644
index 000000000..974fb24f1
--- /dev/null
+++ b/drivers/block/ide-geometry.c
@@ -0,0 +1,225 @@
+/*
+ * linux/drivers/block/ide-geometry.c
+ */
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+/*
+ * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
+ * controller that is BIOS compatible with ST-506, and thus showing up in our
+ * BIOS table, but not register compatible, and therefore not present in CMOS.
+ *
+ * Furthermore, we will assume that our ST-506 drives <if any> are the primary
+ * drives in the system -- the ones reflected as drive 1 or 2. The first
+ * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
+ * nibble. This will be either a 4 bit drive type or 0xf indicating use byte
+ * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
+ * means we have an AT controller hard disk for that drive.
+ *
+ * Of course, there is no guarantee that either drive is actually on the
+ * "primary" IDE interface, but we don't bother trying to sort that out here.
+ * If a drive is not actually on the primary interface, then these parameters
+ * will be ignored. This results in the user having to supply the logical
+ * drive geometry as a boot parameter for each drive not on the primary i/f.
+ */
+/*
+ * The only "perfect" way to handle this would be to modify the setup.[cS] code
+ * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
+ * for us during initialization. I have the necessary docs -- any takers? -ml
+ */
+/*
+ * I did this, but it doesnt work - there is no reasonable way to find the
+ * correspondence between the BIOS numbering of the disks and the Linux
+ * numbering. -aeb
+ *
+ * The code below is bad. One of the problems is that drives 1 and 2
+ * may be SCSI disks (even when IDE disks are present), so that
+ * the geometry we read here from BIOS is attributed to the wrong disks.
+ * Consequently, also the "drive->present = 1" below is a mistake.
+ *
+ * Eventually the entire routine below should be removed.
+ */
+void probe_cmos_for_drives (ide_hwif_t *hwif)
+{
+#ifdef __i386__
+ extern struct drive_info_struct drive_info;
+ byte cmos_disks, *BIOS = (byte *) &drive_info;
+ int unit;
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+ if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
+ return;
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+ outb_p(0x12,0x70); /* specify CMOS address 0x12 */
+ cmos_disks = inb_p(0x71); /* read the data from 0x12 */
+ /* Extract drive geometry from CMOS+BIOS if not already setup */
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ if ((cmos_disks & (0xf0 >> (unit*4))) &&
+ !drive->present && !drive->nobios) {
+ drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
+ drive->head = drive->bios_head = *(BIOS+2);
+ drive->sect = drive->bios_sect = *(BIOS+14);
+ drive->ctl = *(BIOS+8);
+#if 0
+ drive->present = 1;
+#endif
+ }
+ BIOS += 16;
+ }
+#endif
+}
+
+
+/*
+ * If heads is nonzero: find a translation with this many heads and S=63.
+ * Otherwise: find out how OnTrack Disk Manager would translate the disk.
+ */
+static void
+ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) {
+ struct hd_driveid *id = drive->id;
+ static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+ const byte *headp = dm_head_vals;
+ unsigned long total, tracks;
+
+ /*
+ * The specs say: take geometry as obtained from Identify,
+ * compute total capacity C*H*S from that, and truncate to
+ * 1024*255*63. Now take S=63, H the first in the sequence
+ * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+ */
+ if (id)
+ total = id->cyls * id->heads * id->sectors;
+ else
+ total = drive->cyl * drive->head * drive->sect;
+
+ *s = 63;
+
+ if (heads) {
+ *h = heads;
+ *c = total / (63 * heads);
+ return;
+ }
+
+#if 0
+ while (63 * headp[0] * 1024 < total && headp[1] != 0)
+ headp++;
+ *h = headp[0];
+ *c = total / (63 * headp[0]);
+#else
+ /* The code below differs in two aspects:
+ (i) It will not produce geometries like C/H/S = 1024/64/63
+ because of the `>='. This follows OnTracks text (which
+ claims that 512 <= C <= 1023), but not OnTracks code.
+ (ii) It starts dividing by 63, so that a rounding down occurs.
+ For example, with C=11159, H=10, S=37 we find total=4128830
+ and DM would make C=512, H=128, S=63, but we make 1024/64/63
+ if `>=' is replaced by `>'.
+ The reason we use this code is mainly that we have done so for
+ a long time without getting complaints.
+ */
+
+ tracks = total / 63;
+ while (*c >= 1024) {
+ *h = *headp;
+ *c = tracks / *h;
+ if (*++headp == 0)
+ break;
+ }
+#endif
+}
+
+/*
+ * This routine is called from the partition-table code in pt/msdos.c.
+ * It has two tasks:
+ * (i) to handle Ontrack DiskManager by offsetting everything by 63 sectors,
+ * or to handle EZdrive by remapping sector 0 to sector 1.
+ * (ii) to invent a translated geometry.
+ * Part (i) is suppressed if the user specifies the "noremap" option
+ * on the command line.
+ * Part (ii) is suppressed if the user specifies an explicit geometry.
+ *
+ * The ptheads parameter is either 0 or tells about the number of
+ * heads shown by the end of the first nonempty partition.
+ * If this is either 16, 32, 64, 128, 240 or 255 we'll believe it.
+ *
+ * The xparm parameter has the following meaning:
+ * 0 = convert to CHS with fewer than 1024 cyls
+ * using the same method as Ontrack DiskManager.
+ * 1 = same as "0", plus offset everything by 63 sectors.
+ * -1 = similar to "0", plus redirect sector 0 to sector 1.
+ * 2 = convert to a CHS geometry with "ptheads" heads.
+ *
+ * Returns 0 if the translation was not possible, if the device was not
+ * an IDE disk drive, or if a geometry was "forced" on the commandline.
+ * Returns 1 if the geometry translation was successful.
+ */
+int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
+{
+ ide_drive_t *drive;
+ const char *msg1 = "";
+ int heads = 0;
+ int c, h, s;
+ int transl = 1; /* try translation */
+ int ret = 0;
+
+ drive = get_info_ptr(i_rdev);
+ if (!drive)
+ return 0;
+
+ /* remap? */
+ if (drive->remap_0_to_1 != 2) {
+ if (xparm == 1) { /* DM */
+ drive->sect0 = 63;
+ msg1 = " [remap +63]";
+ ret = 1;
+ } else if (xparm == -1) { /* EZ-Drive */
+ if (drive->remap_0_to_1 == 0) {
+ drive->remap_0_to_1 = 1;
+ msg1 = " [remap 0->1]";
+ ret = 1;
+ }
+ }
+ }
+
+ /* There used to be code here that assigned drive->id->CHS
+ to drive->CHS and that to drive->bios_CHS. However,
+ some disks have id->C/H/S = 4092/16/63 but are larger than 2.1 GB.
+ In such cases that code was wrong. Moreover,
+ there seems to be no reason to do any of these things. */
+
+ /* translate? */
+ if (drive->forced_geom)
+ transl = 0;
+
+ /* does ptheads look reasonable? */
+ if (ptheads == 32 || ptheads == 64 || ptheads == 128 ||
+ ptheads == 240 || ptheads == 255)
+ heads = ptheads;
+
+ if (xparm == 2) {
+ if (!heads ||
+ (drive->bios_head >= heads && drive->bios_sect == 63))
+ transl = 0;
+ }
+ if (xparm == -1) {
+ if (drive->bios_head > 16)
+ transl = 0; /* we already have a translation */
+ }
+
+ if (transl) {
+ ontrack(drive, heads, &c, &h, &s);
+ drive->bios_cyl = c;
+ drive->bios_head = h;
+ drive->bios_sect = s;
+ ret = 1;
+ }
+
+ drive->part[0].nr_sects = current_capacity(drive);
+
+ if (ret)
+ printk("%s%s [%d/%d/%d]", msg, msg1,
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ return ret;
+}
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
index 3ba39f600..311bd470b 100644
--- a/drivers/block/ide-pci.c
+++ b/drivers/block/ide-pci.c
@@ -507,7 +507,7 @@ check_if_enabled:
if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
continue; /* no room in ide_hwifs[] */
if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
- ide_init_hwif_ports(&hwif->hw, base, (ctl + 2), NULL);
+ ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
}
diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c
index 90fbf9cbc..1ad5b3b96 100644
--- a/drivers/block/ide-pmac.c
+++ b/drivers/block/ide-pmac.c
@@ -30,8 +30,9 @@
#include <asm/mediabay.h>
#include <asm/feature.h>
#ifdef CONFIG_PMAC_PBOOK
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/irq.h>
#endif
#include "ide_modes.h"
@@ -50,9 +51,9 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct notifier_block *, unsigned long, void *);
-struct notifier_block idepmac_sleep_notifier = {
- idepmac_notify
+static int idepmac_notify(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+ idepmac_notify, SLEEP_LEVEL_BLOCK,
};
#endif /* CONFIG_PMAC_PBOOK */
@@ -224,7 +225,7 @@ void __init pmac_ide_probe(void)
pmac_ide_count = i;
#ifdef CONFIG_PMAC_PBOOK
- notifier_chain_register(&sleep_notifier_list, &idepmac_sleep_notifier);
+ pmu_register_sleep_notifier(&idepmac_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
}
@@ -384,29 +385,107 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify(struct notifier_block *this,
- unsigned long code, void *p)
+static void idepmac_sleep_disk(int i, unsigned long base)
{
- int i, timeout;
+ int j;
+
+ /* Reset to PIO 0 */
+ out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
+
+ /* FIXME: We only handle the master IDE */
+ if (ide_hwifs[i].drives[0].media == ide_disk) {
+ /* Spin down the drive */
+ outb(0xa0, base+0x60);
+ outb(0x0, base+0x30);
+ outb(0x0, base+0x20);
+ outb(0x0, base+0x40);
+ outb(0x0, base+0x50);
+ outb(0xe0, base+0x70);
+ outb(0x2, base+0x160);
+ for (j = 0; j < 10; j++) {
+ int status;
+ mdelay(100);
+ status = inb(base+0x70);
+ if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+ break;
+ }
+ }
+}
+
+static void idepmac_wake_disk(int i, unsigned long base)
+{
+ int j;
+
+ /* Revive IDE disk and controller */
+ feature_set(pmac_ide_node[i], FEATURE_IDE_enable);
+ mdelay(1);
+ feature_set(pmac_ide_node[i], FEATURE_IDE_DiskPower);
+ mdelay(100);
+ feature_set(pmac_ide_node[i], FEATURE_IDE_Reset);
+ mdelay(1);
+ /* Make sure we are still PIO0 */
+ out_le32((unsigned *)(base + 0x200 + _IO_BASE), 0x2f8526);
+ mdelay(100);
+
+ /* Wait up to 10 seconds (enough for recent drives) */
+ for (j = 0; j < 100; j++) {
+ int status;
+ mdelay(100);
+ status = inb(base + 0x70);
+ if (!(status & BUSY_STAT))
+ break;
+ }
+}
- switch (code) {
- case PBOOK_SLEEP:
- /* do anything here?? */
+/* Here we handle media bay devices */
+static void
+idepmac_wake_bay(int i, unsigned long base)
+{
+ int timeout;
+
+ timeout = 5000;
+ while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
+ mdelay(1);
+ --timeout;
+ }
+}
+
+static int idepmac_notify(struct pmu_sleep_notifier *self, int when)
+{
+ int i, ret;
+ unsigned long base;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ break;
+ case PBOOK_SLEEP_REJECT:
+ break;
+ case PBOOK_SLEEP_NOW:
+ for (i = 0; i < pmac_ide_count; ++i) {
+ if ((base = pmac_ide_regbase[i]) == 0)
+ continue;
+ /* Disable irq during sleep */
+ disable_irq(pmac_ide_irq[i]);
+ ret = check_media_bay_by_base(base, MB_CD);
+ if (ret == -ENODEV)
+ /* not media bay - put the disk to sleep */
+ idepmac_sleep_disk(i, base);
+ }
break;
case PBOOK_WAKE:
- /* wait for the controller(s) to become ready */
- timeout = 5000;
for (i = 0; i < pmac_ide_count; ++i) {
- unsigned long base = pmac_ide_regbase[i];
- if (check_media_bay_by_base(base, MB_CD) == -EINVAL)
+ if ((base = pmac_ide_regbase[i]) == 0)
continue;
- while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
- mdelay(1);
- --timeout;
- }
+ /* We don't handle media bay devices this way */
+ ret = check_media_bay_by_base(base, MB_CD);
+ if (ret == -ENODEV)
+ idepmac_wake_disk(i, base);
+ else if (ret == 0)
+ idepmac_wake_bay(i, base);
+ enable_irq(pmac_ide_irq[i]);
}
break;
}
- return NOTIFY_DONE;
+ return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 74b3f71c6..d2cb4b34b 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -526,7 +526,7 @@ void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int t
* current_capacity() returns the capacity (in sectors) of a drive
* according to its current geometry/LBA settings.
*/
-static unsigned long current_capacity (ide_drive_t *drive)
+unsigned long current_capacity (ide_drive_t *drive)
{
if (!drive->present)
return 0;
@@ -1067,13 +1067,16 @@ static inline void start_request (ide_drive_t *drive)
goto kill_rq;
}
block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-#if FAKE_FDISK_FOR_EZDRIVE
- if (block == 0 && drive->remap_0_to_1)
+
+ /* Yecch - this will shift the entire interval,
+ possibly killing some innocent following sector */
+ if (block == 0 && drive->remap_0_to_1 == 1)
block = 1; /* redirect MBR access to EZ-Drive partn table */
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
+
#if (DISK_RECOVERY_TIME > 0)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif
+
SELECT_DRIVE(hwif, drive);
if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name);
@@ -1513,7 +1516,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* get_info_ptr() returns the (ide_drive_t *) for a given device number.
* It returns NULL if the given device number does not match any present drives.
*/
-static ide_drive_t *get_info_ptr (kdev_t i_rdev)
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
{
int major = MAJOR(i_rdev);
unsigned int h;
@@ -1609,11 +1612,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
}
spin_unlock_irqrestore(&io_request_lock, flags);
do_hwgroup_request(hwgroup);
- save_flags(flags); /* all CPUs; overkill? */
- cli(); /* all CPUs; overkill? */
if (action == ide_wait && rq->rq_status != RQ_INACTIVE)
down(&sem); /* wait for it to be serviced */
- restore_flags(flags); /* all CPUs; overkill? */
return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
@@ -2321,10 +2321,11 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GETGEO:
{
struct hd_geometry *loc = (struct hd_geometry *) arg;
+ unsigned short bios_cyl = drive->bios_cyl; /* truncate */
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
- if (put_user(drive->bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+ if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
(unsigned long *) &loc->start)) return -EFAULT;
return 0;
@@ -2343,7 +2344,8 @@ static int ide_ioctl (struct inode *inode, struct file *file,
return -EINVAL;
if (drive->id == NULL)
return -ENOMSG;
- if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+ if (copy_to_user((char *)arg, (char *)drive->id,
+ (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
return -EFAULT;
return 0;
@@ -2629,6 +2631,7 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
* "hdx=nowerr" : ignore the WRERR_STAT bit on this drive
* "hdx=cdrom" : drive is present, and is a cdrom drive
* "hdx=cyl,head,sect" : disk drive is present, with specified geometry
+ * "hdx=noremap" : do not remap 0->1 even though EZD was detected
* "hdx=autotune" : driver will attempt to tune interface speed
* to the fastest PIO mode supported,
* if possible for this drive only.
@@ -2735,7 +2738,8 @@ void __init ide_setup (char *s)
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
"serialize", "autotune", "noautotune",
- "slow", "swapdata", "bswap", "flash", NULL};
+ "slow", "swapdata", "bswap", "flash",
+ "remap", "noremap", NULL};
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES;
@@ -2772,13 +2776,19 @@ void __init ide_setup (char *s)
case -8: /* "slow" */
drive->slow = 1;
goto done;
- case -9: /* swapdata or bswap */
+ case -9: /* "swapdata" or "bswap" */
case -10:
drive->bswap = 1;
goto done;
- case -11:
+ case -11: /* "flash" */
drive->ata_flash = 1;
goto done;
+ case -12: /* "remap" */
+ drive->remap_0_to_1 = 1;
+ goto done;
+ case -13: /* "noremap" */
+ drive->remap_0_to_1 = 2;
+ goto done;
case 3: /* cyl,head,sect */
drive->media = ide_disk;
drive->cyl = drive->bios_cyl = vals[0];
@@ -3023,113 +3033,6 @@ done:
}
/*
- * This routine is called from the partition-table code in genhd.c
- * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
- *
- * The second parameter, "xparm", determines exactly how the translation
- * will be handled:
- * 0 = convert to CHS with fewer than 1024 cyls
- * using the same method as Ontrack DiskManager.
- * 1 = same as "0", plus offset everything by 63 sectors.
- * -1 = similar to "0", plus redirect sector 0 to sector 1.
- * >1 = convert to a CHS geometry with "xparm" heads.
- *
- * Returns 0 if the translation was not possible, if the device was not
- * an IDE disk drive, or if a geometry was "forced" on the commandline.
- * Returns 1 if the geometry translation was successful.
- */
-
-int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
-{
- ide_drive_t *drive;
-
- static const byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
- const byte *heads = head_vals;
- unsigned long tracks;
-
- drive = get_info_ptr(i_rdev);
- if (!drive)
- return 0;
-
- if (drive->forced_geom) {
- /*
- * Update the current 3D drive values.
- */
- drive->id->cur_cyls = drive->bios_cyl;
- drive->id->cur_heads = drive->bios_head;
- drive->id->cur_sectors = drive->bios_sect;
- return 0;
- }
-
- if (xparm > 1 && xparm <= drive->bios_head && drive->bios_sect == 63) {
- /*
- * Update the current 3D drive values.
- */
- drive->id->cur_cyls = drive->bios_cyl;
- drive->id->cur_heads = drive->bios_head;
- drive->id->cur_sectors = drive->bios_sect;
- return 0; /* we already have a translation */
- }
-
- printk("%s ", msg);
-
- if (xparm < 0 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) {
- /*
- * Update the current 3D drive values.
- */
- drive->id->cur_cyls = drive->bios_cyl;
- drive->id->cur_heads = drive->bios_head;
- drive->id->cur_sectors = drive->bios_sect;
- return 0; /* small disk: no translation needed */
- }
-
- if (drive->id) {
- drive->cyl = drive->id->cyls;
- drive->head = drive->id->heads;
- drive->sect = drive->id->sectors;
- }
- drive->bios_cyl = drive->cyl;
- drive->bios_head = drive->head;
- drive->bios_sect = drive->sect;
- drive->special.b.set_geometry = 1;
-
- tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
- drive->bios_sect = 63;
- if (xparm > 1) {
- drive->bios_head = xparm;
- drive->bios_cyl = tracks / drive->bios_head;
- } else {
- while (drive->bios_cyl >= 1024) {
- drive->bios_head = *heads;
- drive->bios_cyl = tracks / drive->bios_head;
- if (0 == *++heads)
- break;
- }
-#if FAKE_FDISK_FOR_EZDRIVE
- if (xparm == -1) {
- drive->remap_0_to_1 = 1;
- printk("[remap 0->1] ");
- } else
-#endif /* FAKE_FDISK_FOR_EZDRIVE */
- if (xparm == 1) {
- drive->sect0 = 63;
- drive->bios_cyl = (tracks - 1) / drive->bios_head;
- printk("[remap +63] ");
- }
- }
-
- drive->part[0].nr_sects = current_capacity(drive);
- printk("[%d/%d/%d]", drive->bios_cyl, drive->bios_head, drive->bios_sect);
- /*
- * Update the current 3D drive values.
- */
- drive->id->cur_cyls = drive->bios_cyl;
- drive->id->cur_heads = drive->bios_head;
- drive->id->cur_sectors = drive->bios_sect;
- return 1;
-}
-
-/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
*/
static void __init probe_for_hwifs (void)
@@ -3524,6 +3427,9 @@ EXPORT_SYMBOL(ide_register);
EXPORT_SYMBOL(ide_unregister);
EXPORT_SYMBOL(ide_setup_ports);
+EXPORT_SYMBOL(get_info_ptr);
+EXPORT_SYMBOL(current_capacity);
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c
index 5bbd0c3e7..aeffcc9ba 100644
--- a/drivers/block/pdc202xx.c
+++ b/drivers/block/pdc202xx.c
@@ -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 "PDC202XX_FORCE_BURST_BIT"
+ * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT"
*
* There is only one BIOS in the three contollers.
*
@@ -521,15 +521,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 PDC202XX_FORCE_BURST_BIT
+#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT
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 /* PDC202XX_FORCE_BURST_BIT */
+#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */
-#ifdef PDC202XX_FORCE_MASTER_MODE
+#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE
if (!(primary_mode & 1)) {
printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
name, primary_mode, (primary_mode|1));
@@ -543,7 +543,7 @@ 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 /* PDC202XX_FORCE_MASTER_MODE */
+#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */
return dev->irq;
}
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
index eaf1a8357..95c25b519 100644
--- a/drivers/char/adbmouse.c
+++ b/drivers/char/adbmouse.c
@@ -35,8 +35,8 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
+#include <linux/adb_mouse.h>
-#include <asm/adb_mouse.h>
#ifdef __powerpc__
#include <asm/processor.h>
#endif
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 4620a3d60..42c2642f6 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -144,7 +144,7 @@ busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
wake_up(&mse->wait);
if (mse->fasyncptr)
- kill_fasync(mse->fasyncptr, SIGIO);
+ kill_fasync(mse->fasyncptr, SIGIO, POLL_IN);
}
}
@@ -450,13 +450,10 @@ bus_mouse_init(void)
#ifdef CONFIG_ATARIMOUSE
atari_mouse_init();
#endif
-#ifdef CONFIG_MAC_MOUSE
- mac_mouse_init();
-#endif
#ifdef CONFIG_SUN_MOUSE
sun_mouse_init();
#endif
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
adb_mouse_init();
#endif
#ifdef CONFIG_RPCMOUSE
diff --git a/drivers/char/console.c b/drivers/char/console.c
index d0503cdcb..f452237ab 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -681,7 +681,7 @@ int vc_resize(unsigned int lines, unsigned int cols,
else {
unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
if (!p) {
- for (i = 0; i< currcons; i++)
+ for (i = first; i < currcons; i++)
if (newscreens[i])
kfree_s(newscreens[i], ss);
return -ENOMEM;
diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c
index 42fae3568..d8ac176c2 100644
--- a/drivers/char/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -233,7 +233,6 @@ struct kbdiacr accent_table[MAX_DIACR] = {
{'A', 'A', '\305'}, {'a', 'a', '\345'},
{'A', 'E', '\306'}, {'a', 'e', '\346'},
{',', 'C', '\307'}, {',', 'c', '\347'},
- {'\'', 'C', '\307'}, {'\'', 'c', '\347'},
{'`', 'E', '\310'}, {'`', 'e', '\350'},
{'\'', 'E', '\311'}, {'\'', 'e', '\351'},
{'^', 'E', '\312'}, {'^', 'e', '\352'},
@@ -260,4 +259,4 @@ struct kbdiacr accent_table[MAX_DIACR] = {
{'s', 'z', '\337'}, {'i', 'j', '\377'},
};
-unsigned int accent_table_size = 70;
+unsigned int accent_table_size = 68;
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
index 97b237ca3..38010e29b 100644
--- a/drivers/char/dn_keyb.c
+++ b/drivers/char/dn_keyb.c
@@ -469,7 +469,7 @@ static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
if (mouse_dy > 2048)
mouse_dy = 2048;
if (mouse_fasyncptr)
- kill_fasync(mouse_fasyncptr, SIGIO);
+ kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN);
}
mouse_byte_count=0;
/* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c
index 12ab4d628..55deade81 100644
--- a/drivers/char/drm/fops.c
+++ b/drivers/char/drm/fops.c
@@ -197,7 +197,7 @@ int drm_write_string(drm_device_t *dev, const char *s)
send -= count;
}
- if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+ if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_OUT);
DRM_DEBUG("waking\n");
wake_up_interruptible(&dev->buf_readers);
return 0;
diff --git a/drivers/char/ftape/Config.in b/drivers/char/ftape/Config.in
index 2f837be5b..59004dcf2 100644
--- a/drivers/char/ftape/Config.in
+++ b/drivers/char/ftape/Config.in
@@ -1,17 +1,17 @@
#
# Ftape configuration
#
-dep_tristate 'Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE
+dep_tristate ' Zftape, the VFS interface' CONFIG_ZFTAPE $CONFIG_FTAPE
if [ "$CONFIG_ZFTAPE" != "n" ]; then
- int 'Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240
- comment 'The compressor will be built as a module only!'
- define_bool CONFIG_ZFT_COMPRESSOR m
+ int ' Default block size' CONFIG_ZFT_DFLT_BLK_SZ 10240
+ comment ' The compressor will be built as a module only!'
+ define_bool CONFIG_ZFT_COMPRESSOR m
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- int 'Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3
+ int ' Number of ftape buffers (EXPERIMENTAL)' CONFIG_FT_NR_BUFFERS 3
fi
if [ "$CONFIG_PROC_FS" = "y" ]; then
- bool 'Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS y
+ bool ' Enable procfs status report (+2kb)' CONFIG_FT_PROC_FS
fi
choice 'Debugging output' \
"Normal CONFIG_FT_NORMAL_DEBUG \
@@ -25,14 +25,14 @@ choice 'Floppy tape controllers' \
FC-10/FC-20 CONFIG_FT_PROBE_FC10 \
Alt/82078 CONFIG_FT_ALT_FDC" Standard
if [ "$CONFIG_FT_STD_FDC" != "y" ]; then
- comment ' Consult the manuals of your tape drive for the correct settings!'
- hex ' IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0
- int ' IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0
- int ' DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0
+ comment ' Consult the manuals of your tape drive for the correct settings!'
+ hex ' IO base of the floppy disk controller' CONFIG_FT_FDC_BASE 0
+ int ' IRQ channel of the floppy disk controller' CONFIG_FT_FDC_IRQ 0
+ int ' DMA channel of the floppy disk controller' CONFIG_FT_FDC_DMA 0
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- int 'Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8
- int 'Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
+ int ' Default FIFO threshold (EXPERIMENTAL)' CONFIG_FT_FDC_THR 8
+ int ' Maximal data rate to use (EXPERIMENTAL)' CONFIG_FT_FDC_MAX_RATE 2000
fi
comment 'ONLY for DEC Alpha architectures'
-int 'CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
+int ' CPU clock frequency of your DEC Alpha' CONFIG_FT_ALPHA_CLOCK 0
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
index a41eaac33..810decada 100644
--- a/drivers/char/joystick/Config.in
+++ b/drivers/char/joystick/Config.in
@@ -2,18 +2,18 @@
# Joystick lowlevel driver configuration
#
-dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
-dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
-dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
-dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
-dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
-dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
-dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
+dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
+dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
+dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
+dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
+dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
+dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
+dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+ dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
fi
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index def0b7c19..5989fbff5 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/random.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <asm/keyboard.h>
#include <asm/bitops.h>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index ff3158e96..9be0a51f5 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -50,7 +50,7 @@ extern void prom_con_init(void);
#ifdef CONFIG_MDA_CONSOLE
extern void mda_console_init(void);
#endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+#if defined(CONFIG_ADB)
extern void adbdev_init(void);
#endif
#ifdef CONFIG_USB
@@ -268,7 +268,8 @@ 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__)
+#if (!defined(CONFIG_PPC) && !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)
{
@@ -517,7 +518,8 @@ static struct file_operations null_fops = {
NULL /* fsync */
};
-#if !defined(CONFIG_PPC) && !defined(__mc68000__)
+#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
+ defined(CONFIG_HAVE_IO_PORTS)
static struct file_operations port_fops = {
memory_lseek,
read_port,
@@ -571,7 +573,8 @@ static int memory_open(struct inode * inode, struct file * filp)
case 3:
filp->f_op = &null_fops;
break;
-#if !defined(CONFIG_PPC) && !defined(__mc68000__)
+#if (!defined(CONFIG_PPC) && !defined(__mc68000__) && !defined(__mips__)) || \
+ defined(CONFIG_HAVE_IO_PORTS)
case 4:
filp->f_op = &port_fops;
break;
@@ -667,7 +670,7 @@ int __init chr_dev_init(void)
#ifdef CONFIG_VIDEO_BT848
i2c_init();
#endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
+#if defined(CONFIG_ADB)
adbdev_init();
#endif
#ifdef CONFIG_VIDEO_DEV
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index e9eec975c..c30f10594 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -261,6 +261,12 @@ int __init misc_init(void)
#ifdef CONFIG_NWFLASH
nwflash_init();
#endif
+#ifdef CONFIG_SGI_NEWPORT_GFX
+ gfx_register ();
+#endif
+#ifdef CONFIG_SGI
+ streamable_init ();
+#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 7251a4e05..0717fa418 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -9,7 +9,7 @@
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
- * ==FILEDATE 19990524==
+ * ==FILEDATE 19990901==
*
* This code is released under the GNU General Public License (GPL)
*
@@ -21,8 +21,13 @@
* 1. tty write calls represent one complete transmit frame of data
* The device driver should accept the complete frame or none of
* the frame (busy) in the write method. Each write call should have
- * a byte count in the range of 2-4096 bytes (2 is min HDLC frame
- * with 1 addr byte and 1 ctrl byte).
+ * a byte count in the range of 2-65535 bytes (2 is min HDLC frame
+ * with 1 addr byte and 1 ctrl byte). The max byte count of 65535
+ * should include any crc bytes required. For example, when using
+ * CCITT CRC32, 4 crc bytes are required, so the maximum size frame
+ * the application may transmit is limited to 65531 bytes. For CCITT
+ * CRC16, the maximum application frame size would be 65533.
+ *
*
* 2. receive callbacks from the device driver represents
* one received frame. The device driver should bypass
@@ -73,7 +78,7 @@
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.2"
+#define HDLC_VERSION "1.11"
#include <linux/version.h>
#include <linux/config.h>
@@ -100,6 +105,7 @@
#include <linux/malloc.h>
#include <linux/tty.h>
#include <linux/errno.h>
+#include <linux/sched.h> /* to get the struct task_struct */
#include <linux/string.h> /* used in new tty drivers */
#include <linux/signal.h> /* used in new tty drivers */
#include <asm/system.h>
@@ -113,6 +119,13 @@
#include <linux/kerneld.h>
#endif
+#if LINUX_VERSION_CODE < VERSION(2,3,0)
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define set_current_state(a) current->state = (a)
+#endif
+
#if LINUX_VERSION_CODE >= VERSION(2,1,4)
#include <asm/segment.h>
#define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -189,18 +202,21 @@ typedef size_t rw_count_t;
/*
* Buffers for individual HDLC frames
*/
-#define MAX_HDLC_FRAME_SIZE 4096
+#define MAX_HDLC_FRAME_SIZE 65535
#define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 30
+#define MAX_RX_BUF_COUNT 60
#define DEFAULT_TX_BUF_COUNT 1
+
typedef struct _n_hdlc_buf
{
struct _n_hdlc_buf *link;
int count;
- char buf[MAX_HDLC_FRAME_SIZE];
+ char buf[1];
} N_HDLC_BUF;
+#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe)
+
typedef struct _n_hdlc_buf_list
{
N_HDLC_BUF *head;
@@ -246,12 +262,16 @@ static struct n_hdlc *n_hdlc_alloc (void);
#if LINUX_VERSION_CODE >= VERSION(2,1,19)
MODULE_PARM(debuglevel, "i");
+MODULE_PARM(maxframe, "i");
#endif
/* debug level can be set by insmod for debugging purposes */
#define DEBUG_LEVEL_INFO 1
int debuglevel=0;
+/* max frame size for memory allocations */
+ssize_t maxframe=4096;
+
/* TTY callbacks */
static rw_ret_t n_hdlc_tty_read(struct tty_struct *,
@@ -353,6 +373,9 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
return;
}
+#if defined(TTY_NO_WRITE_SPLIT)
+ clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
tty->disc_data = NULL;
if (tty == n_hdlc->backup_tty)
n_hdlc->backup_tty = 0;
@@ -383,7 +406,9 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_open() called\n",__FILE__,__LINE__);
+ printk("%s(%d)n_hdlc_tty_open() called (major=%u,minor=%u)\n",
+ __FILE__,__LINE__,
+ MAJOR(tty->device), MINOR(tty->device));
/* There should not be an existing table for this slot. */
if (n_hdlc) {
@@ -399,9 +424,14 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
tty->disc_data = n_hdlc;
n_hdlc->tty = tty;
-
+
MOD_INC_USE_COUNT;
+#if defined(TTY_NO_WRITE_SPLIT)
+ /* change tty_io write() to not split large writes into 8K chunks */
+ set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+
/* Flush any pending characters in the driver and discipline. */
if (tty->ldisc.flush_buffer)
@@ -597,18 +627,26 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
return;
}
+ if ( count>maxframe ) {
+ if (debuglevel >= DEBUG_LEVEL_INFO)
+ printk("%s(%d) rx count>maxframesize, data discarded\n",
+ __FILE__,__LINE__);
+ return;
+ }
+
/* get a free HDLC buffer */
buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
if (!buf) {
/* no buffers in free list, attempt to allocate another rx buffer */
/* unless the maximum count has been reached */
if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
- buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_ATOMIC);
+ buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC);
}
if (!buf) {
- printk("%s(%d) no more rx buffers, data discarded\n",
- __FILE__,__LINE__);
+ if (debuglevel >= DEBUG_LEVEL_INFO)
+ printk("%s(%d) no more rx buffers, data discarded\n",
+ __FILE__,__LINE__);
return;
}
@@ -622,7 +660,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
/* wake up any blocked reads and perform async signalling */
wake_up_interruptible (&n_hdlc->read_wait);
if (n_hdlc->tty->fasync != NULL)
- kill_fasync (n_hdlc->tty->fasync, SIGIO);
+ kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN);
} /* end of n_hdlc_tty_receive() */
@@ -678,12 +716,11 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- /* TODO: no timeout? current->timeout = 0;*/
interruptible_sleep_on (&n_hdlc->read_wait);
if (signal_pending(current))
return -EINTR;
}
-
+
if (rbuf->count > nr) {
/* frame too large for caller's buffer (discard frame) */
ret = (rw_ret_t)-EOVERFLOW;
@@ -739,13 +776,13 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
return -EIO;
/* verify frame size */
- if (count > MAX_HDLC_FRAME_SIZE) {
+ if (count > maxframe ) {
if (debuglevel & DEBUG_LEVEL_INFO)
printk (KERN_WARNING
"n_hdlc_tty_write: truncating user packet "
"from %lu to %d\n", (unsigned long) count,
- MAX_HDLC_FRAME_SIZE);
- count = MAX_HDLC_FRAME_SIZE;
+ maxframe );
+ count = maxframe;
}
/* Allocate transmit buffer */
@@ -754,8 +791,7 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
/* sleep until transmit buffer available */
add_wait_queue(&n_hdlc->write_wait, &wait);
while (!tbuf) {
- /* TODO: no timeout? current->timeout = 0;*/
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
n_hdlc = tty2n_hdlc (tty);
@@ -773,7 +809,7 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&n_hdlc->write_wait, &wait);
}
@@ -1000,16 +1036,20 @@ static struct n_hdlc *n_hdlc_alloc (void)
/* allocate free rx buffer list */
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
- buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL);
+ buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
if (buf)
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
+ else if (debuglevel >= DEBUG_LEVEL_INFO)
+ printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
}
- /* allocate free rx buffer list */
+ /* allocate free tx buffer list */
for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
- buf = (N_HDLC_BUF*)kmalloc(sizeof(N_HDLC_BUF),GFP_KERNEL);
+ buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
if (buf)
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
+ else if (debuglevel >= DEBUG_LEVEL_INFO)
+ printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
}
/* Initialize the control block */
@@ -1108,7 +1148,14 @@ int init_module(void)
static struct tty_ldisc n_hdlc_ldisc;
int status;
- printk("HDLC line discipline: version %s\n", szVersion);
+ /* range check maxframe arg */
+ if ( maxframe<4096)
+ maxframe=4096;
+ else if ( maxframe>65535)
+ maxframe=65535;
+
+ printk("HDLC line discipline: version %s, maxframe=%u\n",
+ szVersion, maxframe);
/* Register the tty discipline */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index d95cda30e..9027aa67e 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -604,7 +604,7 @@ send_signal:
tty->canon_head = tty->read_head;
tty->canon_data++;
if (tty->fasync)
- kill_fasync(tty->fasync, SIGIO);
+ kill_fasync(tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
return;
@@ -706,7 +706,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
if (tty->fasync)
- kill_fasync(tty->fasync, SIGIO);
+ kill_fasync(tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
@@ -854,6 +854,7 @@ static inline int copy_from_read_buf(struct tty_struct *tty,
retval = 0;
n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
if (n) {
+ mb();
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
index 0c00dcfa5..7e4518e15 100644
--- a/drivers/char/pc110pad.c
+++ b/drivers/char/pc110pad.c
@@ -30,6 +30,8 @@
#include <asm/signal.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include "pc110pad.h"
@@ -51,7 +53,7 @@ static struct pc110pad_params current_params;
static wait_queue_head_t queue;
static struct fasync_struct *asyncptr;
static int active=0; /* number of concurrent open()s */
-
+static struct semaphore read_lock;
/*
* Utility to reset a timer to go off some time in the future.
@@ -75,7 +77,7 @@ static void wake_readers(void)
{
wake_up_interruptible(&queue);
if(asyncptr)
- kill_fasync(asyncptr, SIGIO);
+ kill_fasync(asyncptr, SIGIO, POLL_IN);
}
@@ -503,10 +505,13 @@ static int close_pad(struct inode * inode, struct file * file)
*/
static int open_pad(struct inode * inode, struct file * file)
{
+ unsigned long flags;
+
if (active++)
return 0;
MOD_INC_USE_COUNT;
+ save_flags(flags);
cli();
outb(0x30, current_params.io+2); /* switch off digitiser */
pad_irq(0,0,0); /* read to flush any pending bytes */
@@ -522,7 +527,7 @@ static int open_pad(struct inode * inode, struct file * file)
synthesize_tap=0;
del_timer(&bounce_timer);
del_timer(&tap_timer);
- sti();
+ restore_flags(flags);
return 0;
}
@@ -556,14 +561,19 @@ static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t
{
int r;
+ down(&read_lock);
for(r=0; r<count; r++)
{
if(!read_byte_count)
new_sample(read_bytes);
if(put_user(read_bytes[read_byte_count], buffer+r))
- return -EFAULT;
+ {
+ r = -EFAULT;
+ break;
+ }
read_byte_count = (read_byte_count+1)%3;
}
+ up(&read_lock);
return r;
}
@@ -681,6 +691,7 @@ static void pc110pad_unload(void)
int init_module(void)
{
+ init_MUTEX(&read_lock);
return pc110pad_init();
}
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 2acab7d8f..1118cf950 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -37,6 +37,8 @@
#include <asm/irq.h>
#include <asm/system.h>
+#include <asm/io.h>
+
/* Some configuration switches are present in the include file... */
#include <linux/pc_keyb.h>
@@ -100,7 +102,6 @@ static unsigned char mouse_reply_expected = 0;
static void kb_wait(void)
{
unsigned long timeout = KBC_TIMEOUT;
- unsigned char status;
do {
/*
@@ -404,7 +405,7 @@ static inline void handle_mouse_event(unsigned char scancode)
if (head != queue->tail) {
queue->head = head;
if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO);
+ kill_fasync(queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
}
@@ -421,32 +422,43 @@ static inline void handle_mouse_event(unsigned char scancode)
static unsigned char handle_kbd_event(void)
{
unsigned char status = kbd_read_status();
+ unsigned int work = 10000;
while (status & KBD_STAT_OBF) {
unsigned char scancode;
scancode = kbd_read_input();
-
if (status & KBD_STAT_MOUSE_OBF) {
handle_mouse_event(scancode);
} else {
+#ifdef CONFIG_VT
if (do_acknowledge(scancode))
handle_scancode(scancode, !(scancode & 0x80));
+#endif
mark_bh(KEYBOARD_BH);
}
status = kbd_read_status();
+
+ if(!work--)
+ {
+ printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n",
+ status);
+ break;
+ }
}
return status;
}
+
static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long flags;
+#ifdef CONFIG_VT
kbd_pt_regs = regs;
-
+#endif
spin_lock_irqsave(&kbd_controller_lock, flags);
handle_kbd_event();
spin_unlock_irqrestore(&kbd_controller_lock, flags);
@@ -660,9 +672,9 @@ static char * __init initialize_kbd(void)
kbd_write_command_w(KBD_CCMD_WRITE_MODE);
kbd_write_output_w(KBD_MODE_KBD_INT
- | KBD_MODE_SYS
- | KBD_MODE_DISABLE_MOUSE
- | KBD_MODE_KCC);
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
kbd_write_command_w(KBD_CCMD_READ_MODE);
@@ -697,6 +709,8 @@ static char * __init initialize_kbd(void)
void __init pckbd_init_hw(void)
{
+ kbd_request_region();
+
/* Flush any pending input. */
kbd_clear_input();
@@ -832,7 +846,7 @@ static int release_aux(struct inode * inode, struct file * file)
return 0;
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
- aux_free_irq(inode);
+ aux_free_irq(AUX_DEV);
return 0;
}
@@ -847,7 +861,7 @@ static int open_aux(struct inode * inode, struct file * file)
return 0;
}
queue->head = queue->tail = 0; /* Flush input queue */
- if (aux_request_irq(keyboard_interrupt, inode)) {
+ if (aux_request_irq(keyboard_interrupt, AUX_DEV)) {
aux_count--;
return -EBUSY;
}
diff --git a/drivers/char/pms.c b/drivers/char/pms.c
index 72653aa19..c96570b73 100644
--- a/drivers/char/pms.c
+++ b/drivers/char/pms.c
@@ -22,6 +22,7 @@
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/ioport.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
@@ -1024,21 +1025,11 @@ static int init_mediavision(void)
return 0;
}
-static void shutdown_mediavision(void)
-{
- release_region(io_port,3);
- release_region(0x9A01, 1);
-}
-
/*
- * Module stuff
+ * Initialization and module stuff
*/
-#ifdef MODULE
-int init_module(void)
-#else
-int init_pms_cards(struct video_init *v)
-#endif
+static int __init init_pms_cards(void)
{
printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
@@ -1057,15 +1048,21 @@ int init_pms_cards(struct video_init *v)
return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER);
}
-#ifdef MODULE
-
MODULE_PARM(io_port,"i");
MODULE_PARM(mem_base,"i");
-void cleanup_module(void)
+static void __exit shutdown_mediavision(void)
+{
+ release_region(io_port,3);
+ release_region(0x9A01, 1);
+}
+
+static void __exit cleanup_pms_module(void)
{
shutdown_mediavision();
video_unregister_device((struct video_device *)&pms_device);
}
-#endif
+module_init(init_pms_cards);
+module_exit(cleanup_pms_module);
+
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index c210b0785..d73f128d8 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -34,8 +34,12 @@
* YIELD parport_yield_blocking
* WCTLONIRQ on interrupt, set control lines
* CLRIRQ clear (and return) interrupt count
+ * SETTIME sets device timeout (struct timeval)
+ * GETTIME gets device timeout (struct timeval)
* read/write read or write in current IEEE 1284 protocol
* select wait for interrupt (in readfds)
+ *
+ * Added SETTIME/GETTIME ioctl, Fred Barnes 1999.
*/
#include <linux/module.h>
@@ -74,6 +78,9 @@ struct pp_struct {
#define PP_BUFFER_SIZE 256
#define PARDEVICE_MAX 8
+/* ROUND_UP macro from fs/select.c */
+#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+
static inline void enable_irq (struct pp_struct *pp)
{
struct parport *port = pp->pdev->port;
@@ -356,6 +363,8 @@ static int pp_ioctl(struct inode *inode, struct file *file,
unsigned char mask;
int mode;
int ret;
+ struct timeval par_timeout;
+ long to_jiffies;
case PPRSTATUS:
reg = parport_read_status (port);
@@ -451,6 +460,33 @@ static int pp_ioctl(struct inode *inode, struct file *file,
atomic_sub (ret, &pp->irqc);
return 0;
+ case PPSETTIME:
+ if (copy_from_user (&par_timeout, (struct timeval *)arg,
+ sizeof(struct timeval))) {
+ return -EFAULT;
+ }
+ /* Convert to jiffies, place in pp->pdev->timeout */
+ if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
+ return -EINVAL;
+ }
+ to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
+ to_jiffies += par_timeout.tv_sec * (long)HZ;
+ if (to_jiffies <= 0) {
+ return -EINVAL;
+ }
+ pp->pdev->timeout = to_jiffies;
+ return 0;
+
+ case PPGETTIME:
+ to_jiffies = pp->pdev->timeout;
+ par_timeout.tv_sec = to_jiffies / HZ;
+ par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
+ if (copy_to_user ((struct timeval *)arg, &par_timeout,
+ sizeof(struct timeval))) {
+ return -EFAULT;
+ }
+ return 0;
+
default:
printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
cmd);
diff --git a/drivers/char/ppdev.h b/drivers/char/ppdev.h
index 976374aed..f466f11e6 100644
--- a/drivers/char/ppdev.h
+++ b/drivers/char/ppdev.h
@@ -10,6 +10,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999
*/
#define PP_MAJOR 99
@@ -72,3 +73,9 @@ struct ppdev_frob_struct {
/* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */
#define PPSETPHASE _IOW(PP_IOCTL, 0x94, int)
+
+/* Set and get port timeout (struct timeval's) */
+#define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval)
+#define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval)
+
+
diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c
index 8d5f9aa34..3de17ad5c 100644
--- a/drivers/char/qpmouse.c
+++ b/drivers/char/qpmouse.c
@@ -134,7 +134,7 @@ static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
}
queue->head = head;
if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO);
+ kill_fasync(queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7d99d5b68..17711734f 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -661,25 +661,31 @@ static inline ssize_t do_tty_write(
if (down_interruptible(&inode->i_sem)) {
return -ERESTARTSYS;
}
- for (;;) {
- unsigned long size = PAGE_SIZE*2;
- if (size > count)
- size = count;
+ if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
lock_kernel();
- ret = write(tty, file, buf, size);
+ written = write(tty, file, buf, count);
unlock_kernel();
- if (ret <= 0)
- break;
- written += ret;
- buf += ret;
- count -= ret;
- if (!count)
- break;
- ret = -ERESTARTSYS;
- if (signal_pending(current))
- break;
- if (current->need_resched)
- schedule();
+ } else {
+ for (;;) {
+ unsigned long size = PAGE_SIZE*2;
+ if (size > count)
+ size = count;
+ lock_kernel();
+ ret = write(tty, file, buf, size);
+ unlock_kernel();
+ if (ret <= 0)
+ break;
+ written += ret;
+ buf += ret;
+ count -= ret;
+ if (!count)
+ break;
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ if (current->need_resched)
+ schedule();
+ }
}
if (written) {
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
@@ -1996,7 +2002,8 @@ int tty_unregister_driver(struct tty_driver *driver)
{
int retval;
struct tty_driver *p;
- int found = 0;
+ int i, found = 0;
+ struct termios *tp;
const char *othername = NULL;
if (*driver->refcount)
@@ -2027,6 +2034,23 @@ int tty_unregister_driver(struct tty_driver *driver)
if (driver->next)
driver->next->prev = driver->prev;
+ /*
+ * Free the termios and termios_locked structures because
+ * we don't want to get memory leaks when modular tty
+ * drivers are removed from the kernel.
+ */
+ for (i = 0; i < driver->num; i++) {
+ tp = driver->termios[i];
+ if (tp) {
+ driver->termios[i] = NULL;
+ kfree_s(tp, sizeof(struct termios));
+ }
+ tp = driver->termios_locked[i];
+ if (tp) {
+ driver->termios_locked[i] = NULL;
+ kfree_s(tp, sizeof(struct termios));
+ }
+ }
proc_tty_unregister_driver(driver);
return 0;
}
diff --git a/drivers/fc4/Config.in b/drivers/fc4/Config.in
index 8328f32bd..a11ab5b3e 100644
--- a/drivers/fc4/Config.in
+++ b/drivers/fc4/Config.in
@@ -6,22 +6,22 @@ comment 'Fibre Channel support'
tristate 'Fibre Channel and FC4 SCSI support' CONFIG_FC4
if [ ! "$CONFIG_FC4" = "n" ]; then
- comment 'FC4 drivers'
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
- tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
- fi
- comment 'FC4 targets'
- dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
- else
- dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
- fi
+ comment 'FC4 drivers'
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC
+ tristate 'Sun SOC+ (aka SOCAL)' CONFIG_FC4_SOCAL
+ fi
+ comment 'FC4 targets'
+ dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ dep_tristate 'Sun Enterprise Network Array (A5000 and EX500)' CONFIG_SCSI_FCAL $CONFIG_SCSI
+ else
+ dep_tristate 'Generic FC-AL disk driver' CONFIG_SCSI_FCAL $CONFIG_SCSI
+ fi
else
- define_bool CONFIG_FC4_SOC n
- define_bool CONFIG_FC4_SOCAL n
- define_bool CONFIG_SCSI_PLUTO n
- define_bool CONFIG_SCSI_FCAL n
+ define_bool CONFIG_FC4_SOC n
+ define_bool CONFIG_FC4_SOCAL n
+ define_bool CONFIG_SCSI_PLUTO n
+ define_bool CONFIG_SCSI_FCAL n
fi
endmenu
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 9a5759fef..dc14d2ce6 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -13,13 +13,11 @@ SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
L_TARGET := macintosh.a
+L_OBJS :=
M_OBJS :=
-ifndef CONFIG_MBX
-L_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o
-endif
-ifeq ($(CONFIG_MAC_KEYBOARD),y)
-LX_OBJS := adb.o
+ifeq ($(CONFIG_PMAC_PBOOK),y)
+ L_OBJS += mediabay.o
endif
ifeq ($(CONFIG_MAC_SERIAL),y)
@@ -38,8 +36,36 @@ else
endif
endif
-ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o
+ifdef CONFIG_ADB
+ LX_OBJS := adb.o
+endif
+
+ifdef CONFIG_ADB_KEYBOARD
+ L_OBJS += mac_keyb.o
+endif
+
+ifdef CONFIG_ADB_MACII
+ L_OBJS += via-macii.o
+endif
+
+ifdef CONFIG_ADB_MACIISI
+ L_OBJS += via-maciisi.o
+endif
+
+ifdef CONFIG_ADB_CUDA
+ L_OBJS += via-cuda.o
+endif
+
+ifdef CONFIG_ADB_IOP
+ L_OBJS += adb-iop.o
+endif
+
+ifdef CONFIG_ADB_PMU
+ L_OBJS += via-pmu.o
+endif
+
+ifdef CONFIG_ADB_MACIO
+ L_OBJS += macio-adb.o
endif
include $(TOPDIR)/Rules.make
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index be5c45a6c..73a53a6f4 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -24,29 +24,59 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/notifier.h>
#include <linux/wait.h>
-#include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC
+#include <asm/prom.h>
#include <asm/hydra.h>
-#include <linux/init.h>
+#endif
EXPORT_SYMBOL(adb_controller);
EXPORT_SYMBOL(adb_client_list);
-EXPORT_SYMBOL(adb_hardware);
-struct adb_controller *adb_controller = NULL;
+extern struct adb_driver via_macii_driver;
+extern struct adb_driver via_maciisi_driver;
+extern struct adb_driver via_cuda_driver;
+extern struct adb_driver adb_iop_driver;
+extern struct adb_driver via_pmu_driver;
+extern struct adb_driver macio_adb_driver;
+
+static struct adb_driver *adb_driver_list[] = {
+#ifdef CONFIG_ADB_MACII
+ &via_macii_driver,
+#endif
+#ifdef CONFIG_ADB_MACIISI
+ &via_maciisi_driver,
+#endif
+#ifdef CONFIG_ADB_CUDA
+ &via_cuda_driver,
+#endif
+#ifdef CONFIG_ADB_IOP
+ &adb_iop_driver,
+#endif
+#ifdef CONFIG_ADB_PMU
+ &via_pmu_driver,
+#endif
+#ifdef CONFIG_ADB_MACIO
+ &macio_adb_driver,
+#endif
+ NULL
+};
+
+struct adb_driver *adb_controller;
struct notifier_block *adb_client_list = NULL;
-enum adb_hw adb_hardware = ADB_NONE;
+static int adb_got_sleep = 0;
#ifdef CONFIG_PMAC_PBOOK
-static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
-static struct notifier_block adb_sleep_notifier = {
+static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
- NULL,
- 0
+ SLEEP_LEVEL_ADB,
};
#endif
@@ -109,6 +139,15 @@ static int adb_scan_bus(void)
adb_request(&req, NULL, ADBREQ_SYNC, 3,
(i<< 4) | 0xb, (highFree | 0x60), 0xfe);
/*
+ * See if anybody actually moved. This is suggested
+ * by HW TechNote 01:
+ *
+ * http://developer.apple.com/technotes/hw/hw_01.html
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ (highFree << 4) | 0xf);
+ if (req.reply_len <= 1) continue;
+ /*
* Test whether there are any device(s) left
* at address i.
*/
@@ -159,49 +198,73 @@ static int adb_scan_bus(void)
return devmask;
}
-void adb_init(void)
+int __init adb_init(void)
{
+ struct adb_driver *driver;
+ int i;
+
+#ifdef CONFIG_PPC
if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
+ return 0;
+#endif
+#ifdef CONFIG_MAC
+ if (!MACH_IS_MAC)
+ return 0;
+#endif
- via_cuda_init();
- via_pmu_init();
- macio_adb_init();
-
- if (adb_controller == NULL)
+ adb_controller = NULL;
+
+ i = 0;
+ while ((driver = adb_driver_list[i++]) != NULL) {
+ if (!driver->probe()) {
+ adb_controller = driver;
+ break;
+ }
+ }
+ if ((adb_controller == NULL) || adb_controller->init()) {
printk(KERN_WARNING "Warning: no ADB interface detected\n");
- else
- {
- adb_hardware = adb_controller->kind;
+ } else {
#ifdef CONFIG_PMAC_PBOOK
- notifier_chain_register(&sleep_notifier_list,
- &adb_sleep_notifier);
+ pmu_register_sleep_notifier(&adb_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
adb_reset_bus();
}
+ return 0;
}
+__initcall(adb_init);
#ifdef CONFIG_PMAC_PBOOK
/*
* notify clients before sleep and reset bus afterwards
*/
int
-adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x)
+adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
int ret;
- switch (code) {
- case PBOOK_SLEEP:
- ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
- if (ret & NOTIFY_STOP_MASK)
- return -EBUSY;
- case PBOOK_WAKE:
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ adb_got_sleep = 1;
+ ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+ if (ret & NOTIFY_STOP_MASK)
+ return PBOOK_SLEEP_REFUSE;
+ break;
+ case PBOOK_SLEEP_REJECT:
+ if (adb_got_sleep) {
+ adb_got_sleep = 0;
adb_reset_bus();
- break;
+ }
+ break;
+
+ case PBOOK_SLEEP_NOW:
+ break;
+ case PBOOK_WAKE:
+ adb_reset_bus();
+ break;
}
- return NOTIFY_DONE;
+ return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PMAC_PBOOK */
@@ -277,6 +340,9 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *),
req->data[i+1] = va_arg(list, int);
va_end(list);
+ if (flags & ADBREQ_NOSEND)
+ return 0;
+
return adb_controller->send_request(req, flags & ADBREQ_SYNC);
}
@@ -413,7 +479,7 @@ static int adb_open(struct inode *inode, struct file *file)
{
struct adbdev_state *state;
- if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
+ if (MINOR(inode->i_rdev) > 0 || adb_controller == NULL)
return -ENXIO;
state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
if (state == 0)
@@ -540,6 +606,7 @@ static ssize_t adb_write(struct file *file, const char *buf,
goto out;
atomic_inc(&state->n_pending);
+ if (adb_controller == NULL) return -ENXIO;
/* Special case for ADB_BUSRESET request, all others are sent to
the controller */
@@ -582,8 +649,15 @@ static struct file_operations adb_fops = {
void adbdev_init()
{
+#ifdef CONFIG_PPC
if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
+ return;
+#endif
+#ifdef CONFIG_MAC
+ if (!MACH_IS_MAC)
+ return;
+#endif
+
if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
}
diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
index 76c118474..93be8f08f 100644
--- a/drivers/macintosh/mac_keyb.c
+++ b/drivers/macintosh/mac_keyb.c
@@ -39,12 +39,13 @@
#include <linux/init.h>
#include <linux/tty_flip.h>
#include <linux/config.h>
+#include <linux/notifier.h>
#include <asm/bitops.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_ll.h>
@@ -239,7 +240,7 @@ static void init_trackball(int id);
static void init_turbomouse(int id);
static void init_microspeed(int id);
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
/* XXX: Hook for mouse driver */
void (*adb_mouse_interrupt_hook)(unsigned char *, int);
int adb_emulate_buttons = 0;
@@ -250,6 +251,7 @@ int adb_button3_keycode = 0x7c; /* right option key */
extern int console_loglevel;
extern struct kbd_struct kbd_table[];
+extern wait_queue_head_t keypress_wait;
extern void handle_scancode(unsigned char, int);
@@ -334,7 +336,7 @@ input_keycode(int keycode, int repeat)
if (!repeat)
del_timer(&repeat_timer);
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
/*
* XXX: Add mouse button 2+3 fake codes here if mouse open.
* Keep track of 'button' states here as we only send
@@ -364,7 +366,7 @@ input_keycode(int keycode, int repeat)
}
return;
}
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
if (kbd->kbdmode != VC_RAW) {
if (!up_flag && !dont_repeat[keycode]) {
@@ -420,7 +422,7 @@ static void mac_put_queue(int ch)
}
}
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
static void
mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
{
@@ -552,7 +554,7 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
}
}
}
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
/* XXX Needs to get rid of this, see comments in pmu.c */
extern int backlight_level;
@@ -566,7 +568,11 @@ buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
*/
/* Ignore data from register other than 0 */
+#if 0
if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
+#else
+ if ((data[0] & 0x3) || (nb < 2))
+#endif
return;
switch (data[1]&0xf )
@@ -592,22 +598,26 @@ buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
/* brightness decrease */
case 0xa:
/* down event */
+#ifdef CONFIG_PPC
if ( data[1] == (data[1]&0xf) ) {
if (backlight_level > 2)
pmu_set_brightness(backlight_level-2);
else
pmu_set_brightness(0);
}
+#endif
break;
/* brightness increase */
case 0x9:
/* down event */
+#ifdef CONFIG_PPC
if ( data[1] == (data[1]&0xf) ) {
if (backlight_level < 0x1e)
pmu_set_brightness(backlight_level+2);
else
pmu_set_brightness(0x1f);
}
+#endif
break;
}
}
@@ -672,8 +682,14 @@ static void leds_done(struct adb_request *req)
void __init mackbd_init_hw(void)
{
+#ifdef CONFIG_PPC
if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
+ return;
+#endif
+#ifdef CONFIG_MAC
+ if (!MACH_IS_MAC)
+ return;
+#endif
/* setup key map */
memcpy(key_maps[0], macplain_map, sizeof(plain_map));
@@ -684,7 +700,7 @@ void __init mackbd_init_hw(void)
memcpy(key_maps[8], macalt_map, sizeof(plain_map));
memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map));
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
/* initialize mouse interrupt hook */
adb_mouse_interrupt_hook = NULL;
#endif
@@ -720,9 +736,9 @@ mackeyb_probe(void)
struct adb_request req;
int i;
-#ifdef CONFIG_ADBMOUSE
+#ifdef CONFIG_ADB_MOUSE
adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
-#endif /* CONFIG_ADBMOUSE */
+#endif /* CONFIG_ADB_MOUSE */
adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 2a9fc5ad8..52fc92198 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -8,7 +8,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <asm/prom.h>
-#include <asm/adb.h>
+#include <linux/adb.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/hydra.h>
@@ -59,28 +59,38 @@ static volatile struct adb_regs *adb;
static struct adb_request *current_req, *last_req;
static unsigned char adb_rbuf[16];
+static int macio_probe(void);
+static int macio_init(void);
static void macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
-static int macio_adb_send_request(struct adb_request *req, int sync);
+static int macio_send_request(struct adb_request *req, int sync);
static int macio_adb_autopoll(int devs);
static void macio_adb_poll(void);
static int macio_adb_reset_bus(void);
static void completed(void);
-static struct adb_controller macio_controller = {
- ADB_MACIO,
- macio_adb_send_request,
+struct adb_driver macio_adb_driver = {
+ "MACIO",
+ macio_probe,
+ macio_init,
+ macio_send_request,
+ /*macio_write,*/
macio_adb_autopoll,
- macio_adb_reset_bus,
- macio_adb_poll
+ macio_adb_poll,
+ macio_adb_reset_bus
};
-void macio_adb_init(void)
+int macio_probe(void)
+{
+ return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+}
+
+int macio_init(void)
{
struct device_node *adbs;
adbs = find_compatible_devices("adb", "chrp,adb0");
if (adbs == 0)
- return;
+ return -ENXIO;
#if 0
{ int i;
@@ -101,7 +111,7 @@ void macio_adb_init(void)
0, "ADB", (void *)0)) {
printk(KERN_ERR "ADB: can't get irq %d\n",
adbs->intrs[0].line);
- return;
+ return -EAGAIN;
}
out_8(&adb->ctrl.r, 0);
@@ -112,12 +122,7 @@ void macio_adb_init(void)
out_8(&adb->autopoll.r, APE);
out_8(&adb->intr_enb.r, DFB | TAG);
- adb_controller = &macio_controller;
-// adb_hardware = ADB_MACIO;
-
-// adb_send_request = macio_adb_send_request;
-// adb_autopoll = macio_adb_autopoll;
-// adb_reset_bus = macio_reset_bus;
+ return 0;
}
static int macio_adb_autopoll(int devs)
@@ -143,7 +148,7 @@ static int macio_adb_reset_bus(void)
}
/* Send an ADB command */
-static int macio_adb_send_request(struct adb_request *req, int sync)
+static int macio_send_request(struct adb_request *req, int sync)
{
unsigned long mflags;
int i;
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
index 93fe07774..53590a42a 100644
--- a/drivers/macintosh/macserial.c
+++ b/drivers/macintosh/macserial.c
@@ -36,14 +36,22 @@
#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/feature.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
#ifdef CONFIG_KGDB
#include <asm/kgdb.h>
#endif
#include "macserial.h"
+#ifdef CONFIG_PMAC_PBOOK
+static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier serial_sleep_notifier = {
+ serial_notify_sleep,
+ SLEEP_LEVEL_MISC,
+};
+#endif
+
/*
* It would be nice to dynamically allocate everything that
* depends on NUM_SERIAL, so we could support any number of
@@ -1909,6 +1917,10 @@ probe_sccs()
}
*pp = 0;
zs_channels_found = n;
+#ifdef CONFIG_PMAC_PBOOK
+ if (n)
+ pmu_register_sleep_notifier(&serial_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
}
/* rs_init inits the driver */
@@ -2470,3 +2482,40 @@ void __init zs_kgdb_hook(int tty_num)
set_debug_traps(); /* init stub */
}
#endif /* ifdef CONFIG_KGDB */
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+ int i;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ case PBOOK_SLEEP_REJECT:
+ break;
+
+ case PBOOK_SLEEP_NOW:
+ for (i=0; i<zs_channels_found; i++) {
+ struct mac_serial *info = &zs_soft[i];
+ if (info->flags & ZILOG_INITIALIZED) {
+ shutdown(info);
+ info->flags |= ZILOG_SLEEPING;
+ }
+ }
+ break;
+ case PBOOK_WAKE:
+ for (i=0; i<zs_channels_found; i++) {
+ struct mac_serial *info = &zs_soft[i];
+ if (info->flags & ZILOG_SLEEPING) {
+ info->flags &= ~ZILOG_SLEEPING;
+ startup(info, 0);
+ }
+ }
+ break;
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
index 135d5a970..e2f137f73 100644
--- a/drivers/macintosh/macserial.h
+++ b/drivers/macintosh/macserial.h
@@ -68,6 +68,7 @@ struct serial_struct {
#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+#define ZILOG_SLEEPING 0x01000000 /* have shut it down for sleep */
/* Software state per channel */
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 0936b8bfb..83fd1d140 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -26,7 +26,16 @@
#include <asm/feature.h>
#include <asm/mediabay.h>
#include <asm/init.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#ifdef CONFIG_PMAC_PBOOK
+static int mb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier mb_sleep_notifier = {
+ mb_notify_sleep,
+ SLEEP_LEVEL_MEDIABAY,
+};
+#endif
#undef MB_USE_INTERRUPTS
@@ -77,13 +86,13 @@ int media_bay_count = 0;
* Hold the media-bay reset signal true for this many ticks
* after a device is inserted before releasing it.
*/
-#define MB_RESET_COUNT 20
+#define MB_RESET_COUNT 40
/*
* Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
* (or until the device is ready) before registering the IDE interface.
*/
-#define MB_IDE_WAIT 1000
+#define MB_IDE_WAIT 1500
static void poll_media_bay(int which);
static void set_media_bay(int which, int id);
@@ -157,6 +166,10 @@ media_bay_init(void)
{
printk(KERN_INFO "Registered %d media-bay(s)\n", media_bay_count);
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&mb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
kernel_thread(media_bay_task, NULL, 0);
}
}
@@ -298,9 +311,16 @@ poll_media_bay(int which)
int id = MB_CONTENTS(which);
if (id == media_bays[which].last_value) {
- if (id != media_bays[which].content_id
- && ++media_bays[which].value_count >= MB_STABLE_COUNT)
- set_media_bay(which, id);
+ if (id != media_bays[which].content_id
+ && ++media_bays[which].value_count >= MB_STABLE_COUNT) {
+ /* If the device type changes without going thru "MB_NO", we force
+ a pass by "MB_NO" to make sure things are properly reset */
+ if ((id != MB_NO) && (media_bays[which].content_id != MB_NO)) {
+ set_media_bay(which, MB_NO);
+ udelay(500);
+ }
+ set_media_bay(which, id);
+ }
} else {
media_bays[which].last_value = id;
media_bays[which].value_count = 0;
@@ -319,27 +339,28 @@ set_media_bay(int which, int id)
switch (id) {
case MB_CD:
- feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
feature_set(bay->dev_node, FEATURE_Mediabay_enable);
- feature_set(bay->dev_node, FEATURE_CD_power);
feature_set(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+ udelay(500);
+ feature_set(bay->dev_node, FEATURE_CD_power);
printk(KERN_INFO "media bay %d contains a CD-ROM drive\n", which);
break;
case MB_FD:
- feature_clear(bay->dev_node, FEATURE_CD_power);
feature_set(bay->dev_node, FEATURE_Mediabay_enable);
feature_set(bay->dev_node, FEATURE_Mediabay_floppy_enable);
feature_set(bay->dev_node, FEATURE_SWIM3_enable);
printk(KERN_INFO "media bay %d contains a floppy disk drive\n", which);
break;
case MB_NO:
- feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
feature_clear(bay->dev_node, FEATURE_CD_power);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+ feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
+ feature_set(bay->dev_node, FEATURE_Mediabay_reset);
printk(KERN_INFO "media bay %d is empty\n", which);
break;
default:
- feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
- feature_clear(bay->dev_node, FEATURE_CD_power);
feature_set(bay->dev_node, FEATURE_Mediabay_enable);
printk(KERN_INFO "media bay %d contains an unknown device (%d)\n",
which, id);
@@ -348,3 +369,62 @@ set_media_bay(int which, int id)
udelay(500);
}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int __pmac
+mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+ volatile struct media_bay_info* bay;
+ int i;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ case PBOOK_SLEEP_REJECT:
+ break;
+
+ case PBOOK_SLEEP_NOW:
+ for (i=0; i<media_bay_count; i++) {
+ bay = &media_bays[i];
+ feature_clear(bay->dev_node, FEATURE_Mediabay_enable);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_IDE_enable);
+ feature_clear(bay->dev_node, FEATURE_SWIM3_enable);
+ feature_clear(bay->dev_node, FEATURE_Mediabay_floppy_enable);
+ feature_set(bay->dev_node, FEATURE_Mediabay_reset);
+ feature_clear(bay->dev_node, FEATURE_CD_power);
+ out_8(&media_bays[i].addr->contents, 0x70);
+ }
+ break;
+ case PBOOK_WAKE:
+ for (i=0; i<media_bay_count; i++) {
+ bay = &media_bays[i];
+ feature_set(bay->dev_node, FEATURE_Mediabay_enable);
+ /* I suppose this is enough delay to stabilize MB_CONTENT ... */
+ mdelay(10);
+ /* We re-enable the bay using it's previous content only if
+ it did not change */
+ if (MB_CONTENTS(i) == bay->content_id) {
+ set_media_bay(i, bay->content_id);
+ if (bay->content_id != MB_NO) {
+ mdelay(400);
+ /* Clear the bay reset */
+ feature_clear(bay->dev_node, FEATURE_Mediabay_reset);
+ /* This small delay makes sure the device has time
+ to assert the BUSY bit (used by IDE sleep) */
+ udelay(100);
+ /* We reset the state machine timers in case we were in the
+ middle of a wait loop */
+ if (bay->reset_timer)
+ bay->reset_timer = MB_RESET_COUNT;
+ if (bay->cd_timer)
+ bay->cd_timer = MB_IDE_WAIT;
+ }
+ }
+ }
+ break;
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 1742b1620..2e2dbf66c 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -14,16 +14,31 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#ifdef CONFIG_PPC
#include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
+#include <asm/machdep.h>
+#else
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+#endif
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/system.h>
#include <linux/init.h>
static volatile unsigned char *via;
+#ifdef CONFIG_MAC
+#define CUDA_IRQ IRQ_MAC_ADB
+#define __openfirmware
+#define eieio()
+#else
+#define CUDA_IRQ vias->intrs[0].line
+#endif
+
/* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */
#define B 0 /* B-side data */
@@ -73,27 +88,38 @@ static unsigned char cuda_rbuf[16];
static unsigned char *reply_ptr;
static int reading_reply;
static int data_index;
+#ifdef CONFIG_PPC
static struct device_node *vias;
+#endif
static int cuda_fully_inited = 0;
-static int init_via(void);
+static int cuda_probe(void);
+static int cuda_init(void);
+static int cuda_init_via(void);
static void cuda_start(void);
-static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
-static int cuda_adb_send_request(struct adb_request *req, int sync);
+static int cuda_send_request(struct adb_request *req, int sync);
static int cuda_adb_autopoll(int devs);
-static int cuda_adb_reset_bus(void);
-static int cuda_send_request(struct adb_request *req);
-
-
-static struct adb_controller cuda_controller = {
- ADB_VIACUDA,
- cuda_adb_send_request,
+void cuda_poll(void);
+static int cuda_reset_adb_bus(void);
+static int cuda_write(struct adb_request *req);
+
+int cuda_request(struct adb_request *req,
+ void (*done)(struct adb_request *), int nbytes, ...);
+
+struct adb_driver via_cuda_driver = {
+ "CUDA",
+ cuda_probe,
+ cuda_init,
+ cuda_send_request,
+ /*cuda_write,*/
cuda_adb_autopoll,
- cuda_adb_reset_bus,
- cuda_poll
+ cuda_poll,
+ cuda_reset_adb_bus
};
+#ifdef CONFIG_PPC
void
find_via_cuda()
{
@@ -106,7 +132,7 @@ find_via_cuda()
#if 0
{ int i;
- printk("via_cuda_init: node = %p, addrs =", vias->node);
+ printk("find_via_cuda: node = %p, addrs =", vias->node);
for (i = 0; i < vias->n_addrs; ++i)
printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
printk(", intrs =");
@@ -124,31 +150,56 @@ find_via_cuda()
via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000);
cuda_state = idle;
+ sys_ctrler = SYS_CTRLER_CUDA;
+}
+#endif /* CONFIG_PPC */
- if (!init_via()) {
- printk(KERN_ERR "init_via failed\n");
- via = NULL;
- }
-
- adb_controller = &cuda_controller;
+static int
+cuda_probe()
+{
+#ifdef CONFIG_PPC
+ if (sys_ctrler != SYS_CTRLER_CUDA)
+ return -ENODEV;
+#else
+ if (macintosh_config->adb_type != MAC_ADB_CUDA)
+ return -ENODEV;
+ via = via1;
+#endif
+ return 0;
}
-void
-via_cuda_init(void)
+static int
+cuda_init(void)
{
+ int err;
+
if (via == NULL)
- return;
+ return -ENODEV;
- if (request_irq(vias->intrs[0].line, via_interrupt, 0, "VIA", (void *)0)) {
- printk(KERN_ERR "VIA: can't get irq %d\n", vias->intrs[0].line);
- return;
+ err = cuda_init_via();
+ if (err) {
+ printk(KERN_ERR "cuda_probe: init_via() failed\n");
+ via = NULL;
+ return err;
}
- /* Clear and enable interrupts */
+ /* Clear and enable interrupts, but only on PPC. On 68K it's done */
+ /* for us by the the main VIA driver in arch/m68k/mac/via.c */
+
+#ifndef CONFIG_MAC
via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */
via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */
+#endif
+
+ if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+ printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
+ return -EAGAIN;
+ }
+
+ printk("adb: CUDA driver v0.5 for Unified ADB.\n");
cuda_fully_inited = 1;
+ return 0;
}
#define WAIT_FOR(cond, what) \
@@ -156,14 +207,14 @@ via_cuda_init(void)
for (x = 1000; !(cond); --x) { \
if (x == 0) { \
printk("Timeout waiting for " what); \
- return 0; \
+ return -ENXIO; \
} \
udelay(100); \
} \
} while (0)
static int
-init_via()
+cuda_init_via()
{
int x;
@@ -172,7 +223,9 @@ init_via()
via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; /* SR data in */
eieio();
x = via[SR]; eieio(); /* clear any left-over data */
+#ifndef CONFIG_MAC
via[IER] = 0x7f; eieio(); /* disable interrupts from VIA */
+#endif
eieio();
/* delay 4ms and then clear any pending interrupt */
@@ -198,12 +251,12 @@ init_via()
x = via[SR]; eieio();
via[B] |= TIP; eieio(); /* should be unnecessary */
- return 1;
+ return 0;
}
/* Send an ADB command */
static int
-cuda_adb_send_request(struct adb_request *req, int sync)
+cuda_send_request(struct adb_request *req, int sync)
{
int i;
@@ -214,7 +267,7 @@ cuda_adb_send_request(struct adb_request *req, int sync)
req->reply_expected = 1;
- i = cuda_send_request(req);
+ i = cuda_write(req);
if (i)
return i;
@@ -243,7 +296,7 @@ cuda_adb_autopoll(int devs)
/* Reset adb bus - how do we do this?? */
static int
-cuda_adb_reset_bus(void)
+cuda_reset_adb_bus(void)
{
struct adb_request req;
@@ -276,11 +329,11 @@ cuda_request(struct adb_request *req, void (*done)(struct adb_request *),
req->data[i] = va_arg(list, int);
va_end(list);
req->reply_expected = 1;
- return cuda_send_request(req);
+ return cuda_write(req);
}
static int
-cuda_send_request(struct adb_request *req)
+cuda_write(struct adb_request *req)
{
unsigned long flags;
@@ -336,17 +389,17 @@ cuda_start()
void
cuda_poll()
{
- int ie;
+ unsigned long flags;
- __save_flags(ie);
- __cli();
+ save_flags(flags);
+ cli();
if (via[IFR] & SR_INT)
- via_interrupt(0, 0, 0);
- __restore_flags(ie);
+ cuda_interrupt(0, 0, 0);
+ restore_flags(flags);
}
static void
-via_interrupt(int irq, void *arg, struct pt_regs *regs)
+cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
{
int x, status;
struct adb_request *req;
@@ -355,7 +408,7 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs)
return;
status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
- /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */
+ /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
switch (cuda_state) {
case idle:
/* CUDA has sent us the first byte of data - unsolicited */
@@ -469,7 +522,7 @@ via_interrupt(int irq, void *arg, struct pt_regs *regs)
break;
default:
- printk("via_interrupt: unknown cuda_state %d?\n", cuda_state);
+ printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
}
}
@@ -490,9 +543,3 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
printk("\n");
}
}
-
-int
-cuda_present(void)
-{
- return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
-}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 94cc54635..cff3f5cb7 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -21,10 +21,12 @@
#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/cuda.h>
#include <asm/prom.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
-#include <asm/cuda.h>
+#include <asm/machdep.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -32,6 +34,7 @@
#include <asm/irq.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
@@ -70,6 +73,7 @@ static volatile unsigned char *via;
#define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
+#define CB2_INT 0x08
#define CB1_INT 0x10 /* transition on CB1 input */
static enum pmu_state {
@@ -98,11 +102,13 @@ static int pmu_fully_inited = 0;
int asleep;
struct notifier_block *sleep_notifier_list;
+static int pmu_probe(void);
+static int pmu_init(void);
static int init_pmu(void);
static int pmu_queue_request(struct adb_request *req);
static void pmu_start(void);
static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static int pmu_adb_send_request(struct adb_request *req, int sync);
+static int pmu_send_request(struct adb_request *req, int sync);
static int pmu_adb_autopoll(int devs);
static int pmu_adb_reset_bus(void);
static void send_byte(int x);
@@ -112,15 +118,31 @@ static void pmu_done(struct adb_request *req);
static void pmu_handle_data(unsigned char *data, int len,
struct pt_regs *regs);
static void set_volume(int level);
+#ifdef CONFIG_PMAC_PBOOK
+static void pmu_pass_intr(unsigned char *data, int len);
+#endif
-static struct adb_controller pmu_controller = {
- ADB_VIAPMU,
- pmu_adb_send_request,
+struct adb_driver via_pmu_driver = {
+ "PMU",
+ pmu_probe,
+ pmu_init,
+ pmu_send_request,
+ /*pmu_queue_request,*/
pmu_adb_autopoll,
- pmu_adb_reset_bus,
- pmu_poll
+ pmu_poll,
+ pmu_adb_reset_bus
};
+extern void low_sleep_handler(void);
+extern void sleep_save_intrs(int);
+extern void sleep_restore_intrs(void);
+
+extern int grackle_pcibios_read_config_word(unsigned char bus,
+ unsigned char dev_fn, unsigned char offset, unsigned short *val);
+
+extern int grackle_pcibios_write_config_word(unsigned char bus,
+ unsigned char dev_fn, unsigned char offset, unsigned short val);
+
/*
* This table indicates for each PMU opcode:
* - the number of data bytes to be sent with the command, or -1
@@ -164,13 +186,21 @@ static s8 pmu_data_len[256][2] __openfirmwaredata = {
/*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
};
+static char *pbook_type[] = {
+ "Unknown PowerBook",
+ "PowerBook 2400/3400/3500(G3)",
+ "PowerBook G3 Series",
+ "1999 PowerBook G3",
+};
-void __openfirmware
+int __openfirmware
find_via_pmu()
{
+ if (via != 0)
+ return 1;
vias = find_devices("via-pmu");
if (vias == 0)
- return;
+ return 0;
if (vias->next != 0)
printk(KERN_WARNING "Warning: only using 1st via-pmu\n");
@@ -179,7 +209,7 @@ find_via_pmu()
#if 0
{ int i;
- printk("via_pmu_init: node = %p, addrs =", vias->node);
+ printk("find_via_pmu: node = %p, addrs =", vias->node);
for (i = 0; i < vias->n_addrs; ++i)
printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
printk(", intrs =");
@@ -192,12 +222,14 @@ find_via_pmu()
printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n",
vias->n_addrs, vias->n_intrs);
if (vias->n_addrs < 1 || vias->n_intrs < 1)
- return;
+ return 0;
}
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
|| device_is_compatible(vias->parent, "ohare")))
pmu_kind = PMU_OHARE_BASED;
+ else if (device_is_compatible(vias->parent, "paddington"))
+ pmu_kind = PMU_PADDINGTON_BASED;
else if (device_is_compatible(vias->parent, "heathrow"))
pmu_kind = PMU_HEATHROW_BASED;
else
@@ -209,23 +241,28 @@ find_via_pmu()
pmu_state = idle;
- if (!init_pmu())
+ if (!init_pmu()) {
via = NULL;
+ return 0;
+ }
- adb_controller = &pmu_controller;
+ printk(KERN_INFO "PMU driver initialized for %s\n",
+ pbook_type[pmu_kind]);
+ sys_ctrler = SYS_CTRLER_PMU;
+ return 1;
+}
- if (via)
- printk(KERN_INFO "PMU driver initialized for %s\n",
- (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
- ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
- "Unknown PowerBook"));
+static int __openfirmware
+pmu_probe()
+{
+ return vias == NULL? -ENODEV: 0;
}
-void __openfirmware
-via_pmu_init(void)
+static int __openfirmware
+pmu_init(void)
{
if (vias == NULL)
- return;
+ return -ENXIO;
bright_req_1.complete = 1;
bright_req_2.complete = 1;
@@ -235,7 +272,7 @@ via_pmu_init(void)
(void *)0)) {
printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
vias->intrs[0].line);
- return;
+ return -ENXIO;
}
/* Enable interrupts */
@@ -245,6 +282,8 @@ via_pmu_init(void)
/* Enable backlight */
pmu_enable_backlight(1);
+
+ return 0;
}
static int __openfirmware
@@ -292,20 +331,19 @@ pmu_get_model(void)
/* Send an ADB command */
static int __openfirmware
-pmu_adb_send_request(struct adb_request *req, int sync)
+pmu_send_request(struct adb_request *req, int sync)
{
- int i, ret;
+ int i, ret;
+
+ if ((vias == NULL) || (!pmu_fully_inited)) {
+ req->complete = 1;
+ return -ENXIO;
+ }
- if ((vias == NULL) || (!pmu_fully_inited))
- {
- req->complete = 1;
- return -ENXIO;
- }
+ ret = -EINVAL;
- ret = -EINVAL;
-
- switch (req->data[0]) {
- case PMU_PACKET:
+ switch (req->data[0]) {
+ case PMU_PACKET:
for (i = 0; i < req->nbytes - 1; ++i)
req->data[i] = req->data[i+1];
--req->nbytes;
@@ -316,7 +354,7 @@ pmu_adb_send_request(struct adb_request *req, int sync)
req->reply_len = 0;
ret = pmu_queue_request(req);
break;
- case CUDA_PACKET:
+ case CUDA_PACKET:
switch (req->data[1]) {
case CUDA_GET_TIME:
if (req->nbytes != 2)
@@ -344,7 +382,7 @@ pmu_adb_send_request(struct adb_request *req, int sync)
break;
}
break;
- case ADB_PACKET:
+ case ADB_PACKET:
for (i = req->nbytes - 1; i > 1; --i)
req->data[i+2] = req->data[i];
req->data[3] = req->nbytes - 2;
@@ -356,19 +394,17 @@ pmu_adb_send_request(struct adb_request *req, int sync)
req->reply_len = 0;
ret = pmu_queue_request(req);
break;
- }
- if (ret)
- {
- req->complete = 1;
- return ret;
- }
-
- if (sync) {
- while (!req->complete)
- pmu_poll();
- }
+ }
+ if (ret) {
+ req->complete = 1;
+ return ret;
+ }
- return 0;
+ if (sync)
+ while (!req->complete)
+ pmu_poll();
+
+ return 0;
}
/* Enable/disable autopolling */
@@ -513,19 +549,25 @@ pmu_queue_request(struct adb_request *req)
static void __openfirmware
send_byte(int x)
{
- out_8(&via[ACR], 0x1c);
- out_8(&via[SR], x);
- out_8(&via[B], via[B] & ~0x10); /* assert TREQ */
+ volatile unsigned char *v = via;
+
+ out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);
+ out_8(&v[SR], x);
+ out_8(&v[B], in_8(&v[B]) & ~TREQ); /* assert TREQ */
}
static void __openfirmware
recv_byte()
{
- out_8(&via[ACR], 0x0c);
- in_8(&via[SR]); /* resets SR */
- out_8(&via[B], via[B] & ~0x10);
+ volatile unsigned char *v = via;
+
+ out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);
+ in_8(&v[SR]); /* resets SR */
+ out_8(&v[B], in_8(&v[B]) & ~0x10);
}
+static int disable_poll;
+
static void __openfirmware
pmu_start()
{
@@ -545,7 +587,9 @@ pmu_start()
data_len = pmu_data_len[req->data[0]][0];
/* set the shift register to shift out and send a byte */
+ ++disable_poll;
send_byte(req->data[0]);
+ --disable_poll;
out:
restore_flags(flags);
@@ -554,13 +598,15 @@ out:
void __openfirmware
pmu_poll()
{
- int ie;
+ unsigned long flags;
- __save_flags(ie);
- __cli();
+ if (disable_poll)
+ return;
+ save_flags(flags);
+ cli();
if (via[IFR] & (SR_INT | CB1_INT))
via_pmu_interrupt(0, 0, 0);
- __restore_flags(ie);
+ restore_flags(flags);
}
static void __openfirmware
@@ -569,6 +615,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
int intr;
int nloop = 0;
+ ++disable_poll;
while ((intr = in_8(&via[IFR])) != 0) {
if (++nloop > 1000) {
printk(KERN_DEBUG "PMU: stuck in intr loop, "
@@ -580,11 +627,9 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
else if (intr & CB1_INT) {
adb_int_pending = 1;
out_8(&via[IFR], CB1_INT);
- } else
- {
- /* -- Disabled printk, will happen _really_ often on
- PowerBooks ((CB2 interrupts) --
- printk(KERN_DEBUG "PMU: spurrious interrupt intr=%x\n", intr); */
+ }
+ intr &= ~(SR_INT | CB1_INT);
+ if (intr != 0) {
out_8(&via[IFR], intr);
}
}
@@ -597,6 +642,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
pmu_start();
}
}
+ --disable_poll;
}
static void __openfirmware
@@ -605,17 +651,17 @@ pmu_sr_intr(struct pt_regs *regs)
struct adb_request *req;
int bite, timeout;
+ if (via[B] & TREQ) {
+ printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
+ out_8(&via[IFR], SR_INT);
+ return;
+ }
if (via[B] & TACK)
- printk(KERN_DEBUG "PMU: sr_intr but ack still high! (%x)\n",
+ printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n",
via[B]);
- /* if reading grab the byte, and reset the interrupt */
- if ((via[ACR] & SR_OUT) == 0)
- bite = in_8(&via[SR]);
- out_8(&via[IFR], SR_INT);
-
/* reset TREQ and wait for TACK to go high */
- out_8(&via[B], via[B] | TREQ);
+ out_8(&via[B], in_8(&via[B]) | TREQ);
timeout = 3200;
while ((in_8(&via[B]) & TACK) == 0) {
if (--timeout < 0) {
@@ -625,6 +671,11 @@ pmu_sr_intr(struct pt_regs *regs)
udelay(10);
}
+ /* if reading grab the byte, and reset the interrupt */
+ if (pmu_state == reading || pmu_state == reading_intr)
+ bite = in_8(&via[SR]);
+ out_8(&via[IFR], SR_INT);
+
switch (pmu_state) {
case sending:
req = current_req;
@@ -707,8 +758,6 @@ pmu_done(struct adb_request *req)
static void __openfirmware
pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
{
- static int show_pmu_ints = 1;
-
asleep = 0;
if (len < 1) {
adb_int_pending = 0;
@@ -730,21 +779,34 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
}
pmu_done(req);
} else {
- adb_input(data+1, len-1, regs, 1);
+#ifdef CONFIG_XMON
+ if (len == 4 && data[1] == 0x2c) {
+ extern int xmon_wants_key, xmon_pmu_keycode;
+ if (xmon_wants_key) {
+ xmon_pmu_keycode = data[2];
+ return;
+ }
+ }
+#endif /* CONFIG_XMON */
+ /*
+ * XXX On the [23]400 the PMU gives us an up
+ * event for keycodes 0x74 or 0x75 when the PC
+ * card eject buttons are released, so we
+ * ignore those events.
+ */
+ if (!(pmu_kind == PMU_OHARE_BASED && len == 4
+ && data[1] == 0x2c && data[3] == 0xff
+ && (data[2] & ~1) == 0xf4))
+ adb_input(data+1, len-1, regs, 1);
}
+ } else if (data[0] == 0x08 && len == 3) {
+ /* sound/brightness buttons pressed */
+ pmu_set_brightness(data[1] >> 3);
+ set_volume(data[2]);
} else {
- if (data[0] == 0x08 && len == 3) {
- /* sound/brightness buttons pressed */
- pmu_set_brightness(data[1] >> 3);
- set_volume(data[2]);
- } else if (show_pmu_ints
- && !(data[0] == PMU_INT_TICK && len == 1)) {
- int i;
- printk(KERN_DEBUG "pmu intr");
- for (i = 0; i < len; ++i)
- printk(" %.2x", data[i]);
- printk("\n");
- }
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_pass_intr(data, len);
+#endif
}
}
@@ -759,38 +821,46 @@ pmu_enable_backlight(int on)
struct adb_request req;
if (vias == NULL)
- return ;
+ return;
- if (on) {
- /* first call: get current backlight value */
- if (backlight_level < 0) {
- switch(pmu_kind) {
- case PMU_OHARE_BASED:
+ /* first call: get current backlight value */
+ if (on && backlight_level < 0) {
+ switch (pmu_kind) {
+ case PMU_OHARE_BASED:
pmu_request(&req, NULL, 2, 0xd9, 0);
while (!req.complete)
pmu_poll();
backlight_level = req.reply[1] >> 3;
- printk(KERN_DEBUG "pmu: controls returned bright: %d\n", (int)req.reply[1]);
break;
- case PMU_HEATHROW_BASED:
+ case PMU_HEATHROW_BASED:
+ /* We cannot use nvram_read_byte here (not yet initialized) */
pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
while (!req.complete)
pmu_poll();
- printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", (int)req.reply[1]);
backlight_level = req.reply[1];
+ printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
+ break;
+ case PMU_PADDINGTON_BASED:
+ /* the G3 PB 1999 has a backlight node
+ and chrp-structured nvram */
+ /* XXX should read macos's "blkt" property in nvram
+ for this node. For now this ensures that the
+ backlight doesn't go off as soon as linux boots. */
+ backlight_level = 20;
break;
- default:
+ default:
backlight_enabled = 0;
return;
}
- }
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- LEVEL_TO_BRIGHT(backlight_level));
- while (!req.complete)
- pmu_poll();
+ }
+ if (on) {
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ LEVEL_TO_BRIGHT(backlight_level));
+ while (!req.complete)
+ pmu_poll();
}
pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
+ PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
while (!req.complete)
pmu_poll();
backlight_enabled = on;
@@ -847,7 +917,7 @@ pmu_restart(void)
{
struct adb_request req;
- __cli();
+ cli();
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
PMU_INT_TICK );
@@ -866,7 +936,7 @@ pmu_shutdown(void)
{
struct adb_request req;
- __cli();
+ cli();
pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
PMU_INT_TICK );
@@ -881,13 +951,69 @@ pmu_shutdown(void)
;
}
+#ifdef CONFIG_PMAC_PBOOK
+
+static LIST_HEAD(sleep_notifiers);
+
int
-pmu_present(void)
+pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
{
- return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+ struct list_head *list;
+ struct pmu_sleep_notifier *current;
+
+ for (list = sleep_notifiers.next; list != &sleep_notifiers;
+ list = list->next) {
+ current = list_entry(list, struct pmu_sleep_notifier, list);
+ if (n->priority > current->priority)
+ break;
+ }
+ __list_add(&n->list, list->prev, list);
+ return 0;
}
-#ifdef CONFIG_PMAC_PBOOK
+int
+pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
+{
+ if (n->list.next == 0)
+ return -ENOENT;
+ list_del(&n->list);
+ n->list.next = 0;
+ return 0;
+}
+
+/* Sleep is broadcast last-to-first */
+static int
+broadcast_sleep(int when, int can_cancel)
+{
+ int ret = PBOOK_SLEEP_OK;
+ struct list_head *list;
+ struct pmu_sleep_notifier *current;
+
+ for (list = sleep_notifiers.prev; list != &sleep_notifiers;
+ list = list->prev) {
+ current = list_entry(list, struct pmu_sleep_notifier, list);
+ ret = current->notifier_call(current, when);
+ if (can_cancel && (ret != PBOOK_SLEEP_OK))
+ return ret;
+ }
+ return ret;
+}
+
+/* Wake is broadcast first-to-last */
+static int
+broadcast_wake(void)
+{
+ int ret = PBOOK_SLEEP_OK;
+ struct list_head *list;
+ struct pmu_sleep_notifier *current;
+
+ for (list = sleep_notifiers.next; list != &sleep_notifiers;
+ list = list->next) {
+ current = list_entry(list, struct pmu_sleep_notifier, list);
+ current->notifier_call(current, PBOOK_WAKE);
+ }
+ return ret;
+}
/*
* This struct is used to store config register values for
@@ -897,10 +1023,11 @@ static struct pci_save {
u16 command;
u16 cache_lat;
u16 intr;
+ u32 rom_address;
} *pbook_pci_saves;
static int n_pbook_pci_saves;
-static inline void __openfirmware
+static void __openfirmware
pbook_pci_save(void)
{
int npci;
@@ -922,12 +1049,13 @@ pbook_pci_save(void)
pci_read_config_word(pd, PCI_COMMAND, &ps->command);
pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+ pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
++ps;
--npci;
}
}
-static inline void __openfirmware
+static void __openfirmware
pbook_pci_restore(void)
{
u16 cmd;
@@ -948,7 +1076,7 @@ pbook_pci_restore(void)
PCI_BASE_ADDRESS_0 + j*4,
pd->resource[j].start);
pci_write_config_dword(pd, PCI_ROM_ADDRESS,
- pd->resource[PCI_ROM_RESOURCE].start);
+ ps->rom_address);
pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
ps->cache_lat);
pci_write_config_word(pd, PCI_INTERRUPT_LINE,
@@ -963,43 +1091,147 @@ pbook_pci_restore(void)
/*
* Put the powerbook to sleep.
*/
-#define IRQ_ENABLE ((unsigned int *)0xf3000024)
-#define MEM_CTRL ((unsigned int *)0xf8000070)
+
+#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38))
+#define GRACKLE_PM (1<<7)
+#define GRACKLE_DOZE (1<<5)
+#define GRACKLE_NAP (1<<4)
+#define GRACKLE_SLEEP (1<<3)
+
+int __openfirmware powerbook_sleep_G3(void)
+{
+ int ret;
+ unsigned long save_l2cr;
+ unsigned long save_fcr;
+ unsigned long wait;
+ unsigned short pmcr1;
+ struct adb_request sleep_req;
+ struct device_node *macio;
+ unsigned long macio_base = 0;
+
+ macio = find_devices("mac-io");
+ if (macio != 0 && macio->n_addrs > 0)
+ macio_base = (unsigned long)
+ ioremap(macio->addrs[0].address, 0x40);
-int __openfirmware powerbook_sleep(void)
+ /* Sync the disks. */
+ /* XXX It would be nice to have some way to ensure that
+ * nobody is dirtying any new buffers while we wait. */
+ fsync_dev(0);
+
+ /* Notify device drivers */
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+ if (ret != PBOOK_SLEEP_OK) {
+ broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
+ printk("pmu: sleep rejected\n");
+ return -EBUSY;
+ }
+ broadcast_sleep(PBOOK_SLEEP_NOW, 0);
+
+ /* Give the disks a little time to actually finish writing */
+ for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ mb();
+
+ /* Disable all interrupts except pmu */
+ sleep_save_intrs(vias->intrs[0].line);
+
+ /* Make sure the decrementer won't interrupt us */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+#if 0
+ /* Save the state of PCI config space for some slots */
+ pbook_pci_save();
+#endif
+ /* For 750, save backside cache setting and disable it */
+ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
+ if (save_l2cr)
+ _set_L2CR(0);
+
+ if (macio_base != 0) {
+ save_fcr = in_le32(FEATURE_CTRL(macio_base));
+ /* Check if this is still valid on older powerbooks */
+ out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL));
+ }
+
+ if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
+ giveup_fpu(current);
+
+ grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);
+ /* Apparently, MacOS uses NAP mode for Grackle ??? */
+ pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP);
+ pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
+ grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!sleep_req.complete)
+ mb();
+
+ cli();
+ while (pmu_state != idle)
+ pmu_poll();
+
+ /* Call low-level ASM sleep handler */
+ low_sleep_handler();
+
+ /* We're awake again, stop grackle PM */
+ grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);
+ pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
+ grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+
+ sti();
+#if 0
+ /* According to someone from Apple, this should not be needed,
+ at least not for all devices. Let's keep it for now until we
+ have something that works. */
+ pbook_pci_restore();
+#endif
+ set_context(current->mm->context);
+
+ /* Restore L2 cache */
+ if (save_l2cr)
+ _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+
+ /* reenable interrupts */
+ sleep_restore_intrs();
+
+ /* Notify drivers */
+ broadcast_wake();
+
+ return 0;
+}
+
+#define PB3400_MEM_CTRL ((unsigned int *)0xf8000070)
+
+int __openfirmware powerbook_sleep_3400(void)
{
int ret, i, x;
- static int save_backlight;
- static unsigned int save_irqen;
unsigned long msr;
unsigned int hid0;
unsigned long p, wait;
struct adb_request sleep_req;
- /* Notify device drivers */
- ret = notifier_call_chain(&sleep_notifier_list, PBOOK_SLEEP, NULL);
- if (ret & NOTIFY_STOP_MASK)
- return -EBUSY;
-
/* Sync the disks. */
/* XXX It would be nice to have some way to ensure that
* nobody is dirtying any new buffers while we wait. */
fsync_dev(0);
- /* Turn off the display backlight */
- save_backlight = backlight_enabled;
- if (save_backlight)
- pmu_enable_backlight(0);
+ /* Notify device drivers */
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, 1);
+ if (ret != PBOOK_SLEEP_OK) {
+ broadcast_sleep(PBOOK_SLEEP_REJECT, 0);
+ printk("pmu: sleep rejected\n");
+ return -EBUSY;
+ }
+ broadcast_sleep(PBOOK_SLEEP_NOW, 0);
/* Give the disks a little time to actually finish writing */
for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
mb();
/* Disable all interrupts except pmu */
- save_irqen = in_le32(IRQ_ENABLE);
- for (i = 0; i < 32; ++i)
- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
- disable_irq(i);
+ sleep_save_intrs(vias->intrs[0].line);
+
+ /* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
/* Save the state of PCI config space for some slots */
@@ -1008,9 +1240,9 @@ int __openfirmware powerbook_sleep(void)
/* Set the memory controller to keep the memory refreshed
while we're asleep */
for (i = 0x403f; i >= 0x4000; --i) {
- out_be32(MEM_CTRL, i);
+ out_be32(PB3400_MEM_CTRL, i);
do {
- x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
+ x = (in_be32(PB3400_MEM_CTRL) >> 16) & 0x3ff;
} while (x == 0);
if (x >= 0x100)
break;
@@ -1020,6 +1252,7 @@ int __openfirmware powerbook_sleep(void)
pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
while (!sleep_req.complete)
mb();
+
/* displacement-flush the L2 cache - necessary? */
for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
i = *(volatile int *)p;
@@ -1035,7 +1268,7 @@ int __openfirmware powerbook_sleep(void)
udelay(10);
/* OK, we're awake again, start restoring things */
- out_be32(MEM_CTRL, 0x3f);
+ out_be32(PB3400_MEM_CTRL, 0x3f);
pbook_pci_restore();
/* wait for the PMU interrupt sequence to complete */
@@ -1043,21 +1276,10 @@ int __openfirmware powerbook_sleep(void)
mb();
/* reenable interrupts */
- for (i = 0; i < 32; ++i)
- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
- enable_irq(i);
+ sleep_restore_intrs();
/* Notify drivers */
- notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
-
- /* reenable ADB autopoll */
- pmu_adb_autopoll(adb_dev_map);
-
- /* Turn on the screen backlight, if it was on before */
- if (save_backlight)
- pmu_enable_backlight(1);
-
- /* Wait for the hard disk to spin up */
+ broadcast_wake();
return 0;
}
@@ -1065,15 +1287,112 @@ int __openfirmware powerbook_sleep(void)
/*
* Support for /dev/pmu device
*/
+#define RB_SIZE 10
+struct pmu_private {
+ struct list_head list;
+ int rb_get;
+ int rb_put;
+ struct rb_entry {
+ unsigned short len;
+ unsigned char data[16];
+ } rb_buf[RB_SIZE];
+ wait_queue_head_t wait;
+ spinlock_t lock;
+};
+
+static LIST_HEAD(all_pmu_pvt);
+static spinlock_t all_pvt_lock = SPIN_LOCK_UNLOCKED;
+
+static void pmu_pass_intr(unsigned char *data, int len)
+{
+ struct pmu_private *pp;
+ struct list_head *list;
+ int i;
+ unsigned long flags;
+
+ if (len > sizeof(pp->rb_buf[0].data))
+ len = sizeof(pp->rb_buf[0].data);
+ spin_lock_irqsave(&all_pvt_lock, flags);
+ for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) {
+ pp = list_entry(list, struct pmu_private, list);
+ i = pp->rb_put + 1;
+ if (i >= RB_SIZE)
+ i = 0;
+ if (i != pp->rb_get) {
+ struct rb_entry *rp = &pp->rb_buf[pp->rb_put];
+ rp->len = len;
+ memcpy(rp->data, data, len);
+ pp->rb_put = i;
+ wake_up_interruptible(&pp->wait);
+ }
+ }
+ spin_unlock_irqrestore(&all_pvt_lock, flags);
+}
+
static int __openfirmware pmu_open(struct inode *inode, struct file *file)
{
+ struct pmu_private *pp;
+ unsigned long flags;
+
+ pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL);
+ if (pp == 0)
+ return -ENOMEM;
+ pp->rb_get = pp->rb_put = 0;
+ spin_lock_init(&pp->lock);
+ init_waitqueue_head(&pp->wait);
+ spin_lock_irqsave(&all_pvt_lock, flags);
+ list_add(&pp->list, &all_pmu_pvt);
+ spin_unlock_irqrestore(&all_pvt_lock, flags);
+ file->private_data = pp;
return 0;
}
static ssize_t __openfirmware pmu_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
- return 0;
+ struct pmu_private *pp = file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret;
+
+ if (count < 1 || pp == 0)
+ return -EINVAL;
+ ret = verify_area(VERIFY_WRITE, buf, count);
+ if (ret)
+ return ret;
+
+ add_wait_queue(&pp->wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ for (;;) {
+ ret = -EAGAIN;
+ spin_lock(&pp->lock);
+ if (pp->rb_get != pp->rb_put) {
+ int i = pp->rb_get;
+ struct rb_entry *rp = &pp->rb_buf[i];
+ ret = rp->len;
+ if (ret > count)
+ ret = count;
+ if (ret > 0 && copy_to_user(buf, rp->data, ret))
+ ret = -EFAULT;
+ if (++i >= RB_SIZE)
+ i = 0;
+ pp->rb_get = i;
+ }
+ spin_unlock(&pp->lock);
+ if (ret >= 0)
+ break;
+
+ if (file->f_flags & O_NONBLOCK)
+ break;
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ break;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&pp->wait, &wait);
+
+ return ret;
}
static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
@@ -1082,26 +1401,65 @@ static ssize_t __openfirmware pmu_write(struct file *file, const char *buf,
return 0;
}
+static unsigned int pmu_fpoll(struct file *filp, poll_table *wait)
+{
+ struct pmu_private *pp = filp->private_data;
+ unsigned int mask = 0;
+
+ if (pp == 0)
+ return 0;
+ poll_wait(filp, &pp->wait, wait);
+ spin_lock(&pp->lock);
+ if (pp->rb_get != pp->rb_put)
+ mask |= POLLIN;
+ spin_unlock(&pp->lock);
+ return mask;
+}
+
+static int pmu_release(struct inode *inode, struct file *file)
+{
+ struct pmu_private *pp = file->private_data;
+ unsigned long flags;
+
+ if (pp != 0) {
+ file->private_data = 0;
+ spin_lock_irqsave(&all_pvt_lock, flags);
+ list_del(&pp->list);
+ spin_unlock_irqrestore(&all_pvt_lock, flags);
+ kfree(pp);
+ }
+ return 0;
+}
+
/* Note: removed __openfirmware here since it causes link errors */
-static int /*__openfirmware*/ pmu_ioctl(struct inode * inode, struct file *filp,
+static int pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
int error;
__u32 value;
switch (cmd) {
- case PMU_IOC_SLEEP:
- if (pmu_kind != PMU_OHARE_BASED)
- return -ENOSYS;
- return powerbook_sleep();
- case PMU_IOC_GET_BACKLIGHT:
+ case PMU_IOC_SLEEP:
+ switch (pmu_kind) {
+ case PMU_OHARE_BASED:
+ error = powerbook_sleep_3400();
+ break;
+ case PMU_HEATHROW_BASED:
+ case PMU_PADDINGTON_BASED:
+ error = powerbook_sleep_G3();
+ break;
+ default:
+ error = ENOSYS;
+ }
+ return error;
+ case PMU_IOC_GET_BACKLIGHT:
return put_user(backlight_level, (__u32 *)arg);
- case PMU_IOC_SET_BACKLIGHT:
+ case PMU_IOC_SET_BACKLIGHT:
error = get_user(value, (__u32 *)arg);
if (!error)
pmu_set_brightness(value);
return error;
- case PMU_IOC_GET_MODEL:
+ case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, (__u32 *)arg);
}
return -EINVAL;
@@ -1112,12 +1470,12 @@ static struct file_operations pmu_device_fops = {
pmu_read,
pmu_write,
NULL, /* no readdir */
- NULL, /* no poll yet */
+ pmu_fpoll,
pmu_ioctl,
NULL, /* no mmap */
pmu_open,
NULL, /* flush */
- NULL /* no release */
+ pmu_release,
};
static struct miscdevice pmu_device = {
diff --git a/drivers/misc/Config.in b/drivers/misc/Config.in
index 9467c5e45..5b793e214 100644
--- a/drivers/misc/Config.in
+++ b/drivers/misc/Config.in
@@ -4,13 +4,6 @@
mainmenu_option next_comment
comment 'Misc devices'
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Generic ACPI support' CONFIG_ACPI
-fi
-
-# PIIX4 ACPI requires PCI for setup and a hardcoded TSC for timing
-if [ "$CONFIG_PCI" = "y" -a "$CONFIG_X86_TSC" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'PIIX4 ACPI support' CONFIG_PIIX4_ACPI
-fi
+tristate 'Generic ACPI support' CONFIG_ACPI
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 8368614ad..6183d1231 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -26,10 +26,6 @@ else
endif
endif
-ifdef CONFIG_PIIX4_ACPI
-O_OBJS += piix4_acpi.o
-endif
-
include $(TOPDIR)/Rules.make
fastdep:
diff --git a/drivers/misc/acpi.c b/drivers/misc/acpi.c
index 27137fa40..99911093b 100644
--- a/drivers/misc/acpi.c
+++ b/drivers/misc/acpi.c
@@ -18,6 +18,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/*
+ * See http://www.geocities.com/SiliconValley/Hardware/3165/
+ * for the user-level ACPI stuff
+ */
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
@@ -46,6 +51,10 @@
static struct acpi_facp *acpi_facp = NULL;
static unsigned long acpi_facp_addr = 0;
static unsigned long acpi_dsdt_addr = 0;
+
+static volatile u32 acpi_pm1_status = 0;
+static volatile u32 acpi_gpe_status = 0;
+static volatile u32 acpi_gpe_level = 0;
static DECLARE_WAIT_QUEUE_HEAD(acpi_wait_event);
/*
@@ -73,6 +82,19 @@ static void acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
}
/*
+ * Get the value of the fixed event enable register
+ */
+static u32 acpi_read_pm1_enable(struct acpi_facp *facp)
+{
+ int offset = facp->pm1_evt_len >> 1;
+ u32 value = inw(facp->pm1a_evt + offset);
+ if (facp->pm1b_evt) {
+ value |= inw(facp->pm1b_evt + offset);
+ }
+ return value;
+}
+
+/*
* Set the value of the fixed event enable register (enable events)
*/
static void acpi_write_pm1_enable(struct acpi_facp *facp, u32 value)
@@ -128,6 +150,28 @@ static void acpi_write_gpe_status(struct acpi_facp *facp, u32 value)
}
/*
+ * Get the value of the general-purpose event enable register
+ */
+static u32 acpi_read_gpe_enable(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ int i, size, offset;
+
+ offset = facp->gpe0_len >> 1;
+ if (facp->gpe1) {
+ size = facp->gpe1_len >> 1;
+ for (i = size - 1; i >= 0; i--) {
+ value = (value << 8) | inb(facp->gpe1 + offset + i);
+ }
+ }
+ size = facp->gpe0_len >> 1;
+ for (i = size - 1; i >= 0; i--) {
+ value = (value << 8) | inb(facp->gpe0 + offset + i);
+ }
+ return value;
+}
+
+/*
* Set the value of the general-purpose event enable register (enable events)
*/
static void acpi_write_gpe_enable(struct acpi_facp *facp, u32 value)
@@ -157,7 +201,8 @@ static struct acpi_table *__init acpi_map_table(u32 addr)
if (addr) {
// map table header to determine size
table = (struct acpi_table *)
- ioremap_nocache((unsigned long) addr, sizeof(struct acpi_table));
+ ioremap_nocache((unsigned long) addr,
+ sizeof(struct acpi_table));
if (table) {
unsigned long table_size = table->length;
iounmap(table);
@@ -201,10 +246,13 @@ static int __init acpi_map_tables(void)
// strip trailing space and print OEM identifier
memcpy_fromio(oem, rsdp->oem, 6);
oem[6] = '\0';
- for (j = 5; j > 0 && (oem[j] == '\0' || oem[j] == ' '); j--) {
+ for (j = 5;
+ j > 0 && (oem[j] == '\0' || oem[j] == ' ');
+ j--) {
oem[j] = '\0';
}
- printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n", oem, (void *) i);
+ printk(KERN_INFO "ACPI: \"%s\" found at 0x%p\n",
+ oem, (void *) i);
break;
}
@@ -252,6 +300,7 @@ static int __init acpi_map_tables(void)
*/
static void acpi_unmap_tables(void)
{
+ acpi_idle = NULL;
acpi_dsdt_addr = 0;
acpi_facp_addr = 0;
acpi_unmap_table((struct acpi_table *) acpi_facp);
@@ -263,17 +312,32 @@ static void acpi_unmap_tables(void)
*/
static void acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
{
- u32 status;
-
- // detect and disable any fixed events
- status = acpi_read_pm1_status(acpi_facp);
- acpi_write_pm1_enable(acpi_facp, ~status);
-
- // detect and disable any general-purpose events
- status = acpi_read_gpe_status(acpi_facp);
- acpi_write_gpe_enable(acpi_facp, ~status);
-
+ u32 pm1_status, gpe_status, gpe_level, gpe_edge;
+ // detect and clear fixed events
+ pm1_status = (acpi_read_pm1_status(acpi_facp)
+ & acpi_read_pm1_enable(acpi_facp));
+ acpi_write_pm1_status(acpi_facp, pm1_status);
+
+ // detect and handle general-purpose events
+ gpe_status = (acpi_read_gpe_status(acpi_facp)
+ & acpi_read_gpe_enable(acpi_facp));
+ gpe_level = gpe_status & acpi_gpe_level;
+ if (gpe_level) {
+ // disable level-triggered events
+ acpi_write_gpe_enable(
+ acpi_facp,
+ acpi_read_gpe_enable(acpi_facp) & ~gpe_level);
+ }
+ gpe_edge = gpe_status & ~gpe_level;
+ if (gpe_edge) {
+ // clear edge-triggered events
+ while (acpi_read_gpe_status(acpi_facp) & gpe_edge)
+ acpi_write_gpe_status(acpi_facp, gpe_edge);
+ }
+
// notify process reading /dev/acpi
+ acpi_pm1_status |= pm1_status;
+ acpi_gpe_status |= gpe_status;
wake_up_interruptible(&acpi_wait_event);
}
@@ -311,17 +375,79 @@ static int acpi_ioctl(struct inode *inode,
(void *) arg,
sizeof(struct acpi_find_tables));
if (!status) {
- struct acpi_find_tables *rqst = (struct acpi_find_tables *) arg;
+ struct acpi_find_tables *rqst
+ = (struct acpi_find_tables *) arg;
put_user(acpi_facp_addr, &rqst->facp);
put_user(acpi_dsdt_addr, &rqst->dsdt);
status = 0;
}
break;
+ case ACPI_ENABLE_EVENT:
+ status = verify_area(VERIFY_READ,
+ (void *) arg,
+ sizeof(struct acpi_enable_event));
+ if (!status) {
+ struct acpi_enable_event *rqst
+ = (struct acpi_enable_event *) arg;
+ u32 pm1_enable, gpe_enable, gpe_level;
+ u32 pm1_enabling, gpe_enabling;
+
+ get_user(pm1_enable, &rqst->pm1_enable);
+ get_user(gpe_enable, &rqst->gpe_enable);
+ get_user(gpe_level, &rqst->gpe_level);
+ gpe_level &= gpe_enable;
+
+ // clear previously disabled events before enabling
+ pm1_enabling = (pm1_enable
+ & ~acpi_read_pm1_enable(acpi_facp));
+ acpi_write_pm1_status(acpi_facp, pm1_enabling);
+ gpe_enabling = (gpe_enable &
+ ~acpi_read_gpe_enable(acpi_facp));
+ while (acpi_read_gpe_status(acpi_facp) & gpe_enabling)
+ acpi_write_gpe_status(acpi_facp, gpe_enabling);
+
+ acpi_write_pm1_enable(acpi_facp, pm1_enable);
+ acpi_write_gpe_enable(acpi_facp, gpe_enable);
+ acpi_gpe_level = gpe_level;
+
+ status = 0;
+ }
+ break;
case ACPI_WAIT_EVENT:
- interruptible_sleep_on(&acpi_wait_event);
- if (signal_pending(current))
- return -ERESTARTSYS;
- status = 0;
+ status = verify_area(VERIFY_WRITE,
+ (void *) arg,
+ sizeof(struct acpi_wait_event));
+ if (!status) {
+ struct acpi_wait_event *rqst
+ = (struct acpi_wait_event *) arg;
+ u32 pm1_status = 0;
+ u32 gpe_status = 0;
+
+ for (;;) {
+ unsigned long flags;
+
+ // we need an atomic exchange here
+ save_flags(flags);
+ cli();
+ pm1_status = acpi_pm1_status;
+ acpi_pm1_status = 0;
+ gpe_status = acpi_gpe_status;
+ acpi_gpe_status = 0;
+ restore_flags(flags);
+
+ if (pm1_status || gpe_status)
+ break;
+
+ // wait for an event to arrive
+ interruptible_sleep_on(&acpi_wait_event);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+
+ put_user(pm1_status, &rqst->pm1_status);
+ put_user(gpe_status, &rqst->gpe_status);
+ status = 0;
+ }
break;
}
return status;
@@ -355,6 +481,48 @@ static struct miscdevice acpi_device =
NULL
};
+/* Make it impossible to enter L2/L3 until after we've initialized */
+static unsigned long acpi_p_lvl2_lat = ~0UL;
+static unsigned long acpi_p_lvl3_lat = ~0UL;
+
+/* Initialize to guaranteed harmless port read */
+static u16 acpi_p_lvl2 = 0x80;
+static u16 acpi_p_lvl3 = 0x80;
+
+static void acpi_idle_handler(void)
+{
+ unsigned long time;
+ static int sleep_level = 1;
+
+ time = inl(acpi_facp->pm_tmr);
+ switch (sleep_level) {
+ case 1:
+ __asm__ __volatile__("sti ; hlt": : :"memory");
+ break;
+ case 2:
+ inb(acpi_p_lvl2);
+ break;
+ case 3:
+ /* Disable PCI arbitration while sleeping, to avoid DMA corruption? */
+ if (acpi_facp->pm2_cnt) {
+ unsigned int port = acpi_facp->pm2_cnt;
+ outb(inb(port) | ACPI_ARB_DIS, port);
+ inb(acpi_p_lvl3);
+ outb(inb(port) & ~ACPI_ARB_DIS, port);
+ break;
+ }
+ inb(acpi_p_lvl3);
+ }
+ time = (inl(acpi_facp->pm_tmr) - time) & ACPI_TMR_MASK;
+
+ if (time > acpi_p_lvl3_lat)
+ sleep_level = 3;
+ else if (time > acpi_p_lvl2_lat)
+ sleep_level = 2;
+ else
+ sleep_level = 1;
+}
+
/*
* Initialize and enable ACPI
*/
@@ -376,6 +544,17 @@ static int __init acpi_init(void)
if (misc_register(&acpi_device)) {
printk(KERN_ERR "ACPI: misc. register failed\n");
}
+
+ /*
+ * Set up the ACPI idle function. Note that we can't really
+ * do this with multiple CPU's, we'd need a per-CPU ACPI
+ * device..
+ */
+#ifdef __SMP__
+ if (smp_num_cpus > 1)
+ return 0;
+#endif
+ acpi_idle = acpi_idle_handler;
return 0;
}
@@ -389,7 +568,8 @@ static void __exit acpi_exit(void)
// disable and clear any pending events
acpi_write_gpe_enable(acpi_facp, 0);
while (acpi_read_gpe_status(acpi_facp)) {
- acpi_write_gpe_status(acpi_facp, acpi_read_gpe_status(acpi_facp));
+ acpi_write_gpe_status(acpi_facp,
+ acpi_read_gpe_status(acpi_facp));
}
acpi_write_pm1_enable(acpi_facp, 0);
acpi_write_pm1_status(acpi_facp, acpi_read_pm1_status(acpi_facp));
@@ -405,6 +585,7 @@ static void __exit acpi_exit(void)
module_init(acpi_init)
module_exit(acpi_exit)
+
#else
__initcall(acpi_init);
diff --git a/drivers/misc/piix4_acpi.c b/drivers/misc/piix4_acpi.c
deleted file mode 100644
index 9cd3625b9..000000000
--- a/drivers/misc/piix4_acpi.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * linux/drivers/misc/piix4_acpi.c
- *
- * (C) Copyright 1999 Linus Torvalds
- *
- * A PM driver for the ACPI portion of the Intel PIIX4
- * chip.
- *
- * This has been known to occasionally work on some laptops.
- *
- * It probably only works on Intel PII machines that support
- * the STPCLK protocol.
- */
-
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-extern void (*acpi_idle)(void);
-
-/*
- * This first part should be common to all ACPI
- * CPU sleep functionality. Assuming we get the
- * timing heuristics in a better shape than "none" ;)
- */
-
-typedef void (*sleep_fn_t)(void);
-
-/*
- * Our "sleep mode" is a fixed point number
- * with two binary places, ranging between
- * [0 .. 3[
- */
-#define Cx_SHIFT 2
-#define MAXMODE ((3 << Cx_SHIFT)-1)
-
-/*
- * NOTE!
- *
- * Right now this always defaults to C3, which is just broken.
- * The exit latency is usually too high for much busy IO activity,
- * and generally it's not always the best thing to do.
- *
- * We should just read the cycle counter around all the cases,
- * and if we pause for a long time we go to a deeper sleep, while
- * a short wait makes us go into a lighter sleep.
- */
-static void common_acpi_idle(sleep_fn_t *sleep)
-{
- int mode = MAXMODE;
-
- while (1) {
- while (!current->need_resched) {
- unsigned int time;
-
- time = get_cycles();
- sleep[(mode) >> Cx_SHIFT]();
- time = get_cycles() - time;
-
- /*
- * Yeah, yeah, yeah.
- * if (time > Large && mode < MAXMODE) mode++;
- * if (time < Small && mode > 0) mode--;
- * Yadda-yadda-yadda.
- *
- * "Large" is on the order of half a timer tick.
- * "Small" is on the order of Large >> 2 or so.
- *
- * Somebody should _really_ look at the exact
- * details. The ACPI bios would give some made-up
- * numbers, they might be useful (or maybe not:
- * they are probably tuned for whatever Windows
- * does, so don't take them for granted).
- */
- }
- schedule();
- check_pgt_cache();
- }
-}
-
-/* Ok, here starts the magic PIIX4 knowledge */
-
-/*
- * Ehh.. We "know" about the northbridge
- * bus arbitration stuff. Maybe somebody
- * should actually verify this some day?
- */
-#define NORTHBRIDGE_CONTROL 0x22
-#define NB_ARBITRATE 0x01
-
-/*
- * PIIX4 ACPI IO offsets and defines
- */
-#define PMEN 0x02
-#define PMCNTRL 0x04
-#define PMTMR 0x08
-#define GPSTS 0x0c
-#define GPEN 0x0E
-
-#define PCNTRL 0x10
-#define CC_EN 0x0200
-#define BST_EN 0x0400
-#define SLEEP_EN 0x0800
-#define STPCLK_EN 0x1000
-#define CLKRUN_EN 0x2000
-
-#define PLVL2 0x14
-#define PLVL3 0x15
-
-/*
- * PIIX4 ACPI PCI configurations offsets and defines
- */
-#define DEVACTB 0x58
-#define BRLD_EN_IRQ0 0x01
-#define BRLD_EN_IRQ 0x02
-
-#define PMREGMISC 0x80
-#define PMIOSE 0x01
-
-static unsigned int piix4_base_address = 0;
-
-static void piix4_c1_sleep(void)
-{
- asm volatile("sti ; hlt" : : : "memory");
-}
-
-static void piix4_c2_sleep(void)
-{
- outl(CLKRUN_EN | CC_EN, piix4_base_address + PCNTRL);
- inb(piix4_base_address + PLVL2);
-}
-
-static void piix4_c3_sleep(void)
-{
- __cli();
- outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL);
- outb(NB_ARBITRATE, NORTHBRIDGE_CONTROL);
- inb(piix4_base_address + PLVL3);
- outb(0, NORTHBRIDGE_CONTROL);
- __sti();
-}
-
-static sleep_fn_t piix4_sleep[] = {
- piix4_c1_sleep, /* low-latency C1 (ie "sti ; hlt") */
- piix4_c2_sleep, /* medium latency C2 (ie LVL2 stopckl) */
- piix4_c3_sleep /* high-latency C3 (ie LVL3 sleep) */
-};
-
-static void piix4_acpi_idle(void)
-{
- common_acpi_idle(piix4_sleep);
-}
-
-static int __init piix4_acpi_init(void)
-{
- /* This is the PIIX4 ACPI device */
- struct pci_dev *dev;
- u32 base, val;
- u16 cmd;
- u8 pmregmisc;
-
-#ifdef __SMP__
- /*
- * We can't really do idle things with multiple CPU's, I'm
- * afraid. We'd need a per-CPU ACPI device.
- */
- if (smp_num_cpus > 1)
- return -1;
-#endif
- dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
-
- if (!dev)
- return -1;
-
- /*
- * Read the IO base value, and verify that it makes sense
- *
- * We could enable this if it wasn't enabled before, but
- * let's walk before we run..
- */
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- if (!(cmd & PCI_COMMAND_IO))
- return -1;
-
- pci_read_config_byte(dev, PMREGMISC, &pmregmisc);
- if (!(pmregmisc & PMIOSE))
- return -1;
-
- pci_read_config_dword(dev, 0x40, &base);
- if (!(base & PCI_BASE_ADDRESS_SPACE_IO))
- return -1;
-
- base &= PCI_BASE_ADDRESS_IO_MASK;
- if (!base)
- return -1;
-
- printk("Found PIIX4 ACPI device at %04x\n", base);
- piix4_base_address = base;
-
- /* Enable stopcklock, sleep and bursts, along with clock control */
- outl(CLKRUN_EN | CC_EN | STPCLK_EN | SLEEP_EN, piix4_base_address + PCNTRL);
-
- /* Make all unmasked interrupts be BREAK events */
- pci_read_config_dword(dev, DEVACTB, &val);
- pci_write_config_dword(dev, DEVACTB, val | BRLD_EN_IRQ0 | BRLD_EN_IRQ);
-
- /* Set up the new idle handler.. */
- acpi_idle = piix4_acpi_idle;
- return 0;
-}
-
-__initcall(piix4_acpi_init);
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 1902e5070..b091fc5f0 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -7,12 +7,12 @@ comment 'ARCnet devices'
tristate 'ARCnet support' CONFIG_ARCNET
if [ "$CONFIG_ARCNET" != "n" ]; then
- bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
- bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
- dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
- dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
- dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
- dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
+ bool ' Enable arc0e (ARCnet "Ether-Encap" packet format)' CONFIG_ARCNET_ETH
+ bool ' Enable arc0s (ARCnet RFC1051 packet format)' CONFIG_ARCNET_1051
+ dep_tristate ' ARCnet COM90xx (normal) chipset driver' CONFIG_ARCNET_COM90xx $CONFIG_ARCNET
+ dep_tristate ' ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
+ dep_tristate ' ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
+ dep_tristate ' ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
fi
endmenu
@@ -20,9 +20,9 @@ endmenu
tristate 'Dummy net driver support' CONFIG_DUMMY
tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_NETLINK" = "y" ]; then
- tristate 'Ethertap network tap' CONFIG_ETHERTAP
- fi
+ if [ "$CONFIG_NETLINK" = "y" ]; then
+ tristate 'Ethertap network tap (EXPERIMENTAL)' CONFIG_ETHERTAP
+ fi
fi
tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000
@@ -36,145 +36,154 @@ comment 'Ethernet (10 or 100Mbit)'
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
- if [ "$CONFIG_ARM" = "y" ]; then
- if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
- tristate 'AM79C961A support' CONFIG_ARM_AM79C961A
- else
- source drivers/acorn/net/Config.in
- fi
- fi
- if [ "$CONFIG_PPC" = "y" ]; then
- tristate 'MACE (Power Mac ethernet) support' CONFIG_MACE
- tristate 'BMAC (G3 ethernet) support' CONFIG_BMAC
- fi
- if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'Ariadne support' CONFIG_ARIADNE
- tristate 'Ariadne II support' CONFIG_ARIADNE2
- tristate 'A2065 support' CONFIG_A2065
- tristate 'Hydra support' CONFIG_HYDRA
- fi
- if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
- tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
- fi
- bool '3COM cards' CONFIG_NET_VENDOR_3COM
- if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
- tristate '3c501 support' CONFIG_EL1
- tristate '3c503 support' CONFIG_EL2
- tristate '3c505 support' CONFIG_ELPLUS
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate '3c507 support' CONFIG_EL16
+ if [ "$CONFIG_ARM" = "y" ]; then
+ if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
+ tristate ' AM79C961A support' CONFIG_ARM_AM79C961A
+ else
+ source drivers/acorn/net/Config.in
+ fi
+ fi
+ if [ "$CONFIG_PPC" = "y" ]; then
+ tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE
+ tristate ' BMAC (G3 ethernet) support' CONFIG_BMAC
+ fi
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ tristate ' Ariadne support' CONFIG_ARIADNE
+ tristate ' Ariadne II support' CONFIG_ARIADNE2
+ tristate ' A2065 support' CONFIG_A2065
+ tristate ' Hydra support' CONFIG_HYDRA
+ fi
+ if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
+ tristate ' MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
+ fi
+ bool ' 3COM cards' CONFIG_NET_VENDOR_3COM
+ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
+ tristate ' 3c501 support' CONFIG_EL1
+ tristate ' 3c503 support' CONFIG_EL2
+ tristate ' 3c505 support' CONFIG_ELPLUS
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' 3c507 support (EXPERIMENTAL)' CONFIG_EL16
+ fi
+ tristate ' 3c509/3c529 (MCA)/3c579 support' CONFIG_EL3
+ tristate ' 3c515 ISA Fast EtherLink' CONFIG_3C515
if [ "$CONFIG_MCA" = "y" ]; then
- tristate '3c523 support' CONFIG_ELMC
- tristate '3c527 support' CONFIG_ELMC_II
+ tristate ' 3c523 support' CONFIG_ELMC
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' 3c527 support (EXPERIMENTAL)' CONFIG_ELMC_II
+ fi
fi
- fi
- tristate '3c509/3c579 support' CONFIG_EL3
- tristate '3c515 ISA Fast EtherLink' CONFIG_3C515
- tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
- fi
- tristate 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
- bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
- if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
- tristate 'WD80*3 support' CONFIG_WD80x3
- if [ "$CONFIG_MCA" = "y" ]; then
- tristate 'SMC Ultra MCA support' CONFIG_ULTRAMCA
- fi
- tristate 'SMC Ultra support' CONFIG_ULTRA
- tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32
- tristate 'SMC 9194 support' CONFIG_SMC9194
+ tristate ' 3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
+ fi
+ tristate ' AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
+ bool ' Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
+ if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
+ tristate ' WD80*3 support' CONFIG_WD80x3
+ if [ "$CONFIG_MCA" = "y" ]; then
+ tristate ' SMC Ultra MCA support' CONFIG_ULTRAMCA
+ fi
+ tristate ' SMC Ultra support' CONFIG_ULTRA
+ tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32
+ tristate ' SMC 9194 support' CONFIG_SMC9194
fi
- bool 'Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+ bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'NI5010 support' CONFIG_NI5010
+ tristate ' NI5010 support (EXPERIMENTAL)' CONFIG_NI5010
fi
- tristate 'NI5210 support' CONFIG_NI52
- tristate 'NI6510 support' CONFIG_NI65
+ tristate ' NI5210 support' CONFIG_NI52
+ tristate ' NI6510 support' CONFIG_NI65
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
- tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900
- tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
- tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
+ # tristate ' Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI
+ tristate ' Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN
+ tristate ' RealTek 8129/8139 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8139
+ tristate ' SiS 900 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_SIS900
+ tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+ fi
+ tristate ' DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
+ bool ' Other ISA cards' CONFIG_NET_ISA
+ if [ "$CONFIG_NET_ISA" = "y" ]; then
+ tristate ' Cabletron E21xx support' CONFIG_E2100
+ tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+ tristate ' EtherExpress 16 support' CONFIG_EEXPRESS
+ tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO
+ tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
+ tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
+ tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
+ tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I
+ fi
+ tristate ' NE2000/NE1000 support' CONFIG_NE2000
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
+ fi
+ bool ' SK_G16 support' CONFIG_SK_G16
+ fi
+ if [ "$CONFIG_MCA" = "y" ]; then
+ tristate ' SKnet MCA support' CONFIG_SKMC
+ tristate ' NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
+ fi
+ bool ' EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
+ if [ "$CONFIG_NET_EISA" = "y" ]; then
+ tristate ' AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
+# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# tristate ' Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
+# fi
+ tristate ' Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
if [ "$CONFIG_ACENIC" != "n" ]; then
- bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+ bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
fi
- fi
- bool 'Other ISA cards' CONFIG_NET_ISA
- if [ "$CONFIG_NET_ISA" = "y" ]; then
- tristate 'AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
- tristate 'Cabletron E21xx support' CONFIG_E2100
- tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
- tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
- tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
- tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
- tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X
- tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
- tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
- tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I
- fi
- tristate 'NE2000/NE1000 support' CONFIG_NE2000
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
- fi
- bool 'SK_G16 support' CONFIG_SK_G16
- fi
- if [ "$CONFIG_MCA" = "y" ]; then
- tristate 'NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
- tristate 'SKnet MCA support' CONFIG_SKMC
- fi
- bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
- if [ "$CONFIG_NET_EISA" = "y" ]; then
- tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
- fi
- tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
- tristate 'CS89x0 support' CONFIG_CS89x0
- tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
- tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
- tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
- tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
- tristate 'Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
- fi
- tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
- tristate 'TI ThunderLAN support' CONFIG_TLAN
- tristate 'VIA Rhine support' CONFIG_VIA_RHINE
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
- tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
- bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
- fi
- tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
- fi
- bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
- if [ "$CONFIG_NET_POCKET" = "y" ]; then
- bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP
- tristate 'D-Link DE600 pocket adaptor support' CONFIG_DE600
- tristate 'D-Link DE620 pocket adaptor support' CONFIG_DE620
- fi
+ tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+ tristate ' CS89x0 support' CONFIG_CS89x0
+ tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+ tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
+ tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
+ tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390
+ tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210
+ fi
+ tristate ' PCI NE2000 support' CONFIG_NE2K_PCI
+ # tristate ' Sundance Alta support' CONFIG_ALTA
+ tristate ' TI ThunderLAN support' CONFIG_TLAN
+ tristate ' VIA Rhine support' CONFIG_VIA_RHINE
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
+ tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+ bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+ fi
+ fi
+ bool ' Pocket and portable adapters' CONFIG_NET_POCKET
+ if [ "$CONFIG_NET_POCKET" = "y" ]; then
+ bool ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
+ tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
+ fi
fi
endmenu
bool 'FDDI driver support' CONFIG_FDDI
if [ "$CONFIG_FDDI" = "y" ]; then
- bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+ bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
- if [ "$CONFIG_HIPPI" = "y" ]; then
- tristate 'Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
- if [ "$CONFIG_ROADRUNNER" != "n" ]; then
- bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
- fi
- fi
+ bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+ if [ "$CONFIG_HIPPI" = "y" ]; then
+ tristate ' Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+ if [ "$CONFIG_ROADRUNNER" != "n" ]; then
+ bool ' Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
+ fi
+ fi
fi
#
@@ -182,133 +191,66 @@ fi
#
if [ "$CONFIG_ATALK" != "n" ]; then
- mainmenu_option next_comment
- comment 'Appletalk devices'
- dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
- dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
- if [ "$CONFIG_COPS" != "n" ]; then
- bool 'Dayna firmware support' CONFIG_COPS_DAYNA
- bool 'Tangent firmware support' CONFIG_COPS_TANGENT
- fi
- dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
- if [ "$CONFIG_IPDDP" != "n" ]; then
- bool 'IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
- bool 'Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
- fi
- endmenu
+ mainmenu_option next_comment
+ comment 'Appletalk devices'
+ dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
+ dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
+ if [ "$CONFIG_COPS" != "n" ]; then
+ bool ' Dayna firmware support' CONFIG_COPS_DAYNA
+ bool ' Tangent firmware support' CONFIG_COPS_TANGENT
+ fi
+ dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
+ if [ "$CONFIG_IPDDP" != "n" ]; then
+ bool ' IP to Appletalk-IP Encapsulation support' CONFIG_IPDDP_ENCAP
+ bool ' Appletalk-IP to IP Decapsulation support' CONFIG_IPDDP_DECAP
+ fi
+ endmenu
fi
if [ ! "$CONFIG_PARPORT" = "n" ]; then
- dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
+ dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
fi
tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
if [ ! "$CONFIG_PPP" = "n" ]; then
- dep_tristate 'PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
- dep_tristate 'PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
- dep_tristate 'PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
+ dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+ dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+ dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
fi
tristate 'SLIP (serial line) support' CONFIG_SLIP
if [ "$CONFIG_SLIP" != "n" ]; then
- bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
- bool ' Keepalive and linefill' CONFIG_SLIP_SMART
- bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
+ bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
+ bool ' Keepalive and linefill' CONFIG_SLIP_SMART
+ bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
fi
+mainmenu_option next_comment
+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
- tristate 'AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
- tristate 'Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
-
-fi
-
-mainmenu_option next_comment
-comment 'Token ring devices'
+ dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
+ tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+ tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
-bool 'Token Ring driver support' CONFIG_TR
-if [ "$CONFIG_TR" = "y" ]; then
- tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR
-# tristate 'IBM Lanstreamer PCI adaptor support' CONFIG_IBMLS
- tristate 'IBM Olympic chipset PCI adapter support' CONFIG_IBMOL
- tristate 'SysKonnect adapter support' CONFIG_SKTR
fi
endmenu
+source drivers/net/tokenring/Config.in
+
bool 'Fibre Channel driver support' CONFIG_NET_FC
if [ "$CONFIG_NET_FC" = "y" ]; then
- tristate 'Interphase 5526 Tachyon chipset based adaptor support' CONFIG_IPHASE5526
+ dep_tristate ' Interphase 5526 Tachyon chipset based adapter support' CONFIG_IPHASE5526 $CONFIG_SCSI
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
- tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
-fi
-
-#
-# WAN drivers support
-#
-
-mainmenu_option next_comment
-comment 'Wan interfaces'
-
-
-# There is no way to detect a comtrol sv11 - force it modular for now.
-#
-dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
-#
-# The COSA/SRP driver has not been tested as non-modular yet.
-#
-dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
-#
-# There is no way to detect a Sealevel board. Force it modular
-#
-dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
-
-tristate 'Frame relay DLCI support' CONFIG_DLCI
-if [ "$CONFIG_DLCI" != "n" ]; then
- int ' Max open DLCI' CONFIG_DLCI_COUNT 24
- int ' Max DLCI per device' CONFIG_DLCI_MAX 8
- dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+ tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
+ tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
fi
-#
-# Wan router core.
-#
-
-if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
- bool 'WAN drivers' CONFIG_WAN_DRIVERS
- if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
- dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS
- if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
- int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1
- bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
- bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
- bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate 'Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_DRIVERS
- if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
- bool ' Cyclom 2X X.25 support (EXPERIMENTAL)' CONFIG_CYCLOMX_X25
- fi
- fi
- fi
-fi
-
-endmenu
-
-
-#
-# X.25 network drivers
-#
-if [ "$CONFIG_X25" != "n" ]; then
-if [ "$CONFIG_LAPB" != "n" ]; then
- dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
- dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
-fi
-fi
+source drivers/net/wan/Config.in
if [ "$CONFIG_PCMCIA" != "n" ]; then
source drivers/net/pcmcia/Config.in
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e1abc4c0e..4589d0ee3 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -5,7 +5,7 @@
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc pcmcia
+ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan
L_TARGET := net.a
L_OBJS := auto_irq.o
@@ -24,10 +24,6 @@ CONFIG_7990_BUILTIN :=
CONFIG_7990_MODULE :=
CONFIG_82596_BUILTIN :=
CONFIG_82596_MODULE :=
-CONFIG_85230_BUILTIN :=
-CONFIG_85230_MODULE :=
-CONFIG_SYNCPPP_BUILTIN :=
-CONFIG_SYNCPPP_MODULE :=
ifeq ($(CONFIG_PCMCIA),y)
SUB_DIRS += pcmcia
@@ -60,38 +56,6 @@ ifeq ($(CONFIG_SEEQ8005),y)
L_OBJS += seeq8005.o
endif
-ifeq ($(CONFIG_IBMTR),y)
-L_OBJS += ibmtr.o
-else
- ifeq ($(CONFIG_IBMTR),m)
- M_OBJS += ibmtr.o
- endif
-endif
-
-ifeq ($(CONFIG_IBMLS),y)
-L_OBJS += lanstreamer.o
-else
- ifeq ($(CONFIG_IBMLS),m)
- M_OBJS += lanstreamer.o
- endif
-endif
-
-ifeq ($(CONFIG_IBMOL),y)
-L_OBJS += olympic.o
-else
- ifeq ($(CONFIG_IBMOL),m)
- M_OBJS += olympic.o
- endif
-endif
-
-ifeq ($(CONFIG_SKTR),y)
-L_OBJS += sktr.o
-else
- ifeq ($(CONFIG_SKTR),m)
- M_OBJS += sktr.o
- endif
-endif
-
ifeq ($(CONFIG_ETHERTAP),y)
L_OBJS += ethertap.o
else
@@ -123,6 +87,13 @@ else
endif
endif
+ifeq ($(CONFIG_PCMCIA_PCNET),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_PCMCIA_PCNET),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
ifeq ($(CONFIG_SHAPER),y)
L_OBJS += shaper.o
@@ -609,6 +580,15 @@ else
endif
endif
+ifeq ($(CONFIG_DM9102),y)
+L_OBJS += dmfe.o
+else
+ ifeq ($(CONFIG_DM9102),m)
+ M_OBJS += dmfe.o
+ endif
+endif
+
+
ifeq ($(CONFIG_YELLOWFIN),y)
L_OBJS += yellowfin.o
else
@@ -811,14 +791,6 @@ else
endif
endif
-ifeq ($(CONFIG_LAPBETHER),y)
-L_OBJS += lapbether.o
-else
- ifeq ($(CONFIG_LAPBETHER),m)
- M_OBJS += lapbether.o
- endif
-endif
-
ifeq ($(CONFIG_EPIC100),y)
L_OBJS += epic100.o
else
@@ -827,63 +799,6 @@ else
endif
endif
-ifeq ($(CONFIG_HOSTESS_SV11),y)
-L_OBJS += hostess_sv11.o
-CONFIG_85230_BUILTIN = y
-CONFIG_SYNCPPP_BUILTIN = y
-else
- ifeq ($(CONFIG_HOSTESS_SV11),m)
- CONFIG_85230_MODULE = y
- CONFIG_SYNCPPP_MODULE = y
- M_OBJS += hostess_sv11.o
- endif
-endif
-
-ifeq ($(CONFIG_SEALEVEL_4021),y)
-L_OBJS += sealevel.o
-CONFIG_85230_BUILTIN = y
-CONFIG_SYNCPPP_BUILTIN = y
-else
- ifeq ($(CONFIG_SEALEVEL_4021),m)
- CONFIG_85230_MODULE = y
- CONFIG_SYNCPPP_MODULE = y
- M_OBJS += sealevel.o
- endif
-endif
-
-
-ifeq ($(CONFIG_COSA),y)
-L_OBJS += cosa.o
-CONFIG_SYNCPPP_BUILTIN = y
-else
- ifeq ($(CONFIG_COSA),m)
- CONFIG_SYNCPPP_MODULE = y
- M_OBJS += cosa.o
- endif
-endif
-
-# If anything built-in uses syncppp, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-
-ifdef CONFIG_SYNCPPP_BUILTIN
-LX_OBJS += syncppp.o
-else
- ifdef CONFIG_SYNCPPP_MODULE
- MX_OBJS += syncppp.o
- endif
-endif
-
-# If anything built-in uses Z85230, then build it into the kernel also.
-# If not, but a module uses it, build as a module.
-
-ifdef CONFIG_85230_BUILTIN
-LX_OBJS += z85230.o
-else
- ifdef CONFIG_85230_MODULE
- MX_OBJS += z85230.o
- endif
-endif
-
# If anything built-in uses slhc, then build it into the kernel also.
# If not, but a module uses it, build as a module.
ifdef CONFIG_SLHC_BUILTIN
@@ -914,6 +829,14 @@ else
endif
endif
+ifeq ($(CONFIG_PCMCIA_PCNET),y)
+CONFIG_8390_BUILTIN = y
+else
+ ifeq ($(CONFIG_PCMCIA_PCNET),m)
+ CONFIG_8390_MODULE = y
+ endif
+endif
+
# If anything built-in uses the 8390, then build it into the kernel also.
# If not, but a module uses it, build as a module.
ifdef CONFIG_8390_BUILTIN
@@ -1036,22 +959,6 @@ else
endif
endif
-ifeq ($(CONFIG_SDLA),y)
-L_OBJS += sdla.o
-else
- ifeq ($(CONFIG_SDLA),m)
- M_OBJS += sdla.o
- endif
-endif
-
-ifeq ($(CONFIG_DLCI),y)
-L_OBJS += dlci.o
-else
- ifeq ($(CONFIG_DLCI),m)
- M_OBJS += dlci.o
- endif
-endif
-
ifeq ($(CONFIG_ARIADNE),y)
L_OBJS += ariadne.o
else
@@ -1128,68 +1035,6 @@ else
endif
endif
-ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
-L_OBJS += starfire.o
-else
- ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
- M_OBJS += starfire.o
- endif
-endif
-
-ifeq ($(CONFIG_VENDOR_SANGOMA),y)
- LX_OBJS += sdladrv.o
- L_OBJS += sdlamain.o
- ifeq ($(CONFIG_WANPIPE_X25),y)
- L_OBJS += sdla_x25.o
- endif
- ifeq ($(CONFIG_WANPIPE_FR),y)
- L_OBJS += sdla_fr.o
- endif
- ifeq ($(CONFIG_WANPIPE_PPP),y)
- L_OBJS += sdla_ppp.o
- endif
-endif
-
-ifeq ($(CONFIG_VENDOR_SANGOMA),m)
- MX_OBJS += sdladrv.o
- M_OBJS += wanpipe.o
- WANPIPE_OBJS = sdlamain.o
- ifeq ($(CONFIG_WANPIPE_X25),y)
- WANPIPE_OBJS += sdla_x25.o
- endif
- ifeq ($(CONFIG_WANPIPE_FR),y)
- WANPIPE_OBJS += sdla_fr.o
- endif
- ifeq ($(CONFIG_WANPIPE_PPP),y)
- WANPIPE_OBJS += sdla_ppp.o
- endif
-endif
-
-ifeq ($(CONFIG_CYCLADES_SYNC),y)
- LX_OBJS += cycx_drv.o
- L_OBJS += cycx_main.o
- ifeq ($(CONFIG_CYCLOMX_X25),y)
- L_OBJS += cycx_x25.o
- endif
-endif
-
-ifeq ($(CONFIG_CYCLADES_SYNC),m)
- MX_OBJS += cycx_drv.o
- M_OBJS += cyclomx.o
- CYCLOMX_OBJS = cycx_main.o
- ifeq ($(CONFIG_CYCLOMX_X25),y)
- CYCLOMX_OBJS += cycx_x25.o
- endif
-endif
-
-ifeq ($(CONFIG_X25_ASY),y)
-L_OBJS += x25_asy.o
-else
- ifeq ($(CONFIG_X25_ASY),m)
- M_OBJS += x25_asy.o
- endif
-endif
-
#
# HIPPI adapters
#
@@ -1211,6 +1056,24 @@ else
endif
endif
+ifeq ($(CONFIG_TR),y)
+SUB_DIRS += tokenring
+MOD_IN_SUB_DIRS += tokenring
+else
+ ifeq ($(CONFIG_TR),m)
+ MOD_IN_SUB_DIRS += tokenring
+ endif
+endif
+
+ifeq ($(CONFIG_WAN),y)
+SUB_DIRS += wan
+MOD_IN_SUB_DIRS += wan
+else
+ ifeq ($(CONFIG_WAN),m)
+ MOD_IN_SUB_DIRS += wan
+ endif
+endif
+
ifeq ($(CONFIG_NET_FC),y)
SUB_DIRS += fc
MOD_IN_SUB_DIRS += fc
@@ -1225,11 +1088,5 @@ include $(TOPDIR)/Rules.make
clean:
rm -f core *.o *.a *.s
-wanpipe.o: $(WANPIPE_OBJS)
- ld -r -o $@ $(WANPIPE_OBJS)
-
-cyclomx.o: $(CYCLOMX_OBJS)
- ld -r -o $@ $(CYCLOMX_OBJS)
-
rcpci.o: rcpci45.o rclanmtl.o
$(LD) -r -o rcpci.o rcpci45.o rclanmtl.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 27c431e14..a10d519f5 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -12,6 +12,8 @@
* Donald J. Becker, <becker@super.org>
*
* Changelog:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
+ * - fix sbni: s/device/net_device/
* Paul Gortmaker (06/98):
* - sort probes in a sane way, make sure all (safe) probes
* get run once & failed autoprobes don't autoprobe again.
@@ -104,6 +106,7 @@ extern int pamsnet_probe(struct net_device *);
extern int tlan_probe(struct net_device *);
extern int mace_probe(struct net_device *);
extern int bmac_probe(struct net_device *);
+extern int ncr885e_probe(struct net_device *);
extern int cs89x0_probe(struct net_device *dev);
extern int ethertap_probe(struct net_device *dev);
extern int ether1_probe (struct net_device *dev);
@@ -118,11 +121,12 @@ extern int bagetlance_probe(struct net_device *);
extern int dec_lance_probe(struct net_device *);
extern int mvme147lance_probe(struct net_device *dev);
extern int via_rhine_probe(struct net_device *dev);
-extern int starfire_probe(struct net_device *dev);
extern int tc515_probe(struct net_device *dev);
extern int lance_probe(struct net_device *dev);
+extern int starfire_probe(struct net_device *dev);
extern int rcpci_probe(struct net_device *);
extern int mac_onboard_sonic_probe(struct net_device *dev);
+extern int dmfe_reg_board(struct net_device *);
/* Gigabit Ethernet adapters */
extern int yellowfin_probe(struct net_device *dev);
@@ -143,6 +147,9 @@ extern int rr_hippi_probe(struct net_device *);
/* Fibre Channel adapters */
extern int iph5526_probe(struct net_device *dev);
+/* SBNI adapters */
+extern int sbni_probe(struct net_device *);
+
struct devprobe
{
int (*probe)(struct net_device *dev);
@@ -216,6 +223,11 @@ struct devprobe pci_probes[] __initdata = {
#ifdef CONFIG_SIS900
{sis900_probe, 0},
#endif
+
+#ifdef CONFIG_DM9102
+ {dmfe_reg_board, 0},
+#endif
+
#ifdef CONFIG_YELLOWFIN
{yellowfin_probe, 0},
#endif
@@ -293,10 +305,10 @@ struct devprobe mca_probes[] __initdata = {
/*
* ISA probes that touch addresses < 0x400 (including those that also
- * look for EISA/PCI cards in addition to ISA cards).
+ * look for EISA/PCI/MCA cards in addition to ISA cards).
*/
struct devprobe isa_probes[] __initdata = {
-#ifdef CONFIG_EL3 /* ISA, EISA (MCA someday) 3c5x9 */
+#ifdef CONFIG_EL3 /* ISA, EISA, MCA 3c5x9 */
{el3_probe, 0},
#endif
#ifdef CONFIG_HP100 /* ISA, EISA & PCI */
@@ -458,6 +470,9 @@ struct devprobe ppc_probes[] __initdata = {
#ifdef CONFIG_BMAC
{bmac_probe, 0},
#endif
+#ifdef CONFIG_NCR885E
+ {ncr885e_probe, 0},
+#endif
{NULL, 0},
};
@@ -781,6 +796,7 @@ struct net_device eql_dev = {
/* Token-ring device probe */
extern int ibmtr_probe(struct net_device *);
extern int olympic_probe(struct net_device *);
+extern int sktr_probe(struct net_device *);
static int
trif_probe(struct net_device *dev)
@@ -876,6 +892,29 @@ static struct net_device tr0_dev = {
# undef NEXT_DEV
# define NEXT_DEV (&fc0_dev)
#endif
+
+
+#ifdef CONFIG_SBNI
+ static struct net_device sbni7_dev =
+ {"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
+ static struct net_device sbni6_dev =
+ {"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
+ static struct net_device sbni5_dev =
+ {"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
+ static struct net_device sbni4_dev =
+ {"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
+ static struct net_device sbni3_dev =
+ {"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
+ static struct net_device sbni2_dev =
+ {"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
+ static struct net_device sbni1_dev =
+ {"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
+ static struct net_device sbni0_dev =
+ {"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+
+#undef NEXT_DEV
+#define NEXT_DEV (&sbni0_dev)
+#endif
#ifdef CONFIG_NET_SB1000
diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c
index d8bddd665..353b44dc8 100644
--- a/drivers/net/arcnet.c
+++ b/drivers/net/arcnet.c
@@ -474,10 +474,12 @@ arcnet_open(struct net_device *dev)
lp->sdev=(struct net_device *)kmalloc(sizeof(struct net_device)+10,GFP_KERNEL);
if(lp->sdev == NULL)
{
+#ifdef CONFIG_ARCNET_ETH
if(lp->edev)
kfree(lp->edev);
lp->edev=NULL;
return -ENOMEM;
+#endif
}
memcpy(lp->sdev,dev,sizeof(struct net_device));
lp->sdev->name=(char *)(lp+1);
diff --git a/drivers/net/ncr885_debug.h b/drivers/net/ncr885_debug.h
new file mode 100644
index 000000000..bd1fead2d
--- /dev/null
+++ b/drivers/net/ncr885_debug.h
@@ -0,0 +1,54 @@
+#ifndef _H_NCR885_DEBUG
+#define _H_NCR885_DEBUG
+
+struct ncr885e_regs {
+ unsigned long tx_status;
+ unsigned long rx_status;
+ unsigned long mac_config;
+ unsigned long tx_control;
+ unsigned long rx_control;
+ unsigned long tx_cmd_ptr;
+ unsigned long rx_cmd_ptr;
+ unsigned long int_status;
+};
+
+#ifndef __KERNEL__
+
+struct ncr885e_private {
+
+ struct dbdma_cmd *head;
+ struct dbdma_cmd *tx_cmds;
+ struct dbdma_cmd *rx_cmds;
+ struct dbdma_cmd *stop_cmd;
+
+ struct sk_buff *tx_skbufs[NR_TX_RING];
+ struct sk_buff *rx_skbufs[NR_RX_RING];
+
+ int rx_current;
+ int rx_dirty;
+
+ int tx_dirty;
+ int tx_current;
+
+ unsigned short tx_status[NR_TX_RING];
+
+ unsigned char tx_fullup;
+ unsigned char tx_active;
+
+ struct net_device_stats stats;
+
+ struct device *dev;
+
+ struct timer_list tx_timeout;
+ int timeout_active;
+
+ spinlock_t lock;
+};
+
+#endif /* __KERNEL__ */
+
+
+#define NCR885E_GET_PRIV _IOR('N',1,sizeof( struct ncr885e_private ))
+#define NCR885E_GET_REGS _IOR('N',2,sizeof( struct ncr885e_regs ))
+
+#endif
diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c
new file mode 100644
index 000000000..277f92520
--- /dev/null
+++ b/drivers/net/ncr885e.c
@@ -0,0 +1,1458 @@
+/*
+ * An Ethernet driver for the dual-function NCR 53C885 SCSI/Ethernet
+ * controller.
+ *
+ *
+ * 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.
+ *
+ */
+
+static const char *version =
+"ncr885e.c:v0.8 11/30/98 dan@synergymicro.com\n";
+
+#include <linux/config.h>
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/uaccess.h>
+
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "ncr885e.h"
+#include "ncr885_debug.h"
+
+static const char *chipname = "ncr885e";
+
+/* debugging flags */
+#if 0
+#define DEBUG_FUNC 0x0001
+#define DEBUG_PACKET 0x0002
+#define DEBUG_CMD 0x0004
+#define DEBUG_CHANNEL 0x0008
+#define DEBUG_INT 0x0010
+#define DEBUG_RX 0x0020
+#define DEBUG_TX 0x0040
+#define DEBUG_DMA 0x0080
+#define DEBUG_MAC 0x0100
+#define DEBUG_DRIVER 0x0200
+#define DEBUG_ALL 0x1fff
+#endif
+
+#ifdef DEBUG_NCR885E
+#define NCR885E_DEBUG 0
+#else
+#define NCR885E_DEBUG 0
+#endif
+
+/* The 885's Ethernet PCI device id. */
+#ifndef PCI_DEVICE_ID_NCR_53C885_ETHERNET
+#define PCI_DEVICE_ID_NCR_53C885_ETHERNET 0x0701
+#endif
+
+#define NR_RX_RING 8
+#define NR_TX_RING 8
+#define MAX_TX_ACTIVE (NR_TX_RING-1)
+#define NCMDS_TX NR_TX_RING
+
+#define RX_BUFLEN (ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT 5*HZ
+
+#define NCR885E_TOTAL_SIZE 0xe0
+
+#define TXSR (1<<6) /* tx: xfer status written */
+#define TXABORT (1<<7) /* tx: abort */
+#define EOP (1<<7) /* rx: end of packet written to buffer */
+
+int ncr885e_debug = NCR885E_DEBUG;
+static int print_version = 0;
+
+struct ncr885e_private {
+
+ /* preserve a 1-1 marking with buffs */
+ struct dbdma_cmd *head;
+ struct dbdma_cmd *tx_cmds;
+ struct dbdma_cmd *rx_cmds;
+ struct dbdma_cmd *stop_cmd;
+
+ struct sk_buff *tx_skbufs[NR_TX_RING];
+ struct sk_buff *rx_skbufs[NR_RX_RING];
+
+ int rx_current;
+ int rx_dirty;
+
+ int tx_dirty;
+ int tx_current;
+
+ unsigned short tx_status[NR_TX_RING];
+
+ unsigned char tx_fullup;
+ unsigned char tx_active;
+
+ struct net_device_stats stats;
+
+ struct net_device *dev;
+
+ struct timer_list tx_timeout;
+ int timeout_active;
+
+ spinlock_t lock;
+};
+
+#ifdef MODULE
+static struct net_device *root_dev = NULL;
+#endif
+
+
+static int ncr885e_open( struct net_device *dev );
+static int ncr885e_close( struct net_device *dev );
+static void ncr885e_rx( struct net_device *dev );
+static void ncr885e_tx( struct net_device *dev );
+static int ncr885e_probe1( struct net_device *dev, unsigned long ioaddr,
+ unsigned char irq );
+static int ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev );
+static struct net_device_stats *ncr885e_stats( struct net_device *dev );
+static void ncr885e_set_multicast( struct net_device *dev );
+static void ncr885e_config( struct net_device *dev );
+static int ncr885e_set_address( struct net_device *dev, void *addr );
+static void ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs );
+static void show_dbdma_cmd( volatile struct dbdma_cmd *cmd );
+#if 0
+static int read_eeprom( unsigned int ioadddr, int location );
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void show_mii( unsigned long ioaddr );
+static int read_mii( unsigned long ioaddr, int reg );
+static void write_mii( unsigned long ioaddr, int reg, int data );
+#endif /* NCR885E_DEBUG_MII */
+
+#define TX_RESET_FLAGS (TX_CHANNEL_RUN|TX_CHANNEL_PAUSE|TX_CHANNEL_WAKE)
+#define RX_RESET_FLAGS (RX_CHANNEL_RUN|RX_CHANNEL_PAUSE|RX_CHANNEL_WAKE)
+
+
+#if 0
+static int
+debug_ioctl( struct net_device *dev, struct ifreq *req, int cmd )
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ struct ncr885e_private *data;
+ struct ncr885e_regs *regs;
+ unsigned long flags;
+
+ union {
+ struct ncr885e_regs dump;
+ struct ncr885e_private priv;
+ } temp;
+
+ switch( cmd ) {
+
+ /* dump the rx ring status */
+ case NCR885E_GET_PRIV:
+
+ data = (struct ncr885e_private *) &req->ifr_data;
+
+ if ( verify_area(VERIFY_WRITE, &req->ifr_data,
+ sizeof( struct ncr885e_private )))
+ return -EFAULT;
+
+ memcpy((char *) &temp.priv, sp, sizeof( struct ncr885e_private ));
+ copy_to_user( data, (char *) &temp.priv, sizeof( struct ncr885e_private));
+ break;
+
+ case NCR885E_GET_REGS:
+
+ regs = (struct ncr885e_regs *) &req->ifr_data;
+
+ if ( verify_area( VERIFY_WRITE, &req->ifr_data,
+ sizeof( struct ncr885e_regs )))
+ return -EFAULT;
+
+ spin_lock_irqsave( &sp->lock, flags );
+
+ temp.dump.tx_status = inl( ioaddr + TX_CHANNEL_STATUS );
+ temp.dump.rx_status = inl( ioaddr + RX_CHANNEL_STATUS );
+ temp.dump.mac_config = inl( ioaddr + MAC_CONFIG );
+ temp.dump.tx_control = inl( ioaddr + TX_CHANNEL_CONTROL );
+ temp.dump.rx_control = inl( ioaddr + RX_CHANNEL_CONTROL );
+ temp.dump.tx_cmd_ptr = inl( ioaddr + TX_CMD_PTR_LO );
+ temp.dump.rx_cmd_ptr = inl( ioaddr + RX_CMD_PTR_LO );
+ temp.dump.int_status = inl( ioaddr + INTERRUPT_STATUS_REG );
+
+ spin_unlock_irqrestore( &sp->lock, flags );
+ copy_to_user( regs, (char *) &temp.dump, sizeof( struct ncr885e_regs ));
+
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+#endif
+
+/* Enable interrupts on the 53C885 */
+static inline void
+ncr885e_enable( struct net_device *dev )
+
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned short reg;
+
+ reg = inw(ioaddr + INTERRUPT_ENABLE);
+ outw(reg | INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE);
+}
+
+/* Disable interrupts on the 53c885 */
+static inline void
+ncr885e_disable( struct net_device *dev )
+
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned short reg;
+
+ reg = inw( ioaddr + INTERRUPT_ENABLE );
+ outw( reg & ~INTERRUPT_INTE, ioaddr + INTERRUPT_ENABLE );
+}
+
+
+static inline void
+ncr885e_reset( struct net_device *dev )
+
+{
+ unsigned short reg;
+ unsigned long cntl;
+ int i;
+ unsigned long ioaddr = dev->base_addr;
+
+ if (ncr885e_debug > 1)
+ printk( KERN_INFO "%s: Resetting 53C885...\n", dev->name );
+
+ /* disable interrupts on the 53C885 */
+ ncr885e_disable( dev );
+
+ /* disable rx in the MAC */
+ reg = inw( ioaddr + MAC_CONFIG );
+ outw( reg & ~MAC_CONFIG_RXEN, ioaddr + MAC_CONFIG );
+
+ for( i=0; i < 100; i++ ) {
+
+ if ( !(inw( ioaddr + MAC_CONFIG ) & MAC_CONFIG_RXEN ))
+ break;
+ udelay( 10 );
+ }
+
+ reg = inw( ioaddr + MAC_CONFIG );
+ outw( reg | MAC_CONFIG_SRST, ioaddr + MAC_CONFIG );
+ outw( reg, ioaddr + MAC_CONFIG );
+
+ /* disable both rx and tx DBDMA channels */
+ outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+ outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+ for( i=0; i < 100; i++ ) {
+
+ if ( !(inw( ioaddr + TX_CHANNEL_STATUS ) & TX_DBDMA_ENABLE ) &&
+ !(inw( ioaddr + RX_CHANNEL_STATUS ) & RX_DBDMA_ENABLE ))
+ break;
+ udelay( 10 );
+ }
+
+ /* perform a "software reset" */
+ cntl = inl( ioaddr + DBDMA_CONTROL );
+ outl( cntl | DBDMA_SRST, ioaddr + DBDMA_CONTROL );
+
+ for( i=0; i < 100; i++ ) {
+
+ if ( !(inl( ioaddr + DBDMA_CONTROL ) & DBDMA_SRST ))
+ break;
+ udelay( 10 );
+ }
+
+ /* books says that a software reset should be done to the MAC, as
+ well. This true??? */
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: reset complete\n", dev->name );
+
+}
+
+
+/* configure the 53C885 chip.
+
+ The DBDMA command descriptors on the 53C885 can be programmed to
+ branch, interrupt or pause conditionally or always by using the
+ interrupt, branch and wait select registers. */
+
+static void
+ncr885e_config( struct net_device *dev )
+
+{
+ unsigned long ioaddr = dev->base_addr;
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: Configuring 53C885.\n", dev->name );
+
+ ncr885e_reset( dev );
+
+ /* The 53C885 can be programmed to perform conditional DBDMA
+ branches, interrupts or waits.
+
+ Neither channel makes use of "wait", as it requires that the
+ DBDMA engine to be restarted. Don't go there. The rx channel
+ will branch upon the successful reception of a packet ('EOP' in
+ the xfer_status field). The branch address is to the STOP
+ DBDMA command descriptor, which shuts down the rx channel until
+ the interrupt is serviced. */
+
+ /* cause tx channel to stop after "status received" */
+ outl( 0, ioaddr + TX_INT_SELECT );
+ outl( (TX_WAIT_STAT_RECV << 16) | TX_WAIT_STAT_RECV,
+ ioaddr + TX_WAIT_SELECT );
+ outl( 0, ioaddr + TX_BRANCH_SELECT );
+
+ /* cause rx channel to branch to the STOP descriptor on "End-of-Packet" */
+#if 0
+ outl( (RX_INT_SELECT_EOP << 16) | RX_INT_SELECT_EOP,
+ ioaddr + RX_INT_SELECT );
+#else
+ outl( 0, ioaddr + RX_INT_SELECT );
+#endif
+#if 0
+ outl( 0, ioaddr + RX_WAIT_SELECT );
+#else
+ outl( (RX_WAIT_SELECT_EOP << 16) | RX_WAIT_SELECT_EOP,
+ ioaddr + RX_WAIT_SELECT );
+#endif
+#if 1
+ outl( 0, ioaddr + RX_BRANCH_SELECT );
+#else
+ outl( (RX_BRANCH_SELECT_EOP << 16) | RX_BRANCH_SELECT_EOP,
+ ioaddr + RX_BRANCH_SELECT );
+#endif
+
+ /* configure DBDMA */
+ outl( (DBDMA_BE | DBDMA_DPMRLE | DBDMA_TDPCE |
+ DBDMA_DDPE | DBDMA_TDPE |
+ (DBDMA_BURST_4 << DBDMA_TX_BST_SHIFT) |
+ (DBDMA_BURST_4 << DBDMA_RX_BST_SHIFT) |
+ (DBDMA_TX_ARBITRATION_DEFAULT) |
+ (DBDMA_RX_ARBITRATION_DEFAULT)), ioaddr + DBDMA_CONTROL );
+
+ outl( 0, ioaddr + TX_THRESHOLD );
+
+ /* disable MAC loopback */
+ outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+ MAC_CONFIG_PADEN | (0x18 << 16)),
+ ioaddr + MAC_CONFIG );
+
+ /* configure MAC */
+ outl( (MAC_CONFIG_ITXA | MAC_CONFIG_RXEN | MAC_CONFIG_RETRYL |
+ MAC_CONFIG_PADEN | ( 0x18 << 16)), ioaddr + MAC_CONFIG );
+
+ outw( (0x1018), ioaddr + NBTOB_INTP_GAP );
+
+ /* clear and enable interrupts */
+ inw( ioaddr + INTERRUPT_CLEAR );
+ ncr885e_enable( dev );
+
+ /* and enable them in the chip */
+ outl( (INTERRUPT_INTE|INTERRUPT_TX_MASK|INTERRUPT_RX_MASK)<<16,
+ ioaddr + INTERRUPT_ENABLE - 2);
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: 53C885 config complete.\n", dev->name );
+
+ return;
+}
+
+
+
+/*
+ transmit interrupt */
+
+static void
+ncr885e_tx( struct net_device *dev )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ volatile struct dbdma_cmd *cp, *dp;
+ unsigned short txbits, xfer;
+ int i;
+
+ del_timer( &sp->tx_timeout );
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: ncr885e_tx: active=%d, dirty=%d, current=%d\n",
+ dev->name, sp->tx_active, sp->tx_dirty, sp->tx_current );
+
+ sp->timeout_active = 0;
+
+ i = sp->tx_dirty;
+ cp = sp->tx_cmds + (i*3);
+ dp = cp+1;
+ sp->tx_active--;
+
+ xfer = inw( &dp->xfer_status );
+ txbits = inw( &sp->tx_status[i] );
+
+ if (ncr885e_debug > 4) {
+ show_dbdma_cmd( cp );
+ show_dbdma_cmd( dp );
+ }
+
+ /* get xmit result */
+ txbits = inw( &sp->tx_status[i] );
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: tx xfer=%04x, txbits=%04x\n", dev->name,
+ xfer, txbits );
+
+ /* look for any channel status (?) */
+ if ( xfer ) {
+
+ dev_kfree_skb( sp->tx_skbufs[i] );
+ mark_bh( NET_BH );
+
+ if ( txbits & TX_STATUS_TXOK ) {
+ sp->stats.tx_packets++;
+ sp->stats.tx_bytes += inw( &cp->req_count );
+ }
+
+ /* dropped packets */
+ if ( txbits & (TX_STATUS_TDLC|TX_STATUS_TDEC) ) {
+ sp->stats.tx_dropped++;
+ }
+
+ /* add the collisions */
+ sp->stats.collisions += ( txbits & 0x04 );
+
+ }
+
+ dev->tbusy = 0;
+
+ return;
+}
+
+/* rx interrupt handling */
+static void
+ncr885e_rx( struct net_device *dev )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ volatile struct dbdma_cmd *cp;
+ struct sk_buff *skb;
+ int i, nb;
+ unsigned short status;
+ unsigned char *data, *stats;
+ unsigned long rxbits, ioaddr = dev->base_addr;
+
+ i = sp->rx_current;
+ cp = sp->rx_cmds + (i*2);
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: ncr885e_rx dirty=%d, current=%d (cp@%p)\n",
+ dev->name, sp->rx_dirty, sp->rx_current, cp );
+
+ nb = inw( &cp->req_count ) - inw( &cp->res_count );
+ status = inw( &cp->xfer_status );
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO "%s: (rx %d) bytes=%d, xfer_status=%04x\n",
+ dev->name, i, nb, status );
+
+ if ( status ) {
+
+ skb = sp->rx_skbufs[i];
+ data = skb->data;
+ stats = data + nb - 3;
+ rxbits = (stats[0]|stats[1]<<8|stats[2]<<16);
+
+ if (ncr885e_debug > 3)
+ printk( KERN_INFO " rx_bits=%06lx\n", rxbits );
+
+ skb->dev = dev;
+ skb_put( skb, nb-3 );
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
+ sp->rx_skbufs[i] = 0;
+
+ if ( rxbits & RX_STATUS_RXOK ) {
+ sp->stats.rx_packets++;
+ sp->stats.rx_bytes += nb;
+ }
+
+ if ( rxbits & RX_STATUS_MCAST )
+ sp->stats.multicast++;
+
+ }
+
+ sp->rx_dirty = sp->rx_current;
+
+ if ( ++sp->rx_current >= NR_RX_RING )
+ sp->rx_current = 0;
+
+ /* fix up the one we just trashed */
+ cp = sp->rx_cmds + (sp->rx_dirty * 2);
+
+ skb = dev_alloc_skb( RX_BUFLEN + 2 );
+ if ( skb != 0 ) {
+ skb_reserve( skb, 2 );
+ sp->rx_skbufs[sp->rx_dirty] = skb;
+ }
+
+ if (ncr885e_debug > 2)
+ printk( KERN_INFO "%s: ncr885e_rx: using ring index %d, filling cp @ %p\n",
+ dev->name, sp->rx_current, cp );
+
+ outw( RX_BUFLEN, &cp->req_count );
+ outw( 0, &cp->res_count );
+ data = skb->data;
+ outl( virt_to_bus( data ), &cp->phy_addr );
+ outw( 0, &cp->xfer_status );
+
+ cp = sp->rx_cmds + (sp->rx_current * 2);
+
+ /* restart rx DMA */
+ outl( virt_to_bus( cp ), ioaddr + RX_CMD_PTR_LO );
+ outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+ ioaddr + RX_CHANNEL_CONTROL );
+
+ return;
+}
+
+static void
+ncr885e_misc_ints( struct net_device *dev, unsigned short status )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ struct dbdma_cmd *cp;
+ unsigned long ioaddr = dev->base_addr;
+
+ if (ncr885e_debug > 1)
+ printk( KERN_INFO "miscellaneous interrupt handled; status=%02x\n",
+ status );
+
+ /* various transmit errors */
+ if ( status &
+ (INTERRUPT_PPET | INTERRUPT_PBFT | INTERRUPT_IIDT) ) {
+
+ /* illegal instruction in tx dma */
+ if ( status & INTERRUPT_IIDT ) {
+
+ cp = (struct dbdma_cmd *) bus_to_virt( inl( ioaddr + TX_CMD_PTR_LO ));
+ printk( KERN_INFO "%s: tx illegal insn:\n", dev->name );
+ printk( KERN_INFO " tx DBDMA - cmd = %p, status = %04x\n",
+ cp, inw( ioaddr + TX_CHANNEL_STATUS ));
+ printk( KERN_INFO " command = %04x, phy_addr=%08x, req_count=%04x\n",
+ inw( &cp->command ), inw( &cp->phy_addr ), inw( &cp->req_count ));
+ }
+
+ if ( status & INTERRUPT_PPET )
+ printk( KERN_INFO "%s: tx PCI parity error\n", dev->name );
+
+ if ( status & INTERRUPT_PBFT )
+ printk( KERN_INFO "%s: tx PCI bus fault\n", dev->name );
+ }
+
+ /* look for rx errors */
+ if ( status &
+ (INTERRUPT_PPER | INTERRUPT_PBFR | INTERRUPT_IIDR)) {
+
+ /* illegal instruction in rx dma */
+ if ( status & INTERRUPT_IIDR ) {
+#if 0
+ cmd = inl( ioaddr + RX_CMD_PTR_LO );
+#endif
+ printk( KERN_ERR "%s: rx illegal DMA instruction:\n", dev->name );
+ printk( KERN_ERR " channel status=%04x,\n",
+ inl( ioaddr + RX_CHANNEL_STATUS ));
+#if 0
+ show_dbdma_cmd( bus_to_virt( inl( ioaddr + RX_CMD_PTR_LO )));
+ printk( KERN_ERR " instr (%08x) %08x %08x %08x\n",
+ (int) cmd, cmd[0], cmd[1], cmd[2] );
+#endif
+ }
+
+ /* PCI parity error */
+ if ( status & INTERRUPT_PPER )
+ printk( KERN_INFO "%s: rx PCI parity error\n", dev->name );
+
+ if ( status & INTERRUPT_PBFR )
+ printk( KERN_INFO "%s: rx PCI bus fault\n", dev->name );
+
+ sp->stats.rx_errors++;
+ }
+
+ if ( status & INTERRUPT_WI ) {
+ printk( KERN_INFO "%s: link pulse\n", dev->name );
+ }
+
+ /* bump any counters */
+
+
+ return;
+}
+
+static void
+ncr885e_interrupt( int irq, void *dev_id, struct pt_regs *regs )
+
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct ncr885e_private *sp;
+ unsigned short status;
+ int ioaddr;
+
+ if ( dev == NULL ) {
+ printk( KERN_ERR "symba: Interrupt IRQ %d for unknown device\n", irq );
+ return;
+ }
+
+ ioaddr = dev->base_addr;
+ sp = (struct ncr885e_private *) dev->priv;
+ spin_lock( &sp->lock );
+
+ if ( dev->interrupt ) {
+ printk( KERN_ERR "%s: Re-entering interrupt handler...\n",
+ dev->name );
+ }
+
+ dev->interrupt = 1;
+ status = inw( ioaddr + INTERRUPT_CLEAR );
+
+ if (ncr885e_debug > 2)
+ printk( KERN_INFO "%s: 53C885 interrupt 0x%02x\n", dev->name, status );
+
+ /* handle non-tx and rx interrupts first */
+ if ( status & ~(INTERRUPT_DIT|INTERRUPT_DIR))
+ ncr885e_misc_ints( dev, status );
+
+ /* look for tx interrupt: more to transmit, DBDMA stopped, or tx done */
+ if ( ( status & INTERRUPT_DIT ) ) {
+
+ if (ncr885e_debug > 2)
+ printk( KERN_INFO "%s: tx int; int=%02x, chan stat=%02x\n",
+ dev->name, status, inw( ioaddr + TX_CHANNEL_STATUS ));
+
+ /* turn off timer */
+ del_timer( &sp->tx_timeout );
+ sp->timeout_active = 0;
+
+ /* stop DMA */
+ outl( TX_DBDMA_ENABLE << 16, ioaddr + TX_CHANNEL_CONTROL );
+
+ ncr885e_tx( dev );
+ }
+
+ if ( status & INTERRUPT_DIR ) {
+
+ if ( ncr885e_debug > 2 )
+ printk( KERN_INFO "%s: rx interrupt; int=%02x, rx channel stat=%02x\n",
+ dev->name, status, inw( ioaddr + RX_CHANNEL_STATUS ));
+
+ /* stop DMA */
+ outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+ /* and handle the interrupt */
+ ncr885e_rx( dev );
+ }
+
+ dev->interrupt = 0;
+ spin_unlock( &sp->lock );
+
+ return;
+}
+
+
+/* doesn't set the address permanently, however... */
+static int
+ncr885e_set_address( struct net_device *dev, void *addr )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ struct sockaddr *saddr = addr;
+ unsigned long flags;
+ unsigned short reg[3];
+ unsigned char *ioaddr, *p;
+ int i;
+
+ memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+ p = (unsigned char *) dev->dev_addr;
+ printk( KERN_INFO "%s: setting new MAC address - ", dev->name );
+#if 0
+ for( p = (unsigned char *) dev->dev_addr, i=0; i < 6; i++, p++ )
+ printk("%c%2.2x", i ? ':' : ' ', *p );
+#endif
+
+
+ p = (unsigned char *) &reg;
+ for( i=0; i < 6; i++ )
+ p[i] = dev->dev_addr[i];
+
+#if 0
+ printk("%s: Setting new mac address - ", dev->name );
+ for( i=0; i < 6; i++ ) {
+ printk("%02x", i ? ':' : ' ', p[i] );
+ }
+
+ printk("\n");
+#endif
+
+ /* stop rx for the change */
+ outl( RX_DBDMA_ENABLE << 16, ioaddr + RX_CHANNEL_CONTROL );
+
+ spin_lock_irqsave( &sp->lock, flags );
+
+ ioaddr = (unsigned char *) dev->base_addr;
+
+ for( i = 0; i < 3; i++ ) {
+ reg[i] = ((reg[i] & 0xff) << 8) | ((reg[i] >> 8) & 0xff);
+ printk("%04x ", reg[i] );
+ outw( reg[i], ioaddr + STATION_ADDRESS_0 + (i*2));
+ }
+ printk("\n");
+
+ spin_unlock_irqrestore( &sp->lock, flags );
+
+ /* restart rx */
+ outl((RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+ ioaddr + RX_CHANNEL_CONTROL );
+
+ return 0;
+}
+
+static void
+ncr885e_tx_timeout( unsigned long data )
+
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ unsigned long flags, ioaddr;
+ int i;
+
+ save_flags( flags );
+ cli();
+
+ ioaddr = dev->base_addr;
+ sp->timeout_active = 0;
+ i = sp->tx_dirty;
+
+ /* if we weren't active, bail... */
+ if ( sp->tx_active == 0 ) {
+ printk( KERN_INFO "%s: ncr885e_timeout...tx not active!\n", dev->name );
+ goto out;
+ }
+
+ printk( KERN_ERR "%s: 53C885 timed out. Resetting...\n", dev->name );
+
+ /* disable rx and tx DMA */
+ outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );
+ outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+
+ /* reset the chip */
+ ncr885e_config( dev );
+ ncr885e_enable( dev );
+
+ /* clear the wedged skb in the tx ring */
+ sp->tx_active = 0;
+ ++sp->stats.tx_errors;
+
+ if ( sp->tx_skbufs[i] ) {
+ dev_kfree_skb( sp->tx_skbufs[i] );
+ sp->tx_skbufs[i] = 0;
+ }
+
+ /* start anew from the beginning of the ring buffer (why not?) */
+ sp->tx_current = 0;
+ dev->tbusy = 0;
+ mark_bh( NET_BH );
+
+ /* restart rx dma */
+ outl( (RX_DBDMA_ENABLE << 16) | RX_CHANNEL_RUN,
+ ioaddr + RX_CHANNEL_CONTROL );
+ out:
+
+ restore_flags( flags );
+}
+
+static inline void
+ncr885e_set_timeout( struct net_device *dev )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if ( sp->timeout_active )
+ del_timer( &sp->tx_timeout );
+
+ sp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+ sp->tx_timeout.function = ncr885e_tx_timeout;
+ sp->tx_timeout.data = (unsigned long) dev;
+ add_timer( &sp->tx_timeout );
+ sp->timeout_active = 1;
+ restore_flags( flags );
+}
+
+
+/*
+ * The goal is to set up DBDMA such that the rx ring contains only
+ * one DMA descriptor per ring element and the tx ring has two (using
+ * the cool features of branch- and wait-select. However, I'm not sure
+ * if it's possible. For now, we plod through it with 3 descriptors
+ * for tx, and two for rx.
+ */
+
+static int
+ncr885e_open( struct net_device *dev )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+ struct sk_buff *skb;
+ int i, size;
+ char *data;
+ struct dbdma_cmd *cp;
+ unsigned long flags;
+
+ /* allocate enough space for the tx and rx rings and a STOP descriptor */
+ size = (sizeof( struct dbdma_cmd ) *
+ ((NR_TX_RING * 3) + (NR_RX_RING * 2) + 1));
+
+ cp = kmalloc( size, GFP_KERNEL );
+
+ if ( cp == 0 ) {
+ printk( KERN_ERR "Insufficient memory (%d bytes) for DBDMA\n", size );
+ return -ENOMEM;
+ }
+
+ spin_lock_init( &sp->lock );
+ spin_lock_irqsave( &sp->lock, flags );
+
+ memset((char *) cp, 0, size );
+ sp->head = cp;
+
+ sp->stop_cmd = cp;
+ outl( DBDMA_STOP, &cp->command );
+
+ sp->rx_cmds = ++cp;
+
+ for( i = 0; i < NR_RX_RING; i++ ) {
+
+ cp = sp->rx_cmds + (i*2);
+ skb = dev_alloc_skb( RX_BUFLEN + 2 );
+
+ /* if there is insufficient memory, make this last ring use a
+ static buffer and leave the loop with that skb as final one */
+ if ( skb == 0 ) {
+ printk( KERN_ERR "%s: insufficient memory for rx ring buffer\n",
+ dev->name );
+ break;
+ }
+
+ skb_reserve( skb, 2 );
+ sp->rx_skbufs[i] = skb;
+ data = skb->data;
+
+ /* The DMA commands here are done such that an EOP is the only
+ way that we should get an interrupt. This means that we could
+ fill more than one skbuff before getting the interrupt at EOP. */
+
+ /* Handle rx DMA such that it always interrupts.... */
+ outw( (INPUT_MORE|INTR_ALWAYS), &cp->command );
+ outw( RX_BUFLEN, &cp->req_count );
+ outw( 0, &cp->res_count );
+ outl( virt_to_bus( data ), &cp->phy_addr );
+ outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+ outw( 0, &cp->xfer_status );
+#if 0
+ printk( KERN_INFO "rx at %p\n", cp );
+ show_dbdma_cmd( cp );
+#endif
+ ++cp;
+
+ outw( DBDMA_STOP, &cp->command );
+
+ }
+
+ /* initialize to all rx buffers are available, fill limit is the end */
+ sp->rx_dirty = 0;
+ sp->rx_current = 0;
+
+ /* fill the tx ring */
+ sp->tx_cmds = cp+1;
+
+ for( i = 0; i < NR_TX_RING; i++ ) {
+
+ /* minimal setup for tx command */
+ cp = sp->tx_cmds + (i*3);
+ outw( OUTPUT_LAST, &cp->command );
+ if (ncr885e_debug > 3) {
+ printk( KERN_INFO "tx OUTPUT_LAST at %p\n", cp );
+ show_dbdma_cmd( cp );
+ }
+
+ /* full setup for the status cmd */
+ cp++;
+ outw( INPUT_LAST|INTR_ALWAYS|WAIT_IFCLR, &cp->command );
+ outl( virt_to_bus( &sp->tx_status[i] ), &cp->phy_addr );
+ outw( 2, &cp->req_count );
+ if ( ncr885e_debug > 3) {
+ printk( KERN_INFO "tx INPUT_LAST cmd at %p\n", cp );
+ show_dbdma_cmd( cp );
+ }
+
+ ++cp;
+ outw( DBDMA_STOP, &cp->command );
+
+ }
+#if 0
+ /* chain the last tx DMA command to the STOP cmd */
+ outw((INPUT_LAST|INTR_ALWAYS|BR_ALWAYS), &cp->command );
+ outl( virt_to_bus( sp->stop_cmd ), &cp->cmd_dep );
+#endif
+ sp->tx_active = 0;
+ sp->tx_current = 0;
+ sp->tx_dirty = 0;
+
+ spin_unlock_irqrestore( &sp->lock, flags );
+
+ /* the order seems important here for some reason. If the MPIC isn't
+ enabled before the ethernet chip is enabled, shrapnel from the
+ bootloader causes us to receive interrupts even though we've not
+ yet enabled the tx channel. Go figure. It'd be better to configure
+ the chip in the probe1() routine, but then we don't see interrupts
+ at all. Everything looks all right on the logic analyzer, but... */
+
+ ncr885e_config( dev );
+
+ /* enable ethernet interrupts */
+ if ( request_irq( dev->irq, &ncr885e_interrupt, SA_SHIRQ, chipname, dev )) {
+ printk( KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq );
+ return -EAGAIN;
+ }
+
+ (void) inw( ioaddr + INTERRUPT_CLEAR );
+
+ ncr885e_enable( dev );
+
+ /* start rx DBDMA */
+ outl( virt_to_bus( sp->rx_cmds ), ioaddr + RX_CMD_PTR_LO );
+ outl( (RX_DBDMA_ENABLE << 16)|RX_CHANNEL_RUN,
+ ioaddr + RX_CHANNEL_CONTROL );
+
+ dev->start = 1;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+static int
+ncr885e_xmit_start( struct sk_buff *skb, struct net_device *dev )
+
+{
+ struct ncr885e_private *sp = (struct ncr885e_private *) dev->priv;
+ volatile struct dbdma_cmd *cp, *dp;
+ unsigned long flags, ioaddr = dev->base_addr;
+ int len, next, fill, entry;
+
+ if ( ncr885e_debug > 3)
+ printk( KERN_INFO "%s: xmit_start len=%d, dirty=%d, current=%d, active=%d\n",
+ dev->name, skb->len, sp->tx_dirty, sp->tx_current, sp->tx_active );
+
+ spin_lock_irqsave( &sp->lock, flags );
+
+ /* find the free slot in the ring buffer */
+ fill = sp->tx_current;
+ next = fill + 1;
+
+ if ( next >= NR_TX_RING )
+ next = 0;
+
+ /* mark ourselves as busy, even if we have too many packets waiting */
+ dev->tbusy = 1;
+
+ /* see if it's necessary to defer this packet */
+ if ( sp->tx_active >= MAX_TX_ACTIVE ) {
+ spin_unlock_irqrestore( &sp->lock, flags );
+ return -1;
+ }
+
+ sp->tx_active++; /* bump "active tx" count */
+ sp->tx_current = next; /* and show that we've used this buffer */
+ sp->tx_dirty = fill; /* and mark this one to get picked up */
+
+ len = skb->len;
+
+ if ( len > ETH_FRAME_LEN ) {
+ printk( KERN_DEBUG "%s: xmit frame too long (%d)\n", dev->name, len );
+ len = ETH_FRAME_LEN;
+ }
+
+ /* get index into the tx DBDMA chain */
+ entry = fill * 3;
+ sp->tx_skbufs[fill] = skb;
+ cp = sp->tx_cmds + entry;
+ dp = cp + 1;
+
+ /* update the rest of the OUTPUT_MORE descriptor */
+ outw( len, &cp->req_count );
+ outl( virt_to_bus( skb->data ), &cp->phy_addr );
+ outw( 0, &cp->xfer_status );
+ outw( 0, &cp->res_count );
+
+ /* and finish off the INPUT_MORE */
+ outw( 0, &dp->xfer_status );
+ outw( 0, &dp->res_count );
+ sp->tx_status[fill] = 0;
+ outl( virt_to_bus( &sp->tx_status[fill] ), &dp->phy_addr );
+
+ if ( ncr885e_debug > 2 )
+ printk(KERN_INFO "%s: xmit_start: active %d, tx_current %d, tx_dirty %d\n",
+ dev->name, sp->tx_active, sp->tx_current, sp->tx_dirty );
+
+ if ( ncr885e_debug > 4 ) {
+ show_dbdma_cmd( cp );
+ show_dbdma_cmd( dp );
+ }
+
+
+ /* restart the tx DMA engine */
+ outl( virt_to_bus( cp ), ioaddr + TX_CMD_PTR_LO );
+ outl( (TX_DBDMA_ENABLE << 16)|TX_CHANNEL_RUN,
+ ioaddr + TX_CHANNEL_CONTROL );
+
+ ncr885e_set_timeout( dev );
+
+ spin_unlock_irqrestore( &sp->lock, flags );
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+static int
+ncr885e_close(struct net_device *dev)
+
+{
+ int i;
+ struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ spin_lock( &np->lock );
+
+ printk(KERN_INFO "%s: NCR885E Ethernet closing...\n", dev->name );
+
+ if (ncr885e_debug > 1)
+ printk(KERN_DEBUG "%s: Shutting down Ethernet chip\n", dev->name);
+
+ ncr885e_disable(dev);
+
+ del_timer(&np->tx_timeout);
+
+ /* flip off rx and tx */
+ outl( (RX_DBDMA_ENABLE << 16), ioaddr + RX_CHANNEL_CONTROL );
+ outl( (TX_DBDMA_ENABLE << 16), ioaddr + TX_CHANNEL_CONTROL );
+
+ /* free up the IRQ */
+ free_irq( dev->irq, dev );
+
+ for( i = 0; i < NR_RX_RING; i++ ) {
+ if (np->rx_skbufs[i])
+ dev_kfree_skb( np->rx_skbufs[i] );
+ np->rx_skbufs[i] = 0;
+ }
+#if 0
+ for (i = 0; i < NR_TX_RING; i++) {
+ if (np->tx_skbufs[i])
+ dev_kfree_skb(np->tx_skbufs[i]);
+ np->tx_skbufs[i] = 0;
+ }
+#endif
+ spin_unlock( &np->lock );
+
+ kfree( np->head );
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+
+/*
+ * multicast promiscuous mode isn't used here. Allow code in the
+ * IP stack to determine which multicast packets are good or bad....
+ * (this avoids having to use the hash table registers)
+ */
+static void
+ncr885e_set_multicast( struct net_device *dev )
+
+{
+ int ioaddr = dev->base_addr;
+
+ if ( ncr885e_debug > 3 )
+ printk("%s: set_multicast: dev->flags = %x, AF=%04x\n",
+ dev->name, dev->flags, inw( ioaddr + ADDRESS_FILTER ));
+
+ if ( dev->flags & IFF_PROMISC ) {
+ printk( KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name );
+ outw( ADDRESS_RPPRO, ioaddr + ADDRESS_FILTER );
+ }
+
+ /* accept all multicast packets without checking the mc_list. */
+ else if ( dev->flags & IFF_ALLMULTI ) {
+ printk( KERN_INFO "%s: Enabling all multicast packets.\n",
+ dev->name );
+ outw( ADDRESS_RPPRM, ioaddr + ADDRESS_FILTER );
+ }
+
+ /* enable broadcast rx */
+ else {
+ outw( ADDRESS_RPABC, ioaddr + ADDRESS_FILTER );
+ }
+}
+
+static struct net_device_stats *
+ncr885e_stats( struct net_device *dev )
+
+{
+ struct ncr885e_private *np = (struct ncr885e_private *) dev->priv;
+
+ return &np->stats;
+}
+
+/* By this function, we're certain that we have a 885 Ethernet controller
+ * so we finish setting it up and wrap up all the required Linux ethernet
+ * configuration.
+ */
+
+static int
+ncr885e_probe1( struct net_device *dev, unsigned long ioaddr, unsigned char irq )
+
+{
+ struct ncr885e_private *sp;
+ unsigned short station_addr[3], val;
+ unsigned char *p;
+ int i;
+
+ dev = init_etherdev( dev, 0 );
+
+ /* construct private data for the 885 ethernet */
+ dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL );
+
+ if ( dev->priv == NULL )
+ return -ENOMEM;
+
+ sp = (struct ncr885e_private *) dev->priv;
+ memset( sp, 0, sizeof( struct ncr885e_private ));
+
+ /* snag the station address and display it */
+ for( i = 0; i < 3; i++ ) {
+ val = inw( ioaddr + STATION_ADDRESS_0 + (i*2));
+ station_addr[i] = ((val >> 8) & 0xff) | ((val << 8) & 0xff00);
+ }
+
+ printk( KERN_INFO "%s: %s at %08lx,", dev->name, chipname, ioaddr );
+
+ p = (unsigned char *) &station_addr;
+
+ for( i=0; i < 6; i++ ) {
+ dev->dev_addr[i] = *p;
+ printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i] );
+ p++;
+ }
+
+ printk(", IRQ %d.\n", irq );
+
+ request_region( ioaddr, NCR885E_TOTAL_SIZE, dev->name );
+
+ /* set up a timer */
+ init_timer( &sp->tx_timeout );
+ sp->timeout_active = 0;
+
+ dev->base_addr = ioaddr;
+ dev->irq = irq;
+
+ ether_setup( dev );
+
+ /* everything else */
+ dev->open = ncr885e_open;
+ dev->stop = ncr885e_close;
+ dev->get_stats = ncr885e_stats;
+ dev->hard_start_xmit = ncr885e_xmit_start;
+ dev->set_multicast_list = ncr885e_set_multicast;
+ dev->set_mac_address = ncr885e_set_address;
+
+ return 0;
+}
+
+/* Since the NCR 53C885 is a multi-function chip, I'm not worrying about
+ * trying to get the the device(s) in slot order. For our (Synergy's)
+ * purpose, there's just a single 53C885 on the board and we don't
+ * worry about the rest.
+ */
+
+int __init ncr885e_probe( struct net_device *dev )
+{
+ struct pci_dev *pdev = NULL;
+ unsigned int ioaddr, chips = 0;
+ unsigned short cmd;
+ unsigned char irq, latency;
+
+ while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR,
+ PCI_DEVICE_ID_NCR_53C885_ETHERNET,
+ pdev )) != NULL ) {
+
+ if ( !print_version ) {
+ print_version++;
+ printk( KERN_INFO "%s", version );
+ }
+
+ /* Use I/O space */
+ pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, &ioaddr );
+ pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq );
+
+ ioaddr &= ~3;
+ /* Adjust around the Grackle... */
+#ifdef CONFIG_GEMINI
+ ioaddr |= 0xfe000000;
+#endif
+
+ if ( check_region( ioaddr, NCR885E_TOTAL_SIZE ))
+ continue;
+
+ /* finish off the probe */
+ if ( !(ncr885e_probe1( dev, ioaddr, irq ))) {
+
+ chips++;
+
+ /* Access is via I/O space, bus master enabled... */
+ pci_read_config_word( pdev, PCI_COMMAND, &cmd );
+
+ if ( !(cmd & PCI_COMMAND_MASTER) ) {
+ printk( KERN_INFO " PCI master bit not set! Now setting.\n");
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_word( pdev, PCI_COMMAND, cmd );
+ }
+
+ if ( !(cmd & PCI_COMMAND_IO) ) {
+ printk( KERN_INFO " Enabling I/O space.\n" );
+ cmd |= PCI_COMMAND_IO;
+ pci_write_config_word( pdev, PCI_COMMAND, cmd );
+ }
+
+ pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &latency );
+
+ if ( latency < 10 ) {
+ printk( KERN_INFO " PCI latency timer (CFLT) is unreasonably"
+ " low at %d. Setting to 255.\n", latency );
+ pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 255 );
+ }
+ }
+ }
+
+ if ( !chips )
+ return -ENODEV;
+ else
+ return 0;
+}
+
+/* debugging to peek at dma descriptors */
+static void
+show_dbdma_cmd( volatile struct dbdma_cmd *cmd )
+
+{
+ printk( KERN_INFO " cmd %04x, physaddr %08x, req_count %04x\n",
+ inw( &cmd->command ), inl( &cmd->phy_addr ), inw( &cmd->req_count ));
+ printk( KERN_INFO " res_count %04x, xfer_status %04x, branch %08x\n",
+ inw( &cmd->res_count ), inw( &cmd->xfer_status ),inl( &cmd->cmd_dep ));
+}
+
+#if 0
+static int
+read_eeprom( unsigned int ioaddr, int location )
+
+{
+ int loop;
+ unsigned char val;
+
+ outb( (location & 0xff), ioaddr + EE_WORD_ADDR );
+
+ /* take spillover from location in control reg */
+ outb(EE_CONTROL_RND_READB | (location & (0x7<<8)), ioaddr + EE_CONTROL);
+
+ loop = 1000;
+ while( (inb( ioaddr + EE_STATUS) & EE_SEB) &&
+ (loop > 0) ) {
+ udelay( 10 );
+ loop--;
+ }
+
+ if ( inb( ioaddr + EE_STATUS ) & EE_SEE ) {
+ printk("%s: Serial EEPROM read error\n", chipname);
+ val = 0xff;
+ }
+
+ else
+ val = inb( ioaddr + EE_READ_DATA );
+
+ return (int) val;
+}
+#endif
+
+#ifdef NCR885E_DEBUG_MII
+static void
+show_mii( unsigned long ioaddr )
+
+{
+ int phyctrl, phystat, phyadvert, phypartner, phyexpan;
+
+ phyctrl = read_mii( ioaddr, MII_AUTO_NEGOTIATION_CONTROL );
+ phystat = read_mii( ioaddr, MII_AUTO_NEGOTIATION_STATUS );
+ phyadvert = read_mii( ioaddr, MII_AUTO_NEGOTIATION_ADVERTISEMENT );
+ phypartner = read_mii( ioaddr, MII_AUTO_NEGOTIATION_LINK_PARTNER );
+ phyexpan = read_mii( ioaddr, MII_AUTO_NEGOTIATION_EXPANSION );
+
+ printk( KERN_INFO "PHY: advert=%d %s, partner=%s %s, link=%d, %s%s\n",
+ (phyadvert & MANATECH_100BASETX_FULL_DUPLEX ? 100 : 10),
+ (phyctrl & MANC_AUTO_NEGOTIATION_ENABLE ? "auto" : "fixed"),
+ (phypartner & MANLP_ACKNOWLEDGE ?
+ (phypartner & MANATECH_100BASETX_FULL_DUPLEX ? "100" : "10") :
+ "?"),
+ (phyexpan & MANE_LINK_PARTNER_AUTO_ABLE ? "auto" : "fixed"),
+ (phyctrl & MANC_PHY_SPEED_100 ? 100 : 10),
+ (phystat & MANS_LINK_STATUS ? "up" : "down"),
+ (phyexpan & MANE_PARALLEL_DETECTION_FAULT ? " PD-fault" : "" ));
+ return;
+}
+
+
+static int
+read_mii( unsigned long ioaddr, int reg )
+
+{
+ int timeout;
+
+
+ timeout = 100000;
+
+ while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+
+ if ( timeout-- < 0 ) {
+ printk( KERN_INFO "Timed out waiting for MII\n" );
+ return -1;
+ }
+ }
+
+ outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+ outw( MIIM_RSTAT, ioaddr + MIIM_COMMAND );
+
+ timeout = 100000;
+ while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+ if ( timeout-- < 0 ) {
+ printk( KERN_INFO "Timed out waiting for MII\n" );
+ return -1;
+ }
+ }
+
+ return( inw( ioaddr + MII_READ_DATA ));
+}
+
+static void
+write_mii( unsigned long ioaddr, int reg, int data )
+
+{
+ int timeout=100000;
+
+ printk( KERN_INFO "MII indicator: %02x\n", inw( ioaddr + MII_INDICATOR ));
+
+ while( inw( ioaddr + MII_INDICATOR ) & MII_BUSY ) {
+ if ( timeout-- <= 0 ) {
+ printk( KERN_INFO "Timeout waiting to write to MII\n" );
+ return;
+ }
+ udelay( 10 );
+ }
+
+ outw( (1<<8) + reg, ioaddr + MII_ADDRESS );
+ outw( data, ioaddr + MII_WRITE_DATA );
+
+ return;
+}
+
+#endif /* NCR885E_DEBUG_MII */
+
+#ifdef MODULE
+#if defined(LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("dan@synergymicro.com");
+MODULE_DESCRIPTION("Symbios 53C885 Ethernet driver");
+MODULE_PARM(debug, "i");
+#endif
+
+static int debug = 1;
+
+int
+init_module(void)
+{
+ if ( debug >= 0)
+ ncr885e_debug = debug;
+
+ return ncr885e_probe( NULL );
+}
+
+void
+cleanup_module(void)
+{
+ struct ncr885e_private *np;
+
+ if ( root_dev ) {
+
+ unregister_netdev( root_dev );
+ np = (struct ncr885e_private *) root_dev->priv;
+ release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );
+ kfree( root_dev->priv );
+ root_dev = NULL;
+ }
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O6 -c symba.c"
+ * End:
+ */
diff --git a/drivers/net/ncr885e.h b/drivers/net/ncr885e.h
new file mode 100644
index 000000000..bbcc82e11
--- /dev/null
+++ b/drivers/net/ncr885e.h
@@ -0,0 +1,367 @@
+#ifndef _NET_H_SYMBA
+#define _NET_H_SYMBA
+
+/* transmit status bit definitions */
+#define TX_STATUS_TXOK (1<<13) /* success */
+#define TX_STATUS_TDLC (1<<12) /* dropped for late colls */
+#define TX_STATUS_TCXSDFR (1<<11) /* excessive deferral */
+#define TX_STATUS_TDEC (1<<10) /* excessive collisions */
+#define TX_STATUS_TAUR (1<<9) /* abort on underrun/"jumbo" */
+#define TX_STATUS_PDFRD (1<<8) /* packet deferred */
+#define TX_STATUS_BCAST (1<<7) /* broadcast ok */
+#define TX_STATUS_MCAST (1<<6) /* multicast ok */
+#define TX_STATUS_CRCERR (1<<5) /* CRC error */
+#define TX_STATUS_LC (1<<4) /* late collision */
+#define TX_STATUS_CCNT_MASK 0xf /* collision count */
+
+#define T_TXOK (1<<13)
+#define T_TDLC (1<<12)
+#define T_TCXSDFR (1<<11)
+#define T_TDEC (1<<10)
+#define T_TAUR (1<<9)
+#define T_PDFRD (1<<8)
+#define T_BCAST (1<<7)
+#define T_MCAST (1<<6)
+#define T_LC (1<<4)
+#define T_CCNT_MASK 0xf
+
+/* receive status bit definitions */
+#define RX_STATUS_RXOVRN (1<<23) /* overrun */
+#define RX_STATUS_CEPS (1<<22) /* carrier event already seen */
+#define RX_STATUS_RXOK (1<<21) /* success */
+#define RX_STATUS_BCAST (1<<20) /* broadcast ok */
+#define RX_STATUS_MCAST (1<<19) /* multicast ok */
+#define RX_STATUS_CRCERR (1<<18) /* CRC error */
+#define RX_STATUS_DR (1<<17) /* dribble nibble */
+#define RX_STATUS_RCV (1<<16) /* rx code violation */
+#define RX_STATUS_PTL (1<<15) /* pkt > 1518 bytes */
+#define RX_STATUS_PTS (1<<14) /* pkt < 64 bytes */
+#define RX_STATUS_LEN_MASK 0x1fff /* length mask */
+
+#define EEPROM_LENGTH 100
+
+
+/* Serial EEPROM interface */
+#define EE_STATUS 0xf0
+#define EE_CONTROL 0xf1
+#define EE_WORD_ADDR 0xf2
+#define EE_READ_DATA 0xf3
+#define EE_WRITE_DATA 0xf4
+#define EE_FEATURE_ENB 0xf5
+
+/* Use on EE_STATUS */
+#define EE_SEB (1<<8)
+#define EE_SEE 1
+
+/* Serial EEPROM commands */
+#define EE_CONTROL_SEQ_READB (1<<4)
+#define EE_CONTROL_RND_WRITEB (1<<5)
+#define EE_CONTROL_RND_READB ((1<<4)|(1<<5))
+
+/* Enable writing to serial EEPROM */
+#define EE_WRITE_ENB 1
+
+/* The 885 configuration register */
+#define MAC_CONFIG 0xa0
+#define MAC_CONFIG_SRST 1<<15
+#define MAC_CONFIG_ITXA 1<<13
+#define MAC_CONFIG_RXEN 1<<12
+#define MAC_CONFIG_INTLB 1<<10
+#define MAC_CONFIG_MODE_MASK (1<<8|1<<9)
+#define MAC_CONFIG_MODE_TP 1<<8
+#define MAC_CONFIG_HUGEN 1<<5
+#define MAC_CONFIG_RETRYL 1<<4
+#define MAC_CONFIG_CRCEN 1<<3
+#define MAC_CONFIG_PADEN 1<<2
+#define MAC_CONFIG_FULLD 1<<1
+#define MAC_CONFIG_NOCFR 1<<0
+
+
+
+
+
+#define TX_WAIT_SELECT 0x18
+#define RX_CHANNEL_CONTROL 0x40
+
+/* Tx channel status */
+#define TX_DBDMA_REG 0x00
+#define TX_CHANNEL_CONTROL 0x00
+#define TX_CHANNEL_STATUS 0x04
+#define TX_STATUS_RUN 1<<15
+#define TX_STATUS_PAUSE 1<<14
+#define TX_STATUS_WAKE 1<<12
+#define TX_STATUS_DEAD 1<<11
+#define TX_STATUS_ACTIVE 1<<10
+#define TX_STATUS_BT 1<<8
+#define TX_STATUS_TXABORT 1<<7
+#define TX_STATUS_TXSR 1<<6
+
+#define TX_CHANNEL_RUN TX_STATUS_RUN
+#define TX_CHANNEL_PAUSE TX_STATUS_PAUSE
+#define TX_CHANNEL_WAKE TX_STATUS_WAKE
+#define TX_CHANNEL_DEAD TX_STATUS_DEAD
+#define TX_CHANNEL_ACTIVE TX_STATUS_ACTIVE
+#define TX_CHANNEL_BT TX_STATUS_BT
+#define TX_CHANNEL_TXABORT TX_STATUS_TXABORT
+#define TX_CHANNEL_TXSR TX_STATUS_TXSR
+
+#define TX_DBDMA_ENABLE (TX_CHANNEL_WAKE | TX_CHANNEL_PAUSE | \
+ TX_CHANNEL_RUN )
+
+/* Transmit command ptr lo register */
+#define TX_CMD_PTR_LO 0x0c
+
+/* Transmit interrupt select register */
+#define TX_INT_SELECT 0x10
+
+/* Transmit branch select register */
+#define TX_BRANCH_SELECT 0x14
+
+/* Transmit wait select register */
+#define TX_WAIT_SELECT 0x18
+#define TX_WAIT_STAT_RECV 0x40
+
+/* Rx channel status */
+#define RX_DBDMA_REG 0x40
+#define RX_CHANNEL_CONTROL 0x40
+#define RX_CHANNEL_STATUS 0x44
+#define RX_STATUS_RUN 1<<15
+#define RX_STATUS_PAUSE 1<<14
+#define RX_STATUS_WAKE 1<<12
+#define RX_STATUS_DEAD 1<<11
+#define RX_STATUS_ACTIVE 1<<10
+#define RX_STATUS_BT 1<<8
+#define RX_STATUS_EOP 1<<6
+
+#define RX_CHANNEL_RUN RX_STATUS_RUN
+#define RX_CHANNEL_PAUSE RX_STATUS_PAUSE
+#define RX_CHANNEL_WAKE RX_STATUS_WAKE
+#define RX_CHANNEL_DEAD RX_STATUS_DEAD
+#define RX_CHANNEL_ACTIVE RX_STATUS_ACTIVE
+#define RX_CHANNEL_BT RX_STATUS_BT
+#define RX_CHANNEL_EOP RX_STATUS_EOP
+
+#define RX_DBDMA_ENABLE (RX_CHANNEL_WAKE | RX_CHANNEL_PAUSE | \
+ RX_CHANNEL_RUN)
+
+/* Receive command ptr lo */
+#define RX_CMD_PTR_LO 0x4c
+
+/* Receive interrupt select register */
+#define RX_INT_SELECT 0x50
+#define RX_INT_SELECT_EOP 0x40
+
+/* Receive branch select */
+#define RX_BRANCH_SELECT 0x54
+#define RX_BRANCH_SELECT_EOP 0x40
+
+/* Receive wait select */
+#define RX_WAIT_SELECT 0x58
+#define RX_WAIT_SELECT_EOP 0x40
+
+/* Event status register */
+#define EVENT_STATUS 0x80
+#define EVENT_TXSR 1<<2
+#define EVENT_EOP 1<<1
+#define EVENT_TXABORT 1<<0
+
+/* Interrupt enable register */
+#define INTERRUPT_ENABLE 0x82
+
+/* Interrupt clear register */
+#define INTERRUPT_CLEAR 0x84
+
+/* Interrupt status register */
+#define INTERRUPT_STATUS_REG 0x86
+
+/* bits for the above three interrupt registers */
+#define INTERRUPT_INTE 1<<15 /* interrupt enable */
+#define INTERRUPT_WI 1<<9 /* wakeup interrupt */
+#define INTERRUPT_ERI 1<<8 /* early recieve interrupt */
+#define INTERRUPT_PPET 1<<7 /* PCI Tx parity error */
+#define INTERRUPT_PBFT 1<<6 /* PCI Tx bus fault */
+#define INTERRUPT_IIDT 1<<5 /* illegal instruction Tx */
+#define INTERRUPT_DIT 1<<4 /* DBDMA Tx interrupt */
+#define INTERRUPT_PPER 1<<3 /* PCI Rx parity error */
+#define INTERRUPT_PBFR 1<<2 /* PCI Rx bus fault */
+#define INTERRUPT_IIDR 1<<1 /* illegal instruction Rx */
+#define INTERRUPT_DIR 1<<0 /* DBDMA Rx interrupt */
+
+#define INTERRUPT_TX_MASK (INTERRUPT_PBFT|INTERRUPT_IIDT| \
+ INTERRUPT_PPET|INTERRUPT_DIT)
+#define INTERRUPT_RX_MASK (INTERRUPT_PBFR|INTERRUPT_IIDR| \
+ INTERRUPT_PPER|INTERRUPT_DIR)
+
+/* chip revision register */
+#define CHIP_REVISION_REG 0x8c
+#define CHIP_PCIREV_MASK (0xf<<16)
+#define CHIP_PCIDEV_MASK 0xff
+
+/* Tx threshold register */
+#define TX_THRESHOLD 0x94
+
+/* General purpose register */
+#define GEN_PURPOSE_REG 0x9e
+
+/* General purpose pin control reg */
+#define GEN_PIN_CONTROL_REG 0x9f
+
+/* DBDMA control register */
+#define DBDMA_CONTROL 0x90
+#define DBDMA_SRST 1<<31
+#define DBDMA_TDPCE 1<<23
+#define DBDMA_BE 1<<22
+#define DBDMA_TAP_MASK (1<<19|1<<20|1<<21)
+#define DBDMA_RAP_MASK (1<<16|1<<17|1<<18)
+#define DBDMA_DPMRLE 1<<15
+#define DBDMA_WIE 1<<14
+#define DBDMA_MP 1<<13
+#define DBDMA_SME 1<<12
+#define DBDMA_CME 1<<11
+#define DBDMA_DDPE 1<<10
+#define DBDMA_TDPE 1<<9
+#define DBDMA_EXTE 1<<8
+#define DBDMA_BST_MASK (1<<4|1<<5|1<<6)
+#define DBDMA_BSR_MASK (1<<0|1<<1|1<<2)
+
+#define DBDMA_BURST_1 (0x00)
+#define DBDMA_BURST_2 (0x01)
+#define DBDMA_BURST_4 (0x02)
+#define DBDMA_BURST_8 (0x03)
+#define DBDMA_BURST_16 (0x04)
+#define DBDMA_BURST_32 (0x05)
+#define DBDMA_BURST_64 (0x06)
+#define DBDMA_BURST_128 (0x07)
+
+#define DBDMA_TX_BST_SHIFT (4)
+#define DBDMA_RX_BST_SHIFT (0)
+
+#define DBDMA_TX_ARBITRATION_DEFAULT ( 1 << 19 )
+#define DBDMA_RX_ARBITRATION_DEFAULT ( 2 << 16 )
+
+
+/* Back-to-back interpacket gap register */
+#define BTOB_INTP_GAP 0xa2
+#define BTOB_INTP_DEFAULT 0x18
+
+/* Non-back-to-back interpacket gap register */
+#define NBTOB_INTP_GAP 0xa4
+
+/* MIIM command register */
+#define MIIM_COMMAND 0xa6
+#define MIIM_SCAN 1<<1
+#define MIIM_RSTAT 1<<0
+
+/* MII address register */
+#define MII_ADDRESS 0xa8
+#define MII_FIAD_MASK (1<<8|1<<9|1<<10|1<<11|1<<12)
+#define MII_RGAD_MASK (1<<0|1<<1|1<<2|1<<3|1<<4)
+
+#define TPPMD_CONTROL_REG 0xa8
+#define TPPMD_FO 1<<1
+#define TPPMD_LB 1<<0
+
+/* MII read and write registers */
+#define MII_WRITE_DATA 0xaa
+#define MII_READ_DATA 0xac
+
+/* MII indicators */
+#define MII_INDICATOR 0xae
+#define MII_NVALID 1<<2
+#define MII_SCAN 1<<1
+#define MII_BUSY 1<<0
+
+/* Address filter */
+#define ADDRESS_FILTER 0xd0
+#define ADDRESS_RPPRM 1<<3 /* multicast promis. mode */
+#define ADDRESS_RPPRO 1<<2 /* promiscuous mode */
+#define ADDRESS_RPAMC 1<<1 /* accept multicasts */
+#define ADDRESS_RPABC 1<<0 /* accept broadcasts */
+
+/* Station addresses
+
+ Note that if the serial EEPROM is disabled, these values are all
+ zero. If, like us, you get the chips when they're fresh, they're
+ also zero and you have to initialize the address */
+#define STATION_ADDRESS_0 0xd2
+#define STATION_ADDRESS_1 0xd4
+#define STATION_ADDRESS_2 0xd6
+
+/* Hash tables */
+#define HASH_TABLE_0 0xd8
+#define HASH_TABLE_1 0xda
+#define HASH_TABLE_2 0xdc
+#define HASH_TABLE_3 0xde
+
+/* PHY indentifiers */
+#define PHY_IDENTIFIER_0 0xe4
+#define PHY_IDENTIFIER_1 0xe6
+
+/* MII Auto-negotiation register definitions */
+
+#define MII_AUTO_NEGOTIATION_CONTROL (0x0000)
+#define MANC_PHY_RESET (0x8000)
+#define MANC_PHY_LOOPBACK_ENABLE (0x4000)
+#define MANC_PHY_LOOPBACK_DISABLE (0x0000)
+#define MANC_PHY_SPEED_100 (0x2000)
+#define MANC_PHY_SPEED_10 (0x0000)
+#define MANC_AUTO_NEGOTIATION_ENABLE (0x1000)
+#define MANC_AUTO_NEGOTIATION_DISABLE (0x0000)
+#define MANC_PHY_POWER_DOWN (0x0800)
+#define MANC_PHY_POWER_UP (0x0000)
+#define MANC_ISOLATE_ENABLE (0x0400)
+#define MANC_ISOLATE_DISABLE (0x0000)
+#define MANC_RESTART_AUTO_NEGOTIATION (0x0200)
+#define MANC_FULL_DUPLEX (0x0100)
+#define MANC_HALF_DUPLEX (0x0000)
+
+#define MII_AUTO_NEGOTIATION_STATUS (0x0001)
+#define MANS_100BASE_T4_HALF_DUPLEX (0x8000)
+#define MANS_100BASE_X_FULL_DUPLEX (0x4000)
+#define MANS_100BASE_X_HALF_DUPLEX (0x2000)
+#define MANS_10MBS_FULL_DUPLEX (0x1000)
+#define MANS_10MBS_HALF_DUPLEX (0x0800)
+#define MANS_AUTO_NEGOTIATION_COMPLETE (0x0020)
+#define MANS_REMOTE_FAULT (0x0010)
+#define MANS_AUTO_NEGOTIATION_ABILITY (0x0008)
+#define MANS_LINK_STATUS (0x0004)
+#define MANS_JABBER_DETECT (0x0002)
+#define MANS_EXTENDED_CAPABILITY (0x0001)
+
+#define MII_PHY_IDENTIFIER_1 (0x0002)
+#define MII_PHY_IDENTIFIER_2 (0x0003)
+
+#define MII_AUTO_NEGOTIATION_ADVERTISEMENT (0x0004)
+#define MANA_NEXT_PAGE (0x8000)
+#define MANA_REMOTE_FAULT (0x2000)
+#define MANA_TECHNOLOGY_ABILITY_MASK (0x1FE0)
+#define MANATECH_10BASET_HALF_DUPLEX (0x0020)
+#define MANATECH_10BASET_FULL_DUPLEX (0x0040)
+#define MANATECH_100BASETX_HALF_DUPLEX (0x0080)
+#define MANATECH_100BASETX_FULL_DUPLEX (0x0100)
+#define MANATECH_100BASET4 (0x0200)
+#define MANA_SELECTOR_MASK (0x001F)
+#define MANASELECTOR_802_3 (0x0001)
+
+#define MII_AUTO_NEGOTIATION_LINK_PARTNER (0x0005)
+#define MANLP_NEXT_PAGE (0x8000)
+#define MANLP_ACKNOWLEDGE (0x4000)
+#define MANLP_REMOTE_FAULT (0x2000)
+#define MANLP_TECHNOLOGY_ABILITY_MASK (0x1FE0)
+#define MANLP_SELECTOR_MASK (0x001F)
+
+#define MII_AUTO_NEGOTIATION_EXPANSION (0x0006)
+#define MANE_PARALLEL_DETECTION_FAULT (0x0010)
+#define MANE_LINK_PARTNER_NEXT_PAGE_ABLE (0x0008)
+#define MANE_NEXT_PAGE_ABLE (0x0004)
+#define MANE_PAGE_RECEIVED (0x0002)
+#define MANE_LINK_PARTNER_AUTO_ABLE (0x0001)
+
+#define MII_AUTO_NEGOTIATION_NEXT_PAGE_TRANSMIT (0x0007)
+#define MANNPT_NEXT_PAGE (0x8000)
+#define MANNPT_MESSAGE_PAGE (0x2000)
+#define MANNPT_ACKNOWLEDGE_2 (0x1000)
+#define MANNPT_TOGGLE (0x0800)
+#define MANNPT_MESSAGE_FIELD_MASK (0x07FF)
+
+#endif
diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
index 8af63739c..81bba9e60 100644
--- a/drivers/net/pcmcia/ray_cs.c
+++ b/drivers/net/pcmcia/ray_cs.c
@@ -57,21 +57,17 @@
left out. If you compile with PCMCIA_DEBUG=0, the debug code will
be present but disabled -- but it can then be enabled for specific
modules at load time with a 'pc_debug=#' option to insmod.
-
- I found that adding -DPCMCIA_DEBUG to the compile options during
- the 'make config' resulted in cardmgr not finding any sockets.
- Therefore, this module uses RAYLINK_DEBUG instead.
- The module option to use is ray_debug=#
- where # is 1 for modest output
- 2 for more output
- ...
*/
#ifdef RAYLINK_DEBUG
-static int ray_debug = RAYLINK_DEBUG;
-MODULE_PARM(ray_debug, "i");
-/* #define DEBUG(n, args...) if (ray_debug>(n)) printk(KERN_DEBUG args); */
-#define DEBUG(n, args...) if (ray_debug>(n)) printk(args);
+#define PCMCIA_DEBUG RAYLINK_DEBUG
+#endif
+#ifdef PCMCIA_DEBUG
+static int ray_debug = 0;
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+/* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(args);
#else
#define DEBUG(n, args...)
#endif
@@ -137,7 +133,6 @@ void start_net(u_long local);
/* void start_net(ray_dev_t *local); */
int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare);
-
/* Create symbol table for registering with kernel in init_module */
EXPORT_SYMBOL(ray_dev_ioctl);
EXPORT_SYMBOL(ray_rx);
@@ -147,40 +142,30 @@ EXPORT_SYMBOL(ray_rx);
/* Bit map of interrupts to choose from */
/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
static u_long irq_mask = 0xdeb8;
-MODULE_PARM(irq_mask,"i");
/* ADHOC=0, Infrastructure=1 */
static int net_type = ADHOC;
-MODULE_PARM(net_type,"i");
/* Hop dwell time in Kus (1024 us units defined by 802.11) */
static int hop_dwell = 128;
-MODULE_PARM(hop_dwell,"i");
/* Beacon period in Kus */
static int beacon_period = 256;
-MODULE_PARM(beacon_period,"i");
/* power save mode (0 = off, 1 = save power) */
static int psm = 0;
-MODULE_PARM(psm,"i");
/* String for network's Extended Service Set ID. 32 Characters max */
static char *essid = NULL;
-MODULE_PARM(essid,"s");
/* Default to encapsulation unless translation requested */
static int translate = 1;
-MODULE_PARM(translate,"i");
static int country = USA;
-MODULE_PARM(country,"i");
static int sniffer = 0;
-MODULE_PARM(sniffer,"i");
static int bc = 0;
-MODULE_PARM(bc,"i");
/* 48 bit physical card address if overriding card's real physical
* address is required. Since IEEE 802.11 addresses are 48 bits
@@ -193,7 +178,6 @@ MODULE_PARM(bc,"i");
* things will happen if it is not 0 in a card address.
*/
static char *phy_addr = NULL;
-MODULE_PARM(phy_addr,"s");
/* The dev_info variable is the "key" that is used to match up this
@@ -214,7 +198,22 @@ static dev_link_t *dev_list = NULL;
'priv' pointer in a dev_link_t structure can be used to point to
a device-specific private data structure, like this.
*/
-static const unsigned int ray_mem_speed = 0x2A;
+static unsigned int ray_mem_speed = 0x2A;
+
+MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
+MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
+MODULE_PARM(irq_mask,"i");
+MODULE_PARM(net_type,"i");
+MODULE_PARM(hop_dwell,"i");
+MODULE_PARM(beacon_period,"i");
+MODULE_PARM(psm,"i");
+MODULE_PARM(essid,"s");
+MODULE_PARM(translate,"i");
+MODULE_PARM(country,"i");
+MODULE_PARM(sniffer,"i");
+MODULE_PARM(bc,"i");
+MODULE_PARM(phy_addr,"s");
+MODULE_PARM(ray_mem_speed, "i");
static UCHAR b5_default_startup_parms[] = {
0, 0, /* Adhoc station */
@@ -284,7 +283,7 @@ static UCHAR b4_default_startup_parms[] = {
/*===========================================================================*/
static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
-static char rcsid[] = " $Id: ray_cs.c,v 1.60 1999/09/01 20:58:45 corey Exp $ - Corey Thomas corey@world.std.com";
+static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
#ifdef CONFIG_PROC_FS
struct proc_dir_entry ray_cs_proc_entry = {
@@ -358,7 +357,7 @@ dev_link_t *ray_attach(void)
local->finder = link;
link->dev = &local->node;
local->card_status = CARD_INSERTED;
- local->authentication_state = UNAUTHENTICATED;
+ local->authentication_state = UNAUTHENTICATED;
local->num_multi = 0;
DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n",
link,dev,local,&ray_interrupt);
@@ -442,8 +441,6 @@ void ray_detach(dev_link_t *link)
if (link->state & DEV_CONFIG) {
ray_release((u_long)link);
if(link->state & DEV_STALE_CONFIG) {
- DEBUG(0,"ray_cs: detach postponed, '%s' "
- "still locked\n", link->dev->dev_name);
link->state |= DEV_STALE_LINK;
return;
}
@@ -472,7 +469,7 @@ void ray_detach(dev_link_t *link)
=============================================================================*/
#define CS_CHECK(fn, args...) \
while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
-#define MAX_TUPLE_SIZE 80
+#define MAX_TUPLE_SIZE 128
void ray_config(dev_link_t *link)
{
client_handle_t handle = link->handle;
@@ -480,7 +477,7 @@ void ray_config(dev_link_t *link)
cisparse_t parse;
int last_fn, last_ret;
int i;
- u_char buf[80];
+ u_char buf[MAX_TUPLE_SIZE];
win_req_t req;
memreq_t mem;
struct net_device *dev = (struct net_device *)link->priv;
@@ -499,6 +496,19 @@ void ray_config(dev_link_t *link)
link->conf.ConfigBase = parse.config.base;
link->conf.Present = parse.config.rmask[0];
+ /* Determine card type and firmware version */
+ buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0;
+ tuple.DesiredTuple = CISTPL_VERS_1;
+ CS_CHECK(GetFirstTuple, handle, &tuple);
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = MAX_TUPLE_SIZE;
+ tuple.TupleOffset = 2;
+ CS_CHECK(GetTupleData, handle, &tuple);
+
+ for (i=0; i<tuple.TupleDataLen - 4; i++)
+ if (buf[i] == 0) buf[i] = ' ';
+ printk(KERN_INFO "ray_cs Detected: %s\n",buf);
+
/* Configure card */
link->state |= DEV_CONFIG;
@@ -562,7 +572,10 @@ void ray_config(dev_link_t *link)
}
link->state &= ~DEV_CONFIG_PENDING;
- DEBUG(0, "ray_cs device loaded\n");
+ printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
+ dev->name, dev->irq);
+ for (i = 0; i < 6; i++)
+ printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
return;
@@ -594,7 +607,8 @@ int ray_init(struct net_device *dev)
/* Check Power up test status and get mac address from card */
if (local->startup_res.startup_word != 0x80) {
-DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word);
+ printk(KERN_INFO "ray_init ERROR card status = %2x\n",
+ local->startup_res.startup_word);
local->card_status = CARD_INIT_ERROR;
return -1;
}
@@ -619,16 +633,12 @@ DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word);
if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr))
{
p = local->sparm.b4.a_mac_addr;
- DEBUG(1,"ray_cs phy address overridden = %2x %2x %2x %2x %2x %2x\n",\
- p[0],p[1],p[2],p[3],p[4],p[5]);
}
else
{
memcpy(&local->sparm.b4.a_mac_addr,
&local->startup_res.station_addr, ADDRLEN);
p = local->sparm.b4.a_mac_addr;
- DEBUG(1,"ray_cs phy addr= %2x %2x %2x %2x %2x %2x\n",\
- p[0],p[1],p[2],p[3],p[4],p[5]);
}
clear_interrupt(local); /* Clear any interrupt from the card */
@@ -647,7 +657,7 @@ int dl_startup_params(struct net_device *dev)
DEBUG(1,"dl_startup_params entered\n");
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs dl_startup_params - device not present\n");
+ DEBUG(2,"ray_cs dl_startup_params - device not present\n");
return -1;
}
@@ -661,14 +671,15 @@ int dl_startup_params(struct net_device *dev)
/* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) == -1) return -1;
+ if ((ccsindex = get_free_ccs(local)) < 0) return -1;
local->dl_param_ccs = ccsindex;
pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs);
/* Interrupt the firmware to process the command */
if (interrupt_ecf(local, ccsindex)) {
- DEBUG(0,"ray dl_startup_params failed - ECF not ready for intr\n");
+ printk(KERN_INFO "ray dl_startup_params failed - "
+ "ECF not ready for intr\n");
local->card_status = CARD_DL_PARAM_ERROR;
writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
return -2;
@@ -723,11 +734,11 @@ void init_startup_params(ray_dev_t *local)
local->sparm.b4.a_curr_country_code = country;
local->sparm.b4.a_hop_pattern_length =
hop_pattern_length[(int)country] - 1;
- if (bc)
- {
- local->sparm.b4.a_ack_timeout = 0x50;
- local->sparm.b4.a_sifs = 0x3f;
- }
+ if (bc)
+ {
+ local->sparm.b4.a_ack_timeout = 0x50;
+ local->sparm.b4.a_sifs = 0x3f;
+ }
}
else { /* Version 5 uses real kus values */
memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms,
@@ -756,30 +767,29 @@ void verify_dl_startup(u_long data)
ray_dev_t *local = (ray_dev_t *)data;
struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs;
UCHAR status;
-/* UCHAR *p = local->sram + HOST_TO_ECF_BASE; */
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs verify_dl_startup - device not present\n");
+ DEBUG(2,"ray_cs verify_dl_startup - device not present\n");
return;
}
-#ifdef RAYLINK_DEBUG
- {
- int i;
- DEBUG(2,"verify_dl_startup parameters sent via ccs %d:\n",\
- local->dl_param_ccs);
- for (i=0; i<sizeof(struct b5_startup_params); i++)
- {
- DEBUG(1," %2x ", readb(local->sram + HOST_TO_ECF_BASE + i));
+#ifdef PCMCIA_DEBUG
+ if (pc_debug > 2) {
+ int i;
+ printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n",
+ local->dl_param_ccs);
+ for (i=0; i<sizeof(struct b5_startup_params); i++) {
+ printk(" %2x", readb(local->sram + HOST_TO_ECF_BASE + i));
}
- DEBUG(1,"\n");
+ printk("\n");
}
#endif
status = readb(&pccs->buffer_status);
if (status!= CCS_BUFFER_FREE)
{
- DEBUG(0,"Download startup params failed. Status = %d\n",status);
+ printk(KERN_INFO "Download startup params failed. Status = %d\n",
+ status);
local->card_status = CARD_DL_PARAM_ERROR;
return;
}
@@ -799,11 +809,11 @@ void start_net(u_long data)
int ccsindex;
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs start_net - device not present\n");
+ DEBUG(2,"ray_cs start_net - device not present\n");
return;
}
/* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) == -1) return;
+ if ((ccsindex = get_free_ccs(local)) < 0) return;
pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
writeb(CCS_START_NETWORK, &pccs->cmd);
writeb(0, &pccs->var.start_network.update_param);
@@ -827,11 +837,11 @@ void join_net(u_long data)
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs join_net - device not present\n");
+ DEBUG(2,"ray_cs join_net - device not present\n");
return;
}
/* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) == -1) return;
+ if ((ccsindex = get_free_ccs(local)) < 0) return;
pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
writeb(CCS_JOIN_NETWORK, &pccs->cmd);
writeb(0, &pccs->var.join_network.update_param);
@@ -867,7 +877,7 @@ void ray_release(u_long arg)
link->state |= DEV_STALE_CONFIG;
return;
}
- del_timer(&local->timer);
+ del_timer(&local->timer);
if (link->dev != '\0') unregister_netdev(dev);
/* Unlink the device chain */
link->dev = NULL;
@@ -962,13 +972,14 @@ int ray_dev_init(struct net_device *dev)
DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_dev_init - device not present\n");
+ DEBUG(2,"ray_dev_init - device not present\n");
return -1;
}
/* Download startup parameters */
if ( (i = dl_startup_params(dev)) < 0)
{
- DEBUG(0,"ray_dev_init dl_startup_params failed - returns 0x%x/n",i);
+ printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
+ "returns 0x%x/n",i);
return -1;
}
@@ -976,15 +987,6 @@ int ray_dev_init(struct net_device *dev)
memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
memset(dev->broadcast, 0xff, ETH_ALEN);
-#ifdef RAYLINK_DEBUG
- {
- UCHAR *p;
- p = (UCHAR *)(local->startup_res.station_addr);
- DEBUG(1,"ray_dev_init card hardware mac addr = %2x %2x %2x %2x %2x %2x\n",\
- p[0],p[1],p[2],p[3],p[4],p[5]);
- }
-#endif
-
DEBUG(2,"ray_dev_init ending\n");
return 0;
}
@@ -996,7 +998,7 @@ int ray_dev_config(struct net_device *dev, struct ifmap *map)
/* Dummy routine to satisfy device structure */
DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_dev_config - device not present\n");
+ DEBUG(2,"ray_dev_config - device not present\n");
return -1;
}
@@ -1010,13 +1012,13 @@ int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
short length;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_dev_start_xmit - device not present\n");
+ DEBUG(2,"ray_dev_start_xmit - device not present\n");
return -1;
}
DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev);
if (dev->tbusy)
{
- DEBUG(2,"ray_dev_start_xmit busy\n");
+ printk(KERN_NOTICE "ray_dev_start_xmit busy\n");
return 1;
}
if (local->authentication_state == NEED_TO_AUTH) {
@@ -1031,7 +1033,7 @@ int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
case XMIT_NO_CCS:
- case XMIT_NEED_AUTH:
+ case XMIT_NEED_AUTH:
dev->tbusy = 1;
return 1;
case XMIT_NO_INTR:
@@ -1058,15 +1060,20 @@ int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev,
DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev);
if (len + TX_HEADER_LENGTH > TX_BUF_SIZE)
{
- DEBUG(0,"ray_hw_xmit packet to large %d bytes\n",len);
+ printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len);
return XMIT_MSG_BAD;
}
- if ((ccsindex = get_free_tx_ccs(local)) == -1)
- {
- DEBUG(2,"ray_hw_xmit - No free tx ccs\n");
+ switch (ccsindex = get_free_tx_ccs(local)) {
+ case ECCSBUSY:
+ DEBUG(2,"ray_hw_xmit tx_ccs table busy\n");
+ case ECCSFULL:
+ DEBUG(2,"ray_hw_xmit No free tx ccs\n");
+ case ECARDGONE:
dev->tbusy = 1;
return XMIT_NO_CCS;
- }
+ default:
+ break;
+ }
addr = TX_BUF_BASE + (ccsindex << 11);
if (msg_type == DATA_TYPE) {
@@ -1186,7 +1193,7 @@ int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
int err = 0;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_dev_ioctl - device not present\n");
+ DEBUG(2,"ray_dev_ioctl - device not present\n");
return -1;
}
DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
@@ -1258,16 +1265,14 @@ void ray_reset(struct net_device *dev) {
int interrupt_ecf(ray_dev_t *local, int ccs)
{
int i = 50;
-/* UCHAR *p = (local->amem + CIS_OFFSET + ECF_INTR_OFFSET); */
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs interrupt_ecf - device not present\n");
+ DEBUG(2,"ray_cs interrupt_ecf - device not present\n");
return -1;
}
DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs);
-/* while ( i && (*p & ECF_INTR_SET)) i--; */
while ( i &&
(readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET))
i--;
@@ -1275,8 +1280,8 @@ int interrupt_ecf(ray_dev_t *local, int ccs)
DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n");
return -1;
}
-
- *(local->sram + SCB_BASE) = ccs;
+ /* Fill the mailbox, then kick the card */
+ writeb(ccs, local->sram + SCB_BASE);
writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
return 0;
} /* interrupt_ecf */
@@ -1290,19 +1295,26 @@ int get_free_tx_ccs(ray_dev_t *local)
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs get_free_tx_ccs - device not present\n");
- return -1;
+ DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n");
+ return ECARDGONE;
}
+ if (test_and_set_bit(0,&local->tx_ccs_lock)) {
+ DEBUG(1,"ray_cs tx_ccs_lock busy\n");
+ return ECCSBUSY;
+ }
+
for (i=0; i < NUMBER_OF_TX_CCS; i++) {
if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
writeb(CCS_END_LIST, &(pccs+i)->link);
+ local->tx_ccs_lock = 0;
return i;
}
}
- DEBUG(1,"ray_cs ERROR no free tx CCS for raylink card\n");
- return -1;
+ local->tx_ccs_lock = 0;
+ DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n");
+ return ECCSFULL;
} /* get_free_tx_ccs */
/*===========================================================================*/
/* Get next free CCS */
@@ -1314,25 +1326,33 @@ int get_free_ccs(ray_dev_t *local)
dev_link_t *link = local->finder;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs get_free_ccs - device not present\n");
- return -1;
+ DEBUG(2,"ray_cs get_free_ccs - device not present\n");
+ return ECARDGONE;
}
+ if (test_and_set_bit(0,&local->ccs_lock)) {
+ DEBUG(1,"ray_cs ccs_lock busy\n");
+ return ECCSBUSY;
+ }
+
for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
writeb(CCS_END_LIST, &(pccs+i)->link);
+ local->ccs_lock = 0;
return i;
}
}
+ local->ccs_lock = 0;
DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n");
- return -1;
+ return ECCSFULL;
} /* get_free_ccs */
/*===========================================================================*/
void authenticate_timeout(u_long data)
{
ray_dev_t *local = (ray_dev_t *)data;
del_timer(&local->timer);
- DEBUG(0,"ray_cs Authentication with access point failed - timeout\n");
+ printk(KERN_INFO "ray_cs Authentication with access point failed"
+ " - timeout\n");
join_net((u_long)local);
}
/*===========================================================================*/
@@ -1381,26 +1401,26 @@ struct enet_statistics *ray_get_stats(struct net_device *dev)
dev_link_t *link = local->finder;
struct status *p = (struct status *)(local->sram + STATUS_BASE);
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_cs enet_statistics - device not present\n");
+ DEBUG(2,"ray_cs enet_statistics - device not present\n");
return &local->stats;
}
- if (p->mrx_overflow_for_host)
+ if (readb(&p->mrx_overflow_for_host))
{
- local->stats.rx_over_errors += ntohs(p->mrx_overflow);
- p->mrx_overflow = 0;
- p->mrx_overflow_for_host = 0;
+ local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow));
+ writeb(0,&p->mrx_overflow);
+ writeb(0,&p->mrx_overflow_for_host);
}
- if (p->mrx_checksum_error_for_host)
+ if (readb(&p->mrx_checksum_error_for_host))
{
- local->stats.rx_crc_errors += ntohs(p->mrx_checksum_error);
- p->mrx_checksum_error = 0;
- p->mrx_checksum_error_for_host = 0;
+ local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error));
+ writeb(0,&p->mrx_checksum_error);
+ writeb(0,&p->mrx_checksum_error_for_host);
}
- if (p->rx_hec_error_for_host)
+ if (readb(&p->rx_hec_error_for_host))
{
- local->stats.rx_frame_errors += ntohs(p->rx_hec_error);
- p->rx_hec_error = 0;
- p->rx_hec_error_for_host = 0;
+ local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error));
+ writeb(0,&p->rx_hec_error);
+ writeb(0,&p->rx_hec_error_for_host);
}
return &local->stats;
}
@@ -1414,11 +1434,11 @@ void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
struct ccs *pccs;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(0,"ray_update_parm - device not present\n");
+ DEBUG(2,"ray_update_parm - device not present\n");
return;
}
- if ((ccsindex = get_free_ccs(local)) == -1)
+ if ((ccsindex = get_free_ccs(local)) < 0)
{
DEBUG(0,"ray_update_parm - No free ccs\n");
return;
@@ -1449,12 +1469,12 @@ static void ray_update_multi_list(struct net_device *dev, int all)
UCHAR *p = local->sram + HOST_TO_ECF_BASE;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(1,"ray_update_multi_list - device not present\n");
+ DEBUG(2,"ray_update_multi_list - device not present\n");
return;
}
else
- DEBUG(1,"ray_update_multi_list(%p)\n",dev);
- if ((ccsindex = get_free_ccs(local)) == -1)
+ DEBUG(2,"ray_update_multi_list(%p)\n",dev);
+ if ((ccsindex = get_free_ccs(local)) < 0)
{
DEBUG(1,"ray_update_multi - No free ccs\n");
return;
@@ -1491,7 +1511,7 @@ static void set_multicast_list(struct net_device *dev)
ray_dev_t *local = (ray_dev_t *)dev->priv;
UCHAR promisc;
- DEBUG(1,"ray_cs set_multicast_list(%p)\n",dev);
+ DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
if (dev->flags & IFF_PROMISC)
{
@@ -1534,30 +1554,23 @@ void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
UCHAR cmd;
UCHAR status;
- if (dev == NULL) {
- link = dev_list;
- dev = (struct net_device *)link->priv;
- DEBUG(4,"ray_cs interrupt dev = %p, link = %p\n",dev,link);
- if (dev->irq != irq)
- {
- DEBUG(0,"ray_cs interrupt irq %d for unknown device.\n", irq);
- return;
- }
- }
+ if ((dev == NULL) || !dev->start)
+ return;
+
DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
- if (dev->interrupt) {
+ if (test_and_set_bit(0,&dev->interrupt)) {
printk("ray_cs Reentering interrupt handler not allowed\n");
return;
}
- dev->interrupt = 1;
+
local = (ray_dev_t *)dev->priv;
link = (dev_link_t *)local->finder;
if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) {
- DEBUG(1,"ray_cs interrupt from device not present or suspended.\n");
+ DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
return;
}
- rcsindex = ((struct scb *)(local->sram))->rcs_index;
+ rcsindex = readb(&((struct scb *)(local->sram))->rcs_index);
if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS))
{
@@ -1602,7 +1615,7 @@ void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
case CCS_JOIN_NETWORK:
if (status == CCS_COMMAND_COMPLETE) {
if (readb(&pccs->var.start_network.net_initiated) == 1) {
- DEBUG(0,"ray_cs interrupt network \"%s\"started\n",\
+ DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\
local->sparm.b4.a_current_ess_id);
}
else {
@@ -1741,16 +1754,16 @@ void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
switch(readb(pmsg))
{
case DATA_TYPE:
- DEBUG(4,"ray_rx data type\n");
+ DEBUG(4,"ray_rx data type\n");
rx_data(dev, prcs, pkt_addr, rx_len);
break;
case AUTHENTIC_TYPE:
- DEBUG(4,"ray_rx authentic type\n");
+ DEBUG(4,"ray_rx authentic type\n");
if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
else rx_authenticate(local, prcs, pkt_addr, rx_len);
break;
case DEAUTHENTIC_TYPE:
- DEBUG(4,"ray_rx deauth type\n");
+ DEBUG(4,"ray_rx deauth type\n");
if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
else rx_deauthenticate(local, prcs, pkt_addr, rx_len);
break;
@@ -1758,7 +1771,7 @@ void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
DEBUG(3,"ray_cs rx NULL msg\n");
break;
case BEACON_TYPE:
- DEBUG(4,"ray_rx beacon type\n");
+ DEBUG(4,"ray_rx beacon type\n");
if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr,
@@ -1909,19 +1922,24 @@ void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
struct ethhdr *peth;
UCHAR srcaddr[ADDRLEN];
UCHAR destaddr[ADDRLEN];
- int i;
- if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)
+ if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)
memcpy(destaddr, pmac->addr_3, ADDRLEN);
else
memcpy(destaddr, pmac->addr_1, ADDRLEN);
memcpy(srcaddr, pmac->addr_2, ADDRLEN);
- DEBUG(3,"skb->data before untranslate");
+#ifdef PCMCIA_DEBUG
+ if (pc_debug > 3) {
+ int i;
+ printk(KERN_DEBUG "skb->data before untranslate");
for (i=0;i<64;i++)
- DEBUG(3,"%02x ",skb->data[i]);
- DEBUG(3,"\ntype = %08x, xsap = %08x, org = %08x\n",type,xsap,org);
- DEBUG(3,"untranslate skb->data = %p\n",skb->data);
+ printk("%02x ",skb->data[i]);
+ printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n",
+ type,xsap,org);
+ printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
+ }
+#endif
if ( xsap != SNAP_ID) {
/* not a snap type so leave it alone */
@@ -1971,10 +1989,15 @@ void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data);
memcpy(peth->h_dest, destaddr, ADDRLEN);
memcpy(peth->h_source, srcaddr, ADDRLEN);
- DEBUG(3,"skb->data after untranslate:");
- for (i=0;i<64;i++)
- DEBUG(3,"%02x ",skb->data[i]);
- DEBUG(3,"\n");
+#ifdef PCMCIA_DEBUG
+ if (pc_debug > 3) {
+ int i;
+ printk(KERN_DEBUG "skb->data after untranslate:");
+ for (i=0;i<64;i++)
+ printk("%02x ",skb->data[i]);
+ printk("\n");
+ }
+#endif
} /* end untranslate */
/*===========================================================================*/
/* Copy data from circular receive buffer to PC memory.
@@ -2020,7 +2043,7 @@ void authenticate(ray_dev_t *local)
dev_link_t *link = local->finder;
DEBUG(0,"ray_cs Starting authentication.\n");
if (!(link->state & DEV_PRESENT)) {
- DEBUG(1,"ray_cs authenticate - device not present\n");
+ DEBUG(2,"ray_cs authenticate - device not present\n");
return;
}
@@ -2046,37 +2069,37 @@ void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
del_timer(&local->timer);
copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
- /* if we are trying to get authenticated */
+ /* if we are trying to get authenticated */
if (local->sparm.b4.a_network_type == ADHOC) {
- DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
- if (msg->var[2] == 1) {
+ DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
+ if (msg->var[2] == 1) {
DEBUG(0,"ray_cs Sending authentication response.\n");
if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
local->authentication_state = NEED_TO_AUTH;
memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN);
}
- }
- }
- else /* Infrastructure network */
- {
- if (local->authentication_state == AWAITING_RESPONSE) {
- /* Verify authentication sequence #2 and success */
- if (msg->var[2] == 2) {
- if ((msg->var[3] | msg->var[4]) == 0) {
- DEBUG(1,"Authentication successful\n");
- local->card_status = CARD_AUTH_COMPLETE;
- associate(local);
- local->authentication_state = AUTHENTICATED;
- }
- else {
- DEBUG(0,"Authentication refused\n");
- local->card_status = CARD_AUTH_REFUSED;
- join_net((u_long)local);
- local->authentication_state = UNAUTHENTICATED;
- }
- }
- }
- }
+ }
+ }
+ else /* Infrastructure network */
+ {
+ if (local->authentication_state == AWAITING_RESPONSE) {
+ /* Verify authentication sequence #2 and success */
+ if (msg->var[2] == 2) {
+ if ((msg->var[3] | msg->var[4]) == 0) {
+ DEBUG(1,"Authentication successful\n");
+ local->card_status = CARD_AUTH_COMPLETE;
+ associate(local);
+ local->authentication_state = AUTHENTICATED;
+ }
+ else {
+ DEBUG(0,"Authentication refused\n");
+ local->card_status = CARD_AUTH_REFUSED;
+ join_net((u_long)local);
+ local->authentication_state = UNAUTHENTICATED;
+ }
+ }
+ }
+ }
} /* end rx_authenticate */
/*===========================================================================*/
@@ -2087,11 +2110,11 @@ void associate(ray_dev_t *local)
struct net_device *dev = link->priv;
int ccsindex;
if (!(link->state & DEV_PRESENT)) {
- DEBUG(1,"ray_cs associate - device not present\n");
+ DEBUG(2,"ray_cs associate - device not present\n");
return;
}
/* If no tx buffers available, return*/
- if ((ccsindex = get_free_ccs(local)) == -1)
+ if ((ccsindex = get_free_ccs(local)) < 0)
{
/* TBD should never be here but... what if we are? */
DEBUG(1,"ray_cs associate - No free ccs\n");
@@ -2125,7 +2148,7 @@ void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs,
struct rx_msg *msg = (struct rx_msg *)buff;
*/
DEBUG(0,"Deauthentication frame received\n");
- local->authentication_state = UNAUTHENTICATED;
+ local->authentication_state = UNAUTHENTICATED;
/* Need to reauthenticate or rejoin depending on reason code */
/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
*/
@@ -2256,9 +2279,8 @@ int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
int ccsindex;
/* If no tx buffers available, return */
- if ((ccsindex = get_free_tx_ccs(local)) == -1)
+ if ((ccsindex = get_free_tx_ccs(local)) < 0)
{
-/* TBD should never be here but... what if we are? */
DEBUG(1,"ray_cs send authenticate - No free tx ccs\n");
return -1;
}
diff --git a/drivers/net/pcmcia/ray_cs.h b/drivers/net/pcmcia/ray_cs.h
index 28502954e..ae28bc71a 100644
--- a/drivers/net/pcmcia/ray_cs.h
+++ b/drivers/net/pcmcia/ray_cs.h
@@ -17,9 +17,14 @@ struct beacon_rx {
+ sizeof(struct tim_element)];
};
+/* Return values for get_free{,_tx}_ccs */
+#define ECCSFULL (-1)
+#define ECCSBUSY (-2)
+#define ECARDGONE (-3)
+
typedef struct ray_dev_t {
int card_status;
- int authentication_state;
+ int authentication_state;
dev_node_t node;
window_handle_t amem_handle; /* handle to window for attribute memory */
window_handle_t rmem_handle; /* handle to window for rx buffer on card */
@@ -28,6 +33,8 @@ typedef struct ray_dev_t {
UCHAR *rmem; /* pointer to receive buffer window */
dev_link_t *finder; /* pointer back to dev_link_t for card */
struct timer_list timer;
+ int tx_ccs_lock;
+ int ccs_lock;
int dl_param_ccs;
union {
struct b4_startup_params b4;
diff --git a/drivers/net/pcmcia/rayctl.h b/drivers/net/pcmcia/rayctl.h
index a301b0bd2..49d9b267b 100644
--- a/drivers/net/pcmcia/rayctl.h
+++ b/drivers/net/pcmcia/rayctl.h
@@ -142,8 +142,6 @@ struct adhoc_beacon
};
/*****************************************************************************/
/*****************************************************************************/
-
-
/* #define C_MAC_HDR_2_WEP 0x40 */
/* TX/RX CCS constants */
#define TX_HEADER_LENGTH 0x1C
@@ -151,6 +149,9 @@ struct adhoc_beacon
#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
+#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2)
+#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
+#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
#define FCS_LEN 4
#define ADHOC 0
@@ -324,17 +325,23 @@ struct adhoc_beacon
#define CARD_ASSOC_COMPLETE (6)
#define CARD_ASSOC_FAILED (16)
-/*** Values for authentication_state */
+/*** Values for authentication_state ***********************************/
#define UNAUTHENTICATED (0)
#define AWAITING_RESPONSE (1)
#define AUTHENTICATED (2)
#define NEED_TO_AUTH (3)
-/*** Values for authentication type */
+/*** Values for authentication type ************************************/
#define OPEN_AUTH_REQUEST (1)
#define OPEN_AUTH_RESPONSE (2)
-
-
+#define BROADCAST_DEAUTH (0xc0)
+/*** Values for timer functions ****************************************/
+#define TODO_NOTHING (0)
+#define TODO_VERIFY_DL_START (-1)
+#define TODO_START_NET (-2)
+#define TODO_JOIN_NET (-3)
+#define TODO_AUTHENTICATE_TIMEOUT (-4)
+#define TODO_SEND_CCS (-5)
/***********************************************************************/
/* Parameter passing structure for update/report parameter CCS's */
struct object_id {
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 234242746..a13789668 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.c,v 1.11 1999/10/09 00:01:24 ralf Exp $
+/* $Id: sgiseeq.c,v 1.12 1999/10/21 00:23:05 ralf Exp $
*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
@@ -71,12 +71,12 @@ static char *sgiseeqstr = "SGI Seeq8003";
struct sgiseeq_rx_desc {
struct hpc_dma_desc rdma;
- unsigned long buf_vaddr;
+ signed int buf_vaddr;
};
struct sgiseeq_tx_desc {
struct hpc_dma_desc tdma;
- unsigned long buf_vaddr;
+ signed int buf_vaddr;
};
/* Warning: This structure is layed out in a certain way because
@@ -87,7 +87,7 @@ struct sgiseeq_init_block { /* Note the name ;-) */
/* Ptrs to the descriptors in KSEG1 uncached space. */
struct sgiseeq_rx_desc *rx_desc;
struct sgiseeq_tx_desc *tx_desc;
- unsigned long _padding[30]; /* Pad out to largest cache line size. */
+ unsigned int _padding[30]; /* Pad out to largest cache line size. */
struct sgiseeq_rx_desc rxvector[SEEQ_RX_BUFFERS];
struct sgiseeq_tx_desc txvector[SEEQ_TX_BUFFERS];
@@ -212,28 +212,28 @@ void sgiseeq_dump_rings(void)
once++;
printk("RING DUMP:\n");
for(i = 0; i < SEEQ_RX_BUFFERS; i++) {
- printk("RX [%d]: @(%p) [%08lx,%08lx,%08lx] ",
+ printk("RX [%d]: @(%p) [%08x,%08x,%08x] ",
i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo,
r[i].rdma.pnext);
i += 1;
- printk("-- [%d]: @(%p) [%08lx,%08lx,%08lx]\n",
+ printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n",
i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo,
r[i].rdma.pnext);
}
for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
- printk("TX [%d]: @(%p) [%08lx,%08lx,%08lx] ",
+ printk("TX [%d]: @(%p) [%08x,%08x,%08x] ",
i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo,
t[i].tdma.pnext);
i += 1;
- printk("-- [%d]: @(%p) [%08lx,%08lx,%08lx]\n",
+ printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n",
i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo,
t[i].tdma.pnext);
}
printk("INFO: [rx_new = %d rx_old=%d] [tx_new = %d tx_old = %d]\n",
gpriv->rx_new, gpriv->rx_old, gpriv->tx_new, gpriv->tx_old);
- printk("RREGS: rx_cbptr[%08lx] rx_ndptr[%08lx] rx_ctrl[%08lx]\n",
+ printk("RREGS: rx_cbptr[%08x] rx_ndptr[%08x] rx_ctrl[%08x]\n",
hregs->rx_cbptr, hregs->rx_ndptr, hregs->rx_ctrl);
- printk("TREGS: tx_cbptr[%08lx] tx_ndptr[%08lx] tx_ctrl[%08lx]\n",
+ printk("TREGS: tx_cbptr[%08x] tx_ndptr[%08x] tx_ctrl[%08x]\n",
hregs->tx_cbptr, hregs->tx_ndptr, hregs->tx_ctrl);
}
#endif
@@ -309,7 +309,7 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
/* Service every received packet. */
for_each_rx(rd, sp) {
len = (PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3);
- pkt_pointer = (unsigned char *)rd->buf_vaddr;
+ pkt_pointer = (unsigned char *)(long)rd->buf_vaddr;
pkt_status = pkt_pointer[len + 2];
if(pkt_status & SEEQ_RSTAT_FIG) {
@@ -364,8 +364,7 @@ static inline void kick_tx(struct sgiseeq_tx_desc *td,
*/
while((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
(HPCDMA_XIU | HPCDMA_ETXD))
- td = (struct sgiseeq_tx_desc *)
- KSEG1ADDR(td->tdma.pnext);
+ td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext);
if(td->tdma.cntinfo & HPCDMA_XIU) {
hregs->tx_ndptr = PHYSADDR(td);
hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
@@ -562,7 +561,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
* entry and the HPC got to the end of the chain before we
* added this new entry and restarted it.
*/
- memcpy((char *)td->buf_vaddr, skb->data, skblen);
+ memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
td->tdma.cntinfo = ((len) & HPCDMA_BCNT) |
(HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);
if(sp->tx_old != sp->tx_new) {
@@ -733,7 +732,8 @@ int sgiseeq_probe(struct net_device *dev)
/* First get the ethernet address of the onboard
* interface from ARCS.
- * (This is fragile; PROM doesn't like running from cache.)
+ * This is fragile; PROM doesn't like running from cache.
+ * On MIPS64 it crashes for some other, yet unknown reason.
*/
ep = romvec->get_evar("eaddr");
str2eaddr(onboard_eth_addr, ep);
diff --git a/drivers/net/sgiseeq.h b/drivers/net/sgiseeq.h
index 4f684f5a1..0b5d39c68 100644
--- a/drivers/net/sgiseeq.h
+++ b/drivers/net/sgiseeq.h
@@ -1,4 +1,4 @@
-/* $Id: sgiseeq.h,v 1.1 1997/06/09 08:34:32 ralf Exp $
+/* $Id: sgiseeq.h,v 1.4 1999/10/09 00:01:24 ralf Exp $
* sgiseeq.h: Defines for the Seeq8003 ethernet controller.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -7,27 +7,27 @@
#define _SGISEEQ_H
struct sgiseeq_wregs {
- volatile unsigned long multicase_high[2];
- volatile unsigned long frame_gap;
- volatile unsigned long control;
+ volatile unsigned int multicase_high[2];
+ volatile unsigned int frame_gap;
+ volatile unsigned int control;
};
struct sgiseeq_rregs {
- volatile unsigned long collision_tx[2];
- volatile unsigned long collision_all[2];
- volatile unsigned long _unused0;
- volatile unsigned long rflags;
+ volatile unsigned int collision_tx[2];
+ volatile unsigned int collision_all[2];
+ volatile unsigned int _unused0;
+ volatile unsigned int rflags;
};
struct sgiseeq_regs {
union {
- volatile unsigned long eth_addr[6];
- volatile unsigned long multicast_low[6];
+ volatile unsigned int eth_addr[6];
+ volatile unsigned int multicast_low[6];
struct sgiseeq_wregs wregs;
struct sgiseeq_rregs rregs;
} rw;
- volatile unsigned long rstat;
- volatile unsigned long tstat;
+ volatile unsigned int rstat;
+ volatile unsigned int tstat;
};
/* Seeq8003 receive status register */
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index c11248958..cdee2d6e6 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -71,6 +71,7 @@ History:
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/version.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
diff --git a/drivers/net/tokenring/.cvsignore b/drivers/net/tokenring/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/net/tokenring/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in
new file mode 100644
index 000000000..8b3065c8a
--- /dev/null
+++ b/drivers/net/tokenring/Config.in
@@ -0,0 +1,15 @@
+#
+# Token Ring driver configuration
+#
+
+mainmenu_option next_comment
+comment 'Token Ring driver support'
+
+bool 'Token Ring driver support' CONFIG_TR
+if [ "$CONFIG_TR" = "y" ]; then
+ tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR
+ tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL
+ tristate ' SysKonnect adapter support' CONFIG_SKTR
+fi
+
+endmenu
diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile
new file mode 100644
index 000000000..038c58b86
--- /dev/null
+++ b/drivers/net/tokenring/Makefile
@@ -0,0 +1,51 @@
+#
+# Makefile for drivers/net/tokenring
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+
+L_TARGET := tr.a
+L_OBJS :=
+M_OBJS :=
+
+ifeq ($(CONFIG_IBMTR),y)
+ L_OBJS += ibmtr.o
+else
+ ifeq ($(CONFIG_IBMTR),m)
+ M_OBJS += ibmtr.o
+ endif
+endif
+
+ifeq ($(CONFIG_IBMOL),y)
+ L_OBJS += olympic.o
+else
+ ifeq ($(CONFIG_IBMOL),m)
+ M_OBJS += olympic.o
+ endif
+endif
+
+ifeq ($(CONFIG_SKTR),y)
+ L_OBJS += sktr.o
+else
+ ifeq ($(CONFIG_SKTR),m)
+ M_OBJS += sktr.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
diff --git a/drivers/net/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index cf2514fa6..85cdfb774 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -79,6 +79,10 @@
*
* Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
* + added spinlocks for SMP sanity (10 March 1999)
+ *
+ * Changes by Jochen Friedrich to enable RFC1469 Option 2 multicasting
+ * i.e. using functional address C0 00 00 04 00 00 to transmit and
+ * receive multicast packets.
*/
/* change the define of IBMTR_DEBUG_MESSAGES to a nonzero value
@@ -211,6 +215,7 @@ static int tok_open(struct net_device *dev);
static int tok_close(struct net_device *dev);
static int tok_send_packet(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats * tok_get_stats(struct net_device *dev);
+static void tok_set_multicast_list(struct net_device *dev);
void ibmtr_readlog(struct net_device *dev);
void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev);
int ibmtr_change_mtu(struct net_device *dev, int mtu);
@@ -778,7 +783,7 @@ static int __init trdev_init(struct net_device *dev)
dev->stop = tok_close;
dev->hard_start_xmit = tok_send_packet;
dev->get_stats = tok_get_stats;
- dev->set_multicast_list = NULL;
+ dev->set_multicast_list = tok_set_multicast_list;
dev->change_mtu = ibmtr_change_mtu;
#ifndef MODULE
@@ -790,6 +795,43 @@ static int __init trdev_init(struct net_device *dev)
}
+static void tok_set_multicast_list(struct net_device *dev)
+{
+ struct tok_info *ti=(struct tok_info *)dev->priv;
+ struct dev_mc_list *mclist;
+ unsigned char address[4];
+
+ int i;
+
+ address[0] = address[1] = address[2] = address[3] = 0;
+
+ mclist = dev->mc_list;
+ for (i=0; i< dev->mc_count; i++)
+ {
+ address[0] |= mclist->dmi_addr[2];
+ address[1] |= mclist->dmi_addr[3];
+ address[2] |= mclist->dmi_addr[4];
+ address[3] |= mclist->dmi_addr[5];
+ mclist = mclist->next;
+ }
+ SET_PAGE(ti->srb);
+ for (i=0; i<sizeof(struct srb_set_funct_addr); i++)
+ writeb(0, ti->srb+i);
+
+ writeb(DIR_SET_FUNC_ADDR,
+ ti->srb + offsetof(struct srb_set_funct_addr, command));
+
+ DPRINTK("Setting functional address: ");
+
+ for (i=0; i<4; i++)
+ {
+ writeb(address[i],
+ ti->srb + offsetof(struct srb_set_funct_addr, funct_address)+i);
+ printk("%02X ", address[i]);
+ }
+ writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
+ printk("\n");
+}
static int tok_open(struct net_device *dev)
{
@@ -1621,12 +1663,10 @@ static void tr_rx(struct net_device *dev)
ti->tr_stats.rx_packets++;
skb->protocol = tr_type_trans(skb,dev);
-
- if (IPv4_p){
+ if (IPv4_p){
skb->csum = chksum;
skb->ip_summed = 1;
}
-
netif_rx(skb);
}
diff --git a/drivers/net/ibmtr.h b/drivers/net/tokenring/ibmtr.h
index f51174c4f..3f3fa6aed 100644
--- a/drivers/net/ibmtr.h
+++ b/drivers/net/tokenring/ibmtr.h
@@ -444,6 +444,6 @@ struct srb_set_funct_addr {
unsigned char reserved1;
unsigned char ret_code;
unsigned char reserved2[3];
- __u32 funct_address;
+ unsigned char funct_address[4];
};
diff --git a/drivers/net/olympic.c b/drivers/net/tokenring/olympic.c
index 460480c48..460480c48 100644
--- a/drivers/net/olympic.c
+++ b/drivers/net/tokenring/olympic.c
diff --git a/drivers/net/olympic.h b/drivers/net/tokenring/olympic.h
index d5a06423a..d5a06423a 100644
--- a/drivers/net/olympic.h
+++ b/drivers/net/tokenring/olympic.h
diff --git a/drivers/net/sktr.c b/drivers/net/tokenring/sktr.c
index f9b877f66..81b2df4bc 100644
--- a/drivers/net/sktr.c
+++ b/drivers/net/tokenring/sktr.c
@@ -24,7 +24,8 @@
*
* Maintainer(s):
* JS Jay Schulist jschlst@samba.anu.edu.au
- * CG Christoph Goos cgoos@syskonnect.de
+ * CG Christoph Goos cgoos@syskonnect.de
+ * AF Adam Fritzler mid@auk.cx
*
* Modification History:
* 29-Aug-97 CG Created
@@ -33,10 +34,14 @@
* 27-May-98 JS Formated to Linux Kernel Format
* 31-May-98 JS Hacked in PCI support
* 16-Jun-98 JS Modulized for multiple cards with one driver
+ * 21-Sep-99 CG Fixed source routing issues for 2.2 kernels
+ * 21-Sep-99 AF Added multicast changes recommended by
+ * Jochen Friedrich <jochen@nwe.de> (untested)
+ * Added detection of compatible Compaq PCI card
*
* To do:
* 1. Selectable 16 Mbps or 4Mbps
- * 2. Multi/Broadcast packet handling
+ * 2. Multi/Broadcast packet handling (might be done)
*
*/
@@ -135,7 +140,6 @@ static void sktr_enable_interrupts(struct net_device *dev);
static void sktr_exec_cmd(struct net_device *dev, unsigned short Command);
static void sktr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue);
/* "F" */
-static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen);
/* "G" */
static struct enet_statistics *sktr_get_stats(struct net_device *dev);
/* "H" */
@@ -254,10 +258,17 @@ static int __init sktr_pci_chk_card(struct net_device *dev)
/* Remove I/O space marker in bit 0. */
pci_ioaddr &= ~3;
- if(vendor != PCI_VENDOR_ID_SK)
+ if((vendor != PCI_VENDOR_ID_SK) &&
+ (vendor != PCI_VENDOR_ID_COMPAQ))
continue;
- if(device != PCI_DEVICE_ID_SK_TR)
+
+ if((vendor == PCI_VENDOR_ID_SK) &&
+ (device != PCI_DEVICE_ID_SK_TR))
+ continue;
+ else if((vendor == PCI_VENDOR_ID_COMPAQ) &&
+ (device != PCI_DEVICE_ID_COMPAQ_TOKENRING))
continue;
+
if(check_region(pci_ioaddr, SKTR_IO_EXTENT))
continue;
request_region(pci_ioaddr, SKTR_IO_EXTENT, pci_cardname);
@@ -390,6 +401,7 @@ static int __init sktr_probe1(struct net_device *dev, int ioaddr)
{
static unsigned version_printed = 0;
struct net_local *tp;
+ int DeviceType = SK_PCI;
int err;
if(sktr_debug && version_printed++ == 0)
@@ -407,6 +419,7 @@ static int __init sktr_probe1(struct net_device *dev, int ioaddr)
err = sktr_isa_chk_card(dev, ioaddr);
if(err < 0)
return (-ENODEV);
+ DeviceType = SK_ISA;
}
/* Setup this devices private information structure */
@@ -414,6 +427,7 @@ static int __init sktr_probe1(struct net_device *dev, int ioaddr)
if(tp == NULL)
return (-ENOMEM);
memset(tp, 0, sizeof(struct net_local));
+ tp->DeviceType = DeviceType;
init_waitqueue_head(&tp->wait_for_tok_int);
dev->priv = tp;
@@ -691,7 +705,9 @@ static void sktr_init_net_local(struct net_device *dev)
skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize);
/* data unreachable for DMA ? then use local buffer */
- if(virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS)
+ if(tp->DeviceType == SK_ISA &&
+ virt_to_bus(tp->Rpl[i].Skb->data) +
+ tp->MaxPacketSize > ISA_MAX_ADDRESS)
{
tp->Rpl[i].SkbStat = SKB_DATA_COPY;
tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i]));
@@ -749,7 +765,7 @@ static void sktr_init_opb(struct net_local *tp)
tp->ocpl.OPENOptions = 0;
tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION;
- tp->ocpl.OPENOptions |= PAD_ROUTING_FIELD;
+/* tp->ocpl.OPENOptions |= PAD_ROUTING_FIELD; no more needed */
tp->ocpl.FullDuplex = 0;
tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF;
@@ -827,32 +843,6 @@ static void sktr_exec_cmd(struct net_device *dev, unsigned short Command)
}
/*
- * Linux always gives 18 byte of source routing information in the frame header.
- * But the length field can indicate shorter length. Then cut header
- * appropriate.
- */
-static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen)
-{
- struct trh_hdr *trh = (struct trh_hdr *)buf;
- int len;
-
- if(buf[8] & TR_RII)
- {
- trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK);
- trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K);
- len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
- if(len < 18)
- {
- memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len);
- *FrameLen -= (18 - len);
- }
- return (&buf[18-len]);
- }
-
- return (buf);
-}
-
-/*
* Gets skb from system, queues it and checks if it can be sent
*/
static int sktr_send_packet(struct sk_buff *skb, struct net_device *dev)
@@ -934,7 +924,8 @@ static void sktr_hardware_send_packet(struct net_device *dev, struct net_local*
tp->QueueSkb++;
/* Is buffer reachable for Busmaster-DMA? */
- if(virt_to_bus((void*)(((long) skb->data) + skb->len))
+ if(tp->DeviceType == SK_ISA &&
+ virt_to_bus((void*)(((long) skb->data) + skb->len))
> ISA_MAX_ADDRESS)
{
/* Copy frame to local buffer */
@@ -942,13 +933,13 @@ static void sktr_hardware_send_packet(struct net_device *dev, struct net_local*
length = skb->len;
buf = tp->LocalTxBuffers[i];
memcpy(buf, skb->data, length);
- newbuf = sktr_fix_srouting(buf, &length);
+ newbuf = buf;
}
else
{
/* Send direct from skb->data */
length = skb->len;
- newbuf = sktr_fix_srouting(skb->data, &length);
+ newbuf = skb->data;
}
/* Source address in packet? */
@@ -1486,53 +1477,65 @@ static struct enet_statistics *sktr_get_stats(struct net_device *dev)
static void sktr_set_multicast_list(struct net_device *dev)
{
struct net_local *tp = (struct net_local *)dev->priv;
- unsigned int OpenOptions;
-
- OpenOptions = tp->ocpl.OPENOptions &
- ~(PASS_ADAPTER_MAC_FRAMES
- | PASS_ATTENTION_FRAMES
- | PASS_BEACON_MAC_FRAMES
- | COPY_ALL_MAC_FRAMES
- | COPY_ALL_NON_MAC_FRAMES);
-
- if(dev->flags & IFF_PROMISC)
- /* Enable promiscuous mode */
- OpenOptions |= COPY_ALL_NON_MAC_FRAMES | COPY_ALL_MAC_FRAMES;
- else
- {
- if(dev->flags & IFF_ALLMULTI)
- /* || dev->mc_count > HW_MAX_ADDRS) */
- {
- /* Disable promiscuous mode, use normal mode. */
- }
- else
- {
- if(dev->mc_count)
- {
- /* Walk the address list, and load the filter */
- }
- }
- }
-
- tp->ocpl.OPENOptions = OpenOptions;
- sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
-
- return;
+ unsigned int OpenOptions;
+
+ OpenOptions = tp->ocpl.OPENOptions &
+ ~(PASS_ADAPTER_MAC_FRAMES
+ | PASS_ATTENTION_FRAMES
+ | PASS_BEACON_MAC_FRAMES
+ | COPY_ALL_MAC_FRAMES
+ | COPY_ALL_NON_MAC_FRAMES);
+
+ tp->ocpl.FunctAddr = 0;
+
+ if(dev->flags & IFF_PROMISC)
+ /* Enable promiscuous mode */
+ OpenOptions |= COPY_ALL_NON_MAC_FRAMES |
+ COPY_ALL_MAC_FRAMES;
+ else
+ {
+ if(dev->flags & IFF_ALLMULTI)
+ {
+ /* Disable promiscuous mode, use normal mode. */
+ tp->ocpl.FunctAddr = 0xFFFFFFFF;
+
+ }
+ else
+ {
+ int i;
+ struct dev_mc_list *mclist = dev->mc_list;
+ for (i=0; i< dev->mc_count; i++)
+ {
+ ((char *)(&tp->ocpl.FunctAddr))[0] |=
+ mclist->dmi_addr[2];
+ ((char *)(&tp->ocpl.FunctAddr))[1] |=
+ mclist->dmi_addr[3];
+ ((char *)(&tp->ocpl.FunctAddr))[2] |=
+ mclist->dmi_addr[4];
+ ((char *)(&tp->ocpl.FunctAddr))[3] |=
+ mclist->dmi_addr[5];
+ mclist = mclist->next;
+ }
+ }
+ sktr_exec_cmd(dev, OC_SET_FUNCT_ADDR);
+ }
+
+ tp->ocpl.OPENOptions = OpenOptions;
+ sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
+ return;
}
/*
* Wait for some time (microseconds)
+ *
+ * udelay() is a bit harsh, but using a looser timer causes
+ * the bring-up-diags to stall indefinitly.
+ *
*/
+
static void sktr_wait(unsigned long time)
{
- long tmp;
-
- tmp = jiffies + time/(1000000/HZ);
- do {
- current->state = TASK_INTERRUPTIBLE;
- tmp = schedule_timeout(tmp);
- } while(time_after(tmp, jiffies));
-
+ udelay(time);
return;
}
@@ -2451,8 +2454,6 @@ static void sktr_rcv_status_irq(struct net_device *dev)
/* Drop frames sent by myself */
if(sktr_chk_frame(dev, rpl->MData))
{
- printk(KERN_INFO "%s: Received my own frame\n",
- dev->name);
if(rpl->Skb != NULL)
dev_kfree_skb(rpl->Skb);
}
@@ -2464,9 +2465,10 @@ static void sktr_rcv_status_irq(struct net_device *dev)
printk("%s: Packet Length %04X (%d)\n",
dev->name, Length, Length);
- /* Indicate the received frame to system the
- * adapter does the Source-Routing padding for
- * us. See: OpenOptions in sktr_init_opb()
+ /* Indicate the received frame to system.
+ * The source routing padding is no more
+ * necessary with 2.2.x kernel.
+ * See: OpenOptions in sktr_init_opb()
*/
skb = rpl->Skb;
if(rpl->SkbStat == SKB_UNAVAILABLE)
@@ -2497,6 +2499,7 @@ static void sktr_rcv_status_irq(struct net_device *dev)
/* Deliver frame to system */
rpl->Skb = NULL;
skb_trim(skb,Length);
+ skb->dev = dev;
skb->protocol = tr_type_trans(skb,dev);
netif_rx(skb);
}
@@ -2529,7 +2532,8 @@ static void sktr_rcv_status_irq(struct net_device *dev)
skb_put(rpl->Skb, tp->MaxPacketSize);
/* Data unreachable for DMA ? then use local buffer */
- if(virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize
+ if(tp->DeviceType == SK_ISA &&
+ virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize
> ISA_MAX_ADDRESS)
{
rpl->SkbStat = SKB_DATA_COPY;
diff --git a/drivers/net/sktr.h b/drivers/net/tokenring/sktr.h
index 4c2a3bf36..90b5c382f 100644
--- a/drivers/net/sktr.h
+++ b/drivers/net/tokenring/sktr.h
@@ -16,6 +16,9 @@
#define TR_RCF_LONGEST_FRAME_MASK 0x0070
#define TR_RCF_FRAME4K 0x0030
+#define SK_ISA 0
+#define SK_PCI 1
+
/*------------------------------------------------------------------*/
/* Bit order for adapter communication with DMA */
/* -------------------------------------------------------------- */
@@ -642,7 +645,7 @@ typedef struct {
* but possibly multiple TPLs for one frame) the length of the TPLs has to be
* initialized in the OPL. (OPEN parameter list)
*/
-#define TPL_NUM 3 /* Number of Transmit Parameter Lists.
+#define TPL_NUM 9 /* Number of Transmit Parameter Lists.
* !! MUST BE >= 3 !!
*/
@@ -1063,6 +1066,8 @@ typedef struct net_local {
unsigned char ScbInUse;
unsigned short CMDqueue;
+ unsigned int DeviceType;
+
unsigned long AdapterOpenFlag:1;
unsigned long AdapterVirtOpenFlag:1;
unsigned long OpenCommandIssued:1;
diff --git a/drivers/net/sktr_firmware.h b/drivers/net/tokenring/sktr_firmware.h
index 25dd973d4..25dd973d4 100644
--- a/drivers/net/sktr_firmware.h
+++ b/drivers/net/tokenring/sktr_firmware.h
diff --git a/drivers/net/wan/.cvsignore b/drivers/net/wan/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/net/wan/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
new file mode 100644
index 000000000..503854a0f
--- /dev/null
+++ b/drivers/net/wan/Config.in
@@ -0,0 +1,64 @@
+#
+# wan devices configuration
+#
+
+mainmenu_option next_comment
+comment 'Wan interfaces'
+
+bool 'Wan interfaces support' CONFIG_WAN
+if [ "$CONFIG_WAN" = "y" ]; then
+
+ # There is no way to detect a comtrol sv11 - force it modular for now.
+
+ dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
+
+ # The COSA/SRP driver has not been tested as non-modular yet.
+
+ dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
+
+ # There is no way to detect a Sealevel board. Force it modular
+
+ dep_tristate 'Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
+
+ tristate 'Frame relay DLCI support' CONFIG_DLCI
+ if [ "$CONFIG_DLCI" != "n" ]; then
+ int 'Max open DLCI' CONFIG_DLCI_COUNT 24
+ int 'Max DLCI per device' CONFIG_DLCI_MAX 8
+ dep_tristate ' SDLA (Sangoma S502/S508) support' CONFIG_SDLA $CONFIG_DLCI
+ fi
+
+ # Wan router core.
+
+ if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
+ bool 'WAN router drivers' CONFIG_WAN_ROUTER_DRIVERS
+ if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then
+ dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS
+ if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
+ int 'Maximum number of cards' CONFIG_WANPIPE_CARDS 1
+ bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25
+ bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
+ bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS
+ if [ "$CONFIG_CYCLADES_SYNC" != "n" ]; then
+ bool ' Cyclom 2X X.25 support' CONFIG_CYCLOMX_X25
+ fi
+ fi
+ fi
+ fi
+
+ # X.25 network drivers
+
+ if [ "$CONFIG_X25" != "n" ]; then
+ if [ "$CONFIG_LAPB" != "n" ]; then
+ dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
+ dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
+ fi
+ fi
+
+ tristate 'SBNI12-xx support' CONFIG_SBNI
+fi
+
+endmenu
+
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
new file mode 100644
index 000000000..73060f5b9
--- /dev/null
+++ b/drivers/net/wan/Makefile
@@ -0,0 +1,181 @@
+# File: drivers/net/wan/Makefile
+#
+# Makefile for the Linux network (wan) device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := wan.a
+L_OBJS :=
+M_OBJS :=
+
+# Need these to keep track of whether the 82530 or SYNCPPP
+# modules should really go in the kernel or a module.
+CONFIG_85230_BUILTIN :=
+CONFIG_85230_MODULE :=
+CONFIG_SYNCPPP_BUILTIN :=
+CONFIG_SYNCPPP_MODULE :=
+
+ifeq ($(CONFIG_HOSTESS_SV11),y)
+L_OBJS += hostess_sv11.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+ ifeq ($(CONFIG_HOSTESS_SV11),m)
+ CONFIG_85230_MODULE = y
+ CONFIG_SYNCPPP_MODULE = y
+ M_OBJS += hostess_sv11.o
+ endif
+endif
+
+ifeq ($(CONFIG_SEALEVEL_4021),y)
+L_OBJS += sealevel.o
+CONFIG_85230_BUILTIN = y
+CONFIG_SYNCPPP_BUILTIN = y
+else
+ ifeq ($(CONFIG_SEALEVEL_4021),m)
+ CONFIG_85230_MODULE = y
+ CONFIG_SYNCPPP_MODULE = y
+ M_OBJS += sealevel.o
+ endif
+endif
+
+ifeq ($(CONFIG_COSA),y)
+L_OBJS += cosa.o
+CONFIG_SYNCPPP_BUILTIN = y
+else
+ ifeq ($(CONFIG_COSA),m)
+ CONFIG_SYNCPPP_MODULE = y
+ M_OBJS += cosa.o
+ endif
+endif
+
+# If anything built-in uses syncppp, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_SYNCPPP_BUILTIN
+LX_OBJS += syncppp.o
+else
+ ifdef CONFIG_SYNCPPP_MODULE
+ MX_OBJS += syncppp.o
+ endif
+endif
+
+# If anything built-in uses Z85230, then build it into the kernel also.
+# If not, but a module uses it, build as a module.
+
+ifdef CONFIG_85230_BUILTIN
+LX_OBJS += z85230.o
+else
+ ifdef CONFIG_85230_MODULE
+ MX_OBJS += z85230.o
+ endif
+endif
+
+ifeq ($(CONFIG_DLCI),y)
+L_OBJS += dlci.o
+else
+ ifeq ($(CONFIG_DLCI),m)
+ M_OBJS += dlci.o
+ endif
+endif
+
+ifeq ($(CONFIG_SDLA),y)
+ L_OBJS += sdla.o
+else
+ ifeq ($(CONFIG_SDLA),m)
+ M_OBJS += sdla.o
+endif
+
+ifeq ($(CONFIG_VENDOR_SANGOMA),y)
+ LX_OBJS += sdladrv.o
+ L_OBJS += sdlamain.o
+ ifeq ($(CONFIG_WANPIPE_X25),y)
+ L_OBJS += sdla_x25.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_FR),y)
+ L_OBJS += sdla_fr.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_PPP),y)
+ L_OBJS += sdla_ppp.o
+ endif
+endif
+
+endif
+
+ifeq ($(CONFIG_VENDOR_SANGOMA),m)
+ MX_OBJS += sdladrv.o
+ M_OBJS += wanpipe.o
+ WANPIPE_OBJS = sdlamain.o
+ ifeq ($(CONFIG_WANPIPE_X25),y)
+ WANPIPE_OBJS += sdla_x25.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_FR),y)
+ WANPIPE_OBJS += sdla_fr.o
+ endif
+ ifeq ($(CONFIG_WANPIPE_PPP),y)
+ WANPIPE_OBJS += sdla_ppp.o
+ endif
+endif
+
+ifeq ($(CONFIG_CYCLADES_SYNC),y)
+ LX_OBJS += cycx_drv.o
+ L_OBJS += cycx_main.o
+ ifeq ($(CONFIG_CYCLOMX_X25),y)
+ L_OBJS += cycx_x25.o
+ endif
+endif
+
+ifeq ($(CONFIG_CYCLADES_SYNC),m)
+ MX_OBJS += cycx_drv.o
+ M_OBJS += cyclomx.o
+ CYCLOMX_OBJS = cycx_main.o
+ ifeq ($(CONFIG_CYCLOMX_X25),y)
+ CYCLOMX_OBJS += cycx_x25.o
+ endif
+endif
+
+ifeq ($(CONFIG_X25_ASY),y)
+L_OBJS += x25_asy.o
+else
+ ifeq ($(CONFIG_X25_ASY),m)
+ M_OBJS += x25_asy.o
+ endif
+endif
+
+ifeq ($(CONFIG_LAPBETHER),y)
+L_OBJS += lapbether.o
+else
+ ifeq ($(CONFIG_LAPBETHER),m)
+ M_OBJS += lapbether.o
+ endif
+endif
+
+ifeq ($(CONFIG_SBNI),y)
+L_OBJS += sbni.o
+else
+ ifeq ($(CONFIG_SBNI),m)
+ M_OBJS += sbni.o
+ endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+clean:
+ rm -f core *.o *.a *.s
+
+wanpipe.o: $(WANPIPE_OBJS)
+ ld -r -o $@ $(WANPIPE_OBJS)
+
+cyclomx.o: $(CYCLOMX_OBJS)
+ ld -r -o $@ $(CYCLOMX_OBJS)
+
diff --git a/drivers/net/cosa.c b/drivers/net/wan/cosa.c
index 863cd4b59..863cd4b59 100644
--- a/drivers/net/cosa.c
+++ b/drivers/net/wan/cosa.c
diff --git a/drivers/net/cosa.h b/drivers/net/wan/cosa.h
index 7b5a39018..7b5a39018 100644
--- a/drivers/net/cosa.h
+++ b/drivers/net/wan/cosa.h
diff --git a/drivers/net/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index 1629bdcf0..1629bdcf0 100644
--- a/drivers/net/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
diff --git a/drivers/net/cycx_main.c b/drivers/net/wan/cycx_main.c
index 52a2abd04..52a2abd04 100644
--- a/drivers/net/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
diff --git a/drivers/net/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 7e79943c0..7e79943c0 100644
--- a/drivers/net/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
diff --git a/drivers/net/dlci.c b/drivers/net/wan/dlci.c
index a8c52f0d6..a8c52f0d6 100644
--- a/drivers/net/dlci.c
+++ b/drivers/net/wan/dlci.c
diff --git a/drivers/net/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 7b24901ce..ba4e49c83 100644
--- a/drivers/net/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -320,7 +320,7 @@ static struct sv11_device *sv11_init(int iobase, int irq)
for(i=0;i<999;i++)
{
sprintf(sv->name,"hdlc%d", i);
- if(dev_get(sv->name)==NULL)
+ if(dev_get(sv->name)==0)
{
struct net_device *d=dev->chanA.netdevice;
diff --git a/drivers/net/lapbether.c b/drivers/net/wan/lapbether.c
index a4564afcb..a4564afcb 100644
--- a/drivers/net/lapbether.c
+++ b/drivers/net/wan/lapbether.c
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
new file mode 100644
index 000000000..9d5fba082
--- /dev/null
+++ b/drivers/net/wan/sbni.c
@@ -0,0 +1,1533 @@
+/*
+ * Driver for Granch SBNI-12 leased line network adapters.
+ *
+ * Copyright 1997 - 1999, Granch ltd.
+ * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * // Whole developers team:
+ * // Yaroslav Polyakov (xenon@granch.ru)
+ * // - main developer of this version
+ * // Alexey Zverev (zverev@granch.ru)
+ * // - previous SBNI driver for linux
+ * // Alexey Chirkov (chirkov@granch.ru)
+ * // - all the hardware work and consulting
+ * // Max Khon (max@iclub.nsu.ru)
+ * // - first SBNI driver for linux
+ * // --------------------------------------------
+ * // also I thank:
+ * // Max Krasnyansky (max@uznet.net)
+ * // - for bug hunting and many ideas
+ * // Alan Cox (Alan.Cox@linux.org)
+ * // - for consulting in some hardcore questions
+ * // Donald Becker (becker@cesdis.gsfc.nasa.gov)
+ * // - for pretty nice skeleton
+ *
+ * More info and useful utilities to work w/ SBNI you can find at
+ * http://www.granch.ru.
+ *
+ * 3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ * - added pre-calculation for CRC, fixed bug with "len-2" frames,
+ * - removed outbound fragmentation (MTU=1000), written CRC-calculation
+ * - on asm, added work with hard_headers and now we have our own cache
+ * - for them, optionally supported word-interchange on some chipsets,
+ * - something else I cant remember ;)
+ *
+ * 3.0.1 = just fixed some bugs (14 apr 1999).
+ * - fixed statistical tx bug
+ * - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
+ * - fixed source address bug.
+ * - fixed permanent nirvana bug
+ *
+ * 3.1.0 = (Katyusha) (26 apr 1999)
+ * - Added balancing feature
+ *
+ * 3.1.1 = (Medea) (5 aug 1999)
+ * - Fixed mac.raw bug
+ * - Thanks to tolix@olviko.ru and
+ * - to Barnaul Brewery, producers of my favorite beer "Medea".
+ *
+ *
+ */
+
+
+#undef GOODBUS16
+#define CRCASM
+#define KATYUSHA
+
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >=0x020200
+#define v22
+#endif
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/config.h> /* for CONFIG_INET. do we need this?*/
+
+#include <net/arp.h>
+
+
+
+#ifdef v22
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#endif
+
+#include "sbni.h"
+
+
+static const char *version =
+"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+
+int sbni_probe(struct net_device *dev);
+static int sbni_probe1(struct net_device *dev, int ioaddr);
+static int sbni_open(struct net_device *dev);
+static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int sbni_close(struct net_device *dev);
+static void sbni_drop_tx_queue(struct net_device *dev);
+static struct enet_statistics *sbni_get_stats(struct net_device *dev);
+void card_start(struct net_device *dev);
+static inline unsigned short sbni_recv(struct net_device *dev);
+void change_level(struct net_device *dev);
+static inline void sbni_xmit(struct net_device *dev);
+static inline void sbni_get_packet(struct net_device* dev);
+static void sbni_watchdog(unsigned long arg);
+static void set_multicast_list(struct net_device *dev);
+static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int sbni_set_mac_address(struct net_device *dev, void *addr);
+unsigned long calc_crc(char *mem, int len, unsigned initial);
+void sbni_nirvana(struct net_device *dev);
+static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len);
+
+static int sbni_rebuild_header(struct sk_buff *skb);
+static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+
+static inline void sbni_outs(int port, void *data, int len);
+static inline void sbni_ins(int port, void *data, int len);
+
+
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static u_char timeout_rxl_tab[] = {
+ 0x03, 0x05, 0x08, 0x0b
+};
+
+static u_char rxl_tab[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
+ 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+/* A zero-terminated list of I/O addresses to be probed */
+static unsigned int netcard_portlist[] = {
+ 0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250,
+ 0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254,
+ 0x264, 0x294, 0x2a4, 0x2b4, 0};
+
+static unsigned char magic_reply[] = {
+ 0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+};
+
+static int def_baud = DEF_RATE;
+static int def_rxl = DEF_RXL_DELTA;
+static long def_mac = 0;
+
+
+/*
+ * CRC-32 stuff
+ */
+
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+/* CRC generator 0xEDB88320 */
+/* CRC remainder 0x2144DF1C */
+/* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
+
+static unsigned long crc32tab[] = {
+ 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
+ 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
+ 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
+ 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
+ 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
+ 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
+ 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
+ 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
+ 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
+ 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
+ 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
+ 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
+ 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
+ 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
+ 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
+ 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
+ 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
+ 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
+ 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
+ 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
+ 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
+ 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
+ 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
+ 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
+ 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
+ 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
+ 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
+ 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
+ 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
+ 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
+ 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
+ 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
+ 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
+ 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
+ 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
+ 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
+ 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
+ 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
+ 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
+ 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
+ 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
+ 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
+ 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
+ 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
+ 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
+ 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
+ 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
+ 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
+ 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
+ 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
+ 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
+ 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
+ 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
+ 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
+ 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
+ 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
+ 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
+ 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
+ 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
+ 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
+ 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
+ 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
+ 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
+ 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
+};
+
+static inline void sbni_outs(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+ outsw(port,data,len/2);
+ if(len & 1)
+ outb(((char*)data)[len - 1],port);
+#else
+ outsb(port,data,len);
+#endif
+}
+
+static inline void sbni_ins(int port, void *data, int len)
+{
+#ifdef GOODBUS16
+ insw(port,data,len/2);
+ if(len & 1)
+ ((char*)data)[len - 1] = inb(port);
+#else
+ insb(port,data,len);
+#endif
+}
+
+
+static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
+{
+ struct sbni_hard_header *hh = (struct sbni_hard_header *)
+ skb_push(skb, sizeof(struct sbni_hard_header));
+
+
+ if(type!=ETH_P_802_3)
+ hh->h_proto = htons(type);
+ else
+ hh->h_proto = htons(len);
+
+ if(saddr)
+ memcpy(hh->h_source,saddr,dev->addr_len);
+ else
+ memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
+
+ if(daddr)
+ {
+ memcpy(hh->h_dest,daddr,dev->addr_len);
+ return dev->hard_header_len;
+ }
+ return -dev->hard_header_len;
+}
+
+
+int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+ unsigned short type = hh->hh_type;
+ struct sbni_hard_header *sbni = (struct sbni_hard_header*)
+ (((u8*)hh->hh_data) - 8);
+ struct net_device *dev = neigh->dev;
+
+
+ if (type == __constant_htons(ETH_P_802_3))
+ return -1;
+
+ sbni->h_proto = type;
+ memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
+ memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
+ return 0;
+}
+
+static int sbni_rebuild_header(struct sk_buff *skb)
+{
+ struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
+ /*
+ * Only ARP/IP is currently supported
+ */
+
+ /*
+ * Try to get ARP to resolve the header.
+ */
+
+#ifdef CONFIG_INET
+ return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;
+#else
+ return 0;
+#endif
+}
+
+static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+{
+ memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+}
+
+
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry sbni_drv = {
+ "sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist
+};
+
+#else
+
+int __init sbni_probe(struct net_device *dev)
+{
+ int i;
+ int base_addr = dev ? dev->base_addr : 0;
+
+ DP( printk("%s: sbni_probe\n", dev->name); )
+
+ if(base_addr > 0x1ff) /* Check a single specified location. */
+ return sbni_probe1(dev, base_addr);
+ else if(base_addr != 0) /* Don't probe at all. */
+ return ENXIO;
+ for(i = 0; (base_addr = netcard_portlist[i]); i++)
+ {
+ if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
+ {
+ /* Lock this address, or later we'll try it again */
+ netcard_portlist[i] = 1;
+ if(sbni_probe1(dev, base_addr) == 0)
+ return 0;
+ }
+ }
+ return ENODEV;
+}
+
+#endif /* have devlist*/
+
+/*
+ * The actual probe.
+ */
+
+/*
+ Valid combinations in CSR0 (for probing):
+
+ VALID_DECODER 0000,0011,1011,1010
+
+ ; 0 ; -
+ TR_REQ ; 1 ; +
+ TR_RDY ; 2 ; -
+ TR_RDY TR_REQ ; 3 ; +
+ BU_EMP ; 4 ; +
+ BU_EMP TR_REQ ; 5 ; +
+ BU_EMP TR_RDY ; 6 ; -
+ BU_EMP TR_RDY TR_REQ ; 7 ; +
+ RC_RDY ; 8 ; +
+ RC_RDY TR_REQ ; 9 ; +
+ RC_RDY TR_RDY ; 10 ; -
+ RC_RDY TR_RDY TR_REQ ; 11 ; -
+ RC_RDY BU_EMP ; 12 ; -
+ RC_RDY BU_EMP TR_REQ ; 13 ; -
+ RC_RDY BU_EMP TR_RDY ; 14 ; -
+ RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
+*/
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+static int __init sbni_probe1(struct net_device *dev, int ioaddr)
+
+{
+ int autoirq = 0;
+ int bad_card = 0;
+ unsigned char csr0;
+ struct net_local* lp;
+ static int version_printed = 0;
+
+ DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
+
+ if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
+ return -ENODEV;
+ if(version_printed++ == 0)
+ printk(version);
+
+ /* check for valid combination in CSR0 */
+ csr0 = inb(ioaddr + CSR0);
+ if(csr0 == 0xff || csr0 == 0)
+ bad_card = 1;
+ else
+ {
+ csr0 &= ~EN_INT;
+ if(csr0 & BU_EMP)
+ csr0 |= EN_INT;
+ if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
+ bad_card = 1;
+ }
+
+ if(bad_card)
+ return ENODEV;
+ else
+ outb(0, ioaddr + CSR0);
+ if(dev->irq < 2)
+ {
+ DP( printk("%s: autoprobing\n", dev->name); );
+ autoirq_setup(5);
+ outb(EN_INT | TR_REQ, ioaddr + CSR0);
+ outb(PR_RES, ioaddr + CSR1);
+ autoirq = autoirq_report(5);
+
+ if(autoirq == 0)
+ {
+ printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
+ return EAGAIN;
+ }
+ }
+ /* clear FIFO buffer */
+ outb(0, ioaddr + CSR0);
+
+ if(autoirq)
+ dev->irq = autoirq;
+
+ {
+ int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
+ if (irqval)
+ {
+ printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
+ return EAGAIN;
+ }
+ }
+
+ /*
+ * Initialize the device structure.
+ */
+
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ if(dev->priv == NULL)
+ {
+ DP( printk("%s: cannot allocate memory\n", dev->name); )
+ return -ENOMEM;
+ }
+
+ memset(dev->priv, 0, sizeof(struct net_local));
+ dev->base_addr = ioaddr;
+ request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
+
+ /*
+ * generate Ethernet address (0x00ff01xxxxxx)
+ */
+
+ *(u16*)dev->dev_addr = htons(0x00ff);
+ *(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
+
+ lp = dev->priv;
+ if(def_rxl < 0)
+ {
+ /* autodetect receive level */
+ lp->rxl_curr = 0xf;
+ lp->rxl_delta = -1;
+ } else {
+ /* fixed receive level */
+ lp->rxl_curr = def_rxl & 0xf;
+ lp->rxl_delta = 0;
+ }
+ lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+ lp->csr1.rate = def_baud & 3;
+ lp->frame_len = DEF_FRAME_LEN;
+ printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n",
+ dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
+ *(unsigned char*)(dev->dev_addr+3),
+ *(unsigned char*)(dev->dev_addr+4),
+ *(unsigned char*)(dev->dev_addr+5)
+ );
+
+ printk("%s: receive level: ", dev->name);
+ if(lp->rxl_delta == 0)
+ printk ("%#1x (fixed)", lp->rxl_curr);
+ else
+ printk ("autodetect");
+ printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
+
+ /*
+ * The SBNI-specific entries in the device structure.
+ */
+ dev->open = &sbni_open;
+ dev->hard_start_xmit = &sbni_start_xmit;
+ dev->stop = &sbni_close;
+ dev->get_stats = &sbni_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->set_mac_address = &sbni_set_mac_address;
+ dev->do_ioctl = &sbni_ioctl;
+
+ /*
+ * Setup the generic properties
+ */
+
+ ether_setup(dev);
+
+ dev->hard_header = sbni_header;
+ dev->hard_header_len = sizeof(struct sbni_hard_header);
+ dev->rebuild_header=sbni_rebuild_header;
+ dev->mtu = DEF_FRAME_LEN;
+
+ dev->hard_header_cache = sbni_header_cache;
+ dev->header_cache_update = sbni_header_cache_update;
+
+ lp->m=dev;
+ lp->me=dev;
+ lp->next_lp=NULL;
+
+ return 0;
+}
+
+/*
+ * Open/initialize the board.
+ */
+
+static int sbni_open(struct net_device *dev)
+{
+ struct net_local* lp = (struct net_local*)dev->priv;
+ struct timer_list* watchdog = &lp->watchdog;
+
+
+ DP( printk("%s: sbni_open\n", dev->name); )
+
+ cli();
+ lp->currframe = NULL;
+
+ card_start(dev);
+ dev->start = 1;
+ /* set timer watchdog */
+ init_timer(watchdog);
+ watchdog->expires = jiffies + SBNI_TIMEOUT;
+ watchdog->data = (unsigned long)dev;
+ watchdog->function = sbni_watchdog;
+ add_timer(watchdog);
+ DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
+
+ sti();
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int sbni_close(struct net_device *dev)
+{
+ int ioaddr = dev->base_addr;
+ struct net_local* lp = (struct net_local*) dev->priv;
+ struct timer_list* watchdog = &lp->watchdog;
+
+
+ DP( printk("%s: sbni_close\n", dev->name); )
+
+ cli();
+
+ sbni_drop_tx_queue(dev);
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ del_timer(watchdog);
+
+ outb(0, ioaddr + CSR0);
+ sti();
+
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local*)dev->priv;
+ struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
+
+#ifdef KATYUSHA
+ struct net_local *nl;
+ int stop;
+#endif
+
+ DP( printk("%s: sbni_start_xmit In \n", dev->name); );
+
+
+ if(lp->me != dev)
+ panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
+
+ if(dev->interrupt)
+ {
+ DP( printk("sbni_xmit_start: interrupt\n"); )
+ /* May be unloading, don't stamp on */
+ return 1; /* the packet buffer this time */
+ }
+
+ hh->number = 1;
+ hh->reserv = 0;
+
+ hh->packetlen = (skb->len - sizeof (unsigned short) -
+ (sizeof(struct sbni_hard_header) - SBNI_HH_SZ))
+ | PACKET_SEND_OK | PACKET_FIRST_FRAME;
+
+ /* we should use hairy method to calculate crc because of extra bytes are
+ livin between hard header and data*/
+ hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
+ hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
+ skb->len - sizeof(struct sbni_hard_header),
+ hh->crc);
+
+#ifdef KATYUSHA
+ /* looking for first idle device */
+ for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
+ {
+ if((!nl->currframe) && (nl->carrier)) /* if idle */
+ {
+ skb->dev = lp->me;
+ nl->currframe = skb;
+ /* set request for transmit */
+ outb(inb(nl->me->base_addr + CSR0) | TR_REQ,
+ nl->me->base_addr + CSR0);
+ stop=1;
+ }
+ }
+
+ if(!stop) /* we havent found any idle.*/
+ {
+ skb_queue_tail(&lp->queue,skb);
+ outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+
+ }
+#else
+ if (lp->currframe || 1)
+ {
+ skb_queue_tail(&lp->queue,skb);
+
+ }
+ else
+ {
+ lp->currframe = skb;
+ }
+ /* set request for transmit */
+ outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+#endif
+ return 0;
+}
+
+void card_start(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local*)dev->priv;
+
+ DP( printk("%s: card_start\n",dev->name); )
+ lp->wait_frame_number = 0;
+ lp->inppos = lp->outpos = 0;
+ lp->eth_trans_buffer_len = 0;
+ lp->tr_err = TR_ERROR_COUNT;
+ lp->last_receive_OK = FALSE;
+ lp->tr_resend = FALSE;
+ lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+ lp->timeout_rxl = 0;
+
+ lp->waitack=0;
+ skb_queue_head_init(&lp->queue);
+ sbni_drop_tx_queue(dev);
+ dev->tbusy = 0;
+
+ dev->interrupt = 0;
+ /* Reset the card and set start parameters */
+ outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
+ outb(EN_INT, dev->base_addr + CSR0);
+}
+
+void sbni_nirvana(struct net_device *dev)
+{
+ sbni_outs(dev->base_addr+DAT,magic_reply,9);
+}
+
+static inline unsigned short sbni_recv(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local*)dev->priv;
+ unsigned long crc;
+ unsigned short packetlen = 0;
+ unsigned short packetinf, packetfirst, receiveframeresend;
+ unsigned char current_frame;
+ unsigned int i, j;
+ unsigned char delme,rcv_res=RCV_WR;
+
+ lp->in_stats.all_rx_number++;
+
+ if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
+ {
+ crc = CRC32_INITIAL;
+ *(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
+ crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
+ *(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
+ crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
+ packetinf = packetlen & PACKET_INF_MASK;
+ packetfirst = packetlen & PACKET_FIRST_FRAME;
+ receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
+ packetlen = packetlen & PACKET_LEN_MASK;
+
+
+ if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
+ {
+ /* read frame number */
+ current_frame = inb(dev->base_addr + DAT);
+ crc = CRC32(current_frame, crc);
+ /* read HandShake counter */
+ lp->HSCounter = inb(dev->base_addr + DAT);
+ crc = CRC32(lp->HSCounter, crc);
+ packetlen -= 2;
+
+ sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
+
+ for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
+ {
+ crc = CRC32(lp->eth_rcv_buffer[i], crc);
+ }
+
+ if(crc == CRC32_REMAINDER)
+ {
+ if(packetlen > 4)
+ rcv_res=RCV_OK;
+ else if(packetlen == 4)
+ rcv_res=RCV_NO;
+
+ if(lp->waitack && packetinf == PACKET_RESEND)
+ lp->in_stats.resend_tx_number++;
+
+
+ switch(packetinf)
+ {
+ case PACKET_SEND_OK:
+ {
+ lp->tr_err = TR_ERROR_COUNT;
+ lp->tr_resend = FALSE;
+ /* if(lp->trans_frame_number){ */
+ lp->outpos += lp->realframelen;
+
+ /* SendComplete
+ * not supported
+ */
+ DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
+ /*
+ * We sucessfully sent current packet
+ */
+
+ if(lp->waitack)
+ {
+ dev_kfree_skb(lp->currframe);
+ lp->stats.tx_packets++;
+#ifdef KATYUSHA
+ lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+#else
+ lp->currframe=skb_dequeue(&lp->queue);
+#endif
+ lp->in_stats.all_tx_number++;
+ lp->waitack=0;
+ }
+
+ /*
+ * reset output active flags
+ */
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ /*} if */
+ }
+ case PACKET_RESEND:
+ {
+ if(lp->tr_err) /**/
+ lp->tr_err--;
+ if(lp->ok_curr < 0xffffffff)
+ lp->ok_curr++;
+ if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
+ {
+ if(packetfirst)
+ {
+ if(lp->wait_frame_number)
+ {
+ for(i = lp->inppos, j = 0;
+ i < (lp->inppos + packetlen - 4);
+ i++, j++)
+ lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
+ }
+ lp->wait_frame_number = current_frame;
+ lp->inppos = 0;
+ }
+ if(current_frame == lp->wait_frame_number)
+ {
+ lp->inppos += (packetlen - 4);
+ if(lp->wait_frame_number == 1)
+ {
+ sbni_get_packet(dev);
+ lp->inppos = 0;
+ }
+ lp->wait_frame_number--;
+ }
+ }
+ lp->last_receive_OK = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ else
+ {
+ DP(printk("%s: bad CRC32\n",dev->name));
+ change_level(dev);
+ }
+ }
+ else
+ {
+ DP(printk("%s: bad len\n ",dev->name));
+ change_level(dev);
+ lp->stats.rx_over_errors++;
+ }
+ }
+ else
+ {
+ DP(printk("%s: bad sig\n",dev->name));
+ change_level(dev);
+ }
+ outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
+ return (rcv_res);
+}
+
+void change_level(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local*)dev->priv;
+
+ lp->in_stats.bad_rx_number++;
+ lp->stats.tx_errors++;
+ if(lp->rxl_delta == 0)
+ return;
+ /*
+ * set new rxl_delta value
+ */
+ if(lp->rxl_curr == 0)
+ lp->rxl_delta = 1;
+ else if(lp->rxl_curr == 0xf)
+ lp->rxl_delta = -1;
+ else if(lp->ok_curr < lp->ok_prev)
+ lp->rxl_delta = -lp->rxl_delta;
+ /*
+ * set new rxl_curr value
+ */
+ lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
+ outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
+
+
+ /*
+ * update ok_prev/ok_curr counters
+ */
+ lp->ok_prev = lp->ok_curr;
+ lp->ok_curr = 0;
+
+ DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
+ dev->name,lp->rxl_curr, lp->rxl_delta); )
+
+}
+
+static inline void sbni_xmit(struct net_device *dev)
+{
+ struct net_local* lp = (struct net_local *)dev->priv;
+ struct sk_buff *skb;
+
+ skb=lp->currframe;
+
+ DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
+
+ /* push signature*/
+ outb(SBNI_SIG, dev->base_addr + DAT);
+
+ /* push frame w/o crc [HAiRY]*/
+ sbni_outs(dev->base_addr + DAT,
+ &((struct sbni_hard_header *)(skb->data))->packetlen,
+ SBNI_HH_SZ - sizeof(unsigned));
+
+ sbni_outs(dev->base_addr + DAT,
+ skb->data + sizeof(struct sbni_hard_header),
+ skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */
+
+ /* push crc */
+ sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
+
+ lp->waitack=1;
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the ether interface interrupts.
+ */
+static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ struct net_local* lp;
+ u_char csr0;
+ unsigned short rcv_res = RCV_NO;
+
+
+ if(dev == NULL || dev->irq != irq)
+ {
+ printk("sbni: irq %d for unknown device\n", irq);
+ return;
+ }
+
+ if(dev->interrupt)
+ {
+ printk("%s: Reentering the interrupt driver!\n", dev->name);
+ return;
+ }
+ dev->interrupt = 1;
+
+ csr0 = inb(dev->base_addr + CSR0);
+ DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
+
+ lp=dev->priv;
+
+ if(!lp->carrier)
+ lp->carrier=1;
+
+ /*
+ * Disable adapter interrupts
+ */
+ outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
+ lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
+ csr0 = inb(dev->base_addr + CSR0);
+
+ if(csr0 & (TR_RDY | RC_RDY))
+ {
+ if(csr0 & RC_RDY)
+ rcv_res = sbni_recv(dev);
+
+ if((lp->currframe) && (rcv_res != RCV_WR))
+ sbni_xmit(dev);
+ else if (rcv_res == RCV_OK)
+ sbni_nirvana(dev);
+
+ csr0 = inb(dev->base_addr + CSR0);
+ DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
+ }
+
+
+ DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
+
+ /* here we should send pong */
+ outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
+ if(lp->currframe)
+ outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
+ else
+ csr0 = inb(dev->base_addr + CSR0);
+
+ /*
+ * Enable adapter interrupts
+ */
+
+ outb(csr0 | EN_INT, dev->base_addr + CSR0);
+ dev->interrupt = 0;
+}
+
+static struct enet_statistics *sbni_get_stats(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ return &lp->stats;
+}
+
+static inline void sbni_get_packet(struct net_device* dev)
+{
+ struct net_local* lp = (struct net_local*)dev->priv;
+ struct sk_buff* skb;
+ unsigned char *rawp;
+
+
+
+ skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
+
+ if(skb == NULL)
+ {
+ DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
+ lp->stats.rx_dropped++;
+ return;
+ } else {
+#ifdef KATYUSHA
+ skb->dev = lp->m;
+#else
+ skb->dev = dev;
+#endif
+ memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
+ lp->eth_rcv_buffer,
+ lp->inppos);
+
+
+ skb->mac.raw = skb->data + 8;
+
+ if((*(char*)lp->eth_rcv_buffer) & 1)
+ {
+ if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
+ skb->pkt_type=PACKET_BROADCAST;
+ else
+ skb->pkt_type=PACKET_MULTICAST;
+ }
+ else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
+ {
+ if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
+ skb->pkt_type=PACKET_OTHERHOST;
+ }
+
+ if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
+ skb->protocol = *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
+ else
+ {
+ rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
+ if (*(unsigned short *)rawp == 0xFFFF)
+ skb->protocol=htons(ETH_P_802_3);
+ else
+ skb->protocol=htons(ETH_P_802_2);
+ }
+
+
+ skb_pull(skb,SBNI_HH_SZ);
+
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ }
+ return;
+}
+
+static void sbni_watchdog(unsigned long arg)
+{
+ struct net_device* dev = (struct net_device*)arg;
+ struct net_local* lp = (struct net_local *)dev->priv;
+ u_char csr0;
+
+
+
+ DP( printk("%s: watchdog start\n",dev->name); )
+ /*
+ * if no pong received and transmission is not in progress
+ * then assume error
+ */
+ cli();
+ csr0 = inb(dev->base_addr + CSR0);
+ if(csr0 & (RC_CHK | TR_REQ))
+ {
+ if(lp->timer_ticks)
+ {
+ if(csr0 & (RC_RDY | BU_EMP))
+ {
+ lp->timer_ticks--;
+ }
+ }
+ else
+ {
+ if(lp->rxl_delta)
+ {
+ lp->ok_prev = lp->ok_curr;
+ lp->ok_curr = 0;
+ lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
+ lp->timeout_rxl++;
+ if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
+ lp->timeout_rxl = 0;
+ lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+ /*
+ * update ok_prev/ok_curr counters
+ */
+ lp->ok_prev = lp->ok_curr;
+ lp->ok_curr = 0;
+ }
+ if(lp->tr_err)
+ lp->tr_err--;
+ else
+ {
+ /* Drop the queue of tx packets */
+ sbni_drop_tx_queue(dev);
+ lp->carrier=0;
+ }
+
+ /*
+ * send pong
+ */
+
+ csr0 = inb(dev->base_addr + CSR0);
+ outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
+ outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+ lp->in_stats.timeout_number++;
+ }
+ }
+ sti();
+ outb(csr0 | RC_CHK, dev->base_addr + CSR0);
+ if(dev->start)
+ {
+ struct timer_list* watchdog = &lp->watchdog;
+ init_timer(watchdog);
+ watchdog->expires = jiffies + SBNI_TIMEOUT;
+ watchdog->data = arg;
+ watchdog->function = sbni_watchdog;
+ add_timer(watchdog);
+ }
+}
+
+static void sbni_drop_tx_queue(struct net_device *dev)
+{
+ struct net_local* lp = (struct net_local *)dev->priv,*nl;
+ struct sk_buff *tmp;
+
+ /* first of all, we should try to gift our packets to another interface */
+
+ nl=(struct net_local *)lp->m->priv;
+ if(nl==lp)
+ nl=lp->next_lp;
+
+ if(nl)
+ {
+ /* we found device*/
+ if(lp->currframe)
+ {
+ if(!nl->currframe)
+ {
+ nl->currframe=lp->currframe;
+ }
+ else
+ {
+ skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
+ }
+ }
+ lp->currframe=NULL;
+
+ if(!nl->currframe)
+ nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
+
+ /* set request for transmit */
+ outb(inb(nl->me->base_addr + CSR0) | TR_REQ, nl->me->base_addr + CSR0);
+
+ }
+ else
+ {
+ /* *sigh*, we should forget this packets */
+ nl=lp->m->priv;
+
+ while((tmp = skb_dequeue(&nl->queue)) != NULL)
+ {
+ dev_kfree_skb(tmp);
+ lp->stats.tx_packets++;
+ }
+
+ if (lp->currframe)
+ {
+ dev_kfree_skb(lp->currframe);
+ lp->currframe = NULL;
+ lp->stats.tx_packets++;
+ }
+ }
+ lp->waitack=0;
+ dev->tbusy = 0;
+
+ mark_bh(NET_BH);
+ DP( printk("%s: queue dropping stoped\n",dev->name); );
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, clear multicast list
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ /*
+ * always enabled promiscuous mode.
+ */
+ return;
+}
+
+static int sbni_set_mac_address(struct net_device *dev, void *addr)
+{
+ /* struct net_local *lp = (struct net_local *)dev->priv; */
+ struct sockaddr *saddr = addr;
+
+ if(dev->start)
+ {
+ /* Only possible while card isn't started */
+ return -EBUSY;
+ }
+ memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
+ return (0);
+}
+
+static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct net_local* lp = (struct net_local *)dev->priv,*tlp;
+ struct net_device *slave;
+ int error = 0;
+ char tmpstr[6];
+
+
+ switch(cmd)
+ {
+ case SIOCDEVGETINSTATS:
+ {
+ struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
+ DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
+ if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
+ return -EFAULT;
+ break;
+ }
+ case SIOCDEVRESINSTATS:
+ {
+ DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
+ lp->in_stats.all_rx_number = 0;
+ lp->in_stats.bad_rx_number = 0;
+ lp->in_stats.timeout_number = 0;
+ lp->in_stats.all_tx_number = 0;
+ lp->in_stats.resend_tx_number = 0;
+ break;
+ }
+ case SIOCDEVGHWSTATE:
+ {
+ struct sbni_flags flags;
+ flags.rxl = lp->rxl_curr;
+ flags.rate = lp->csr1.rate;
+ flags.fixed_rxl = (lp->rxl_delta == 0);
+ flags.fixed_rate = 1;
+ ifr->ifr_data = *(caddr_t*)&flags;
+ DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
+ break;
+ }
+ case SIOCDEVSHWSTATE:
+ {
+ struct sbni_flags flags;
+ DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
+ /* root only */
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ flags = *(struct sbni_flags*)&ifr->ifr_data;
+ if(flags.fixed_rxl)
+ {
+ lp->rxl_delta = 0;
+ lp->rxl_curr = flags.rxl;
+ }
+ else
+ {
+ lp->rxl_delta = DEF_RXL_DELTA;
+ lp->rxl_curr = DEF_RXL;
+ }
+ lp->csr1.rxl = rxl_tab[lp->rxl_curr];
+ if(flags.fixed_rate)
+ lp->csr1.rate = flags.rate;
+ else
+ lp->csr1.rate = DEF_RATE;
+ /*
+ * Don't be afraid...
+ */
+ outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+
+ DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
+ dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
+ break;
+ }
+
+ case SIOCDEVENSLAVE:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if(copy_from_user( tmpstr, ifr->ifr_data, 6))
+ return -EFAULT;
+ slave=dev_get(tmpstr);
+ if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
+ {
+ printk("%s: Both devices should be UP to enslave!\n",dev->name);
+ return -EINVAL;
+ }
+
+ if(slave)
+ {
+ if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
+ {
+ /* drop queue*/
+ sbni_drop_tx_queue(slave);
+ slave->flags |= IFF_SLAVE;
+ ((struct net_local *)(slave->priv))->m=dev;
+ while(lp->next_lp) //tail it after last slave
+ lp=lp->next_lp;
+ lp->next_lp=slave->priv;
+ lp=(struct net_local *)dev->priv;
+ dev->flags |= IFF_MASTER;
+ }
+ else
+ {
+ printk("%s: one of devices is already slave!\n",dev->name);
+ return -EBUSY;
+ }
+ }
+ else
+ {
+ printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
+ return -ENOENT;
+ }
+ break;
+
+ case SIOCDEVEMANSIPATE:
+ if(!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if(dev->flags & IFF_SLAVE)
+ {
+ dev->flags &= ~IFF_SLAVE;
+ /* exclude us from masters slavelist*/
+ for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
+ if(tlp->next_lp)
+ {
+ tlp->next_lp = lp->next_lp;
+ if(!((struct net_local *)lp->m->priv)->next_lp)
+ {
+ lp->m->flags &= ~IFF_MASTER;
+ }
+ lp->next_lp=NULL;
+ lp->m=dev;
+ }
+ else
+ {
+ printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
+ return -EIO;
+ }
+ }
+ else
+ {
+ printk("%s: isn't slave device!\n",dev->name);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
+ error = -EINVAL;
+ }
+ return (error);
+}
+
+
+
+#ifdef CRCASM
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+
+ __asm__ (
+ "xorl %%eax,%%eax\n\t"
+ "1:\n\t"
+ "lodsb\n\t"
+ "xorb %%dl,%%al\n\t"
+ "shrl $8,%%edx\n\t"
+ "xorl (%%edi,%%eax,4),%%edx\n\t"
+ "loop 1b\n\t"
+ "movl %%edx,%%eax"
+ :
+ : "S" (mem), "D" (&crc32tab[0]), "c" (len), "d" (initial)
+ : "eax", "edx", "ecx"
+ );
+ /* return crc; */
+}
+
+#else
+
+unsigned long calc_crc(char *mem, int len, unsigned initial)
+{
+ unsigned crc;
+ crc = initial;
+
+ for(;len;mem++,len--)
+ {
+ crc = CRC32(*mem, crc);
+ }
+ return(crc);
+}
+#endif /* CRCASM */
+#ifdef MODULE
+
+static int io[SBNI_MAX_NUM_CARDS] = { 0 };
+static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
+static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
+static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
+
+#ifdef v22
+MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
+#endif
+
+
+static int sbniautodetect = -1;
+
+static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = {
+ {
+ "sbni0",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni1",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni2",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni3",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni4",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni5",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni6",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ },
+ {
+ "sbni7",
+ 0, 0, 0, 0, /* memory */
+ 0, 0, /* base, irq */
+ 0, 0, 0, NULL, sbni_probe
+ }
+};
+
+int init_module(void)
+{
+ int devices = 0;
+ int installed = 0;
+ int i;
+
+ /* My simple plug for this huge init_module. "XenON */
+
+ if(sbniautodetect != -1)
+ {
+ /* Autodetect mode */
+ printk("sbni: Autodetect mode (not recommended!) ...\n");
+ if(!sbniautodetect)
+ sbniautodetect=SBNI_MAX_NUM_CARDS;
+ printk("Trying to find %d SBNI cards...\n", sbniautodetect);
+ if(sbniautodetect > SBNI_MAX_NUM_CARDS)
+ {
+ sbniautodetect = SBNI_MAX_NUM_CARDS;
+ printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+ }
+ for(i = 0; i < sbniautodetect; i++)
+ {
+ if(!register_netdev(&dev_sbni[i]))
+ installed++;
+ }
+ if(installed)
+ return 0;
+ else
+ return -EIO;
+ }
+
+ /* Manual mode */
+ for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
+ {
+ if((io[i] != 0) || (irq[i] != 0))
+ devices++;
+ }
+ for(i = 0; i < devices; i++)
+ {
+ dev_sbni[i].irq = irq[i];
+ dev_sbni[i].base_addr = io[i];
+ def_rxl = rxl[i];
+ def_baud = baud[i];
+ def_mac = mac[i];
+ if(register_netdev(&dev_sbni[i]))
+ printk("sbni: card not found!\n");
+ else
+ installed++;
+ }
+ if(installed)
+ return 0;
+ else
+ return -EIO;
+}
+
+void cleanup_module(void)
+{
+ int i;
+ for(i = 0; i < 4; i++)
+ {
+ if(dev_sbni[i].priv)
+ {
+ free_irq(dev_sbni[i].irq, &dev_sbni[i]);
+ release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
+ unregister_netdev(&dev_sbni[i]);
+ kfree(dev_sbni[i].priv);
+ dev_sbni[i].priv = NULL;
+ }
+ }
+}
+#endif /* MODULE */
diff --git a/drivers/net/wan/sbni.h b/drivers/net/wan/sbni.h
new file mode 100644
index 000000000..2e34d8d34
--- /dev/null
+++ b/drivers/net/wan/sbni.h
@@ -0,0 +1,194 @@
+/*
+ * sbni.h - header file for sbni linux device driver
+ *
+ * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
+ *
+ */
+
+/*
+ * SBNI12 definitions
+ *
+ * Revision 2.0.0 1997/08/27
+ * Initial revision
+ *
+ * Revision 2.1.0 1999/04/26
+ * dev_priv structure changed to support balancing and some other features.
+ *
+ */
+
+#ifndef __SBNI_H
+#define __SBNI_H
+
+#define SBNI_DEBUG 0
+
+#if SBNI_DEBUG
+#define DP( A ) A
+#else
+#define DP( A )
+#endif
+
+typedef unsigned char BOOLEAN;
+
+#define TRUE 1
+#define FALSE 0
+
+#define SBNI_IO_EXTENT 0x4
+#define SB_MAX_BUFFER_ARRAY 1023
+
+#define CSR0 0
+#define CSR1 1
+
+#define DAT 2
+
+/* CSR0 mapping */
+#define BU_EMP (1 << 1) /* r z */
+#define RC_CHK (1 << 2) /* rw */
+#define CT_ZER (1 << 3) /* w */
+#define TR_REQ (1 << 4) /* rwz* */
+
+#define TR_RDY (1 << 5) /* r z */
+#define EN_INT (1 << 6) /* rwz* */
+#define RC_RDY (1 << 7) /* r z */
+
+/* CSR1 mapping */
+#define PR_RES (1 << 7) /* w */
+
+struct sbni_csr1 {
+ unsigned rxl:5;
+ unsigned rate:2;
+ unsigned:1;
+};
+
+#define DEF_RXL_DELTA -1
+#define DEF_RXL 0xf
+#define DEF_RATE 0
+#define DEF_FRAME_LEN (1023 - 14 - 9)
+
+#ifdef MODULE
+
+#define SBNI_MAX_NUM_CARDS 8
+#define SBNI_MAX_SLAVES 8
+
+
+#endif /* MODULE */
+
+#define SBNI_SIG 0x5a
+
+#define SB_ETHER_MIN_LEN 60
+
+#define SB_FILLING_CHAR (unsigned char)0x00
+#define TR_ERROR_COUNT 32
+#define CHANGE_LEVEL_START_TICKS 4
+#define SBNI_INTERNAL_QUEUE_SIZE 10 /* 100 ? */
+
+#define PACKET_FIRST_FRAME (unsigned short)0x8000
+#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
+#define PACKET_RESEND 0x4000
+#define PACKET_SEND_OK 0x3000
+#define PACKET_LEN_MASK (unsigned short)0x03ff
+#define PACKET_INF_MASK (unsigned short)0x7000
+
+#define ETHER_ADDR_LEN 6
+
+#define SBNI_TIMEOUT HZ/10 /* ticks to wait for pong or packet */
+ /* sbni watchdog called SBNI_HZ times per sec. */
+
+struct sbni_in_stats {
+ unsigned int all_rx_number;
+ unsigned int bad_rx_number;
+ unsigned int timeout_number;
+ unsigned int all_tx_number;
+ unsigned int resend_tx_number;
+};
+
+
+/*
+ * Board-specific info in dev->priv.
+ */
+struct net_local {
+ struct enet_statistics stats;
+
+ struct timer_list watchdog;
+ unsigned int realframelen; /* the current size of the SB-frame */
+ unsigned int eth_trans_buffer_len; /* tx buffer length */
+ unsigned int outpos;
+ unsigned int inppos;
+ unsigned int frame_len; /* The set SB-frame size */
+ unsigned int tr_err;
+ unsigned int timer_ticks;
+ BOOLEAN last_receive_OK;
+ BOOLEAN tr_resend;
+
+ unsigned char wait_frame_number;
+ unsigned char eth_trans_buffer[1520]; /* tx buffer */
+ unsigned char HSCounter; /* Reserved field */
+ unsigned char eth_rcv_buffer[2600]; /* rx buffer */
+ struct sbni_csr1 csr1;
+ /* Internal Statistics */
+ struct sbni_in_stats in_stats;
+
+ int rxl_curr; /* current receive level value [0..0xf] */
+ int rxl_delta; /* receive level delta (+1, -1)
+ rxl_delta == 0 - receive level
+ autodetection
+ disabled */
+ unsigned int ok_curr; /* current ok frames received */
+ unsigned int ok_prev; /* previous ok frames received */
+ unsigned int timeout_rxl;
+
+ struct sk_buff_head queue;
+ struct sk_buff *currframe;
+ BOOLEAN waitack;
+
+ struct net_device *m; /* master */
+ struct net_device *me; /* me */
+ struct net_local *next_lp; /* next lp */
+
+ int carrier;
+
+
+};
+
+
+struct sbni_hard_header {
+
+ /* internal sbni stuff */
+ unsigned int crc; /* 4 */
+ unsigned short packetlen; /* 2 */
+ unsigned char number; /* 1 */
+ unsigned char reserv; /* 1 */
+
+ /* 8 */
+
+ /* ethernet stuff */
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+ /* +14 */
+ /* 22 */
+
+};
+
+#define SBNI_HH_SZ 22
+
+struct sbni_flags {
+ unsigned rxl:4;
+ unsigned rate:2;
+ unsigned fixed_rxl:1;
+ unsigned fixed_rate:1;
+};
+
+#define RCV_NO 0
+#define RCV_OK 1
+#define RCV_WR 2
+
+
+#define SIOCDEVGETINSTATS SIOCDEVPRIVATE
+#define SIOCDEVRESINSTATS SIOCDEVPRIVATE+1
+#define SIOCDEVGHWSTATE SIOCDEVPRIVATE+2
+#define SIOCDEVSHWSTATE SIOCDEVPRIVATE+3
+#define SIOCDEVENSLAVE SIOCDEVPRIVATE+4
+#define SIOCDEVEMANSIPATE SIOCDEVPRIVATE+5
+
+
+#endif /* __SBNI_H */
diff --git a/drivers/net/sdla.c b/drivers/net/wan/sdla.c
index 9b5152366..9b5152366 100644
--- a/drivers/net/sdla.c
+++ b/drivers/net/wan/sdla.c
diff --git a/drivers/net/sdla_fr.c b/drivers/net/wan/sdla_fr.c
index 6b2201a81..6b2201a81 100644
--- a/drivers/net/sdla_fr.c
+++ b/drivers/net/wan/sdla_fr.c
diff --git a/drivers/net/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
index d35ac7c18..d35ac7c18 100644
--- a/drivers/net/sdla_ppp.c
+++ b/drivers/net/wan/sdla_ppp.c
diff --git a/drivers/net/sdla_x25.c b/drivers/net/wan/sdla_x25.c
index 270c5a59f..270c5a59f 100644
--- a/drivers/net/sdla_x25.c
+++ b/drivers/net/wan/sdla_x25.c
diff --git a/drivers/net/sdladrv.c b/drivers/net/wan/sdladrv.c
index 7182dff42..5e1f6b99e 100644
--- a/drivers/net/sdladrv.c
+++ b/drivers/net/wan/sdladrv.c
@@ -5,6 +5,7 @@
* used by all Sangoma drivers.
*
* Author: Gene Kozin <genek@compuserve.com>
+* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* Copyright: (c) 1995-1996 Sangoma Technologies Inc.
*
diff --git a/drivers/net/sdlamain.c b/drivers/net/wan/sdlamain.c
index ca98eeff9..23b811fc9 100644
--- a/drivers/net/sdlamain.c
+++ b/drivers/net/wan/sdlamain.c
@@ -3,6 +3,7 @@
*
* Author: Gene Kozin <genek@compuserve.com>
* Jaspreet Singh <jaspreet@sangoma.com>
+* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* Copyright: (c) 1995-1997 Sangoma Technologies Inc.
*
diff --git a/drivers/net/sealevel.c b/drivers/net/wan/sealevel.c
index 1dc146711..5cbbff8c9 100644
--- a/drivers/net/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -340,7 +340,7 @@ static struct slvl_board *slvl_init(int iobase, int irq, int txdma, int rxdma, i
for(i=0;i<999;i++)
{
sprintf(sv->name,"hdlc%d", i);
- if(dev_get(sv->name)==NULL)
+ if(dev_get(sv->name)==0)
{
struct net_device *d=sv->chan->netdevice;
diff --git a/drivers/net/syncppp.c b/drivers/net/wan/syncppp.c
index eee3fceb8..eee3fceb8 100644
--- a/drivers/net/syncppp.c
+++ b/drivers/net/wan/syncppp.c
diff --git a/drivers/net/syncppp.h b/drivers/net/wan/syncppp.h
index c03c720ca..c03c720ca 100644
--- a/drivers/net/syncppp.h
+++ b/drivers/net/wan/syncppp.h
diff --git a/drivers/net/x25_asy.c b/drivers/net/wan/x25_asy.c
index 49d041abc..49d041abc 100644
--- a/drivers/net/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
diff --git a/drivers/net/x25_asy.h b/drivers/net/wan/x25_asy.h
index 5abeceb20..5abeceb20 100644
--- a/drivers/net/x25_asy.h
+++ b/drivers/net/wan/x25_asy.h
diff --git a/drivers/net/z85230.c b/drivers/net/wan/z85230.c
index a802170ce..a802170ce 100644
--- a/drivers/net/z85230.c
+++ b/drivers/net/wan/z85230.c
diff --git a/drivers/net/z85230.h b/drivers/net/wan/z85230.h
index 0b4b48748..0b4b48748 100644
--- a/drivers/net/z85230.h
+++ b/drivers/net/wan/z85230.h
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 5a29ff459..8acf46f58 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -151,8 +151,6 @@ static void parport_ieee1284_terminate (struct parport *port)
{
port = port->physport;
- port->ieee1284.phase = IEEE1284_PH_TERMINATE;
-
/* EPP terminates differently. */
switch (port->ieee1284.mode) {
case IEEE1284_MODE_EPP:
@@ -161,17 +159,42 @@ static void parport_ieee1284_terminate (struct parport *port)
/* Terminate from EPP mode. */
/* Event 68: Set nInit low */
- parport_frob_control (port,
- PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
udelay (50);
/* Event 69: Set nInit high, nSelectIn low */
parport_frob_control (port,
- PARPORT_CONTROL_SELECT,
- PARPORT_CONTROL_SELECT);
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
break;
-
+
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ case IEEE1284_MODE_ECPSWE:
+ /* In ECP we can only terminate from fwd idle phase. */
+ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+ /* Event 47: Set nInit high */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_INIT
+ | PARPORT_CONTROL_AUTOFD);
+
+ /* Event 49: PError goes high */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+
+ parport_data_forward (port);
+ DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+ port->name);
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ }
+
+ /* fall-though.. */
+
default:
/* Terminate from all other modes. */
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
index 41780752c..4d460a58d 100644
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -9,8 +9,10 @@
* Note: Make no assumptions about hardware or architecture in this file!
*
* Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Fixed AUTOFD polarity in ecp_forward_to_reverse(). Fred Barnes, 1999
*/
+
#include <linux/config.h>
#include <linux/parport.h>
#include <linux/delay.h>
@@ -336,7 +338,7 @@ int ecp_forward_to_reverse (struct parport *port)
/* Event 38: Set nAutoFd low */
parport_frob_control (port,
PARPORT_CONTROL_AUTOFD,
- 0);
+ PARPORT_CONTROL_AUTOFD);
parport_data_reverse (port);
udelay (5);
@@ -524,12 +526,12 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port,
if (count && dev->port->irq != PARPORT_IRQ_NONE) {
parport_release (dev);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout ((HZ + 99) / 25);
+ schedule_timeout ((HZ + 24) / 25);
parport_claim_or_block (dev);
}
else
/* We must have the device claimed here. */
- parport_wait_event (port, (HZ + 99) / 25);
+ parport_wait_event (port, (HZ + 24) / 25);
/* Is there a signal pending? */
if (signal_pending (current))
@@ -610,10 +612,11 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port,
count += rle_count;
DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
port->name, rle_count);
- }
- else
+ } else {
/* Normal data byte. */
- *buf++ = byte, count++;
+ *buf = byte;
+ buf++, count++;
+ }
}
out:
diff --git a/drivers/parport/init.c b/drivers/parport/init.c
index 7874519c7..432fede95 100644
--- a/drivers/parport/init.c
+++ b/drivers/parport/init.c
@@ -91,6 +91,8 @@ static int __init parport_setup (char *str)
if (sep++) {
if (!strncmp (sep, "auto", 4))
dma[parport_setup_ptr] = PARPORT_DMA_AUTO;
+ else if (!strncmp (sep, "nofifo", 6))
+ dma[parport_setup_ptr] = PARPORT_DMA_NOFIFO;
else if (strncmp (sep, "none", 4)) {
val = simple_strtoul (sep, &endptr, 0);
if (endptr == sep) {
@@ -209,6 +211,8 @@ EXPORT_SYMBOL(parport_device_coords);
EXPORT_SYMBOL(parport_daisy_deselect_all);
EXPORT_SYMBOL(parport_daisy_select);
EXPORT_SYMBOL(parport_daisy_init);
+EXPORT_SYMBOL(parport_find_device);
+EXPORT_SYMBOL(parport_find_class);
#endif
void inc_parport_count(void)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 3b5d18127..a451d85b0 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -10,6 +10,7 @@
*
* Cleaned up include files - Russell King <linux@arm.uk.linux.org>
* DMA support - Bert De Jonghe <bert@sophis.be>
+ * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999
*/
/* This driver should work with any hardware that is broadly compatible
@@ -73,7 +74,12 @@
static void frob_econtrol (struct parport *pb, unsigned char m,
unsigned char v)
{
- outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+ unsigned char ectr = inb (ECONTROL (pb));
+#ifdef DEBUG_PARPORT
+ printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+ m, v, ectr, (ectr & ~m) ^ v);
+#endif
+ outb ((ectr & ~m) ^ v, ECONTROL (pb));
}
#ifdef CONFIG_PARPORT_PC_FIFO
@@ -94,11 +100,8 @@ static int change_mode(struct parport *p, int m)
oecr = inb (ecr);
mode = (oecr >> 5) & 0x7;
if (mode == m) return 0;
- if (mode && m)
- /* We have to go through mode 000 */
- change_mode (p, ECR_SPP);
- if (m < 2 && !(parport_read_control (p) & 0x20)) {
+ if (mode >= 2 && !(priv->ctr & 0x20)) {
/* This mode resets the FIFO, so we may
* have to wait for it to drain first. */
long expire = jiffies + p->physport->cad->timeout;
@@ -127,6 +130,13 @@ static int change_mode(struct parport *p, int m)
}
}
+ if (mode >= 2 && m >= 2) {
+ /* We have to go through mode 001 */
+ oecr &= ~(7 << 5);
+ oecr |= ECR_PS2 << 5;
+ outb (oecr, ecr);
+ }
+
/* Set the mode. */
oecr &= ~(7 << 5);
oecr |= m << 5;
@@ -160,11 +170,11 @@ static int get_fifo_residue (struct parport *p)
residue);
/* Reset the FIFO. */
- frob_econtrol (p, 0xe0, 0x20);
+ frob_econtrol (p, 0xe0, ECR_PS2 << 5);
parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
/* Now change to config mode and clean up. FIXME */
- frob_econtrol (p, 0xe0, 0xe0);
+ frob_econtrol (p, 0xe0, ECR_CNF << 5);
cnfga = inb (CONFIGA (p));
printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
@@ -177,7 +187,7 @@ static int get_fifo_residue (struct parport *p)
* PWord != 1 byte. */
/* Back to PS2 mode. */
- frob_econtrol (p, 0xe0, 0x20);
+ frob_econtrol (p, 0xe0, ECR_PS2 << 5);
return residue;
}
@@ -209,9 +219,9 @@ static int clear_epp_timeout(struct parport *pb)
/*
* Access functions.
*
- * These aren't static because they may be used by the parport_xxx_yyy
- * macros. extern __inline__ versions of several of these are in
- * parport_pc.h.
+ * Most of these aren't static because they may be used by the
+ * parport_xxx_yyy macros. extern __inline__ versions of several
+ * of these are in parport_pc.h.
*/
static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -229,21 +239,6 @@ unsigned char parport_pc_read_data(struct parport *p)
return inb (DATA (p));
}
-unsigned char __frob_control (struct parport *p, unsigned char mask,
- unsigned char val)
-{
- const unsigned char wm = (PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_INIT |
- PARPORT_CONTROL_SELECT);
- struct parport_pc_private *priv = p->physport->private_data;
- unsigned char ctr = priv->ctr;
- ctr = (ctr & ~mask) ^ val;
- ctr &= priv->ctr_writable; /* only write writable bits. */
- outb (ctr, CONTROL (p));
- return priv->ctr = ctr & wm; /* update soft copy */
-}
-
void parport_pc_write_control(struct parport *p, unsigned char d)
{
const unsigned char wm = (PARPORT_CONTROL_STROBE |
@@ -253,18 +248,22 @@ void parport_pc_write_control(struct parport *p, unsigned char d)
/* Take this out when drivers have adapted to the newer interface. */
if (d & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
- parport_pc_data_reverse (p);
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
}
- __frob_control (p, wm, d & wm);
+ __parport_pc_frob_control (p, wm, d & wm);
}
unsigned char parport_pc_read_control(struct parport *p)
{
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
const struct parport_pc_private *priv = p->physport->private_data;
- return priv->ctr; /* Use soft copy */
+ return priv->ctr & wm; /* Use soft copy */
}
unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
@@ -277,16 +276,20 @@ unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
/* Take this out when drivers have adapted to the newer interface. */
if (mask & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
+ printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+ p->name, p->cad->name,
+ (val & 0x20) ? "reverse" : "forward");
+ if (val & 0x20)
parport_pc_data_reverse (p);
+ else
+ parport_pc_data_forward (p);
}
/* Restrict mask and val to control lines. */
mask &= wm;
val &= wm;
- return __frob_control (p, mask, val);
+ return __parport_pc_frob_control (p, mask, val);
}
unsigned char parport_pc_read_status(struct parport *p)
@@ -296,22 +299,22 @@ unsigned char parport_pc_read_status(struct parport *p)
void parport_pc_disable_irq(struct parport *p)
{
- __frob_control (p, 0x10, 0);
+ __parport_pc_frob_control (p, 0x10, 0);
}
void parport_pc_enable_irq(struct parport *p)
{
- __frob_control (p, 0x10, 0x10);
+ __parport_pc_frob_control (p, 0x10, 0x10);
}
void parport_pc_data_forward (struct parport *p)
{
- __frob_control (p, 0x20, 0);
+ __parport_pc_frob_control (p, 0x20, 0);
}
void parport_pc_data_reverse (struct parport *p)
{
- __frob_control (p, 0x20, 0x20);
+ __parport_pc_frob_control (p, 0x20, 0x20);
}
void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
@@ -469,7 +472,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
/* Forward mode. */
- parport_pc_data_forward (port);
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
while (left) {
unsigned char byte;
@@ -559,7 +562,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
/* Forward mode. */
- parport_pc_data_forward (port);
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
while (left) {
long expire = jiffies + port->physport->cad->timeout;
@@ -656,8 +659,8 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
length, flags);
/* Set up parallel port FIFO mode.*/
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
change_mode (port, ECR_PPF); /* Parallel port FIFO */
- parport_pc_data_forward (port);
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -687,8 +690,8 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
outb (0, FIFO (port));
}
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
+ /* Reset the FIFO and return to PS2 mode. */
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
/* De-assert strobe. */
parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
@@ -727,8 +730,8 @@ 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 */
change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_forward (port);
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -758,17 +761,20 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
outb (0, FIFO (port));
}
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
+ /* Reset the FIFO and return to PS2 mode. */
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ /* De-assert strobe. */
parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
/* Host transfer recovery. */
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
+ udelay (5);
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
parport_frob_control (port,
PARPORT_CONTROL_INIT,
PARPORT_CONTROL_INIT);
- parport_pc_data_reverse (port);
- parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
- parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
parport_wait_peripheral (port,
PARPORT_STATUS_PAPEROUT,
PARPORT_STATUS_PAPEROUT);
@@ -819,21 +825,21 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
parport_frob_control (port,
PARPORT_CONTROL_AUTOFD,
PARPORT_CONTROL_AUTOFD);
- parport_pc_data_reverse (port);
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
udelay (5);
/* Event 39: Set nInit low to initiate bus reversal */
parport_frob_control (port,
PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
+ 0);
/* Event 40: PError goes low */
parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
}
/* Set up ECP parallel port mode.*/
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_reverse (port);
port->ieee1284.phase = IEEE1284_PH_REV_DATA;
/* Do the transfer. */
@@ -1054,7 +1060,6 @@ static int __maybe_init parport_ECR_present(struct parport *pb)
struct parport_pc_private *priv = pb->private_data;
unsigned char r = 0xc;
- priv->ecr = 0;
outb (r, CONTROL (pb));
if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
@@ -1120,9 +1125,9 @@ static int __maybe_init parport_PS2_supported(struct parport *pb)
/* cancel input mode */
parport_pc_data_forward (pb);
- if (ok)
+ if (ok) {
pb->modes |= PARPORT_MODE_TRISTATE;
- else {
+ } else {
struct parport_pc_private *priv = pb->private_data;
priv->ctr_writable &= ~0x20;
}
@@ -1180,8 +1185,8 @@ static int __maybe_init parport_ECP_supported(struct parport *pb)
priv->writeIntrThreshold = i;
/* Find out readIntrThreshold */
- frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
- parport_pc_data_reverse (pb);
+ frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */
+ parport_pc_data_reverse (pb); /* Must be in PS2 mode */
frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
frob_econtrol (pb, 1<<2, 1<<2);
frob_econtrol (pb, 1<<2, 0);
@@ -1544,12 +1549,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
if (base_hi && !check_region(base_hi,3)) {
parport_ECR_present(p);
parport_ECP_supported(p);
- parport_ECPPS2_supported(p);
}
if (base != 0x3bc) {
if (!check_region(base+0x3, 5)) {
- parport_EPP_supported(p);
- if (!(p->modes & PARPORT_MODE_EPP))
+ if (!parport_EPP_supported(p))
parport_ECPEPP_supported(p);
}
}
@@ -1558,8 +1561,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
kfree (priv);
return NULL;
}
-
- parport_PS2_supported (p);
+ if (priv->ecr)
+ parport_ECPPS2_supported(p);
+ else
+ parport_PS2_supported (p);
if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
PARPORT_DMA_NONE, ops))) {
@@ -1599,7 +1604,8 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
p->dma = PARPORT_DMA_NONE;
#ifdef CONFIG_PARPORT_PC_FIFO
- if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+ if (p->dma != PARPORT_DMA_NOFIFO &&
+ priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
p->ops->compat_write_data = parport_pc_compat_write_block_pio;
#ifdef CONFIG_PARPORT_1284
p->ops->ecp_write_data = parport_pc_ecp_write_block_pio;
@@ -1672,9 +1678,10 @@ struct parport *__maybe_init parport_pc_probe_port (unsigned long int base,
/* Done probing. Now put the port into a sensible start-up state.
* SELECT | INIT also puts IEEE1284-compliant devices into
* compatibility mode. */
- if (p->modes & PARPORT_MODE_ECP)
+ if (priv->ecr)
/*
* Put the ECP detected port in PS2 mode.
+ * Do this also for ports that have ECR but don't do ECP.
*/
outb (0x34, ECONTROL (p));
@@ -1751,6 +1758,8 @@ static int __init parport_pc_init_pci (int irq, int dma)
{ { 0, -1 }, } },
{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
{ { 0, -1 }, } },
+ { PCI_VENDOR_ID_EXSYS, PCI_DEVICE_ID_EXSYS_4014, 2,
+ { { 2, -1 }, { 3, -1 }, } },
{ 0, }
};
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 94b9f035b..7c127fd18 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -633,7 +633,7 @@ void parport_release(struct pardevice *dev)
}
static int parport_parse_params (int nports, const char *str[], int val[],
- int automatic, int none)
+ int automatic, int none, int nofifo)
{
unsigned int i;
for (i = 0; i < nports && str[i]; i++) {
@@ -641,6 +641,8 @@ static int parport_parse_params (int nports, const char *str[], int val[],
val[i] = automatic;
else if (!strncmp(str[i], "none", 4))
val[i] = none;
+ else if (nofifo && !strncmp(str[i], "nofifo", 4))
+ val[i] = nofifo;
else {
char *ep;
unsigned long r = simple_strtoul(str[i], &ep, 0);
@@ -659,11 +661,11 @@ static int parport_parse_params (int nports, const char *str[], int val[],
int parport_parse_irqs(int nports, const char *irqstr[], int irqval[])
{
return parport_parse_params (nports, irqstr, irqval, PARPORT_IRQ_AUTO,
- PARPORT_IRQ_NONE);
+ PARPORT_IRQ_NONE, 0);
}
int parport_parse_dmas(int nports, const char *dmastr[], int dmaval[])
{
return parport_parse_params (nports, dmastr, dmaval, PARPORT_DMA_AUTO,
- PARPORT_DMA_NONE);
+ PARPORT_DMA_NONE, PARPORT_DMA_NOFIFO);
}
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 45197e4c3..0503f4af1 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -25,6 +25,10 @@ ifdef CONFIG_PROC_FS
L_OBJS += proc.o
endif
-L_OBJS += compat.o quirks.o names.o syscall.o setup.o
+L_OBJS += compat.o quirks.o names.o helper.o
+
+ifndef CONFIG_X86
+L_OBJS += syscall.o setup.o
+endif
include $(TOPDIR)/Rules.make
diff --git a/drivers/pci/devlist.h b/drivers/pci/devlist.h
index f0a86af6d..3b4cce5ce 100644
--- a/drivers/pci/devlist.h
+++ b/drivers/pci/devlist.h
@@ -989,6 +989,10 @@ VENDOR( ATRONICS, "Atronics" )
DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL")
ENDVENDOR()
+VENDOR( EXSYS, "Exsys" )
+ DEVICE( EXSYS, EXSYS_4014, "EX-4014")
+ENDVENDOR()
+
VENDOR( TIGERJET, "TigerJet" )
DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN")
ENDVENDOR()
diff --git a/drivers/pci/helper.c b/drivers/pci/helper.c
new file mode 100644
index 000000000..928cec4b5
--- /dev/null
+++ b/drivers/pci/helper.c
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * drivers/pci/helper.c
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ * This software is free. See the file COPYING for licensing details.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+
+int pci_simple_probe (struct pci_simple_probe_entry *list, size_t match_limit,
+ pci_simple_probe_callback cb, void *drvr_data)
+{
+ struct pci_dev *dev;
+ struct pci_simple_probe_entry *ent;
+ size_t matches = 0;
+ unsigned short vendor, device;
+ int rc;
+
+ if (!list || !cb)
+ return -1;
+
+ dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, NULL);
+ while (dev) {
+ ent = list;
+ while (ent->vendor && ent->device) {
+ vendor = ent->vendor;
+ device = ent->device;
+
+ if (((vendor != 0xFFFF) &&
+ (vendor != dev->vendor)) ||
+ ((device != 0xFFFF) &&
+ (device != dev->device))) {
+ ent++;
+ continue;
+ }
+
+ if (((ent->subsys_vendor) &&
+ (ent->subsys_vendor != dev->subsystem_vendor)) ||
+ ((ent->subsys_device) &&
+ (ent->subsys_device != dev->subsystem_device))) {
+ ent++;
+ continue;
+ }
+
+ rc = (* cb) (dev, matches, ent, drvr_data);
+ if (rc < 0)
+ return rc;
+
+ matches++;
+
+ if (match_limit && match_limit == matches)
+ return matches;
+
+ ent++;
+ }
+
+ dev = pci_find_device (PCI_ANY_ID, PCI_ANY_ID, dev);
+ }
+
+ return matches;
+}
+
+
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 51c229c25..5cf991521 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -17,7 +17,6 @@
#include <linux/malloc.h>
#include <linux/ioport.h>
-#include <asm/pci.h>
#include <asm/page.h>
#undef DEBUG
@@ -125,26 +124,20 @@ pci_find_parent_resource(struct pci_dev *dev, struct resource *res)
int i;
struct resource *best = NULL;
- while (bus) {
- for(i=0; i<4; i++) {
- struct resource *r = bus->resource[i];
- if (!r)
- continue;
- if (res->start && !(res->start >= r->start && res->end <= r->end))
- continue; /* Not contained */
- if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
- continue; /* Wrong type */
- if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
- return r; /* Exact match */
- if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
- best = r; /* Approximating prefetchable by non-prefetchable */
- }
- if (best)
- return best;
- bus = bus->parent;
+ for(i=0; i<4; i++) {
+ struct resource *r = bus->resource[i];
+ if (!r)
+ continue;
+ if (res->start && !(res->start >= r->start && res->end <= r->end))
+ continue; /* Not contained */
+ if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+ continue; /* Wrong type */
+ if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
+ return r; /* Exact match */
+ if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
+ best = r; /* Approximating prefetchable by non-prefetchable */
}
- printk(KERN_ERR "PCI: Bug: Parent resource not found!\n");
- return NULL;
+ return best;
}
@@ -193,47 +186,18 @@ pci_set_master(struct pci_dev *dev)
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (! (cmd & PCI_COMMAND_MASTER)) {
- printk("PCI: Enabling bus mastering for device %s\n", dev->name);
+ printk("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat < 16) {
- printk("PCI: Increasing latency timer of device %s to 64\n", dev->name);
+ printk("PCI: Increasing latency timer of device %s to 64\n", dev->slot_name);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
}
}
/*
- * Assign new address to PCI resource. We hope our resource information
- * is complete. On the PC, we don't re-assign resources unless we are
- * forced to do so or the driver asks us to.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-int __init pci_assign_resource(struct pci_dev *dev, int i)
-{
- struct resource *r = &dev->resource[i];
- struct resource *pr = pci_find_parent_resource(dev, r);
- unsigned long size = r->end + 1;
-
- if (!pr)
- return -EINVAL;
- if (r->flags & IORESOURCE_IO) {
- if (size > 0x100)
- return -EFBIG;
- if (allocate_resource(pr, r, size, 0x1000, ~0, 1024))
- return -EBUSY;
- } else {
- if (allocate_resource(pr, r, size, 0x10000000, ~0, size))
- return -EBUSY;
- }
- if (i < 6)
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start);
- return 0;
-}
-
-/*
* Translate the low bits of the PCI base
* to the resource type
*/
@@ -296,7 +260,7 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
res->end = res->start + (((unsigned long) ~l) << 32);
#else
if (l) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->name);
+ printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
res->start = 0;
res->flags = 0;
continue;
@@ -305,6 +269,7 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
}
if (rom) {
+ dev->rom_base_reg = rom;
res = &dev->resource[PCI_ROM_RESOURCE];
pci_read_config_dword(dev, rom, &l);
pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
@@ -324,8 +289,9 @@ void __init pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
-void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+void __init pci_read_bridge_bases(struct pci_bus *child)
{
+ struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
u32 mem_base_hi, mem_limit_hi;
@@ -333,6 +299,9 @@ void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
struct resource *res;
int i;
+ if (!dev) /* It's a host bus, nothing to read */
+ return;
+
for(i=0; i<3; i++)
child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
@@ -425,31 +394,27 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
dev_cache = NULL;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
- sprintf(dev->name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ sprintf(dev->slot_name, "%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
pci_name_device(dev);
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
class >>= 8; /* upper 3 bytes */
dev->class = class;
class >>= 8;
- dev->hdr_type = hdr_type;
+ dev->hdr_type = hdr_type & 0x7f;
- switch (hdr_type & 0x7f) { /* header type */
+ switch (dev->hdr_type) { /* header type */
case PCI_HEADER_TYPE_NORMAL: /* standard header */
if (class == PCI_CLASS_BRIDGE_PCI)
goto bad;
/*
- * If the card generates interrupts, read IRQ number
- * (some architectures change it during pcibios_fixup())
+ * Read interrupt line and base address registers.
+ * The architecture-dependent code can tweak these, of course.
*/
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
if (irq)
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
dev->irq = irq;
- /*
- * read base address registers, again pcibios_fixup() can
- * tweak these
- */
pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
@@ -468,8 +433,8 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus)
break;
default: /* unknown header */
bad:
- printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
- bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+ printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+ dev->slot_name, hdr_type);
continue;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ec8fcb7a8..d25a0ed29 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -31,7 +31,7 @@ static void __init quirk_passive_release(struct pci_dev *dev)
while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
pci_read_config_byte(d, 0x82, &dlc);
if (!(dlc & 1<<1)) {
- printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->name);
+ printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name);
dlc |= 1<<1;
pci_write_config_byte(d, 0x82, dlc);
}
@@ -99,7 +99,7 @@ static void pci_do_fixups(struct pci_dev *dev, int pass, struct pci_fixup *f)
(f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
(f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
#ifdef DEBUG
- printk("PCI: Calling quirk %p for %s\n", f->hook, dev->name);
+ printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name);
#endif
f->hook(dev);
}
diff --git a/drivers/pci/setup.c b/drivers/pci/setup.c
index 53bf9f582..9c752d0de 100644
--- a/drivers/pci/setup.c
+++ b/drivers/pci/setup.c
@@ -16,7 +16,6 @@
#include <linux/ioport.h>
#include <asm/cache.h>
-#include <asm/pci.h>
#define DEBUG_CONFIG 0
@@ -108,9 +107,12 @@ pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem)
(ie. do not respond to memory space writes) when it is left
enabled. A good example are QlogicISP adapters. */
- pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
- reg &= ~PCI_ROM_ADDRESS_ENABLE;
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
+ if (dev->rom_base_reg) {
+ pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+ reg &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, dev->rom_base_reg, reg);
+ dev->resource[PCI_ROM_RESOURCE].flags &= ~PCI_ROM_ADDRESS_ENABLE;
+ }
/* All of these (may) have I/O scattered all around and may not
use I/O base address registers at all. So we just have to
diff --git a/drivers/pnp/Config.in b/drivers/pnp/Config.in
index a350c4526..de0fa6cfa 100644
--- a/drivers/pnp/Config.in
+++ b/drivers/pnp/Config.in
@@ -6,6 +6,6 @@ comment 'Plug and Play configuration'
tristate 'Plug and Play support' CONFIG_PNP
-dep_tristate 'ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
+dep_tristate ' ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
endmenu
diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c
index dc34fe4cd..3857c487d 100644
--- a/drivers/sbus/char/pcikbd.c
+++ b/drivers/sbus/char/pcikbd.c
@@ -764,7 +764,7 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
queue->head = head;
aux_ready = 1;
if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO);
+ kill_fasync(queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index e8e6a168c..2b3a99604 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -1273,7 +1273,7 @@ push_kbd (int scan)
kbd_head = next;
}
if (kb_fasync)
- kill_fasync (kb_fasync, SIGIO);
+ kill_fasync (kb_fasync, SIGIO, POLL_IN);
wake_up_interruptible (&kbd_wait);
}
diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c
index 77fe2ee77..c3d8462e6 100644
--- a/drivers/sbus/char/sunmouse.c
+++ b/drivers/sbus/char/sunmouse.c
@@ -137,7 +137,7 @@ push_char (char c)
}
sunmouse.ready = 1;
if (sunmouse.fasync)
- kill_fasync (sunmouse.fasync, SIGIO);
+ kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
wake_up_interruptible (&sunmouse.proc_list);
}
@@ -334,7 +334,7 @@ sun_mouse_inbyte(unsigned char byte)
*/
sunmouse.ready = 1;
if (sunmouse.fasync)
- kill_fasync (sunmouse.fasync, SIGIO);
+ kill_fasync (sunmouse.fasync, SIGIO, POLL_IN);
wake_up_interruptible(&sunmouse.proc_list);
}
return;
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index b11de29eb..ccf2268d8 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -92,7 +92,7 @@ static struct miscdevice uctrl_dev = {
#ifdef MODULE
int init_module(void)
#else
-__initfunc(int uctrl_init(void))
+int __init uctrl_init(void)
#endif
{
struct uctrl_driver *driver = &drv;
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index d5fbbd59a..d543e5199 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,33 @@
+Sat Sep 11 18:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * revision 3.2c
+ - Handle correctly (hopefully) jiffies wrap-around.
+ - Restore the entry used to detect 875 until revision 0xff.
+ (I removed it inadvertently, it seems :) )
+ - Replace __initfunc() which is deprecated stuff by __init which
+ is not yet so. ;-)
+ - Add support of some 'resource handling' for linux-2.3.13.
+ Basically the BARs have been changed to something more complex
+ in the pci_dev structure.
+ - Remove some deprecated code.
+
+Sat May 10 11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * revision pre-3.2b-1
+ - Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
+ The 53C895A contains all of the features of the 896 but has only
+ one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing
+ using dual cycle PCI data transfers.
+ - Miscellaneous minor fixes.
+ - Some additions to the README.ncr53c8xx file.
+
+Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * revision 3.2a
+ - Add 'hostid:#id' boot option. This option allows to change the
+ default SCSI id the driver uses for controllers.
+ - Remove nvram layouts and driver set-up structures from the C source,
+ and use the one defined in sym53c8xx_defs.h file.
+ (shared by both drivers).
+ - Set for now MAX LUNS to 16 (instead of 8).
+
Thu Mar 11 23:00 1999 Gerard Roudier (groudier@club-internet.fr)
* revision 3.2 (8xx-896 driver bundle)
- Only define the host template in ncr53c8xx.h and include the
diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx
index 98656d359..260c6b5aa 100644
--- a/drivers/scsi/ChangeLog.sym53c8xx
+++ b/drivers/scsi/ChangeLog.sym53c8xx
@@ -1,3 +1,132 @@
+Sat Sep 11 11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5e
+ - New linux-2.3.13 __setup scheme support added.
+ - Cleanup of the extended error status handling:
+ Use 1 bit per error type.
+ - Also save the extended error status prior to auto-sense.
+ - Add the FE_DIFF chip feature bit to indicate support of
+ diff probing from GPIO3 (825/825A/876/875).
+ - Remove the quirk handling that has been useless since day one.
+ - Work-around PCI chips being reported twice on some platforms.
+ - Add some redundant PCI reads in order to deal with common
+ bridge misbehaviour regarding posted write flushing.
+ - Add some other conditionnal code for people who have to deal
+ with really broken bridges (they will have to edit a source
+ file to try these options).
+ - Handle correctly (hopefully) jiffies wrap-around.
+ - Restore the entry used to detect 875 until revision 0xff.
+ (I removed it inadvertently, it seems :) )
+ - Replace __initfunc() which is deprecated stuff by __init which
+ is not yet so. ;-)
+ - Rewrite the MESSAGE IN scripts more generic by using a MOVE
+ table indirect. Extended messages of any size are accepted now.
+ (Size is limited to 8 for now, but a constant is just to be
+ increased if necessary)
+ - Fix some bug in the fully untested MDP handling:) and share
+ some code between MDP handling and residual calculation.
+ - Calculate the data transfer residual as the 2's complement
+ integer (A positive value in returned on data overrun, and
+ a negative one on underrun).
+ - Add support of some 'resource handling' for linux-2.3.13.
+ Basically the BARs have been changed to something more complex
+ in the pci_dev structure.
+ - Remove some deprecated code.
+
+Sat Jun 5 11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5c
+ - Donnot negotiate on auto-sense if we are currently using 8 bit
+ async transfer for the target.
+ - Only check for SISL/RAID on i386 platforms.
+ (A problem has been reported on PPC with that code).
+ - On MSG REJECT for a negotiation, the driver attempted to restart
+ the SCRIPT processor when this one was already running.
+
+Sat May 29 12:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5b
+ - Force negotiation prior auto-sense.
+ This ensures that the driver will be able to grab the sense data
+ from a device that has received a BUS DEVICE RESET message from
+ another initiator.
+ - Complete all disconnected CCBs for a logical UNIT if we are told
+ about a UNIT ATTENTION for a RESET condition by this target.
+ - Add the control command 'cleardev' that allows to send a ABORT
+ message to a logical UNIT (for test purpose).
+
+Tue May 25 23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5a
+ - Add support for task abort and bus device reset SCSI message
+ and implement proper synchonisation with SCRIPTS to handle
+ correctly task abortion without races.
+ - Send an ABORT message (if untagged) or ABORT TAG message (if tagged)
+ when the driver is told to abort a command that is disconnected and
+ complete the command with appropriate error.
+ If the aborted command is not yet started, remove it from the start
+ queue and complete it with error.
+ - Add the control command 'resetdev' that allows to send a BUS
+ DEVICE RESET message to a target (for test purpose).
+ - Clean-up some unused or useless code.
+
+Fri May 21 23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.5
+ - Add support for CHMOV with Wide controllers.
+ - Handling of the SWIDE (low byte residue at the end of a CHMOV
+ in DATA IN phase with WIDE transfer when the byte count gets odd).
+ - Handling of the IGNORE WIDE RESIDUE message.
+ Handled from SCRIPTS as possible with some optimizations when both
+ a wide device and the controller are odd at the same time (SWIDE
+ present and IGNORE WIDE RESIDUE message on the BUS at the same time).
+ - Check against data OVERRUN/UNDERRUN condition at the end of a data
+ transfer, whatever a SWIDE is present (OVERRUN in DATA IN phase)
+ or the SODL is full (UNDERRUN in DATA out phase).
+ - Handling of the MODIFY DATA POINTER message.
+ This one cannot be handled from SCRIPTS, but hopefully it will not
+ happen very often. :)
+ - Large rewrite of the SCSI MESSAGE handling.
+
+Sun May 9 11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.4
+ - Support for IMMEDIATE ARBITRATION.
+ See the README file for detailed information about this feature.
+ Requires both a compile option and a boot option.
+ - Minor SCRIPTS optimization in reselection pattern for LUN 0.
+ - Simpler algorithm to deal with SCSI command starvation.
+ Just use 2 tag counters in flip/flop and switch to the other
+ one every 3 seconds.
+ - Do some work in SCRIPTS after the SELECT instruction and prior
+ to testing for a PHASE. SYMBIOS say this feature is working fine.
+ (Btw, only problems with Toshiba 3401B had been reported).
+ - Measure the PCI clock speed and donnot attach controllers if
+ result is greater than 37 MHz. Since the precision of the
+ algorithm (from Stefan Esser) is better than 2%, this should
+ be fine.
+ - Fix the misdetection of SYM53C875E (was detected as a 876).
+ - Fix the misdetection of SYM53C810 not A (was detected as a 810A).
+ - Support for up to 256 TAGS per LUN (CMD_PER_LUN).
+ Currently limited to 255 due to Linux limitation. :)
+ - Support for up to 508 active commands (CAN_QUEUE).
+ - Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
+ The 53C895A contains all of the features of the 896 but has only
+ one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing
+ using dual cycle PCI data transfers.
+ - Miscellaneous minor fixes.
+ - Some additions to the README.ncr53c8xx file.
+
+Tue Apr 15 10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.3e
+ - Support for any number of LUNs (64) (SPI2-compliant).
+ (Btw, this may only be ever usefull under linux-2.2 ;-))
+
+Sun Apr 11 10:00 1999 Gerard Roudier (groudier@club-internet.fr)
+ * version sym53c8xx-1.3d
+ - Add 'hostid:#id' boot option. This option allows to change the
+ default SCSI id the driver uses for controllers.
+ - Make SCRIPTS not use self-mastering for PCI.
+ There were still 2 places the driver used this feature of the
+ 53C8XX family.
+ - Move some data structures (nvram layouts and driver set-up) to
+ the sym53c8xx_defs.h file. So, the both drivers will share them.
+ - Set MAX LUNS to 16 (instead of 8).
+
Sat Mar 20 21:00 1999 Gerard Roudier (groudier@club-internet.fr)
* version sym53c8xx-1.3b
- Add support for NCR PQS PDS.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index abb2af5ee..15ba33c8f 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -129,6 +129,14 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_SIM710),y)
+L_OBJS += sim710.o
+else
+ ifeq ($(CONFIG_SCSI_SIM710),m)
+ M_OBJS += sim710.o
+ endif
+endif
+
ifeq ($(CONFIG_A4000T_SCSI),y)
L_OBJS += amiga7xx.o 53c7xx.o
else
@@ -685,6 +693,17 @@ include $(TOPDIR)/Rules.make
53c7xx.o : 53c7xx_d.h
+sim710_d.h: sim710.scr script_asm.pl
+ ln -sf sim710.scr fake7.c
+ $(CPP) -traditional -DCHIP=710 fake7.c | grep -v '^#' | perl -s script_asm.pl -ncr7x0_family
+ mv script.h sim710_d.h
+ mv scriptu.h sim710_u.h
+ rm fake7.c
+
+sim710_u.h: sim710_d.h
+
+sim710.o : sim710_d.h
+
initio.o: ini9100u.c i91uscsi.c
$(CC) $(CFLAGS) -c ini9100u.c -o ini9100u.o
$(CC) $(CFLAGS) -c i91uscsi.c -o i91uscsi.o
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index 0497bbb10..100f9ff95 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -20,11 +20,13 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
AHA-2920C
AHA-2930
AHA-2930U
+ AHA-2930CU
AHA-2930U2
AHA-2940
AHA-2940W
AHA-2940U
AHA-2940UW
+ AHA-2940UW-PRO
AHA-2940AU
AHA-2940U2W
AHA-2940U2
@@ -37,6 +39,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
AHA-2950U2
AHA-2950U2W
AHA-2950U2B
+ AHA-29160M
AHA-3940
AHA-3940U
AHA-3940W
@@ -45,6 +48,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
AHA-3940U2W
AHA-3950U2B
AHA-3950U2D
+ AHA-3960D
+ AHA-39160M
AHA-3985
AHA-3985U
AHA-3985W
@@ -159,6 +164,12 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
on your controller. This helps those people who have cards without
a SEEPROM make sure that linux and all other operating systems think
the same way about your hard drives.
+
+ "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
+ give the card more hardware SCB slots. This allows the driver to use
+ that SCB RAM. Without this option, the driver won't touch the SCB
+ RAM because it is known to cause problems on a few cards out there
+ (such as 3985 class cards).
"aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
to use the correct IRQ type for your card. This only applies to EISA
@@ -464,10 +475,9 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
FTP sites
------------------------------
ftp://ftp.redhat.com/pub/aic/
- - Primary site for Doug Ledford developed driver releases
- ftp://ftp.dialnet.net/pub/linux/aic7xxx
- - Temporary mirror of the redhat.com ftp site while people
- get used to the new address
+ - Out of date. I used to keep stuff here, but too many people
+ complained about having a hard time getting into Red Hat's ftp
+ server. So use the web site below instead.
ftp://ftp.pcnet.com/users/eischen/Linux/
- Dan Eischen's driver distribution area
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
@@ -475,10 +485,8 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Web sites
------------------------------
- http://developer.redhat.com/aic7xxx/
- - Primary web site maintained by Doug Ledford. I haven't actually
- put anything up yet....but I'm planning on it. This information
- is put here as an add for the vapor page :)
+ http://people.redhat.com/dledford/aic7xxx.html
+ - Primary web site maintained by Doug Ledford.
Dean W. Gehnert
deang@teleport.com
diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx
index 2fa1956a2..858673c33 100644
--- a/drivers/scsi/README.ncr53c8xx
+++ b/drivers/scsi/README.ncr53c8xx
@@ -1,10 +1,10 @@
-The Linux NCR53C8XX driver README file
+The Linux NCR53C8XX/SYM53C8XX drivers README file
Written by Gerard Roudier <groudier@club-internet.fr>
21 Rue Carnot
95170 DEUIL LA BARRE - FRANCE
-10 March 1999
+29 May 1999
===============================================================================
1. Introduction
@@ -25,14 +25,39 @@ Written by Gerard Roudier <groudier@club-internet.fr>
8.6 Clear profile counters
8.7 Set flag (no_disc)
8.8 Set verbose level
+ 8.9 Reset all logical units of a target
+ 8.10 Abort all tasks of all logical units of a target
9. Configuration parameters
10. Boot setup commands
10.1 Syntax
10.2 Available arguments
+ 10.2.1 Master parity checking
+ 10.2.2 Scsi parity checking
+ 10.2.3 Scsi disconnections
+ 10.2.4 Special features
+ 10.2.5 Ultra SCSI support
+ 10.2.6 Default number of tagged commands
+ 10.2.7 Default synchronous period factor
+ 10.2.8 Negotiate synchronous with all devices
+ 10.2.9 Verbosity level
+ 10.2.10 Debug mode
+ 10.2.11 Burst max
+ 10.2.12 LED support
+ 10.2.13 Max wide
+ 10.2.14 Differential mode
+ 10.2.15 IRQ mode
+ 10.2.16 Reverse probe
+ 10.2.17 Fix up PCI configuration space
+ 10.2.18 Serial NVRAM
+ 10.2.19 Check SCSI BUS
+ 10.2.20 Exclude a host from being attached
+ 10.2.21 Suggest a default SCSI id for hosts
+ 10.2.22 Enable use of IMMEDIATE ARBITRATION
10.3 Advised boot setup commands
10.4 PCI configuration fix-up boot option
10.5 Serial NVRAM support boot option
10.6 SCSI BUS checking boot option
+ 10.7 IMMEDIATE ARBITRATION boot option
11. Some constants and flags of the ncr53c8xx.h header file
12. Installation
13. Architecture dependent features
@@ -43,6 +68,8 @@ Written by Gerard Roudier <groudier@club-internet.fr>
14.4 Possible data corruption during a Memory Write and Invalidate
14.5 IRQ sharing problems
15. SCSI problem troubleshooting
+ 15.1 Problem tracking
+ 15.2 Understanding hardware error reports
16. Synchonous transfer negotiation tables
16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
@@ -69,11 +96,12 @@ The original driver has been written for 386bsd and FreeBSD by:
It is now available as a bundle of 2 drivers:
- ncr53c8xx generic driver that supports all the SYM53C8XX family including
- the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller.
+ the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
+ the new 895A (1 channel LVD SCSI controller).
- sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest
chips in order to gain advantage of new features, as LOAD/STORE intructions
available since the 810A and hardware phase mismatch available with the
- latest 896.
+ 896 and the 895A.
You can find technical information about the NCR 8xx family in the
PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by
@@ -95,15 +123,17 @@ Usefull SCSI tools written by Eric Youngdale are available at tsx-11:
These tools are not ALPHA but quite clean and work quite well.
It is essential you have the 'scsiinfo' package.
-This short documentation only describes the features of the NCR53C8XX
-driver, configuration parameters and control commands available
-through the proc SCSI file system read / write operations.
+This short documentation describes the features of the generic and enhanced
+drivers, configuration parameters and control commands available through
+the proc SCSI file system read / write operations.
This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
Latest driver version and patches are available at:
ftp://ftp.tux.org/pub/people/gerard-roudier
+or
+ ftp://ftp.symbios.com/mirror/ftp.tux.org/pub/tux/roudier/drivers
I am not a native speaker of English and there are probably lots of
mistakes in this README file. Any help will be welcome.
@@ -136,6 +166,7 @@ Chip SDMS BIOS Wide SCSI std. Max. sync driver driver
875 Y Y FAST20 40 MB/s Y Y
876 Y Y FAST20 40 MB/s Y Y
895 Y Y FAST40 80 MB/s Y Y
+895A Y Y FAST40 80 MB/s Y Y
896 Y Y FAST40 80 MB/s Y Y
@@ -156,21 +187,25 @@ Serial NVRAM: Symbios and Tekram formats
3.1 Optimized SCSI SCRIPTS.
-The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions
-named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from
-memory much faster that the MOVE MEMORY instruction that is supported by the
-53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and
-DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten
-using LOAD/STORE instead of MOVE MEMORY instructions.
+The 810A, 825A, 875, 895, 896 and 895A support new SCSI SCRIPTS instructions
+named LOAD and STORE that allow to move up to 1 DWORD from/to an IO register
+to/from memory much faster that the MOVE MEMORY instruction that is supported
+by the 53c7xx and 53c8xx family.
+The LOAD/STORE instructions support absolute and DSA relative addressing
+modes. The SCSI SCRIPTS had been entirely rewritten using LOAD/STORE instead
+of MOVE MEMORY instructions.
3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller)
-The 896 allows to handle the phase mismatch context saving from SCRIPTS
-(avoids the phase mismatch interrupt that stops the SCSI processor
+The 896 and the 895A allows handling of the phase mismatch context from
+SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor
until the C code has saved the context of the transfer).
Implementing this without using LOAD/STORE instructions would be painfull
-and I did'nt even try it. This chip also supports 64 bit PCI transactions
-and addressing. The SCRIPTS processor is not true 64 bit, but uses segment
+and I did'nt even want to try it.
+
+The 896 chip supports 64 bit PCI transactions and addressing, while the
+895A supports 32 bit PCI transactions and 64 bit addressing.
+The SCRIPTS processor of these chips is not true 64 bit, but uses segment
registers for bit 32-63. Another interesting feature is that LOAD/STORE
instructions that address the on-chip RAM (8k) remain internal to the chip.
@@ -219,9 +254,13 @@ The maximum number of simultaneous tagged commands queued to a device
is currently set to 8 by default. This value is suitable for most SCSI
disks. With large SCSI disks (>= 2GB, cache >= 512KB, average seek time
<= 10 ms), using a larger value may give better performances.
-The driver supports up to 64 commands per device, but using more than
-32 is generally not worth it, unless you are using a very large disk
-or disk array.
+
+The sym53c8xx driver supports up to 255 commands per device, and the
+generic ncr53c8xx driver supports up to 64, but using more than 32 is
+generally not worth-while, unless you are using a very large disk or disk
+array. It is noticeable that most of recent hard disks seem not to accept
+more than 64 simultaneous commands. So, using more than 64 queued commands
+is probably just resource wasting.
If your controller does not have NVRAM or if it is managed by the SDMS
BIOS/SETUP, you can configure tagged queueing feature and device queue
@@ -491,6 +530,24 @@ Available commands:
The driver default verbose level is 1. This command allows to change
th driver verbose level after boot-up.
+8.9 Reset all logical units of a target
+
+ resetdev <target>
+
+ target: target number
+ The driver will try to send a BUS DEVICE RESET message to the target.
+ (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+8.10 Abort all tasks of all logical units of a target
+
+ cleardev <target>
+
+ target: target number
+ The driver will try to send a ABORT message to all the logical units
+ of the target.
+ (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+
9. Configuration parameters
If the firmware of all your devices is perfect enough, all the
@@ -566,10 +623,11 @@ CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
Setup commands can be passed to the driver either at boot time or as a
string variable using 'insmod'.
-A boot setup command for the ncr53c8xx driver begins with the driver name
-"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
-integers separated with comma followed by an optionnal list of comma-
-separated strings. Example of boot setup command under lilo prompt:
+A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the
+driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects
+an optionnal list of integers separated with comma followed by an optional
+list of comma-separated strings. Example of boot setup command under lilo
+prompt:
lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
@@ -582,7 +640,7 @@ Since comma seems not to be allowed when defining a string variable using
The following command will install driver module with the same options as
above.
-insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
+ insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
For the moment, the integer list of arguments is discarded by the driver.
It will be used in the future in order to allow a per controller setup.
@@ -590,40 +648,53 @@ It will be used in the future in order to allow a per controller setup.
Each string argument must be specified as "keyword:value". Only lower-case
characters and digits are allowed.
+In a system that contains multiple 53C8xx adapters insmod will install the
+specified driver on each adapter. To exclude a chip use the 'excl' keyword.
+
+The sequence of commands,
+
+ insmod sym53c8xx sym53c8xx=excl:0x1400
+ insmod ncr53c8xx
+
+installs the sym53c8xx driver on all adapters except the one at IO port
+address 0x1400 and then installs the ncr53c8xx driver to the adapter at IO
+port address 0x1400.
+
+
10.2 Available arguments
-Master parity checking
- mpar:y enabled
- mpar:n disabled
+10.2.1 Master parity checking
+ mpar:y enabled
+ mpar:n disabled
-Scsi parity checking
- spar:y enabled
- spar:n disabled
+10.2.2 Scsi parity checking
+ spar:y enabled
+ spar:n disabled
-Scsi disconnections
- disc:y enabled
- disc:n disabled
+10.2.3 Scsi disconnections
+ disc:y enabled
+ disc:n disabled
-Special features
+10.2.4 Special features
Only apply to 810A, 825A, 860, 875 and 895 controllers.
Have no effect with other ones.
- specf:y (or 1) enabled
- specf:n (or 0) disabled
- specf:3 enabled except Memory Write And Invalidate
+ specf:y (or 1) enabled
+ specf:n (or 0) disabled
+ specf:3 enabled except Memory Write And Invalidate
The default driver setup is 'specf:3'. As a consequence, option 'specf:y'
must be specified in the boot setup command to enable Memory Write And
Invalidate.
-Ultra SCSI support
+10.2.5 Ultra SCSI support
Only apply to 860, 875 and 895 controllers.
Have no effect with other ones.
- ultra:2 Ultra2 enabled
- ultra:1 Ultra enabled
- ultra:n disabled
+ ultra:2 Ultra2 enabled
+ ultra:1 Ultra enabled
+ ultra:n disabled
-Default number of tagged commands
- tags:0 (or tags:1 ) tagged command queuing disabled
- tags:#tags (#tags > 1) tagged command queuing enabled
+10.2.6 Default number of tagged commands
+ tags:0 (or tags:1 ) tagged command queuing disabled
+ tags:#tags (#tags > 1) tagged command queuing enabled
#tags will be truncated to the max queued commands configuration parameter.
This option also allows to specify a command queue depth for each device
that support tagged command queueing.
@@ -635,9 +706,9 @@ Default number of tagged commands
- controller #1 target #1 logical unit #2 -> 32 commands,
- all other logical units (all targets, all controllers) -> 10 commands.
-Default synchronous period factor
- sync:255 disabled (asynchronous transfer mode)
- sync:#factor
+10.2.7 Default synchronous period factor
+ sync:255 disabled (asynchronous transfer mode)
+ sync:#factor
#factor = 10 Ultra-2 SCSI 40 Mega-transfers / second
#factor = 11 Ultra-2 SCSI 33 Mega-transfers / second
#factor < 25 Ultra SCSI 20 Mega-transfers / second
@@ -646,19 +717,19 @@ Default synchronous period factor
In all cases, the driver will use the minimum transfer period supported by
controllers according to NCR53C8XX chip type.
-Negotiate synchronous with all devices
- (force sync nego)
- fsn:y enabled
- fsn:n disabled
+10.2.8 Negotiate synchronous with all devices
+ (force sync nego)
+ fsn:y enabled
+ fsn:n disabled
-Verbosity level
- verb:0 minimal
- verb:1 normal
- verb:2 too much
+10.2.9 Verbosity level
+ verb:0 minimal
+ verb:1 normal
+ verb:2 too much
-Debug mode
- debug:0 clear debug flags
- debug:#x set debug flags
+10.2.10 Debug mode
+ debug:0 clear debug flags
+ debug:#x set debug flags
#x is an integer value combining the following power-of-2 values:
DEBUG_ALLOC 0x1
DEBUG_PHASE 0x2
@@ -677,10 +748,10 @@ Debug mode
You can play safely with DEBUG_NEGO. However, some of these flags may
generate bunches of syslog messages.
-Burst max
- burst:0 burst disabled
- burst:255 get burst length from initial IO register settings.
- burst:#x burst enabled (1<<#x burst transfers max)
+10.2.11 Burst max
+ burst:0 burst disabled
+ burst:255 get burst length from initial IO register settings.
+ burst:#x burst enabled (1<<#x burst transfers max)
#x is an integer value which is log base 2 of the burst transfers max.
The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7).
Other chips only support up to 16 (#x = 4).
@@ -688,42 +759,42 @@ Burst max
and revision ids. By default the driver uses the maximum value supported
by the chip.
-LED support
- led:1 enable LED support
- led:0 disable LED support
+10.2.12 LED support
+ led:1 enable LED support
+ led:0 disable LED support
Donnot enable LED support if your scsi board does not use SDMS BIOS.
(See 'Configuration parameters')
-Max wide
- wide:1 wide scsi enabled
- wide:0 wide scsi disabled
+10.2.13 Max wide
+ wide:1 wide scsi enabled
+ wide:0 wide scsi disabled
Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
If you have connected a wide device with a 50 pins to 68 pins cable
converter, any accepted wide negotiation will break further data transfers.
In such a case, using "wide:0" in the bootup command will be helpfull.
-Differential mode
- diff:0 never set up diff mode
- diff:1 set up diff mode if BIOS set it
- diff:2 always set up diff mode
- diff:3 set diff mode if GPIO3 is not set
+10.2.14 Differential mode
+ diff:0 never set up diff mode
+ diff:1 set up diff mode if BIOS set it
+ diff:2 always set up diff mode
+ diff:3 set diff mode if GPIO3 is not set
-IRQ mode
- irqm:0 always open drain
- irqm:1 same as initial settings (assumed BIOS settings)
- irqm:2 always totem pole
- irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq
- irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq
+10.2.15 IRQ mode
+ irqm:0 always open drain
+ irqm:1 same as initial settings (assumed BIOS settings)
+ irqm:2 always totem pole
+ irqm:0x10 driver will not use SA_SHIRQ flag when requesting irq
+ irqm:0x20 driver will not use SA_INTERRUPT flag when requesting irq
(Bits 0x10 and 0x20 can be combined with hardware irq mode option)
-Reverse probe
- revprob:n probe chip ids from the PCI configuration in this order:
- 810, 815, 820, 860, 875, 885, 895, 896
- revprob:y probe chip ids in the reverse order.
+10.2.16 Reverse probe
+ revprob:n probe chip ids from the PCI configuration in this order:
+ 810, 815, 820, 860, 875, 885, 895, 896
+ revprob:y probe chip ids in the reverse order.
-Fix up PCI configuration space
- pcifix:<option bits>
+10.2.17 Fix up PCI configuration space
+ pcifix:<option bits>
Available option bits:
0x0: No attempt to fix PCI configuration space registers values.
@@ -733,25 +804,52 @@ Fix up PCI configuration space
Use 'pcifix:7' in order to allow the driver to fix up all PCI features.
-Serial NVRAM
- nvram:n do not look for serial NVRAM
- nvram:y test controllers for onboard serial NVRAM
+10.2.18 Serial NVRAM
+ nvram:n do not look for serial NVRAM
+ nvram:y test controllers for onboard serial NVRAM
+ (alternate binary form)
+ mvram=<bits options>
+ 0x01 look for NVRAM (equivalent to nvram=y)
+ 0x02 ignore NVRAM "Synchronous negotiation" parameters for all devices
+ 0x04 ignore NVRAM "Wide negotiation" parameter for all devices
+ 0x08 ignore NVRAM "Scan at boot time" parameter for all devices
+ 0x80 also attach controllers set to OFF in the NVRAM (sym53c8xx only)
-Check SCSI BUS
- buschk:<option bits>
+10.2.19 Check SCSI BUS
+ buschk:<option bits>
Available option bits:
0x0: No check.
0x1: Check and donnot attach the controller on error.
0x2: Check and just warn on error.
-Exclude hosts from being attached
- excl=<io_address>
+10.2.20 Exclude a host from being attached
+ excl=<io_address>
Prevent host at a given io address from being attached.
For example 'ncr53c8xx=excl:0xb400,excl:0xc000' indicate to the
ncr53c8xx driver not to attach hosts at address 0xb400 and 0xc000.
+10.2.21 Suggest a default SCSI id for hosts
+ hostid:255 no id suggested.
+ hostid:#x (0 < x < 7) x suggested for hosts SCSI id.
+
+ If a host SCSI id is available from the NVRAM, the driver will ignore
+ any value suggested as boot option. Otherwise, if a suggested value
+ different from 255 has been supplied, it will use it. Otherwise, it will
+ try to deduce the value previously set in the hardware and use value
+ 7 if the hardware value is zero.
+
+10.2.22 Enable use of IMMEDIATE ARBITRATION
+ (only supported by the sym53c8xx driver. See 10.7 for more details)
+ iarb:0 donnot use this feature.
+ iarb:#x use this feature according to bit fields as follow:
+
+ bit 0 (1) : enable IARB each time the initiator has been reselected
+ when it arbitrated for the SCSI BUS.
+ (#x >> 4) : maximum number of successive settings of IARB if the initiator
+ win arbitration and it has other commands to send to a device.
+
Boot fail safe
safe:y load the following assumed fail safe initial setup
@@ -775,6 +873,7 @@ Boot fail safe
differential support from BIOS settings diff:1
irq mode from BIOS settings irqm:1
SCSI BUS check donnot attach on error buschk:1
+ immediate arbitration disabled iarb:0
10.3 Advised boot setup commands
@@ -837,7 +936,11 @@ use them too.
nvram:n do not look for serial NVRAM
nvram:y test controllers for onboard serial NVRAM
-This option is described below (see 17. Serial NVRAM support).
+This option can also been entered as an hexadecimal value that allows
+to control what information the driver will get from the NVRAM and what
+information it will ignore.
+For details see '17. Serial NVRAM support'.
+
When this option is enabled, the driver tries to detect all boards using
a Serial NVRAM. This memory is used to hold user set up parameters.
@@ -873,12 +976,17 @@ mvram=<bits options>
0x02 ignore NVRAM "Synchronous negotiation" parameters for all devices
0x04 ignore NVRAM "Wide negotiation" parameter for all devices
0x08 ignore NVRAM "Scan at boot time" parameter for all devices
+ 0x80 also attach controllers set to OFF in the NVRAM (sym53c8xx only)
-My Atlas Wide only boots cleanly in 8 bits asynchronous data transfer
-mode. However, it works flawlessly at 20 MB/second with the driver.
-Using "nvram=0x7" allows me to boot in 8 bits/async and to let the driver
-use its setup for synchronous and wide negotiations.
+Option 0x80 is only supported by the sym53c8xx driver and is disabled by
+default. Result is that, by default (option not set), the sym53c8xx driver
+will not attach controllers set to OFF in the NVRAM.
+The ncr53c8xx always tries to attach all the controllers. Option 0x80 has
+not been added to the ncr53c8xx driver, since it has been reported to
+confuse users who use this driver since a long time. If you desire a
+controller not to be attached by the ncr53c8xx driver at Linux boot, you
+must use the 'excl' driver boot option.
10.6 SCSI BUS checking boot option.
@@ -894,6 +1002,45 @@ Unfortunately, the following common SCSI BUS problems are not detected:
On the other hand, either bad cabling, broken devices, not conformant
devices, ... may cause a SCSI signal to be wrong when te driver reads it.
+10.7 IMMEDIATE ARBITRATION boot option
+
+This option is only supported by the SYM53C8XX driver (not by the NCR53C8XX).
+
+SYMBIOS 53C8XX chips are able to arbitrate for the SCSI BUS as soon as they
+have detected an expected disconnection (BUS FREE PHASE). For this process
+to be started, bit 1 of SCNTL1 IO register must be set when the chip is
+connected to the SCSI BUS.
+
+When this feature has been enabled for the current connection, the chip has
+every chance to win arbitration if only devices with lower priority are
+competing for the SCSI BUS. By the way, when the chip is using SCSI id 7,
+then it will for sure win the next SCSI BUS arbitration.
+
+Since, there is no way to know what devices are trying to arbitrate for the
+BUS, using this feature can be extremally unfair. So, you are not advised
+to enable it, or at most enable this feature for the case the chip lost
+the previous arbitration (boot option 'iarb:1').
+
+This feature has the following advantages:
+
+a) Allow the initiator with ID 7 to win arbitration when it wants so.
+b) Overlap at least 4 micro-seconds of arbitration time with the execution
+ of SCRIPTS that deal with the end of the current connection and that
+ starts the next job.
+
+Hmmm... But (a) may just prevent other devices from reselecting the initiator,
+and delay data transfers or status/completions, and (b) may just waste
+SCSI BUS bandwidth if the SCRIPTS execution lasts more than 4 micro-seconds.
+
+The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined
+at compile time and the 'iarb' boot option to have been set to a non zero
+value at boot time. It is not that usefull for real work, but can be used
+to stress SCSI devices or for some applications that can gain advantage of
+it. By the way, if you experience badnesses like 'unexpected disconnections',
+'bad reselections', etc... when using IARB on heavy IO load, you should not
+be surprised, because force-feeding anything and blocking its arse at the
+same time cannot work for a long time. :-))
+
11. Some constants and flags of the ncr53c8xx.h header file
@@ -1107,6 +1254,8 @@ then the request of the IRQ obviously will not succeed for all the drivers.
15. SCSI problem troubleshooting
+15.1 Problem tracking
+
Most SCSI problems are due to a non conformant SCSI bus or to buggy
devices. If infortunately you have SCSI problems, you can check the
following things:
@@ -1153,6 +1302,77 @@ Try to enable one feature at a time with control commands. For example:
Once you have found the device and the feature that cause problems, just
disable that feature for that device.
+15.2 Understanding hardware error reports
+
+When the driver detects an unexpected error condition, it may display a
+message of the following pattern.
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+sym53c876-0: script cmd = 19000000
+sym53c876-0: regdump: da 10 80 95 47 0f 01 07 75 01 81 21 80 01 09 00.
+
+Some fields in such a message may help you understand the cause of the
+problem, as follows:
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+............A.........B.C....D.E..F....G.H.......I.....J...K.......
+
+Field A : target number.
+ SCSI ID of the device the controller was talking with at the moment the
+ error occurs.
+
+Field B : DSTAT io register (DMA STATUS)
+ Bit 0x40 : MDPE Master Data Parity Error
+ Data parity error detected on the PCI BUS.
+ Bit 0x20 : BF Bus Fault
+ PCI bus fault condition detected
+ Bit 0x01 : IID Illegal Instruction Detected
+ Set by the chip when it detects an Illegal Instruction format
+ on some condition that makes an instruction illegal.
+ Bit 0x80 : DFE Dma Fifo Empty
+ Pure status bit that does not indicate an error.
+ If the reported DSTAT value contains a combination of MDPE (0x40),
+ BF (0x20), then the cause may be likely due to a PCI BUS problem.
+
+Field C : SIST io register (SCSI Interrupt Status)
+ Bit 0x08 : SGE SCSI GROSS ERROR
+ Indicates that the chip detected a severe error condition
+ on the SCSI BUS that prevents the SCSI protocol from functionning
+ properly.
+ Bit 0x04 : UDC Undexpected Disconnection
+ Indicates that the device released the SCSI BUS when the chip
+ was not expecting this to happen. A device may behave so to
+ indicate the SCSI initiator that an error condition not reportable using the SCSI protocol has occured.
+ Bit 0x02 : RST SCSI BUS Reset
+ Generally SCSI targets donnot reset the SCSI BUS, although any
+ device on the BUS can reset it at any time.
+ Bit 0x01 : PAR Parity
+ SCSI parity error detected.
+ On a faulty SCSI BUS, any error condition among SGE (0x08), UDC (0x04) and
+ PAR (0x01) may be detected by the chip. If your SCSI system sometimes
+ encounters such error conditions, especially SCSI GROSS ERROR, then a SCSI
+ BUS problem is likely the cause of these errors.
+
+For fields D,E,F,G and H, you may look into the sym53c8xx_defs.h file
+that contains some minimal comments on IO register bits.
+Field D : SOCL Scsi Output Control Latch
+ This register reflects the state of the SCSI control lines the
+ chip want to drive or compare against.
+Field E : SBCL Scsi Bus Control Lines
+ Actual value of control lines on the SCSI BUS.
+Field F : SBDL Scsi Bus Data Lines
+ Actual value of data lines on the SCSI BUS.
+Field G : SXFER SCSI Transfer
+ Contains the setting of the Synchronous Period for output and
+ the current Synchronous offset (offset 0 means asynchronous).
+Field H : SCNTL3 Scsi Control Register 3
+ Contains the setting of timing values for both asynchronous and
+ synchronous data transfers.
+
+Understanding Fields I, J, K and dumps requires to have good knowledge of
+SCSI standards, chip cores functionnals and internal driver data structures.
+You are not required to decode and understand them, unless you want to help
+maintain the driver code.
16. Synchonous transfer negotiation tables
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 812870cda..760dcc75b 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -269,7 +269,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.19"
+#define AIC7XXX_C_VERSION "5.1.20"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -878,13 +878,14 @@ typedef enum {
AHC_SG_PRELOAD = 0x0080,
AHC_SPIOCAP = 0x0100,
AHC_ULTRA3 = 0x0200,
+ AHC_NEW_AUTOTERM = 0x0400,
AHC_AIC7770_FE = AHC_FENONE,
AHC_AIC7850_FE = AHC_SPIOCAP,
AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP,
AHC_AIC7870_FE = AHC_FENONE,
AHC_AIC7880_FE = AHC_ULTRA,
AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
- AHC_QUEUE_REGS|AHC_SG_PRELOAD,
+ AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM,
AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
AHC_AIC7896_FE = AHC_AIC7890_FE,
AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3,
@@ -1351,7 +1352,14 @@ static int aic7xxx_dump_sequencer = 0;
* would result in never finding any devices :)
*/
static int aic7xxx_no_probe = 0;
-
+/*
+ * On some machines, enabling the external SCB RAM isn't reliable yet. I
+ * haven't had time to make test patches for things like changing the
+ * timing mode on that external RAM either. Some of those changes may
+ * fix the problem. Until then though, we default to external SCB RAM
+ * off and give a command line option to enable it.
+ */
+static int aic7xxx_scbram = 0;
/*
* So that insmod can find the variable and make it point to something
*/
@@ -1450,13 +1458,12 @@ aic_inb(struct aic7xxx_host *p, long port)
unsigned char x;
if(p->maddr)
{
- x = p->maddr[port];
+ x = readb(p->maddr + port);
}
else
{
x = inb(p->base + port);
}
- mb();
return(x);
#else
return(inb(p->base + port));
@@ -1469,7 +1476,7 @@ aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
#ifdef MMAPIO
if(p->maddr)
{
- p->maddr[port] = val;
+ writeb(val, p->maddr + port);
}
else
{
@@ -1513,6 +1520,7 @@ aic7xxx_setup(char *s, int *dummy)
{ "pci_parity", &aic7xxx_pci_parity },
{ "dump_card", &aic7xxx_dump_card },
{ "dump_sequencer", &aic7xxx_dump_sequencer },
+ { "scbram", &aic7xxx_scbram },
{ "tag_info", NULL }
};
@@ -6193,7 +6201,7 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
cmd->result = 0;
scb = NULL;
}
- if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+ else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
{
/*
* Turn off the needsdtr, needwdtr, and needppr bits since this device
@@ -6541,6 +6549,105 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
}
#endif
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_command_completion_intr
+ *
+ * Description:
+ * SCSI command completion interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
+{
+ struct aic7xxx_scb *scb = NULL;
+ Scsi_Cmnd *cmd;
+ unsigned char scb_index;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+ if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
+ printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
+#endif
+
+ /*
+ * Read the INTSTAT location after clearing the CMDINT bit. This forces
+ * any posted PCI writes to flush to memory. Gerard Roudier suggested
+ * this fix to the possible race of clearing the CMDINT bit but not
+ * having all command bytes flushed onto the qoutfifo.
+ */
+ aic_outb(p, CLRCMDINT, CLRINT);
+ aic_inb(p, INTSTAT);
+ /*
+ * The sequencer will continue running when it
+ * issues this interrupt. There may be >1 commands
+ * finished, so loop until we've processed them all.
+ */
+
+ while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
+ {
+ scb_index = p->qoutfifo[p->qoutfifonext];
+ p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+ if ( scb_index >= p->scb_data->numscbs )
+ scb = NULL;
+ else
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb == NULL)
+ {
+ printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+ -1, -1, -1, scb_index);
+ continue;
+ }
+ else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+ "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+ (unsigned long) scb->cmd);
+ continue;
+ }
+ else if (scb->flags & SCB_QUEUED_ABORT)
+ {
+ pause_sequencer(p);
+ if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+ (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
+ {
+ unpause_sequencer(p, FALSE);
+ continue;
+ }
+ aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
+ scb->cmd->lun, scb->hscb->tag);
+ scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+ SCB_QUEUED_ABORT);
+ unpause_sequencer(p, FALSE);
+ }
+ else if (scb->flags & SCB_ABORT)
+ {
+ /*
+ * We started to abort this, but it completed on us, let it
+ * through as successful
+ */
+ scb->flags &= ~(SCB_ABORT|SCB_RESET);
+ }
+ switch (status_byte(scb->hscb->target_status))
+ {
+ case QUEUE_FULL:
+ case BUSY:
+ scb->hscb->target_status = 0;
+ scb->cmd->result = 0;
+ aic7xxx_error(scb->cmd) = DID_OK;
+ break;
+ default:
+ cmd = scb->cmd;
+ if (scb->hscb->residual_SG_segment_count != 0)
+ {
+ aic7xxx_calculate_residual(p, scb);
+ }
+ cmd->result |= (aic7xxx_error(cmd) << 16);
+ aic7xxx_done(p, scb);
+ break;
+ }
+ }
+}
+
/*+F*************************************************************************
* Function:
* aic7xxx_isr
@@ -6600,95 +6707,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
*/
if (intstat & CMDCMPLT)
{
- struct aic7xxx_scb *scb = NULL;
- Scsi_Cmnd *cmd;
- unsigned char scb_index;
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
- printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
-#endif
-
- /*
- * Clear interrupt status before running the completion loop.
- * This eliminates a race condition whereby a command could
- * complete between the last check of qoutfifo and the
- * CLRCMDINT statement. This would result in us thinking the
- * qoutfifo was empty when it wasn't, and in actuality be a lost
- * completion interrupt. With multiple devices or tagged queueing
- * this could be very bad if we caught all but the last completion
- * and no more are imediately sent.
- */
- aic_outb(p, CLRCMDINT, CLRINT);
- /*
- * The sequencer will continue running when it
- * issues this interrupt. There may be >1 commands
- * finished, so loop until we've processed them all.
- */
-
- while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
- {
- scb_index = p->qoutfifo[p->qoutfifonext];
- p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
- if ( scb_index >= p->scb_data->numscbs )
- scb = NULL;
- else
- scb = p->scb_data->scb_array[scb_index];
- if (scb == NULL)
- {
- printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
- -1, -1, -1, scb_index);
- continue;
- }
- else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
- "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
- (unsigned long) scb->cmd);
- continue;
- }
- else if (scb->flags & SCB_QUEUED_ABORT)
- {
- pause_sequencer(p);
- if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
- (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
- {
- unpause_sequencer(p, FALSE);
- continue;
- }
- aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
- scb->cmd->lun, scb->hscb->tag);
- scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
- SCB_QUEUED_ABORT);
- unpause_sequencer(p, FALSE);
- }
- else if (scb->flags & SCB_ABORT)
- {
- /*
- * We started to abort this, but it completed on us, let it
- * through as successful
- */
- scb->flags &= ~(SCB_ABORT|SCB_RESET);
- }
- switch (status_byte(scb->hscb->target_status))
- {
- case QUEUE_FULL:
- case BUSY:
- scb->hscb->target_status = 0;
- scb->cmd->result = 0;
- aic7xxx_error(scb->cmd) = DID_OK;
- break;
- default:
- cmd = scb->cmd;
- if (scb->hscb->residual_SG_segment_count != 0)
- {
- aic7xxx_calculate_residual(p, scb);
- }
- cmd->result |= (aic7xxx_error(cmd) << 16);
- aic7xxx_done(p, scb);
- break;
- }
- }
+ aic7xxx_handle_command_completion_intr(p);
}
if (intstat & BRKADRINT)
@@ -7619,9 +7638,10 @@ configure_termination(struct aic7xxx_host *p)
aic_outb(p, SEEMS | SEECS, SEECTL);
sxfrctl1 &= ~STPWEN;
if ( (p->adapter_control & CFAUTOTERM) ||
- (p->features & AHC_ULTRA2) )
+ (p->features & AHC_NEW_AUTOTERM) )
{
- if ( (p->adapter_control & CFAUTOTERM) && !(p->features & AHC_ULTRA2) )
+ if ( (p->adapter_control & CFAUTOTERM) &&
+ !(p->features & AHC_NEW_AUTOTERM) )
{
printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
p->host_no);
@@ -7635,7 +7655,7 @@ configure_termination(struct aic7xxx_host *p)
}
/* Configure auto termination. */
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_NEW_AUTOTERM)
{
if (aic7xxx_override_term == -1)
aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
@@ -7668,7 +7688,7 @@ configure_termination(struct aic7xxx_host *p)
if (max_target <= 8)
internal68_present = 0;
- if ( !(p->features & AHC_ULTRA2) )
+ if ( !(p->features & AHC_NEW_AUTOTERM) )
{
if (max_target > 8)
{
@@ -7698,7 +7718,7 @@ configure_termination(struct aic7xxx_host *p)
* SE Low Term Enable = BRDDAT5 (7890)
* LVD High Term Enable = BRDDAT4 (7890)
*/
- if ( !(p->features & AHC_ULTRA2) &&
+ if ( !(p->features & AHC_NEW_AUTOTERM) &&
(internal50_present && internal68_present && external_present) )
{
printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n",
@@ -7731,7 +7751,7 @@ configure_termination(struct aic7xxx_host *p)
(external_present ? 1 : 0)) <= 1) ||
(enableSE_low != 0) )
{
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_NEW_AUTOTERM)
brddat |= BRDDAT5;
else
sxfrctl1 |= STPWEN;
@@ -7762,7 +7782,7 @@ configure_termination(struct aic7xxx_host *p)
{
if (p->adapter_control & CFSTERM)
{
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_NEW_AUTOTERM)
brddat |= BRDDAT5;
else
sxfrctl1 |= STPWEN;
@@ -9409,7 +9429,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 18,
32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
@@ -9539,7 +9559,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
temp_p->base = pdev->resource[0].start;
temp_p->mbase = pdev->resource[1].start;
current_p = list_p;
- while(current_p)
+ while(current_p && temp_p)
{
if ( ((current_p->pci_bus == temp_p->pci_bus) &&
(current_p->pci_device_fn == temp_p->pci_device_fn)) ||
@@ -9958,7 +9978,8 @@ aic7xxx_detect(Scsi_Host_Template *template)
#endif
if (temp_p->features & AHC_ULTRA2)
{
- if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+ if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
+ (aic7xxx_scbram) )
{
aic_outb(temp_p,
aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
@@ -9966,12 +9987,33 @@ aic7xxx_detect(Scsi_Host_Template *template)
temp_p->flags |= AHC_EXTERNAL_SRAM;
devconfig |= EXTSCBPEN;
}
+ else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+ {
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: external SCB RAM detected, "
+ "but not enabled\n");
+ }
}
- else if (devconfig & RAMPSM)
+ else
{
- devconfig &= ~SCBRAMSEL;
- devconfig |= EXTSCBPEN;
- temp_p->flags |= AHC_EXTERNAL_SRAM;
+ if ((devconfig & RAMPSM) && (aic7xxx_scbram))
+ {
+ devconfig &= ~SCBRAMSEL;
+ devconfig |= EXTSCBPEN;
+ temp_p->flags |= AHC_EXTERNAL_SRAM;
+ }
+ else if (devconfig & RAMPSM)
+ {
+ printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n",
+ board_names[aic_pdevs[i].board_name_index],
+ PCI_SLOT(temp_p->pci_device_fn),
+ PCI_FUNC(temp_p->pci_device_fn));
+ printk("aic7xxx: external SCB RAM detected, "
+ "but not enabled\n");
+ }
}
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
@@ -11588,13 +11630,17 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
if ( aic7xxx_scb_on_qoutfifo(p, scb) )
{
if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
- printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
+ printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
CTL_OF_SCB(scb));
- aic7xxx_run_done_queue(p, TRUE);
+ if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
+ printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
+ CTL_OF_SCB(scb));
+ aic7xxx_handle_command_completion_intr(p);
+ aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
+ return(SCSI_RESET_SUCCESS);
}
if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
{
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index d5d2765a7..abc86e123 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -63,6 +63,10 @@
#include "bvme6000.h"
#endif
+#ifdef CONFIG_SCSI_SIM710
+#include "sim710.h"
+#endif
+
#ifdef CONFIG_A3000_SCSI
#include "a3000.h"
#endif
@@ -455,6 +459,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_BVME6000_SCSI
BVME6000_SCSI,
#endif
+#ifdef CONFIG_SCSI_SIM710
+ SIM710_SCSI,
+#endif
#ifdef CONFIG_SCSI_ADVANSYS
ADVANSYS,
#endif
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index fa8844b67..7b2944b30 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -166,16 +166,9 @@ int imm_detect(Scsi_Host_Template * host)
*/
imm_hosts[i].mode = IMM_NIBBLE;
- if (modes & PARPORT_MODE_PCPS2)
+ if (modes & PARPORT_MODE_TRISTATE)
imm_hosts[i].mode = IMM_PS2;
- if (modes & PARPORT_MODE_PCECPPS2) {
- w_ecr(ppb, 0x20);
- imm_hosts[i].mode = IMM_PS2;
- }
- if (modes & PARPORT_MODE_PCECPEPP)
- w_ecr(ppb, 0x80);
-
/* Done configuration */
imm_pb_release(i);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 168299e0b..671a70e92 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -73,7 +73,7 @@
*/
/*
-** March 7 1999, version 3.2
+** Sep 10 1999, version 3.2c
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -83,7 +83,7 @@
** Parity checking
** Etc...
**
-** Supported NCR chips:
+** Supported NCR/SYMBIOS chips:
** 53C810 (8 bits, Fast SCSI-2, no rom BIOS)
** 53C815 (8 bits, Fast SCSI-2, on board rom BIOS)
** 53C820 (Wide, Fast SCSI-2, no rom BIOS)
@@ -91,6 +91,8 @@
** 53C860 (8 bits, Fast 20, no rom BIOS)
** 53C875 (Wide, Fast 20, on board rom BIOS)
** 53C895 (Wide, Fast 40, on board rom BIOS)
+** 53C895A (Wide, Fast 40, on board rom BIOS)
+** 53C896 (Wide, Fast 40, on board rom BIOS)
**
** Other features:
** Memory mapped IO (linux-1.3.X and above only)
@@ -101,7 +103,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - version 3.2"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - 3.2c"
#define SCSI_NCR_DEBUG_FLAGS (0)
@@ -121,8 +123,10 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
#endif
#include <linux/delay.h>
#include <linux/signal.h>
@@ -147,11 +151,14 @@
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
#include <linux/init.h>
-#else
+#endif
+
+#ifndef __init
+#define __init
+#endif
#ifndef __initdata
#define __initdata
#endif
-#endif
#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
#include <linux/bios32.h>
@@ -368,8 +375,9 @@ static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
** We need to deal with power of 2, for alignment constraints.
*/
#if SCSI_NCR_MAX_TAGS > 64
-#undef SCSI_NCR_MAX_TAGS
-#define SCSI_NCR_MAX_TAGS (64)
+#define MAX_TAGS (64)
+#else
+#define MAX_TAGS SCSI_NCR_MAX_TAGS
#endif
#define NO_TAG (255)
@@ -377,7 +385,7 @@ static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
/*
** Choose appropriate type for tag bitmap.
*/
-#if SCSI_NCR_MAX_TAGS > 32
+#if MAX_TAGS > 32
typedef u_int64 tagmap_t;
#else
typedef u_int32 tagmap_t;
@@ -427,7 +435,17 @@ typedef u_int32 tagmap_t;
#ifdef SCSI_NCR_CAN_QUEUE
#define MAX_START (SCSI_NCR_CAN_QUEUE + 4)
#else
-#define MAX_START (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+** We limit the max number of pending IO to 250.
+** since we donnot want to allocate more than 1
+** PAGE for 'scripth'.
+*/
+#if MAX_START > 250
+#undef MAX_START
+#define MAX_START 250
#endif
/*
@@ -737,34 +755,6 @@ static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
** This structure is initialized from linux config options.
** It can be overridden at boot-up by the boot command line.
*/
-#define SCSI_NCR_MAX_EXCLUDES 8
-struct ncr_driver_setup {
- u_char master_parity;
- u_char scsi_parity;
- u_char disconnection;
- u_char special_features;
- u_char ultra_scsi;
- u_char force_sync_nego;
- u_char reverse_probe;
- u_char pci_fix_up;
- u_char use_nvram;
- u_char verbose;
- u_char default_tags;
- u_short default_sync;
- u_short debug;
- u_char burst_max;
- u_char led_pin;
- u_char max_wide;
- u_char settle_delay;
- u_char diff_support;
- u_char irqm;
- u_char bus_check;
- u_char optimize;
- u_char recovery;
- u_int excludes[SCSI_NCR_MAX_EXCLUDES];
- char tag_ctrl[100];
-};
-
static struct ncr_driver_setup
driver_setup = SCSI_NCR_DRIVER_SETUP;
@@ -794,108 +784,7 @@ static void ncr53c8xx_timeout(unsigned long np);
#define bootverbose (driver_setup.verbose)
#ifdef SCSI_NCR_NVRAM_SUPPORT
-/*
-** Symbios NvRAM data format
-*/
-#define SYMBIOS_NVRAM_SIZE 368
-#define SYMBIOS_NVRAM_ADDRESS 0x100
-
-struct Symbios_nvram {
-/* Header 6 bytes */
- u_short start_marker; /* 0x0000 */
- u_short byte_count; /* excluding header/trailer */
- u_short checksum;
-
-/* Controller set up 20 bytes */
- u_short word0; /* 0x3000 */
- u_short word2; /* 0x0000 */
- u_short word4; /* 0x0000 */
- u_short flags;
-#define SYMBIOS_SCAM_ENABLE (1)
-#define SYMBIOS_PARITY_ENABLE (1<<1)
-#define SYMBIOS_VERBOSE_MSGS (1<<2)
-#define SYMBIOS_CHS_MAPPING (1<<3)
- u_short flags1;
-#define SYMBIOS_SCAN_HI_LO (1)
- u_short word10; /* 0x00 */
- u_short flags3; /* 0x00 */
-#define SYMBIOS_REMOVABLE_FLAGS (3) /* 0=none, 1=bootable, 2=all */
- u_char host_id;
- u_char byte15; /* 0x04 */
- u_short word16; /* 0x0410 */
- u_short word18; /* 0x0000 */
-
-/* Boot order 14 bytes * 4 */
- struct Symbios_host{
- u_char word0; /* 0x0004:ok / 0x0000:nok */
- u_short device_id; /* PCI device id */
- u_short vendor_id; /* PCI vendor id */
- u_char byte6; /* 0x00 */
- u_char device_fn; /* PCI device/function number << 3*/
- u_short word8;
- u_short flags;
-#define SYMBIOS_INIT_SCAN_AT_BOOT (1)
- u_short io_port; /* PCI io_port address */
- } host[4];
-
-/* Targets 8 bytes * 16 */
- struct Symbios_target {
- u_short flags;
-#define SYMBIOS_DISCONNECT_ENABLE (1)
-#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1)
-#define SYMBIOS_SCAN_LUNS (1<<2)
-#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3)
- u_char bus_width; /* 0x08/0x10 */
- u_char sync_offset;
- u_char sync_period; /* 4*period factor */
- u_char byte6; /* 0x00 */
- u_short timeout;
- } target[16];
- u_char spare_devices[19*8];
- u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
-};
-typedef struct Symbios_nvram Symbios_nvram;
-typedef struct Symbios_host Symbios_host;
-typedef struct Symbios_target Symbios_target;
-
-/*
-** Tekram NvRAM data format.
-*/
-#define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_NVRAM_ADDRESS 0
-
-struct Tekram_nvram {
- struct Tekram_target {
- u_char flags;
-#define TEKRAM_PARITY_CHECK (1)
-#define TEKRAM_SYNC_NEGO (1<<1)
-#define TEKRAM_DISCONNECT_ENABLE (1<<2)
-#define TEKRAM_START_CMD (1<<3)
-#define TEKRAM_TAGGED_COMMANDS (1<<4)
-#define TEKRAM_WIDE_NEGO (1<<5)
- u_char sync_index;
- u_short word2;
- } target[16];
- u_char host_id;
- u_char flags;
-#define TEKRAM_MORE_THAN_2_DRIVES (1)
-#define TEKRAM_DRIVES_SUP_1GB (1<<1)
-#define TEKRAM_RESET_ON_POWER_ON (1<<2)
-#define TEKRAM_ACTIVE_NEGATION (1<<3)
-#define TEKRAM_IMMEDIATE_SEEK (1<<4)
-#define TEKRAM_SCAN_LUNS (1<<5)
-#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; 1: boot device; 2:all */
- u_char boot_delay_index;
- u_char max_tags_index;
- u_short flags1;
-#define TEKRAM_F2_F6_ENABLED (1)
- u_short spare[29];
-};
-typedef struct Tekram_nvram Tekram_nvram;
-typedef struct Tekram_target Tekram_target;
-
static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-
#endif /* SCSI_NCR_NVRAM_SUPPORT */
/*
@@ -934,6 +823,7 @@ typedef struct {
ncr_slot slot;
ncr_chip chip;
ncr_nvram *nvram;
+ u_char host_id;
int attach_done;
} ncr_device;
@@ -946,7 +836,6 @@ typedef struct {
#define DEBUG_ALLOC (0x0001)
#define DEBUG_PHASE (0x0002)
-#define DEBUG_POLL (0x0004)
#define DEBUG_QUEUE (0x0008)
#define DEBUG_RESULT (0x0010)
#define DEBUG_SCATTER (0x0020)
@@ -955,8 +844,6 @@ typedef struct {
#define DEBUG_TIMING (0x0100)
#define DEBUG_NEGO (0x0200)
#define DEBUG_TAGS (0x0400)
-#define DEBUG_FREEZE (0x0800)
-#define DEBUG_RESTART (0x1000)
/*
** Enable/Disable debug messages.
@@ -1509,7 +1396,7 @@ struct lcb {
*/
u_char ia_tag; /* Allocation index */
u_char if_tag; /* Freeing index */
- u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer */
+ u_char cb_tags[MAX_TAGS]; /* Circular tags buffer */
u_char usetags; /* Command queuing is active */
u_char maxtags; /* Max nr of tags asked by user */
u_char numtags; /* Current number of tags */
@@ -1755,7 +1642,6 @@ struct ccb {
**----------------------------------------------------------------
*/
Scsi_Cmnd *cmd; /* SCSI command */
- u_long tlimit; /* Deadline for this job */
int data_len; /* Total data length */
/*----------------------------------------------------------------
@@ -3777,7 +3663,8 @@ flush_cache_all();
**==========================================================
*/
-static void __init ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
+static void __init
+ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
{
ncrcmd opcode, new, old, tmp1, tmp2;
ncrcmd *start, *end;
@@ -4043,7 +3930,7 @@ ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
tp->usrtags =
- (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+ (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
tp->usrflag |= UF_NODISC;
@@ -4238,9 +4125,11 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
/*
** Get SCSI addr of host adapter (set by bios?).
*/
- if (!np->myaddr) np->myaddr = INB(nc_scid) & 0x07;
- if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR;
-
+ if (np->myaddr == 255) {
+ np->myaddr = INB(nc_scid) & 0x07;
+ if (!np->myaddr)
+ np->myaddr = SCSI_NCR_MYADDR;
+ }
#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
@@ -4250,30 +4139,53 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
ncr_init_burst(np, burst_max);
/*
- ** Set differential mode and LED support.
- ** Ignore these features for boards known to use a
- ** specific GPIO wiring (Tekram only for now).
- ** Probe initial setting of GPREG and GPCNTL for
- ** other ones.
- */
- if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+ ** Set SCSI BUS mode.
+ **
+ ** - ULTRA2 chips (895/895A/896) report the current
+ ** BUS mode through the STEST4 IO register.
+ ** - For previous generation chips (825/825A/875),
+ ** user has to tell us how to check against HVD,
+ ** since a 100% safe algorithm is not possible.
+ */
+ np->scsi_mode = SMODE_SE;
+ if (np->features & FE_ULTRA2)
+ np->scsi_mode = (np->sv_stest4 & SMODE);
+ else if (np->features & FE_DIFF) {
switch(driver_setup.diff_support) {
- case 3:
+ case 4: /* Trust previous settings if present, then GPIO3 */
+ if (np->sv_scntl3) {
+ if (np->sv_stest2 & 0x20)
+ np->scsi_mode = SMODE_HVD;
+ break;
+ }
+ case 3: /* SYMBIOS controllers report HVD through GPIO3 */
+ if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+ break;
if (INB(nc_gpreg) & 0x08)
+ break;
+ case 2: /* Set HVD unconditionally */
+ np->scsi_mode = SMODE_HVD;
+ case 1: /* Trust previous settings for HVD */
+ if (np->sv_stest2 & 0x20)
+ np->scsi_mode = SMODE_HVD;
break;
- case 2:
- np->rv_stest2 |= 0x20;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_stest2 & 0x20);
- break;
- default:
+ default:/* Don't care about HVD */
break;
}
}
+ if (np->scsi_mode == SMODE_HVD)
+ np->rv_stest2 |= 0x20;
+
+ /*
+ ** Set LED support from SCRIPTS.
+ ** Ignore this feature for boards known to use a
+ ** specific GPIO wiring and for the 895A or 896
+ ** that drive the LED directly.
+ ** Also probe initial setting of GPIO0 as output.
+ */
if ((driver_setup.led_pin ||
(nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
- !(np->sv_gpcntl & 0x01))
+ !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
np->features |= FE_LED0;
/*
@@ -4323,7 +4235,7 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
#endif
tp->usrsync = driver_setup.default_sync;
tp->usrwide = driver_setup.max_wide;
- tp->usrtags = SCSI_NCR_MAX_TAGS;
+ tp->usrtags = MAX_TAGS;
if (!driver_setup.disconnection)
np->target[i].usrflag = UF_NODISC;
}
@@ -4507,6 +4419,7 @@ printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
np->clock_divn = device->chip.nr_divisor;
np->maxoffs = device->chip.offset_max;
np->maxburst = device->chip.burst_max;
+ np->myaddr = device->host_id;
np->script0 = (struct script *)
(((u_long) &host_data->script_data) & CACHE_LINE_MASK);
@@ -4594,6 +4507,7 @@ printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
** Fill Linux host instance structure
*/
instance->max_channel = 0;
+ instance->this_id = np->myaddr;
instance->max_id = np->maxwide ? 16 : 8;
instance->max_lun = SCSI_NCR_MAX_LUN;
#ifndef NCR_IOMAPPED
@@ -4604,6 +4518,8 @@ printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
instance->io_port = device->slot.io_port;
instance->n_io_port = 128;
instance->dma_channel = 0;
+ instance->cmd_per_lun = MAX_TAGS;
+ instance->can_queue = (MAX_START-4);
instance->select_queue_depths = ncr53c8xx_select_queue_depths;
/*
@@ -4885,9 +4801,10 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**
**----------------------------------------------------
*/
- if (np->settle_time && cmd->timeout_per_command >= HZ &&
- np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
- np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+ if (np->settle_time && cmd->timeout_per_command >= HZ) {
+ u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+ if (ktime_dif(np->settle_time, tlimit) > 0)
+ np->settle_time = tlimit;
}
if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -4990,7 +4907,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
** Force ordered tag if necessary to avoid timeouts
** and to preserve interactivity.
*/
- if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
+ if (lp && ktime_exp(lp->tags_stime)) {
if (lp->tags_smap) {
order = M_ORDERED_TAG;
if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){
@@ -4998,7 +4915,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
printk("ordered tag forced.\n");
}
}
- lp->tags_stime = jiffies;
+ lp->tags_stime = ktime_get(3*HZ);
lp->tags_smap = lp->tags_umap;
}
@@ -5221,12 +5138,6 @@ flush_cache_all();
/*
** activate this job.
*/
-
- /* Compute a time limit greater than the middle-level driver one */
- if (cmd->timeout_per_command > 0)
- cp->tlimit = jiffies + cmd->timeout_per_command + HZ;
- else
- cp->tlimit = jiffies + 86400 * HZ;/* No timeout=24 hours */
cp->magic = CCB_MAGIC;
//printk("cp == %08lx\n", cp);
dma_cache_wback_inv((unsigned long)cp, sizeof(*cp));
@@ -5337,7 +5248,7 @@ static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
u_int32 term;
int retv = 0;
- np->settle_time = jiffies + settle_delay * HZ;
+ np->settle_time = ktime_get(settle_delay * HZ);
if (bootverbose > 1)
printk("%s: resetting, "
@@ -5512,7 +5423,6 @@ static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd)
** script to abort the command.
*/
- cp->tlimit = 0;
switch(cp->host_status) {
case HS_BUSY:
case HS_NEGOTIATE:
@@ -5710,7 +5620,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
#endif
if (DEBUG_FLAGS & DEBUG_TINY)
- printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+ printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
cp->host_status,cp->scsi_status);
/*
@@ -6732,7 +6642,7 @@ static void ncr_usercmd (ncb_p np)
static void ncr_timeout (ncb_p np)
{
- u_long thistime = jiffies;
+ u_long thistime = ktime_get(0);
/*
** If release process in progress, let's go
@@ -6745,7 +6655,7 @@ static void ncr_timeout (ncb_p np)
return;
}
- np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+ np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
add_timer(&np->timer);
/*
@@ -7040,8 +6950,9 @@ flush_cache_all();
** We are more soft for UDC.
**=========================================================
*/
- if (jiffies - np->regtime > 10*HZ) {
- np->regtime = jiffies;
+
+ if (ktime_exp(np->regtime)) {
+ np->regtime = ktime_get(10*HZ);
for (i = 0; i<sizeof(np->regdump); i++)
((char*)&np->regdump)[i] = INB_OFF(i);
np->regdump.nc_dstat = dstat;
@@ -7159,7 +7070,7 @@ static int ncr_int_sbmc (ncb_p np)
** Suspend command processing for 1 second and
** reinitialize all except the chip.
*/
- np->settle_time = jiffies + HZ;
+ np->settle_time = ktime_get(1*HZ);
ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
return 1;
}
@@ -8292,7 +8203,7 @@ static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
if (lp) {
if (tag != NO_TAG) {
++lp->ia_tag;
- if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+ if (lp->ia_tag == MAX_TAGS)
lp->ia_tag = 0;
lp->tags_umap |= (((tagmap_t) 1) << tag);
}
@@ -8340,7 +8251,7 @@ static void ncr_free_ccb (ncb_p np, ccb_p cp)
if (lp) {
if (cp->tag != NO_TAG) {
lp->cb_tags[lp->if_tag++] = cp->tag;
- if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+ if (lp->if_tag == MAX_TAGS)
lp->if_tag = 0;
lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
lp->tags_smap &= lp->tags_umap;
@@ -8722,10 +8633,10 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
for (i = 0 ; i < 64 ; i++)
lp->jump_ccb[i] =
cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
- for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+ for (i = 0 ; i < MAX_TAGS ; i++)
lp->cb_tags[i] = i;
- lp->maxnxs = SCSI_NCR_MAX_TAGS;
- lp->tags_stime = jiffies;
+ lp->maxnxs = MAX_TAGS;
+ lp->tags_stime = ktime_get(3*HZ);
}
/*
@@ -9254,8 +9165,7 @@ static void __init ncr_getclock (ncb_p np, int mult)
#define ARG_SEP ','
#endif
-
-void __init ncr53c8xx_setup(char *str, int *ints)
+int __init ncr53c8xx_setup(char *str)
{
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
char *cur = str;
@@ -9339,6 +9249,8 @@ void __init ncr53c8xx_setup(char *str, int *ints)
if (xi < SCSI_NCR_MAX_EXCLUDES)
driver_setup.excludes[xi++] = val;
}
+ else if (!strncmp(cur, "hostid:", 7))
+ driver_setup.host_id = val;
else
printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
@@ -9346,8 +9258,15 @@ void __init ncr53c8xx_setup(char *str, int *ints)
++cur;
}
#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+ return 0;
}
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+#endif
+
static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
uchar bus, uchar device_fn, ncr_device *device);
@@ -9517,7 +9436,7 @@ int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
if (ncr53c8xx)
- ncr53c8xx_setup(ncr53c8xx, (int *) 0);
+ ncr53c8xx_setup(ncr53c8xx);
#endif
if (initverbose >= 2)
@@ -9564,6 +9483,7 @@ if (ncr53c8xx)
#else
device[count].nvram = 0;
#endif
+ device[count].host_id = driver_setup.host_id;
if (ncr53c8xx_pci_init(tpnt, bus, device_fn, &device[count])) {
device[count].nvram = 0;
continue;
@@ -9614,10 +9534,40 @@ if (ncr53c8xx)
** Return the offset immediately after the base address that has
** been read. Btw, we blindly assume that the high 32 bits of 64 bit
** base addresses are set to zero on 32 bit architectures.
-** (the pci generic code now does this for us)
**
*/
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
+static int __init
+pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
+{
+ u_int32 tmp;
+ pcibios_read_config_dword(bus, device_fn, offset, &tmp);
+ *base = tmp;
+ offset += sizeof(u_int32);
+ if ((tmp & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+ pcibios_read_config_dword(bus, device_fn, offset, &tmp);
+ *base |= (((u_long)tmp) << 32);
+#endif
+ offset += sizeof(u_int32);
+ }
+ return offset;
+}
+#elif LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+ *base = pdev->base_address[index++];
+ if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+ *base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
+ ++index;
+ }
+ return index;
+}
+#else /* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
static int __init
pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
{
@@ -9626,6 +9576,7 @@ pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
++index;
return ++index;
}
+#endif
/*
** Read and check the PCI configuration for any detected NCR
@@ -9633,7 +9584,6 @@ pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
** been detected.
*/
-
static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
uchar bus, uchar device_fn, ncr_device *device)
{
@@ -9809,6 +9759,9 @@ static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
* each and every PCI card, if they don't use Fcode?
*/
+ base = __pa(base);
+ base_2 = __pa(base_2);
+
if (!(command & PCI_COMMAND_MASTER)) {
if (initverbose >= 2)
printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
@@ -9837,7 +9790,7 @@ static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
}
if (!latency_timer) {
- latency_timer = 64;
+ latency_timer = 128;
if (initverbose >= 2)
printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
pcibios_write_config_byte(bus, device_fn,
@@ -9849,8 +9802,6 @@ static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
/*
* Check availability of IO space, memory space and master capability.
- * No need to test BARs flags since they are hardwired to the
- * expected value.
*/
if (command & PCI_COMMAND_IO)
io_port &= PCI_BASE_ADDRESS_IO_MASK;
@@ -10140,8 +10091,8 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
device->queue_depth = numtags;
if (device->queue_depth < 2)
device->queue_depth = 2;
- if (device->queue_depth > SCSI_NCR_MAX_TAGS)
- device->queue_depth = SCSI_NCR_MAX_TAGS;
+ if (device->queue_depth > MAX_TAGS)
+ device->queue_depth = MAX_TAGS;
/*
** Since the queue depth is not tunable under Linux,
@@ -10627,8 +10578,6 @@ printk("ncr_user_command: data=%ld\n", uc->data);
uc->data |= DEBUG_ALLOC;
else if ((arg_len = is_keyword(ptr, len, "phase")))
uc->data |= DEBUG_PHASE;
- else if ((arg_len = is_keyword(ptr, len, "poll")))
- uc->data |= DEBUG_POLL;
else if ((arg_len = is_keyword(ptr, len, "queue")))
uc->data |= DEBUG_QUEUE;
else if ((arg_len = is_keyword(ptr, len, "result")))
@@ -10645,10 +10594,6 @@ printk("ncr_user_command: data=%ld\n", uc->data);
uc->data |= DEBUG_NEGO;
else if ((arg_len = is_keyword(ptr, len, "tags")))
uc->data |= DEBUG_TAGS;
- else if ((arg_len = is_keyword(ptr, len, "freeze")))
- uc->data |= DEBUG_FREEZE;
- else if ((arg_len = is_keyword(ptr, len, "restart")))
- uc->data |= DEBUG_RESTART;
else
return -EINVAL;
ptr += arg_len; len -= arg_len;
@@ -10764,7 +10709,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
(u_long) np->reg);
#endif
copy_info(&info, " Synchronous period factor %d, ", (int) np->minsync);
- copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+ copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
if (driver_setup.debug || driver_setup.verbose > 1) {
copy_info(&info, " Debug flags 0x%x, ", driver_setup.debug);
@@ -10941,8 +10886,8 @@ static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
nvram_stop(np, &gpreg);
#ifdef SCSI_NCR_DEBUG_NVRAM
-printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
- nvram->start_marker,
+printk("ncr53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+ nvram->type,
nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
nvram->byte_count, sizeof(*nvram) - 12,
@@ -10950,7 +10895,7 @@ printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d ch
#endif
/* check valid NVRAM signature, verify byte count and checksum */
- if (nvram->start_marker == 0 &&
+ if (nvram->type == 0 &&
!memcmp(nvram->trailer, Symbios_trailer, 6) &&
nvram->byte_count == sizeof(*nvram) - 12 &&
csum == nvram->checksum)
@@ -10966,8 +10911,8 @@ out:
/*
* Read Symbios NvRAM data and compute checksum.
*/
-static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len,
- u_char *gpreg, u_char *gpcntl)
+static u_short __init
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
{
int x;
u_short csum;
@@ -10996,9 +10941,8 @@ static void __init nvram_start(ncr_slot *np, u_char *gpreg)
* WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
* GPIO0 must already be set as an output
*/
-static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data,
- u_char write_data, u_char *gpreg,
- u_char *gpcntl)
+static void __init
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
{
int x;
@@ -11012,9 +10956,8 @@ static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data,
* READ a byte from the NVRAM and then send an ACK to say we have got it,
* GPIO0 must already be set as an input
*/
-static void __init nvram_read_byte(ncr_slot *np, u_char *read_data,
- u_char ack_data, u_char *gpreg,
- u_char *gpcntl)
+static void __init
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
{
int x;
u_char read_bit;
@@ -11032,8 +10975,8 @@ static void __init nvram_read_byte(ncr_slot *np, u_char *read_data,
* Output an ACK to the NVRAM after reading,
* change GPIO0 to output and when done back to an input
*/
-static void __init nvram_writeAck(ncr_slot *np, u_char write_bit,
- u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
{
OUTB (nc_gpcntl, *gpcntl & 0xfe);
nvram_doBit(np, 0, write_bit, gpreg);
@@ -11044,8 +10987,8 @@ static void __init nvram_writeAck(ncr_slot *np, u_char write_bit,
* Input an ACK from NVRAM after writing,
* change GPIO0 to input and when done back to an output
*/
-static void __init nvram_readAck(ncr_slot *np, u_char *read_bit,
- u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
{
OUTB (nc_gpcntl, *gpcntl | 0x01);
nvram_doBit(np, read_bit, 1, gpreg);
@@ -11056,8 +10999,7 @@ static void __init nvram_readAck(ncr_slot *np, u_char *read_bit,
* Read or write a bit to the NVRAM,
* read if GPIO0 input else write if GPIO0 output
*/
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit,
- u_char write_bit, u_char *gpreg)
+static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
{
nvram_setBit(np, write_bit, gpreg, SET_BIT);
nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11079,8 +11021,8 @@ static void __init nvram_stop(ncr_slot *np, u_char *gpreg)
/*
* Set/clear data/clock bit in GPIO0
*/
-static void __init nvram_setBit(ncr_slot *np, u_char write_bit,
- u_char *gpreg, int bit_mode)
+static void __init
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
{
UDELAY (5);
switch (bit_mode){
@@ -11166,8 +11108,8 @@ static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
/*
* Read Tekram NvRAM data and compute checksum.
*/
-static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len,
- u_char *gpreg)
+static u_short __init
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
{
u_char read_bit;
u_short csum;
@@ -11192,8 +11134,7 @@ static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len,
/*
* Send read command and address to NVRAM
*/
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data,
- u_char *read_bit, u_char *gpreg)
+static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
{
int x;
@@ -11207,8 +11148,7 @@ static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data,
/*
* READ a byte from the NVRAM
*/
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data,
- u_char *gpreg)
+static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
{
int x;
u_char read_bit;
@@ -11227,8 +11167,8 @@ static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data,
/*
* Read bit from NVRAM
*/
-static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit,
- u_char *gpreg)
+static void __init
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
{
UDELAY (2);
Tnvram_Clk(np, gpreg);
@@ -11238,8 +11178,8 @@ static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit,
/*
* Write bit to GPIO0
*/
-static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit,
- u_char *gpreg)
+static void __init
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
{
if (write_bit & 0x01)
*gpreg |= 0x02;
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index dbd078299..d9abefc1b 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -176,10 +176,38 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
}
/*
- * This interface is depreciated - users should use the scsi generics
+ * This interface is depreciated - users should use the scsi generic (sg)
* interface instead, as this is a more flexible approach to performing
* generic SCSI commands on a device.
+ *
+ * The structure that we are passed should look like:
+ *
+ * struct sdata {
+ * unsigned int inlen; [i] Length of data to be written to device
+ * unsigned int outlen; [i] Length of data to be read from device
+ * unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12).
+ * [o] Data read from device starts here.
+ * [o] On error, sense buffer starts here.
+ * unsigned char wdata[y]; [i] Data written to device starts here.
+ * };
+ * Notes:
+ * - The SCSI command length is determined by examining the 1st byte
+ * of the given command. There is no way to override this.
+ * - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
+ * - The length (x + y) must be at least OMAX_SB_LEN bytes long to
+ * accomodate the sense buffer when an error occurs.
+ * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
+ * old code will not be surprised.
+ * - If a Unix error occurs (e.g. ENOMEM) then the user will receive
+ * a negative return and the Unix error code in 'errno'.
+ * If the SCSI command succeeds then 0 is returned.
+ * Positive numbers returned are the compacted SCSI error codes (4
+ * bytes in one int) where the lowest byte is the SCSI status.
+ * See the drivers/scsi/scsi.h file for more information on this.
+ *
*/
+#define OMAX_SB_LEN 16 /* Old sense buffer length */
+
int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
{
unsigned long flags;
@@ -195,8 +223,6 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (!sic)
return -EINVAL;
-
-
/*
* Verify that we can read at least this much.
*/
@@ -204,23 +230,13 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
if (result)
return result;
- /*
- * The structure that we are passed should look like:
- *
- * struct sdata {
- * unsigned int inlen;
- * unsigned int outlen;
- * unsigned char cmd[]; # However many bytes are used for cmd.
- * unsigned char data[];
- * };
- */
get_user(inlen, &sic->inlen);
get_user(outlen, &sic->outlen);
/*
* We do not transfer more than MAX_BUF with this interface.
* If the user needs to transfer more data than this, they
- * should use scsi_generics instead.
+ * should use scsi_generics (sg) instead.
*/
if (inlen > MAX_BUF)
return -EINVAL;
@@ -249,19 +265,16 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
*/
cmdlen = COMMAND_SIZE(opcode);
- result = verify_area(VERIFY_READ, cmd_in,
- cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
+ result = verify_area(VERIFY_READ, cmd_in, cmdlen + inlen);
if (result)
return result;
- copy_from_user((void *) cmd, cmd_in, cmdlen);
+ copy_from_user(cmd, cmd_in, cmdlen);
/*
* Obtain the data to be sent to the device (if any).
*/
- copy_from_user((void *) buf,
- (void *) (cmd_in + cmdlen),
- inlen);
+ copy_from_user(buf, cmd_in + cmdlen, inlen);
/*
* Set the lun field to the correct value.
@@ -311,19 +324,18 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
* If there was an error condition, pass the info back to the user.
*/
if (SCpnt->result) {
- result = verify_area(VERIFY_WRITE,
- cmd_in,
- sizeof(SCpnt->sense_buffer));
+ int sb_len = sizeof(SCpnt->sense_buffer);
+
+ sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
+ result = verify_area(VERIFY_WRITE, cmd_in, sb_len);
if (result)
return result;
- copy_to_user((void *) cmd_in,
- SCpnt->sense_buffer,
- sizeof(SCpnt->sense_buffer));
+ copy_to_user(cmd_in, SCpnt->sense_buffer, sb_len);
} else {
result = verify_area(VERIFY_WRITE, cmd_in, outlen);
if (result)
return result;
- copy_to_user((void *) cmd_in, buf, outlen);
+ copy_to_user(cmd_in, buf, outlen);
}
result = SCpnt->result;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9864b94ef..4a2258cb5 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -16,41 +16,28 @@
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.34 (990603)";
- static int sg_version_num = 20134; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.3.35 (990708)";
+ static int sg_version_num = 20335; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
* the kernel/module needs to be built with CONFIG_SCSI_LOGGING
- * (otherwise the macros compile to empty statements), then do
- * something like: 'echo "scsi log all" > /proc/scsi/scsi' to log
- * everything or 'echo "scsi log {token} #N" > /proc/scsi/scsi'
- * where {token} is one of [error,timeout,scan,mlqueue,mlcomplete,
- * llqueue,llcomplete,hlqueue,hlcomplete,ioctl] and #N is 0...7
- * (with 0 meaning off). For example: 'scsi log timeout 7 >
- * /proc/scsi/scsi' to get all logging messages from this driver.
- * Should use hlcomplete but it is too "noisy" (sd uses it).
- *
- * - This driver obtains memory (heap) for the low-level driver to
- * transfer/dma to and from. It is obtained from up to 3 sources:
- * - obtain heap via get_free_pages()
- * - obtain heap from the shared scsi dma pool
- * - obtain heap from kernel directly (kmalloc) [last choice]
- * Each open() attempts to obtain a "reserve" buffer of
- * SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
- * amount actually obtained [which could be 0 bytes] can be found from
- * the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
- * be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
- * is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
- * ioctl() to find out how much was actually obtained.
- * A subsequent write() to this file descriptor will use the
- * reserved buffer unless:
- * - it is already in use (eg during command queuing)
- * - or the write() needs a buffer size larger than the
- * reserved size
- * In these cases the write() will attempt to get the required memory
- * for the duration of this request but, if memory is low, it may
- * fail with ENOMEM.
+ * (otherwise the macros compile to empty statements).
+ * Then before running the program to be debugged enter:
+ * # echo "scsi log timeout 7" > /proc/scsi/scsi
+ * This will send copious output to the console and the log which
+ * is usually /var/log/messages. To turn off debugging enter:
+ * # echo "scsi log timeout 0" > /proc/scsi/scsi
+ * The 'timeout' token was chosen because it is relatively unused.
+ * The token 'hlcomplete' should be used but that triggers too
+ * much output from the sd device driver. To dump the current
+ * state of the SCSI mid level data structures enter:
+ * # echo "scsi dump 1" > /proc/scsi/scsi
+ * To dump the state of sg's data structures get the 'sg_debug'
+ * program from the utilities and enter:
+ * # sg_debug /dev/sga
+ * or any valid sg device name. The state of _all_ sg devices
+ * will be sent to the console and the log.
*
* - The 'alt_address' field in the scatter_list structure and the
* related 'mem_src' indicate the source of the heap allocation.
@@ -146,7 +133,8 @@ typedef struct sg_fd /* holds the state of a file descriptor */
{
struct sg_fd * nextfp; /* NULL when last opened fd on this device */
struct sg_device * parentdp; /* owning device */
- wait_queue_head_t read_wait; /* queue read until command done */
+ wait_queue_head_t read_wait; /* queue read until command done */
+ wait_queue_head_t write_wait; /* write waits on pending read */
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
Sg_scatter_hold reserve; /* buffer held for this file descriptor */
unsigned save_scat_len; /* original length of trunc. scat. element */
@@ -160,7 +148,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
-} Sg_fd; /* 1208 bytes long on i386 */
+} Sg_fd; /* 1212 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
{
@@ -212,7 +200,6 @@ static Sg_device * sg_dev_arr = NULL;
static const int size_sg_header = sizeof(struct sg_header);
-
static int sg_open(struct inode * inode, struct file * filp)
{
int dev = MINOR(inode->i_rdev);
@@ -360,6 +347,8 @@ static ssize_t sg_read(struct file * filp, char * buf,
count = (srp->header.result == 0) ? 0 : -EIO;
sg_finish_rem_req(srp, NULL, 0);
}
+ if (! sfp->cmd_q)
+ wake_up_interruptible(&sfp->write_wait);
return count;
}
@@ -391,10 +380,21 @@ static ssize_t sg_write(struct file * filp, const char * buf,
if (count < (size_sg_header + 6))
return -EIO; /* The minimum scsi command length is 6 bytes. */
- srp = sg_add_request(sfp);
- if (! srp) {
- SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
- return -EDOM;
+ if (! (srp = sg_add_request(sfp))) {
+ if (sfp->cmd_q) {
+ SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
+ return -EDOM;
+ }
+ else { /* old semantics: wait for pending read() to finish */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ k = 0;
+ __wait_event_interruptible(sfp->write_wait,
+ (srp = sg_add_request(sfp)),
+ k);
+ if (k)
+ return k; /* -ERESTARTSYS because signal hit process */
+ }
}
__copy_from_user(&srp->header, buf, size_sg_header);
buf += size_sg_header;
@@ -404,7 +404,7 @@ static ssize_t sg_write(struct file * filp, const char * buf,
if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
sfp->next_cmd_len = 0;
- return -EDOM;
+ return -EIO;
}
cmd_size = sfp->next_cmd_len;
sfp->next_cmd_len = 0; /* reset so only this write() effected */
@@ -490,7 +490,12 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
switch(cmd_in)
{
case SG_SET_TIMEOUT:
- return get_user(sfp->timeout, (int *)arg);
+ result = get_user(val, (int *)arg);
+ if (result) return result;
+ if (val < 0)
+ return -EIO;
+ sfp->timeout = val;
+ return 0;
case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */
return sfp->timeout; /* strange ..., for backward compatibility */
case SG_SET_FORCE_LOW_DMA:
@@ -519,9 +524,12 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
__put_user((int)sdp->device->id, &sg_idp->scsi_id);
__put_user((int)sdp->device->lun, &sg_idp->lun);
__put_user((int)sdp->device->type, &sg_idp->scsi_type);
+ __put_user((short)sdp->device->host->cmd_per_lun,
+ &sg_idp->h_cmd_per_lun);
+ __put_user((short)sdp->device->queue_depth,
+ &sg_idp->d_queue_depth);
__put_user(0, &sg_idp->unused1);
__put_user(0, &sg_idp->unused2);
- __put_user(0, &sg_idp->unused3);
return 0;
}
case SG_SET_FORCE_PACK_ID:
@@ -605,6 +613,13 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
return put_user(sg_version_num, (int *)arg);
case SG_EMULATED_HOST:
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
+ case SG_SCSI_RESET:
+ if (! scsi_block_when_processing_errors(sdp->device))
+ return -EBUSY;
+ result = get_user(val, (int *)arg);
+ if (result) return result;
+ /* Don't do anything till scsi mod level visibility */
+ return 0;
case SCSI_IOCTL_SEND_COMMAND:
/* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
user already has read/write access to the generic device and so
@@ -686,6 +701,9 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
Sg_fd * sfp;
Sg_request * srp = NULL;
int closed = 0;
+ static const int min_sb_len =
+ SG_MAX_SENSE > sizeof(SCpnt->sense_buffer) ?
+ sizeof(SCpnt->sense_buffer) : SG_MAX_SENSE;
if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max)) {
SCSI_LOG_TIMEOUT(1, printk("sg__done: bad args dev=%d\n", dev));
@@ -727,8 +745,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
- memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
- sizeof(SCpnt->sense_buffer));
+ memcpy(srp->header.sense_buffer, SCpnt->sense_buffer, min_sb_len);
switch (host_byte(SCpnt->result))
{ /* This setup of 'result' is for backward compatibility and is best
ignored by the user who should use target, host + driver status */
@@ -798,7 +815,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
/* Now wake up any sg_read() that is waiting for this packet. */
wake_up_interruptible(&sfp->read_wait);
if ((sfp->async_qp) && (! closed))
- kill_fasync(sfp->async_qp, SIGPOLL);
+ kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN);
}
static void sg_debug_all(const Sg_fd * sfp)
@@ -1491,13 +1508,15 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
return sdp->headfp;
}
sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0);
- if (!sfp)
- return NULL;
-
- memset(sfp, 0, sizeof(Sg_fd));
- sfp->my_mem_src = SG_HEAP_KMAL;
-
- init_waitqueue_head(&sfp->read_wait);
+ if (sfp) {
+ memset(sfp, 0, sizeof(Sg_fd));
+ sfp->my_mem_src = SG_HEAP_KMAL;
+ init_waitqueue_head(&sfp->read_wait);
+ init_waitqueue_head(&sfp->write_wait);
+ }
+ else
+ return NULL;
+
sfp->timeout = SG_DEFAULT_TIMEOUT;
sfp->force_packid = SG_DEF_FORCE_PACK_ID;
sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
new file mode 100644
index 000000000..68785fea6
--- /dev/null
+++ b/drivers/scsi/sim710.c
@@ -0,0 +1,1605 @@
+/*
+ * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------------
+ *
+ * MCA card detection code by Trent McNair.
+ *
+ * Various bits of code in this driver have been copied from 53c7,8xx,c,
+ * which is coyright Drew Eckhardt. The scripts for the SCSI chip are
+ * compiled with the script compiler written by Drew.
+ *
+ * This is a simple driver for the NCR53c710. More complex drivers
+ * for this chip (e.g. 53c7xx.c) require that the scsi chip be able to
+ * do DMA block moves between memory and on-chip registers, which can
+ * be a problem if those registers are in the I/O address space. There
+ * can also be problems on hardware where the registers are memory
+ * mapped, if the design is such that memory-to-memory transfers initiated
+ * by the scsi chip cannot access the chip registers.
+ *
+ * This driver is designed to avoid these problems and is intended to
+ * work with any Intel machines using 53c710 chips, including various
+ * Compaq and NCR machines. It was initially written for the Tadpole
+ * TP34V VME board which is 68030 based.
+ *
+ * The driver supports boot-time parameters similar to
+ * sim710=addr:0x9000,irq:15
+ * and insmod parameters similar to
+ * sim710="addr:0x9000 irq:15"
+ *
+ * The complete list of options are:
+ *
+ * addr:0x9000 Specifies the base I/O port (or address) of the 53C710.
+ * irq:15 Specifies the IRQ number used by the 53c710.
+ * debug:0xffff Generates lots of debug output.
+ * ignore:0x0a Makes the driver ignore SCSI IDs 0 and 2.
+ * nodisc:0x70 Prevents disconnects from IDs 6, 5 and 4.
+ * noneg:0x10 Prevents SDTR negotiation on ID 4.
+ *
+ * Current limitations:
+ *
+ * o Async only
+ * o Severely lacking in error recovery
+ * o Auto detection of IRQs and chip addresses only on MCA architectures
+ *
+ */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
+#endif
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_TP34V_SCSI
+
+#include <asm/tp34vhw.h>
+#define MEM_MAPPED
+
+#elif defined(CONFIG_MCA)
+
+#define IO_MAPPED
+
+/*
+ * For each known microchannel card using the 53c710 we need a list
+ * of possible IRQ and IO settings, as well as their corresponding
+ * bit assignment in pos[]. This might get cumbersome if there
+ * are more than a few cards (I only know of 2 at this point).
+ */
+
+#define MCA_53C710_IDS { 0x01bb, 0x01ba, 0x004f }
+
+/* CARD ID 01BB and 01BA use the same pos values */
+
+#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
+ 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
+ 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
+ 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000 }
+
+#define MCA_01BB_IRQS { 3, 5, 11, 14 }
+
+/* CARD ID 004f */
+
+#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600 }
+
+#define MCA_004F_IRQS { 5, 9, 14 }
+
+#else
+
+/* Assume an Intel platform */
+
+#define IO_MAPPED
+
+#endif
+
+#include "scsi.h"
+#include "hosts.h"
+#include "sim710.h"
+
+#include<linux/stat.h>
+
+#define DEBUG
+#undef DEBUG_LIMIT_INTS /* Define to 10 to hang driver after 10 ints */
+
+/* Debug options available via the "debug:0x1234" parameter */
+
+#define DEB_NONE 0x0000 /* Nothing */
+#define DEB_HALT 0x0001 /* Detailed trace of chip halt funtion */
+#define DEB_REGS 0x0002 /* All chip register read/writes */
+#define DEB_SYNC 0x0004 /* Sync/async negotiation */
+#define DEB_PMM 0x0008 /* Phase mis-match handling */
+#define DEB_INTS 0x0010 /* General interrupt trace */
+#define DEB_TOUT 0x0020 /* Selection timeouts */
+#define DEB_RESUME 0x0040 /* Resume addresses for the script */
+#define DEB_CMND 0x0080 /* Commands and status returned */
+#define DEB_FIXUP 0x0100 /* Fixup of scsi addresses */
+#define DEB_DISC 0x0200 /* Disconnect/reselect handling */
+
+#define DEB_ANY 0xffff /* Any and all debug options */
+
+#ifdef DEBUG
+#define DEB(m,x) if (sim710_debug & m) x
+int sim710_debug = 0;
+#else
+#define DEB(m,x)
+#endif
+
+/* Redefine scsi_done to force renegotiation of (a)sync transfers
+ * following any failed command.
+ */
+
+#define SCSI_DONE(cmd) { \
+ DEB(DEB_CMND, printk("scsi%d: Complete %08x\n", \
+ host->host_no, cmd->result)); \
+ if (cmd->result) \
+ hostdata->negotiate |= (1 << cmd->target); \
+ cmd->scsi_done(cmd); \
+ }
+
+#ifndef offsetof
+#define offsetof(t, m) ((size_t) (&((t *)0)->m))
+#endif
+
+
+struct proc_dir_entry proc_scsi_sim710 = {
+ PROC_SCSI_SIM710, 6, "sim710",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+#define STATE_INITIALISED 0
+#define STATE_HALTED 1
+#define STATE_IDLE 2
+#define STATE_BUSY 3
+#define STATE_DISABLED 4
+
+#define MAXBOARDS 2 /* Increase this and the sizes of the
+ arrays below, if you need more.. */
+
+#ifdef MODULE
+
+char *sim710; /* command line passed by insmod */
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("Simple NCR53C710 driver");
+MODULE_PARM(sim710, "s");
+
+#endif
+
+static int sim710_errors = 0; /* Count of error interrupts */
+static int sim710_intrs = 0; /* Count of all interrupts */
+static int ignore_ids = 0; /* Accept all SCSI IDs */
+static int opt_nodisc = 0; /* Allow disconnect on all IDs */
+static int opt_noneg = 0; /* Allow SDTR negotiation on all IDs */
+
+#ifdef CONFIG_TP34V_SCSI
+
+/* Special hardwired case for Tadpole TP34V at the moment, otherwise
+ * boot parameters 'sim710=addr:0x8000,irq:15' (for example) must be given.
+ */
+
+static int no_of_boards = 2;
+
+static unsigned int bases[MAXBOARDS] = {
+ TP34V_SCSI0_BASE, TP34V_SCSI1_BASE
+};
+static unsigned int irq_vectors[MAXBOARDS] = {
+ TP34V_SCSI0_VECTOR, TP34V_SCSI1_VECTOR
+};
+static unsigned int irq_index[MAXBOARDS] = {
+ TP34V_SCSI0_IRQ_INDEX, TP34V_SCSI1_IRQ_INDEX
+};
+
+#else
+
+/* All other cases use boot/module params, or auto-detect */
+
+static int no_of_boards = 0;
+
+static unsigned int bases[MAXBOARDS] = {
+ 0
+};
+static unsigned int irq_vectors[MAXBOARDS] = {
+ 0
+};
+
+#endif
+
+/* The SCSI Script!!! */
+
+#include "sim710_d.h"
+
+/* Now define offsets in the DSA, as (A_dsa_xxx/4) */
+
+#define DSA_SELECT (A_dsa_select/4)
+#define DSA_MSGOUT (A_dsa_msgout/4)
+#define DSA_CMND (A_dsa_cmnd/4)
+#define DSA_STATUS (A_dsa_status/4)
+#define DSA_MSGIN (A_dsa_msgin/4)
+#define DSA_DATAIN (A_dsa_datain/4)
+#define DSA_DATAOUT (A_dsa_dataout/4)
+#define DSA_SIZE (A_dsa_size/4)
+
+#define MAX_SG 128 /* Scatter/Gather elements */
+
+
+#define MAX_MSGOUT 8
+#define MAX_MSGIN 8
+#define MAX_CMND 12
+#define MAX_STATUS 1
+
+struct sim710_hostdata{
+ int state;
+ Scsi_Cmnd * issue_queue;
+ Scsi_Cmnd * running;
+ int chip;
+ u8 negotiate;
+ u8 reselected_identify;
+ u8 msgin_buf[MAX_MSGIN];
+
+ struct sim710_target {
+ Scsi_Cmnd *cur_cmd;
+ u32 resume_offset;
+ u32 data_in_jump;
+ u32 data_out_jump;
+ u32 dsa[DSA_SIZE]; /* SCSI Script DSA area */
+ u8 dsa_msgout[MAX_MSGOUT];
+ u8 dsa_msgin[MAX_MSGIN];
+ u8 dsa_cdb[MAX_CMND];
+ u8 dsa_status[MAX_STATUS];
+ } target[8];
+
+ u32 script[sizeof(SCRIPT)/4] __attribute__ ((aligned (4)));
+};
+
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+ EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */};
+
+
+static void sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static void do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs);
+static __inline__ void run_process_issue_queue(struct sim710_hostdata *);
+static void process_issue_queue (struct sim710_hostdata *, unsigned long flags);
+static int full_reset(struct Scsi_Host * host);
+
+/*
+ * Function: void sim710_setup(char *str, int *ints)
+ */
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+void
+sim710_setup(char *str, int *ints)
+{
+ char *cur = str;
+ char *pc, *pv;
+ int val;
+ int base;
+ int c;
+
+ no_of_boards = 0;
+ while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+ char *pe;
+
+ val = 0;
+ pv = pc;
+ c = *++pv;
+
+ if (c == 'n')
+ val = 0;
+ else if (c == 'y')
+ val = 1;
+ else {
+ base = 0;
+ val = (int) simple_strtoul(pv, &pe, base);
+ }
+ if (!strncmp(cur, "addr:", 5)) {
+ bases[0] = val;
+ no_of_boards = 1;
+ }
+ else if (!strncmp(cur, "irq:", 4))
+ irq_vectors[0] = val;
+ else if (!strncmp(cur, "ignore:", 7))
+ ignore_ids = val;
+ else if (!strncmp(cur, "nodisc:", 7))
+ opt_nodisc = val;
+ else if (!strncmp(cur, "noneg:", 6))
+ opt_noneg = val;
+ else if (!strncmp(cur, "disabled:", 5)) {
+ no_of_boards = -1;
+ return;
+ }
+#ifdef DEBUG
+ else if (!strncmp(cur, "debug:", 6)) {
+ sim710_debug = val;
+ }
+#endif
+ else
+ printk("sim710_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+
+ if ((cur = strchr(cur, ARG_SEP)) != NULL)
+ ++cur;
+ }
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sim710=", sim710_setup);
+#endif
+#endif
+
+/*
+ * Function: static const char *sbcl_to_phase (int sbcl)
+ */
+
+static const char *
+sbcl_to_phase (int sbcl) {
+ switch (sbcl & SBCL_PHASE_MASK) {
+ case SBCL_PHASE_DATAIN:
+ return "DATAIN";
+ case SBCL_PHASE_DATAOUT:
+ return "DATAOUT";
+ case SBCL_PHASE_MSGIN:
+ return "MSGIN";
+ case SBCL_PHASE_MSGOUT:
+ return "MSGOUT";
+ case SBCL_PHASE_CMDOUT:
+ return "CMDOUT";
+ case SBCL_PHASE_STATIN:
+ return "STATUSIN";
+ default:
+ return "unknown";
+ }
+}
+
+
+/*
+ * Function: static void disable (struct Scsi_Host *host)
+ */
+
+static void
+disable (struct Scsi_Host *host)
+{
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+ host->hostdata[0];
+
+ hostdata->state = STATE_DISABLED;
+ printk (KERN_ALERT "scsi%d : disabled. Unload and reload\n",
+ host->host_no);
+}
+
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ *
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int
+ncr_halt (struct Scsi_Host *host)
+{
+ unsigned long flags;
+ unsigned char istat, tmp;
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+ host->hostdata[0];
+ int stage;
+
+ save_flags(flags);
+ cli();
+ /* Stage 0 : eat all interrupts
+ Stage 1 : set ABORT
+ Stage 2 : eat all but abort interrupts
+ Stage 3 : eat all interrupts
+ */
+ for (stage = 0;;) {
+ if (stage == 1) {
+ DEB(DEB_HALT, printk("ncr_halt: writing ISTAT_ABRT\n"));
+ NCR_write8(ISTAT_REG, ISTAT_ABRT);
+ ++stage;
+ }
+ istat = NCR_read8 (ISTAT_REG);
+ if (istat & ISTAT_SIP) {
+ DEB(DEB_HALT, printk("ncr_halt: got ISTAT_SIP, istat=%02x\n", istat));
+ tmp = NCR_read8(SSTAT0_REG);
+ DEB(DEB_HALT, printk("ncr_halt: got SSTAT0_REG=%02x\n", tmp));
+ } else if (istat & ISTAT_DIP) {
+ DEB(DEB_HALT, printk("ncr_halt: got ISTAT_DIP, istat=%02x\n", istat));
+ tmp = NCR_read8(DSTAT_REG);
+ DEB(DEB_HALT, printk("ncr_halt: got DSTAT_REG=%02x\n", tmp));
+ if (stage == 2) {
+ if (tmp & DSTAT_ABRT) {
+ DEB(DEB_HALT, printk("ncr_halt: got DSTAT_ABRT, clearing istat\n"));
+ NCR_write8(ISTAT_REG, 0);
+ ++stage;
+ } else {
+ printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
+ host->host_no);
+ disable (host);
+ }
+ }
+ }
+ if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
+ if (stage == 0)
+ ++stage;
+ else if (stage == 3)
+ break;
+ }
+ }
+ hostdata->state = STATE_HALTED;
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * Function : static void sim710_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose : perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : sim710_init must have been called for this
+ * host.
+ *
+ */
+
+static void
+sim710_soft_reset (struct Scsi_Host *host)
+{
+ unsigned long flags;
+#ifdef CONFIG_TP34V_SCSI
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+ host->hostdata[0];
+#endif
+
+ save_flags(flags);
+ cli();
+#ifdef CONFIG_TP34V_SCSI
+ tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x80;
+#endif
+ /*
+ * Do a soft reset of the chip so that everything is
+ * reinitialized to the power-on state.
+ *
+ * Basically follow the procedure outlined in the NCR53c700
+ * data manual under Chapter Six, How to Use, Steps Necessary to
+ * Start SCRIPTS, with the exception of actually starting the
+ * script and setting up the synchronous transfer gunk.
+ */
+
+ /* XXX Should we reset the scsi bus here? */
+
+ NCR_write8(SCNTL1_REG, SCNTL1_RST); /* Reset the bus */
+ udelay(50);
+ NCR_write8(SCNTL1_REG, 0);
+
+ udelay(500);
+
+ NCR_write8(ISTAT_REG, ISTAT_10_SRST); /* Reset the chip */
+ udelay(50);
+ NCR_write8(ISTAT_REG, 0);
+
+ mdelay(1000); /* Let devices recover */
+
+ NCR_write8(DCNTL_REG, DCNTL_10_COM | DCNTL_700_CF_3);
+ NCR_write8(CTEST7_REG, CTEST7_10_CDIS|CTEST7_STD);
+ NCR_write8(DMODE_REG, DMODE_10_BL_8 | DMODE_10_FC2);
+ NCR_write8(SCID_REG, 1 << host->this_id);
+ NCR_write8(SBCL_REG, 0);
+ NCR_write8(SXFER_REG, 0);
+ NCR_write8(SCNTL1_REG, SCNTL1_ESR_700);
+ NCR_write8(SCNTL0_REG, SCNTL0_EPC | SCNTL0_EPG_700 | SCNTL0_ARB1 |
+ SCNTL0_ARB2);
+
+ NCR_write8(DIEN_REG, DIEN_700_BF |
+ DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+ NCR_write8(SIEN_REG_700,
+ SIEN_PAR | SIEN_700_STO | SIEN_RST | SIEN_UDC | SIEN_SGE | SIEN_MA);
+
+
+#ifdef CONFIG_TP34V_SCSI
+ tpvic.loc_icr[irq_index[hostdata->chip]].icr = 0x30 | TP34V_SCSI0n1_IPL;
+#endif
+
+ restore_flags(flags);
+}
+
+
+/*
+ * Function : static void sim710_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or
+ * after a SCSI bus reset.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void
+sim710_driver_init (struct Scsi_Host *host)
+{
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+ host->hostdata[0];
+ int i;
+
+ hostdata->running = NULL;
+ memcpy (hostdata->script, SCRIPT, sizeof(SCRIPT));
+ for (i = 0; i < PATCHES; i++)
+ hostdata->script[LABELPATCHES[i]] += virt_to_bus(hostdata->script);
+ patch_abs_32 (hostdata->script, 0, reselected_identify,
+ virt_to_bus((void *)&(hostdata->reselected_identify)));
+ patch_abs_32 (hostdata->script, 0, msgin_buf,
+ virt_to_bus((void *)&(hostdata->msgin_buf[0])));
+ hostdata->state = STATE_INITIALISED;
+ hostdata->negotiate = 0xff;
+}
+
+
+/* Handle incoming Synchronous data transfer request. If our negotiate
+ * flag is set then this is a response to our request, otherwise it is
+ * spurious request from the target. Don't really expect target initiated
+ * SDTRs, because we always negotiate on the first command. Could still
+ * get them though..
+ * The chip is currently paused with ACK asserted o the last byte of the
+ * SDTR.
+ * resa is the resume address if the message is in response to our outgoing
+ * SDTR. Only possible on initial identify.
+ * resb is the resume address if the message exchange is initiated by the
+ * target.
+ */
+
+static u32
+handle_sdtr (struct Scsi_Host * host, Scsi_Cmnd * cmd, u32 resa, u32 resb)
+{
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+ struct sim710_target *targdata = hostdata->target + cmd->target;
+ u32 resume_offset;
+
+ if (resa && hostdata->negotiate & (1 << cmd->target)) {
+ DEB(DEB_SYNC, printk("scsi%d: Response to host SDTR = %02x %02x\n",
+ host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));
+ /* We always issue an SDTR with the identify, so we must issue
+ * the CDB next.
+ */
+ resume_offset = resa;
+ hostdata->negotiate &= ~(1 << cmd->target);
+ }
+ else {
+ DEB(DEB_SYNC, printk("scsi%d: Target initiated SDTR = %02x %02x\n",
+ host->host_no, hostdata->msgin_buf[3], hostdata->msgin_buf[4]));
+ memcpy(targdata->dsa_msgout, async_message, sizeof(async_message));
+ targdata->dsa[DSA_MSGOUT] = sizeof(async_message);
+ /* I guess the target could do this anytime; we have to send our
+ * response, and then continue (sending the CDB if not already done).
+ */
+ resume_offset = resb;
+ }
+ return resume_offset;
+}
+
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+ int count, synchronous, sstat;
+ unsigned int ddir;
+
+ count = ((NCR_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+ (NCR_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+ synchronous = NCR_read8 (SXFER_REG) & SXFER_MO_MASK;
+ ddir = NCR_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+ if (ddir) {
+ /* Receive */
+ if (synchronous)
+ count += (NCR_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+ else
+ if (NCR_read8 (SSTAT1_REG) & SSTAT1_ILF)
+ ++count;
+ } else {
+ /* Send */
+ sstat = NCR_read8 (SSTAT1_REG);
+ if (sstat & SSTAT1_OLF)
+ ++count;
+ if (synchronous && (sstat & SSTAT1_ORF))
+ ++count;
+ }
+ return count;
+}
+
+
+static u32
+handle_idd (struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+ struct sim710_hostdata *hostdata =
+ (struct sim710_hostdata *)host->hostdata[0];
+ struct sim710_target *targdata = hostdata->target + cmd->target;
+ u32 resume_offset = 0, index;
+
+ index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);
+
+ switch (index) {
+ case Ent_wait_disc_complete/4 + 2:
+ cmd->result = targdata->dsa_status[0];
+ SCSI_DONE(cmd);
+ targdata->cur_cmd = NULL;
+ resume_offset = Ent_reselect;
+ break;
+ case Ent_wait_disc2/4 + 2:
+ /* Disconnect after command - just wait for a reselect */
+ targdata->resume_offset = Ent_resume_msgin2a;
+ resume_offset = Ent_reselect;
+ break;
+ case Ent_wait_disc3/4 + 2:
+ /* Disconnect after the data phase */
+ targdata->resume_offset = Ent_resume_msgin3a;
+ resume_offset = Ent_reselect;
+ break;
+ case Ent_wait_disc1/4 + 2:
+ /* Disconnect before command - not expected */
+ targdata->resume_offset = Ent_resume_msgin1a;
+ resume_offset = Ent_reselect;
+ break;
+ default:
+ printk("scsi%d: Unexpected Illegal Instruction, script[%04x]\n",
+ host->host_no, index);
+ sim710_errors++;
+ /* resume_offset is zero, which will cause host reset */
+ }
+ return resume_offset;
+}
+
+
+/* Handle a phase mismatch.
+ */
+
+static u32
+handle_phase_mismatch (struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+ struct sim710_hostdata *hostdata =
+ (struct sim710_hostdata *)host->hostdata[0];
+ struct sim710_target *targdata = hostdata->target + cmd->target;
+ u32 resume_offset = 0, index;
+ unsigned char sbcl;
+
+ sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+ index = (u32)((u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script);
+
+ DEB(DEB_PMM, printk("scsi%d: Phase mismatch, phase %s (%x) at script[0x%x]\n",
+ host->host_no, sbcl_to_phase(sbcl), sbcl, index));
+ DEB(DEB_PMM, print_command(cmd->cmnd));
+
+ if (index == Ent_done_ident/4) {
+ /* Sending initial message out - probably rejecting our sync
+ * negotiation request.
+ */
+ NCR_write8(SOCL_REG, 0); /* Negate ATN */
+ if (sbcl == SBCL_PHASE_MSGIN)
+ resume_offset = Ent_resume_rej_ident;
+ else if (sbcl == SBCL_PHASE_CMDOUT) {
+ /* Some old devices (SQ555) switch to cmdout after the first
+ * byte of an identify message, regardless of whether we
+ * have more bytes to send!
+ */
+ printk("scsi%d: Unexpected switch to CMDOUT during IDENTIFY\n",
+ host->host_no);
+ resume_offset = Ent_resume_cmd;
+ }
+ else {
+ printk("scsi%d: Unexpected phase change to %s on initial msgout\n",
+ host->host_no, sbcl_to_phase(sbcl));
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ hostdata->negotiate &= ~(1 << cmd->target);
+ }
+ else if (index > Ent_patch_input_data/4 &&
+ index < Ent_patch_output_data/4) {
+ /* DataIn transfer phase */
+ u32 sg_id, oaddr, olen, naddr, nlen;
+ int residual;
+
+ sg_id = (index - Ent_patch_input_data/4 - 4) / 2;
+ targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] =
+ virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_id * 2 + 2);
+ olen = targdata->dsa[DSA_DATAIN + sg_id * 2];
+ oaddr = targdata->dsa[DSA_DATAIN + sg_id * 2 + 1];
+ residual = datapath_residual (host);
+ if (residual)
+ printk("scsi%d: Residual count %d on DataIn - NOT expected!!!",
+ host->host_no, residual);
+ naddr = NCR_read32(DNAD_REG) - residual;
+ nlen = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;
+ DEB(DEB_PMM, printk("scsi%d: DIN sg %d, old %08x/%08x, new %08x/%08x (%d)\n",
+ host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));
+ if (oaddr+olen != naddr+nlen) {
+ printk("scsi%d: PMM DIN counts error: 0x%x + 0x%x != 0x%x + 0x%x",
+ host->host_no, oaddr, olen, naddr, nlen);
+ }
+ else {
+ targdata->dsa[DSA_DATAIN + sg_id * 2] = nlen;
+ targdata->dsa[DSA_DATAIN + sg_id * 2 + 1] = naddr;
+ resume_offset = Ent_resume_pmm;
+ }
+ }
+ else if (index > Ent_patch_output_data/4 &&
+ index <= Ent_end_data_trans/4) {
+ /* Dataout transfer phase */
+ u32 sg_id, oaddr, olen, naddr, nlen;
+ int residual;
+
+ sg_id = (index - Ent_patch_output_data/4 - 4) / 2;
+ targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] =
+ virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_id * 2 + 2);
+ olen = targdata->dsa[DSA_DATAOUT + sg_id * 2];
+ oaddr = targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1];
+ residual = datapath_residual (host);
+ naddr = NCR_read32(DNAD_REG) - residual;
+ nlen = (NCR_read32(DBC_REG) & 0x00ffffff) + residual;
+ DEB(DEB_PMM, printk("scsi%d: DOUT sg %d, old %08x/%08x, new %08x/%08x (%d)\n",
+ host->host_no, sg_id, oaddr, olen, naddr, nlen, residual));
+ if (oaddr+olen != naddr+nlen) {
+ printk("scsi%d: PMM DOUT counts error: 0x%x + 0x%x != 0x%x + 0x%x",
+ host->host_no, oaddr, olen, naddr, nlen);
+ }
+ else {
+ targdata->dsa[DSA_DATAOUT + sg_id * 2] = nlen;
+ targdata->dsa[DSA_DATAOUT + sg_id * 2 + 1] = naddr;
+ resume_offset = Ent_resume_pmm;
+ }
+ }
+ else {
+ printk("scsi%d: Unexpected phase change to %s at index 0x%x\n",
+ host->host_no, sbcl_to_phase(sbcl), index);
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ /* Flush DMA FIFO */
+ NCR_write8 (CTEST8_REG, CTEST8_10_CLF);
+ while (NCR_read8 (CTEST8_REG) & CTEST8_10_CLF);
+
+ return resume_offset;
+}
+
+
+static u32
+handle_script_int(struct Scsi_Host * host, Scsi_Cmnd * cmd)
+{
+ struct sim710_hostdata *hostdata =
+ (struct sim710_hostdata *)host->hostdata[0];
+ struct sim710_target *targdata = hostdata->target + cmd->target;
+ u32 dsps, resume_offset = 0;
+ unsigned char sbcl;
+
+ dsps = NCR_read32(DSPS_REG);
+
+ switch (dsps) {
+ case A_int_cmd_complete:
+ cmd->result = targdata->dsa_status[0];
+ SCSI_DONE(cmd);
+ targdata->cur_cmd = NULL;
+ resume_offset = Ent_reselect;
+ break;
+ case A_int_msg_sdtr1:
+ resume_offset = handle_sdtr(host, cmd,
+ Ent_resume_msgin1a, Ent_resume_msgin1b);
+ break;
+ case A_int_msg_sdtr2:
+ resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin2b);
+ break;
+ case A_int_msg_sdtr3:
+ resume_offset = handle_sdtr(host, cmd, 0, Ent_resume_msgin3b);
+ break;
+ case A_int_disc1:
+ /* Disconnect before command - not expected */
+ targdata->resume_offset = Ent_resume_msgin1a;
+ resume_offset = Ent_reselect;
+ break;
+ case A_int_disc2:
+ /* Disconnect after command - just wait for a reselect */
+ targdata->resume_offset = Ent_resume_msgin2a;
+ resume_offset = Ent_reselect;
+ break;
+ case A_int_disc3:
+ /* Disconnect after the data phase */
+ targdata->resume_offset = Ent_resume_msgin3a;
+ resume_offset = Ent_reselect;
+ break;
+ case A_int_reselected:
+ hostdata->script[Ent_patch_output_data/4+1] = targdata->data_out_jump;
+ hostdata->script[Ent_patch_input_data/4+1] = targdata->data_in_jump;
+ NCR_write32(DSA_REG, virt_to_bus(targdata->dsa));
+ resume_offset = targdata->resume_offset;
+ break;
+ case A_int_data_bad_phase:
+ sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+ printk("scsi%d: int_data_bad_phase, phase %s (%x)\n",
+ host->host_no, sbcl_to_phase(sbcl), sbcl);
+ break;
+ case A_int_bad_extmsg1a:
+ case A_int_bad_extmsg1b:
+ case A_int_bad_extmsg2a:
+ case A_int_bad_extmsg2b:
+ case A_int_bad_extmsg3a:
+ case A_int_bad_extmsg3b:
+ case A_int_bad_msg1:
+ case A_int_bad_msg2:
+ case A_int_bad_msg3:
+ case A_int_cmd_bad_phase:
+ case A_int_no_msgout1:
+ case A_int_no_msgout2:
+ case A_int_no_msgout3:
+ case A_int_not_cmd_complete:
+ case A_int_sel_no_ident:
+ case A_int_sel_not_cmd:
+ case A_int_status_not_msgin:
+ case A_int_resel_not_msgin:
+ case A_int_selected:
+ case A_int_not_rej:
+ default:
+ sbcl = NCR_read8(SBCL_REG) & SBCL_PHASE_MASK;
+ printk("scsi%d: Unimplemented script interrupt: %08x, phase %s\n",
+ host->host_no, dsps, sbcl_to_phase(sbcl));
+ sim710_errors++;
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ return resume_offset;
+}
+
+
+/* A quick wrapper for sim710_intr_handle to grab the spin lock */
+
+static void
+do_sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ sim710_intr_handle(irq, dev_id, regs);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+/* A "high" level interrupt handler */
+
+static void
+sim710_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int flags;
+ struct Scsi_Host * host = (struct Scsi_Host *)dev_id;
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+ Scsi_Cmnd * cmd;
+ unsigned char istat, dstat;
+ unsigned char sstat0;
+ u32 dsps, resume_offset = 0;
+
+ save_flags(flags);
+ cli();
+ sim710_intrs++;
+ while ((istat = NCR_read8(ISTAT_REG)) & (ISTAT_SIP|ISTAT_DIP)) {
+ dsps = NCR_read32(DSPS_REG);
+ hostdata->state = STATE_HALTED;
+ sstat0 = dstat = 0;
+ if (istat & ISTAT_SIP) {
+ sstat0 = NCR_read8(SSTAT0_REG);
+ }
+ if (istat & ISTAT_DIP) {
+ udelay(10); /* Some comment somewhere about 10cycles
+ * between accesses to sstat0 and dstat ??? */
+ dstat = NCR_read8(DSTAT_REG);
+ }
+ DEB(DEB_INTS, printk("scsi%d: Int %d, istat %02x, sstat0 %02x "
+ "dstat %02x, dsp [%04x], scratch %02x\n",
+ host->host_no, sim710_intrs, istat, sstat0, dstat,
+ (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
+ NCR_read32(SCRATCH_REG)));
+ if ((dstat & DSTAT_SIR) && dsps == A_int_reselected) {
+ /* Reselected. Identify the target from LCRC_REG, and
+ * update current command. If we were trying to select
+ * a device, then that command needs to go back on the
+ * issue_queue for later.
+ */
+ unsigned char lcrc = NCR_read8(LCRC_REG_10);
+ int id = 0;
+
+ if (!(lcrc & 0x7f)) {
+ printk("scsi%d: Reselected with LCRC = %02x\n",
+ host->host_no, lcrc);
+ cmd = NULL;
+ }
+ else {
+ while (!(lcrc & 1)) {
+ id++;
+ lcrc >>= 1;
+ }
+ DEB(DEB_DISC, printk("scsi%d: Reselected by ID %d\n",
+ host->host_no, id));
+ if (hostdata->running) {
+ /* Clear SIGP */
+ (void)NCR_read8(CTEST2_REG_700);
+
+ DEB(DEB_DISC, printk("scsi%d: Select of %d interrupted "
+ "by reselect from %d (%p)\n",
+ host->host_no, hostdata->running->target,
+ id, hostdata->target[id].cur_cmd));
+ cmd = hostdata->running;
+ hostdata->target[cmd->target].cur_cmd = NULL;
+ cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ }
+ cmd = hostdata->running = hostdata->target[id].cur_cmd;
+ }
+ }
+ else
+ cmd = hostdata->running;
+
+ if (!cmd) {
+ printk("scsi%d: No active command!\n", host->host_no);
+ printk("scsi%d: Int %d, istat %02x, sstat0 %02x "
+ "dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n",
+ host->host_no, sim710_intrs, istat, sstat0, dstat,
+ (u32 *)(bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script,
+ NCR_read32(SCRATCH_REG), dsps);
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ else if (sstat0 & SSTAT0_700_STO) {
+ DEB(DEB_TOUT, printk("scsi%d: Selection timeout\n", host->host_no));
+ cmd->result = DID_NO_CONNECT << 16;
+ SCSI_DONE(cmd);
+ hostdata->target[cmd->target].cur_cmd = NULL;
+ resume_offset = Ent_reselect;
+ }
+ else if (dstat & DSTAT_SIR)
+ resume_offset = handle_script_int(host, cmd);
+ else if (sstat0 & SSTAT0_MA) {
+ resume_offset = handle_phase_mismatch(host, cmd);
+ }
+ else if (sstat0 & (SSTAT0_MA|SSTAT0_SGE|SSTAT0_UDC|SSTAT0_RST|SSTAT0_PAR)) {
+ printk("scsi%d: Serious error, sstat0 = %02x\n", host->host_no,
+ sstat0);
+ sim710_errors++;
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ else if (dstat & (DSTAT_BF|DSTAT_ABRT|DSTAT_SSI|DSTAT_WTD)) {
+ printk("scsi%d: Serious error, dstat = %02x\n", host->host_no,
+ dstat);
+ sim710_errors++;
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ else if (dstat & DSTAT_IID) {
+ /* This can be due to a quick reselect while doing a WAIT
+ * DISCONNECT.
+ */
+ resume_offset = handle_idd(host, cmd);
+ }
+ else {
+ sim710_errors++;
+ printk("scsi%d: Spurious interrupt!\n", host->host_no);
+ /* resume_offset is zero, which will cause a host reset */
+ }
+ }
+
+ if (resume_offset) {
+ if (resume_offset == Ent_reselect) {
+ hostdata->running = NULL;
+ hostdata->state = STATE_IDLE;
+ }
+ else
+ hostdata->state = STATE_BUSY;
+ DEB(DEB_RESUME, printk("scsi%d: Resuming at script[0x%x]\n",
+ host->host_no, resume_offset/4));
+#ifdef DEBUG_LIMIT_INTS
+ if (sim710_intrs < DEBUG_LIMIT_INTS)
+#endif
+ NCR_write32(DSP_REG, virt_to_bus(hostdata->script+resume_offset/4));
+ if (resume_offset == Ent_reselect)
+ run_process_issue_queue(hostdata);
+ }
+ else {
+ printk("scsi%d: Failed to handle interrupt. Failing commands "
+ "and resetting SCSI bus and chip\n", host->host_no);
+ mdelay(4000); /* Give chance to read screen!! */
+ full_reset(host);
+ }
+
+ restore_flags(flags);
+}
+
+
+static void
+run_command (struct sim710_hostdata *hostdata, Scsi_Cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->host;
+ struct sim710_target *targdata = hostdata->target + cmd->target;
+ int i, datain, dataout, sg_start;
+ u32 *dip, *dop, dsa;
+
+ DEB(DEB_CMND, printk("scsi%d: id%d starting ", host->host_no,
+ cmd->target));
+ DEB(DEB_CMND, print_command(cmd->cmnd));
+
+ switch (cmd->cmnd[0]) {
+ case INQUIRY:
+ case MODE_SENSE:
+ case READ_6:
+ case READ_10:
+ case READ_CAPACITY:
+ case REQUEST_SENSE:
+ case READ_BLOCK_LIMITS:
+ case READ_TOC:
+ datain = 1;
+ dataout = 0;
+ break;
+ case MODE_SELECT:
+ case WRITE_6:
+ case WRITE_10:
+ datain = 0;
+ dataout = 1;
+ break;
+ case TEST_UNIT_READY:
+ case ALLOW_MEDIUM_REMOVAL:
+ case START_STOP:
+ datain = dataout = 0;
+ break;
+ default:
+ datain = dataout = 1;
+ }
+
+ memcpy(targdata->dsa_cdb, cmd->cmnd, MAX_CMND);
+
+ targdata->dsa_msgout[0] =
+ IDENTIFY((opt_nodisc & (1<<cmd->target)) ? 0 : 1 ,0);
+ if (hostdata->negotiate & (1 << cmd->target)) {
+ if (opt_noneg & (1 << cmd->target)) {
+ hostdata->negotiate ^= (1 << cmd->target);
+ targdata->dsa[DSA_MSGOUT] = 1;
+ }
+ else {
+ DEB(DEB_SYNC, printk("scsi%d: Negotiating async transfers "
+ "for ID %d\n",
+ host->host_no, cmd->target));
+ memcpy(targdata->dsa_msgout+1, async_message, sizeof(async_message));
+ targdata->dsa[DSA_MSGOUT] = sizeof(async_message) + 1;
+ }
+ }
+ else
+ targdata->dsa[DSA_MSGOUT] = 1;
+
+ targdata->dsa_msgin[0] = 0xff;
+ targdata->dsa_status[0] = 0xff;
+
+ targdata->dsa[DSA_SELECT] = (1 << cmd->target) << 16;
+ targdata->dsa[DSA_MSGOUT+1] = virt_to_bus(targdata->dsa_msgout);
+ targdata->dsa[DSA_CMND] = cmd->cmd_len;
+ targdata->dsa[DSA_CMND+1] = virt_to_bus(targdata->dsa_cdb);
+ targdata->dsa[DSA_STATUS] = 1;
+ targdata->dsa[DSA_STATUS+1] = virt_to_bus(targdata->dsa_status);
+ targdata->dsa[DSA_MSGIN] = 1;
+ targdata->dsa[DSA_MSGIN+1] = virt_to_bus(targdata->dsa_msgin);
+
+ sg_start = (MAX_SG - (cmd->use_sg ? cmd->use_sg : 1)) * 2;
+ dip = targdata->dsa + DSA_DATAIN + sg_start;
+ dop = targdata->dsa + DSA_DATAOUT + sg_start;
+
+ for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; i++) {
+ u32 vbuf = cmd->use_sg ?
+ (u32)(((struct scatterlist *)cmd->buffer)[i].address) :
+ (u32)(cmd->request_buffer);
+ u32 bbuf = virt_to_bus((void *)vbuf);
+ u32 cnt = cmd->use_sg ?
+ ((struct scatterlist *)cmd->buffer)[i].length :
+ cmd->request_bufflen;
+
+ if (datain) {
+#ifdef CONFIG_TP34V_SCSI
+ cache_clear(virt_to_phys((void *)vbuf), cnt);
+#endif
+ *dip++ = cnt;
+ *dip++ = bbuf;
+ }
+ if (dataout) {
+#ifdef CONFIG_TP34V_SCSI
+ cache_push(virt_to_phys((void *)vbuf), cnt);
+#endif
+ *dop++ = cnt;
+ *dop++ = bbuf;
+ }
+ }
+ targdata->data_out_jump = hostdata->script[Ent_patch_output_data/4+1] =
+ virt_to_bus(hostdata->script + Ent_patch_output_data/4 + sg_start + 2);
+ targdata->data_in_jump = hostdata->script[Ent_patch_input_data/4+1] =
+ virt_to_bus(hostdata->script + Ent_patch_input_data/4 + sg_start + 2);
+
+ for (i = 0, dsa = virt_to_bus(targdata->dsa); i < 4; i++) {
+ u32 v = hostdata->script[Ent_patch_new_dsa/4 + i * 2];
+
+ v &= ~0x0000ff00;
+ v |= (dsa & 0xff) << 8;
+ hostdata->script[Ent_patch_new_dsa/4 + i * 2] = v;
+ dsa >>= 8;
+ }
+ hostdata->running = targdata->cur_cmd = cmd;
+ hostdata->state = STATE_BUSY;
+
+ NCR_write8(ISTAT_REG, ISTAT_10_SIGP);
+}
+
+
+static volatile int process_issue_queue_running = 0;
+
+static __inline__ void
+run_process_issue_queue(struct sim710_hostdata *hostdata)
+{
+ unsigned long flags;
+ save_flags (flags);
+ cli();
+ if (!process_issue_queue_running) {
+ process_issue_queue_running = 1;
+ process_issue_queue(hostdata, flags);
+ /*
+ * process_issue_queue_running is cleared in process_issue_queue
+ * once it can't do more work, and process_issue_queue exits with
+ * interrupts disabled.
+ */
+ }
+ restore_flags (flags);
+}
+
+
+/*
+ * Function : process_issue_queue (hostdata, flags)
+ *
+ * Purpose : Start next command for any idle target.
+ *
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the
+ * caller must reenable them if it desires.
+ *
+ * NOTE : process_issue_queue should be called from both
+ * sim710_queue_command() and from the interrupt handler
+ * after command completion.
+ */
+
+static void
+process_issue_queue (struct sim710_hostdata *hostdata, unsigned long flags)
+{
+ Scsi_Cmnd *tmp, *prev;
+ int done;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set process_issue_queue_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ */
+
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+ if (hostdata->issue_queue) {
+ if (hostdata->state == STATE_DISABLED) {
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+ tmp->result = (DID_BAD_TARGET << 16);
+ tmp->scsi_done (tmp);
+ done = 0;
+ }
+ else if (hostdata->state == STATE_IDLE) {
+ for (tmp = hostdata->issue_queue, prev = NULL; tmp;
+ prev = tmp, tmp = (Scsi_Cmnd *) tmp->SCp.ptr) {
+ if (hostdata->target[tmp->target].cur_cmd == NULL) {
+ if (prev)
+ prev->SCp.ptr = tmp->SCp.ptr;
+ else
+ hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+ tmp->SCp.ptr = NULL;
+ run_command (hostdata, tmp);
+ done = 0;
+ } /* if target/lun is not busy */
+ } /* scan issue queue for work */
+ } /* host is idle */
+ } /* if hostdata->issue_queue */
+ if (!done)
+ restore_flags (flags);
+ } while (!done);
+ process_issue_queue_running = 0;
+}
+
+
+int
+sim710_queuecommand(Scsi_Cmnd * cmd, void (*done)(Scsi_Cmnd *))
+{
+ struct Scsi_Host *host = cmd->host;
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)host->hostdata[0];
+ Scsi_Cmnd *tmp;
+ unsigned long flags;
+
+ if (cmd->lun) {
+ /* Silently ignore luns other than zero! */
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ return 0;
+ }
+
+ DEB(DEB_CMND, printk("scsi%d: id%d queuing ", host->host_no,
+ cmd->target));
+ DEB(DEB_CMND, print_command(cmd->cmnd));
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->SCp.ptr = NULL;
+ cmd->SCp.buffer = NULL;
+
+ save_flags(flags);
+ cli();
+
+ if (ignore_ids & (1 << cmd->target)) {
+ printk("scsi%d: ignoring target %d\n", host->host_no, cmd->target);
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+#ifdef DEBUG_LIMIT_INTS
+ if (sim710_intrs > DEBUG_LIMIT_INTS) {
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ restore_flags (flags);
+ return 0;
+ }
+#endif
+ if (cmd->use_sg > MAX_SG)
+ panic ("cmd->use_sg = %d\n", cmd->use_sg);
+
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = hostdata->issue_queue; tmp->SCp.ptr;
+ tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+ tmp->SCp.ptr = (unsigned char *) cmd;
+ }
+ restore_flags (flags);
+ run_process_issue_queue(hostdata);
+ return 0;
+}
+
+
+int
+sim710_detect(Scsi_Host_Template * tpnt)
+{
+ unsigned char irq_vector;
+ unsigned char scsi_id;
+ unsigned int base_addr;
+ struct Scsi_Host * host = NULL;
+ struct sim710_hostdata *hostdata;
+ int chips = 0;
+ int indx;
+ int revision;
+ int order, size;
+
+#ifdef MODULE
+ if (sim710)
+ sim710_setup(sim710, (int *)0);
+#endif
+
+ if (no_of_boards < 0) {
+ printk("sim710: NCR53C710 driver disabled\n");
+ return 0;
+ }
+
+#ifdef CONFIG_MCA
+ /* If board details have been specified via boot/module parameters,
+ * then don't bother probing.
+ */
+ if (no_of_boards == 0) {
+ int slot;
+ int pos[3];
+ int mca_53c710_ids[] = MCA_53C710_IDS;
+ int *id_to_check = mca_53c710_ids;
+ static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
+ static int irq_004f_by_pos[] = MCA_004F_IRQS;
+ static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
+ static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
+
+ while ( *id_to_check && no_of_boards < MAXBOARDS) {
+ if (!MCA_bus)
+ return 0;
+
+ if ((slot = mca_find_adapter(*id_to_check, 0)) != MCA_NOTFOUND) {
+
+ pos[0] = mca_read_stored_pos(slot, 2);
+ pos[1] = mca_read_stored_pos(slot, 3);
+ pos[2] = mca_read_stored_pos(slot, 4);
+
+ /*
+ * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2]
+ *
+ * 000000 <disabled> 001010 0x2800
+ * 000001 <invalid> 001011 0x2C00
+ * 000010 0x0800 001100 0x3000
+ * 000011 0x0C00 001101 0x3400
+ * 000100 0x1000 001110 0x3800
+ * 000101 0x1400 001111 0x3C00
+ * 000110 0x1800 010000 0x4000
+ * 000111 0x1C00 010001 0x4400
+ * 001000 0x2000 010010 0x4800
+ * 001001 0x2400 010011 0x4C00
+ * 010100 0x5000
+ *
+ * 00F4 port base by bits 3,2,1 in pos[0]
+ *
+ * 000 <disabled> 001 0x200
+ * 010 0x300 011 0x400
+ * 100 0x500 101 0x600
+ *
+ * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6:
+ *
+ * 00 3 10 11
+ * 01 5 11 14
+ *
+ * 00F4 IRQ specified by bits 6,5,4 in pos[0]
+ *
+ * 100 5 101 9
+ * 110 14
+ */
+
+ if ( *id_to_check == 0x01bb || *id_to_check == 0x01ba ) {
+ bases[no_of_boards] = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
+ irq_vectors[no_of_boards] =
+ irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
+ if (bases[no_of_boards] == 0x0000)
+ printk("sim710: NCR53C710 Adapter ID 0x01bb is disabled.\n");
+ else {
+ no_of_boards++;
+ if ( *id_to_check == 0x01bb )
+ mca_set_adapter_name( slot,
+ "NCR 3360/3430 SCSI SubSystem" );
+ else
+ mca_set_adapter_name(slot,
+ "NCR Dual SIOP SCSI Host Adapter Board");
+ }
+ }
+ else if ( *id_to_check == 0x004f ) {
+ bases[no_of_boards] = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
+ irq_vectors[no_of_boards] =
+ irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
+ if (bases[no_of_boards] == 0x0000)
+ printk("sim710: NCR53C710 Adapter ID 0x004f is disabled.\n");
+ else {
+ no_of_boards++;
+ mca_set_adapter_name(slot,
+ "NCR 53c710 SCSI Host Adapter Board");
+ }
+ }
+ }
+ id_to_check++;
+ }
+ }
+#endif
+
+ if (!no_of_boards) {
+ printk("sim710: No NCR53C710 adapter found.\n");
+ return 0;
+ }
+
+ size = sizeof(struct sim710_hostdata);
+ order = 0;
+ while (size > (PAGE_SIZE << order))
+ order++;
+ size = PAGE_SIZE << order;
+
+ DEB(DEB_ANY, printk("sim710: hostdata %d bytes, size %d, order %d\n",
+ sizeof(struct sim710_hostdata), size, order));
+
+ tpnt->proc_dir = &proc_scsi_sim710;
+
+ for(indx = 0; indx < no_of_boards; indx++) {
+ host = scsi_register(tpnt, 4);
+ host->hostdata[0] = __get_free_pages(GFP_ATOMIC, order);
+ if (host->hostdata[0] == 0)
+ panic ("sim710: Couldn't get hostdata memory");
+ hostdata = (struct sim710_hostdata *)host->hostdata[0];
+ memset(hostdata, 0, size);
+#ifdef CONFIG_TP34V_SCSI
+ cache_push(virt_to_phys(hostdata), size);
+ cache_clear(virt_to_phys(hostdata), size);
+ kernel_set_cachemode((void *)hostdata,size,IOMAP_NOCACHE_SER);
+#endif
+ scsi_id = 7;
+ base_addr = bases[indx];
+ irq_vector = irq_vectors[indx];
+ printk("sim710: Configuring Sim710 (SCSI-ID %d) at %x, IRQ %d\n",
+ scsi_id, base_addr, irq_vector);
+ DEB(DEB_ANY, printk("sim710: hostdata = %p (%d bytes), dsa0 = %p\n",
+ hostdata, sizeof(struct sim710_hostdata),
+ hostdata->target[0].dsa));
+ hostdata->chip = indx;
+ host->irq = irq_vector;
+ host->this_id = scsi_id;
+ host->unique_id = base_addr;
+ host->base = (char *)base_addr;
+
+ ncr_halt(host);
+
+ revision = (NCR_read8(CTEST8_REG) & 0xF0) >> 4;
+ printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+ sim710_soft_reset(host);
+
+ sim710_driver_init(host);
+
+#ifdef CONFIG_TP34V_SCSI
+ if (request_irq(irq_vector,do_sim710_intr_handle, 0, "sim710", host))
+#else
+ if (request_irq(irq_vector,do_sim710_intr_handle, SA_INTERRUPT, "sim710", host))
+#endif
+ {
+ printk("scsi%d : IRQ%d not free, detaching\n",
+ host->host_no, host->irq);
+
+ scsi_unregister (host);
+ }
+ else {
+#ifdef IO_MAPPED
+ request_region((u32)host->base, 64, "sim710");
+#endif
+ chips++;
+ }
+ NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
+ hostdata->state = STATE_IDLE;
+ }
+ return chips;
+}
+
+int
+sim710_abort(Scsi_Cmnd * cmd)
+{
+ struct Scsi_Host * host = cmd->host;
+
+ printk("scsi%d: Unable to abort command for target %d\n",
+ host->host_no, cmd->target);
+ return FAILED;
+}
+
+/*
+ * This is a device reset. Need to select and send a Bus Device Reset msg.
+ */
+
+int
+sim710_dev_reset(Scsi_Cmnd * SCpnt)
+{
+ struct Scsi_Host * host = SCpnt->host;
+
+ printk("scsi%d: Unable to send Bus Device Reset for target %d\n",
+ host->host_no, SCpnt->target);
+ return FAILED;
+}
+
+/*
+ * This is bus reset. We need to reset the bus and fail any active commands.
+ */
+
+int
+sim710_bus_reset(Scsi_Cmnd * SCpnt)
+{
+ struct Scsi_Host * host = SCpnt->host;
+
+ printk("scsi%d: Unable to do SCSI bus reset\n", host->host_no);
+ return FAILED;
+}
+
+static int
+full_reset(struct Scsi_Host * host)
+{
+ struct sim710_hostdata *hostdata = (struct sim710_hostdata *)
+ host->hostdata[0];
+ int target;
+ Scsi_Cmnd *cmd;
+
+ ncr_halt(host);
+ printk("scsi%d: dsp = %08x (script[0x%04x]), scratch = %08x\n",
+ host->host_no, NCR_read32(DSP_REG),
+ ((u32)bus_to_virt(NCR_read32(DSP_REG)) - (u32)hostdata->script)/4,
+ NCR_read32(SCRATCH_REG));
+
+ for (target = 0; target < 7; target++) {
+ if ((cmd = hostdata->target[target].cur_cmd)) {
+ printk("scsi%d: Failing command for ID%d\n",
+ host->host_no, target);
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ hostdata->target[target].cur_cmd = NULL;
+ }
+ }
+
+ sim710_soft_reset(host);
+ sim710_driver_init(host);
+
+ NCR_write32(DSP_REG, virt_to_bus(hostdata->script+Ent_reselect/4));
+ hostdata->state = STATE_IDLE;
+
+ run_process_issue_queue(hostdata);
+
+ return SUCCESS;
+}
+
+/*
+ * This is host reset. We need to reset the chip and the bus.
+ */
+
+int
+sim710_host_reset(Scsi_Cmnd * SCpnt)
+{
+ struct Scsi_Host * host = SCpnt->host;
+
+ printk("scsi%d: >>>>>>>>>>>> Host reset <<<<<<<<<<<<\n", host->host_no);
+
+ return full_reset(host);
+}
+
+#ifdef MODULE
+
+int
+sim710_release(struct Scsi_Host *host)
+{
+ free_irq(host->irq, host);
+#ifdef IO_MAPPED
+ release_region((u32)host->base, 64);
+#endif
+ return 1;
+}
+
+Scsi_Host_Template driver_template = SIM710_SCSI;
+
+#include "scsi_module.c"
+#endif
diff --git a/drivers/scsi/sim710.h b/drivers/scsi/sim710.h
new file mode 100644
index 000000000..5511ed455
--- /dev/null
+++ b/drivers/scsi/sim710.h
@@ -0,0 +1,845 @@
+#ifndef _SIM710_H
+#define _SIM710_H
+
+/*
+ * sim710.h - Copyright (C) 1999 Richard Hirst
+ */
+
+#include <linux/types.h>
+
+int sim710_detect(Scsi_Host_Template *);
+int sim710_command(Scsi_Cmnd *);
+int sim710_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int sim710_abort(Scsi_Cmnd * SCpnt);
+int sim710_bus_reset(Scsi_Cmnd * SCpnt);
+int sim710_dev_reset(Scsi_Cmnd * SCpnt);
+int sim710_host_reset(Scsi_Cmnd * SCpnt);
+int sim710_biosparam(Disk *, kdev_t, int*);
+#ifdef MODULE
+int sim710_release(struct Scsi_Host *);
+#else
+#define sim710_release NULL
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE)
+#include <scsi/scsicam.h>
+
+extern struct proc_dir_entry proc_scsi_sim710;
+
+#define SIM710_SCSI { proc_dir: &proc_scsi_sim710, \
+ name: "Simple 53c710", \
+ detect: sim710_detect, \
+ release: sim710_release, \
+ queuecommand: sim710_queuecommand, \
+ eh_abort_handler: sim710_abort, \
+ eh_device_reset_handler: sim710_dev_reset, \
+ eh_bus_reset_handler: sim710_bus_reset, \
+ eh_host_reset_handler: sim710_host_reset, \
+ bios_param: scsicam_bios_param, \
+ can_queue: 8, \
+ this_id: 7, \
+ sg_tablesize: 128, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING, \
+ use_new_eh_code: 1}
+
+#endif
+
+#ifndef HOSTS_C
+
+#ifdef __BIG_ENDIAN
+#define bE 3 /* 0 for little endian, 3 for big endian */
+#else
+#define bE 0
+#endif
+
+/* SCSI control 0 rw, default = 0xc0 */
+#define SCNTL0_REG (0x00^bE)
+#define SCNTL0_ARB1 0x80 /* 0 0 = simple arbitration */
+#define SCNTL0_ARB2 0x40 /* 1 1 = full arbitration */
+#define SCNTL0_STRT 0x20 /* Start Sequence */
+#define SCNTL0_WATN 0x10 /* Select with ATN */
+#define SCNTL0_EPC 0x08 /* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700 0x04 /* Enable parity generation */
+#define SCNTL0_AAP 0x02 /* ATN/ on parity error */
+#define SCNTL0_TRG 0x01 /* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG (0x01^bE)
+#define SCNTL1_EXC 0x80 /* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB 0x40 /* contents of SODL on bus */
+#define SCNTL1_ESR_700 0x20 /* Enable SIOP response to selection
+ and reselection */
+#define SCNTL1_CON 0x10 /* Connected */
+#define SCNTL1_RST 0x08 /* SCSI RST/ */
+#define SCNTL1_AESP 0x04 /* Force bad parity */
+#define SCNTL1_SND_700 0x02 /* Start SCSI send */
+#define SCNTL1_IARB_800 0x02 /* Immediate Arbitration, start
+ arbitration immediately after
+ busfree is detected */
+#define SCNTL1_RCV_700 0x01 /* Start SCSI receive */
+#define SCNTL1_SST_800 0x01 /* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800 (0x02^bE)
+#define SCNTL2_800_SDU 0x80 /* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 (0x03^bE)
+#define SCNTL3_800_SCF_SHIFT 4
+#define SCNTL3_800_SCF_MASK 0x70
+#define SCNTL3_800_SCF2 0x40 /* Synchronous divisor */
+#define SCNTL3_800_SCF1 0x20 /* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0 0x10 /* 0x10 = SCLK/1 */
+ /* 0x20 = SCLK/1.5
+ 0x30 = SCLK/2
+ 0x40 = SCLK/3 */
+
+#define SCNTL3_800_CCF_SHIFT 0
+#define SCNTL3_800_CCF_MASK 0x07
+#define SCNTL3_800_CCF2 0x04 /* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1 0x02 /* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0 0x01 /* 0x02 25.01 - 37.5
+ 0x03 37.51 - 50
+ 0x04 50.01 - 66 */
+
+/*
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID. This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700 (0x02^bE)
+#define SDID_REG_800 (0x06^bE)
+
+#define GP_REG_800 (0x07^bE) /* General purpose IO */
+#define GP_800_IO1 0x02
+#define GP_800_IO2 0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700 (0x03^bE)
+#define SIEN0_REG_800 (0x40^bE)
+#define SIEN_MA 0x80 /* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC 0x40 /* Function complete */
+#define SIEN_700_STO 0x20 /* Selection or reselection timeout */
+#define SIEN_800_SEL 0x20 /* Selected */
+#define SIEN_700_SEL 0x10 /* Selected or reselected */
+#define SIEN_800_RESEL 0x10 /* Reselected */
+#define SIEN_SGE 0x08 /* SCSI gross error */
+#define SIEN_UDC 0x04 /* Unexpected disconnect */
+#define SIEN_RST 0x02 /* SCSI RST/ received */
+#define SIEN_PAR 0x01 /* Parity error */
+
+/*
+ * SCSI chip ID rw
+ * NCR53c700 :
+ * When arbitrating, the highest bit is used, when reselection or selection
+ * occurs, the chip responds to all IDs for which a bit is set.
+ * default = 0x00
+ */
+#define SCID_REG (0x04^bE)
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE 0x40 /* Enable response to reselection */
+#define SCID_800_SRE 0x20 /* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK 0x07 /* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG (0x05^bE)
+#define SXFER_DHP 0x80 /* Disable halt on parity */
+
+#define SXFER_TP2 0x40 /* Transfer period msb */
+#define SXFER_TP1 0x20
+#define SXFER_TP0 0x10 /* lsb */
+#define SXFER_TP_MASK 0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT 5
+#define SXFER_TP_4 0x00 /* Divisors */
+#define SXFER_TP_5 0x10<<1
+#define SXFER_TP_6 0x20<<1
+#define SXFER_TP_7 0x30<<1
+#define SXFER_TP_8 0x40<<1
+#define SXFER_TP_9 0x50<<1
+#define SXFER_TP_10 0x60<<1
+#define SXFER_TP_11 0x70<<1
+
+#define SXFER_MO3 0x08 /* Max offset msb */
+#define SXFER_MO2 0x04
+#define SXFER_MO1 0x02
+#define SXFER_MO0 0x01 /* lsb */
+#define SXFER_MO_MASK 0x0f
+#define SXFER_MO_SHIFT 0
+
+/*
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when
+ * the Assert Data Bus bit of the SCNTL1 register is set and
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700 (0x06^bE)
+#define SODL_REG_800 (0x54^bE)
+
+
+/*
+ * SCSI output control latch rw, default = 0
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in. Otherwise no data transfer will occur due to
+ * phase mismatch.
+ */
+
+#define SOCL_REG (0x07^bE)
+#define SOCL_REQ 0x80 /* REQ */
+#define SOCL_ACK 0x40 /* ACK */
+#define SOCL_BSY 0x20 /* BSY */
+#define SOCL_SEL 0x10 /* SEL */
+#define SOCL_ATN 0x08 /* ATN */
+#define SOCL_MSG 0x04 /* MSG */
+#define SOCL_CD 0x02 /* C/D */
+#define SOCL_IO 0x01 /* I/O */
+
+/*
+ * SCSI first byte received latch ro
+ * This register contains the first byte received during a block MOVE
+ * SCSI SCRIPTS instruction, including
+ *
+ * Initiator mode Target mode
+ * Message in Command
+ * Status Message out
+ * Data in Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can
+ * operate on.
+ */
+#define SFBR_REG (0x08^bE)
+
+/*
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of
+ * ACK/
+ */
+#define SIDL_REG_700 (0x09^bE)
+#define SIDL_REG_800 (0x50^bE)
+
+/*
+ * SCSI bus data lines ro
+ * This register reflects the instantaneous status of the SCSI data
+ * lines. Note that SCNTL0 must be set to disable parity checking,
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700 (0x0a^bE)
+#define SBDL_REG_800 (0x58^bE)
+
+#define SSID_REG_800 (0x0a^bE)
+#define SSID_800_VAL 0x80 /* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK 0x07 /* Device which performed operation */
+
+
+
+/*
+ * SCSI bus control lines rw,
+ * instantaneous readout of control lines
+ */
+#define SBCL_REG (0x0b^bE)
+#define SBCL_REQ 0x80 /* REQ ro */
+#define SBCL_ACK 0x40 /* ACK ro */
+#define SBCL_BSY 0x20 /* BSY ro */
+#define SBCL_SEL 0x10 /* SEL ro */
+#define SBCL_ATN 0x08 /* ATN ro */
+#define SBCL_MSG 0x04 /* MSG ro */
+#define SBCL_CD 0x02 /* C/D ro */
+#define SBCL_IO 0x01 /* I/O ro */
+#define SBCL_PHASE_CMDOUT SBCL_CD
+#define SBCL_PHASE_DATAIN SBCL_IO
+#define SBCL_PHASE_DATAOUT 0
+#define SBCL_PHASE_MSGIN (SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT (SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN (SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK (SBCL_CD|SBCL_IO|SBCL_MSG)
+/*
+ * Synchronous SCSI Clock Control bits
+ * 0 - set by DCNTL
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0
+ */
+#define SBCL_SSCF1 0x02 /* wo, -66 only */
+#define SBCL_SSCF0 0x01 /* wo, -66 only */
+#define SBCL_SSCF_MASK 0x03
+
+/*
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two
+ */
+/* DMA status ro */
+#define DSTAT_REG (0x0c^bE)
+#define DSTAT_DFE 0x80 /* DMA FIFO empty */
+#define DSTAT_800_MDPE 0x40 /* Master Data Parity Error */
+#define DSTAT_BF 0x20 /* Bus Fault */
+#define DSTAT_ABRT 0x10 /* Aborted - set on error */
+#define DSTAT_SSI 0x08 /* SCRIPTS single step interrupt */
+#define DSTAT_SIR 0x04 /* SCRIPTS interrupt received -
+ set when INT instruction is
+ executed */
+#define DSTAT_WTD 0x02 /* Watchdog timeout detected */
+#define DSTAT_OPC 0x01 /* Illegal instruction */
+#define DSTAT_IID 0x01 /* Same thing, different name */
+
+
+#define SSTAT0_REG (0x0d^bE) /* SCSI status 0 ro */
+#define SIST0_REG_800 (0x42^bE) /* SCSI status 0 ro */
+#define SSTAT0_MA 0x80 /* ini : phase mismatch,
+ * tgt : ATN/ asserted
+ */
+#define SSTAT0_CMP 0x40 /* function complete */
+#define SSTAT0_700_STO 0x20 /* Selection or reselection timeout */
+#define SSTAT0_800_SEL 0x20 /* Selected */
+#define SSTAT0_700_SEL 0x10 /* Selected or reselected */
+#define SIST0_800_RSL 0x10 /* Reselected */
+#define SSTAT0_SGE 0x08 /* SCSI gross error */
+#define SSTAT0_UDC 0x04 /* Unexpected disconnect */
+#define SSTAT0_RST 0x02 /* SCSI RST/ received */
+#define SSTAT0_PAR 0x01 /* Parity error */
+
+#define SSTAT1_REG (0x0e^bE) /* SCSI status 1 ro */
+#define SSTAT1_ILF 0x80 /* SIDL full */
+#define SSTAT1_ORF 0x40 /* SODR full */
+#define SSTAT1_OLF 0x20 /* SODL full */
+#define SSTAT1_AIP 0x10 /* Arbitration in progress */
+#define SSTAT1_LOA 0x08 /* Lost arbitration */
+#define SSTAT1_WOA 0x04 /* Won arbitration */
+#define SSTAT1_RST 0x02 /* Instant readout of RST/ */
+#define SSTAT1_SDP 0x01 /* Instant readout of SDP/ */
+
+#define SSTAT2_REG (0x0f^bE) /* SCSI status 2 ro */
+#define SSTAT2_FF3 0x80 /* number of bytes in synchronous */
+#define SSTAT2_FF2 0x40 /* data FIFO */
+#define SSTAT2_FF1 0x20
+#define SSTAT2_FF0 0x10
+#define SSTAT2_FF_MASK 0xf0
+#define SSTAT2_FF_SHIFT 4
+
+/*
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP 0x08 /* SDP */
+#define SSTAT2_MSG 0x04 /* MSG */
+#define SSTAT2_CD 0x02 /* C/D */
+#define SSTAT2_IO 0x01 /* I/O */
+#define SSTAT2_PHASE_CMDOUT SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT 0
+#define SSTAT2_PHASE_MSGIN (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT (SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN (SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+#define DSA_REG 0x10 /* DATA structure address */
+
+#define CTEST0_REG_700 (0x14^bE) /* Chip test 0 ro */
+#define CTEST0_REG_800 (0x18^bE) /* Chip test 0 ro */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG 0x02 /* Real target mode */
+#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
+ * SCSI bus to host, 0 =
+ * host to SCSI.
+ */
+
+#define CTEST1_REG_700 (0x15^bE) /* Chip test 1 ro */
+#define CTEST1_REG_800 (0x19^bE) /* Chip test 1 ro */
+#define CTEST1_FMT3 0x80 /* Identify which byte lanes are empty */
+#define CTEST1_FMT2 0x40 /* in the DMA FIFO */
+#define CTEST1_FMT1 0x20
+#define CTEST1_FMT0 0x10
+
+#define CTEST1_FFL3 0x08 /* Identify which bytes lanes are full */
+#define CTEST1_FFL2 0x04 /* in the DMA FIFO */
+#define CTEST1_FFL1 0x02
+#define CTEST1_FFL0 0x01
+
+#define CTEST2_REG_700 (0x16^bE) /* Chip test 2 ro */
+#define CTEST2_REG_800 (0x1a^bE) /* Chip test 2 ro */
+
+#define CTEST2_800_DDIR 0x80 /* 1 = SCSI->host */
+#define CTEST2_800_SIGP 0x40 /* A copy of SIGP in ISTAT.
+ Reading this register clears */
+#define CTEST2_800_CIO 0x20 /* Configured as IO */.
+#define CTEST2_800_CM 0x10 /* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF 0x20 /* SCSI Offset Compare,
+ * As an initiator, this bit is
+ * one when the synchronous offset
+ * is zero, as a target this bit
+ * is one when the synchronous
+ * offset is at the maximum
+ * defined in SXFER
+ */
+#define CTEST2_700_SFP 0x10 /* SCSI FIFO parity bit,
+ * reading CTEST3 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_700_DFP 0x08 /* DMA FIFO parity bit,
+ * reading CTEST6 unloads a byte
+ * from the FIFO and sets this
+ */
+#define CTEST2_TEOP 0x04 /* SCSI true end of process,
+ * indicates a totally finished
+ * transfer
+ */
+#define CTEST2_DREQ 0x02 /* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK 0x01
+
+/*
+ * Chip test 3 ro
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size. Note that a GROSS
+ * error results if a read is attempted on this register. Also note
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700 (0x17^bE)
+/* Chip test 3 rw */
+#define CTEST3_REG_800 (0x1b^bE)
+#define CTEST3_800_V3 0x80 /* Chip revision */
+#define CTEST3_800_V2 0x40
+#define CTEST3_800_V1 0x20
+#define CTEST3_800_V0 0x10
+#define CTEST3_800_FLF 0x08 /* Flush DMA FIFO */
+#define CTEST3_800_CLF 0x04 /* Clear DMA FIFO */
+#define CTEST3_800_FM 0x02 /* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_400 (0x18^bE) /* Chip test 4 rw */
+#define CTEST4_REG_800 (0x21^bE) /* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS 0x80 /* Burst mode disable */
+#define CTEST4_ZMOD 0x40 /* High impedance mode */
+#define CTEST4_SZM 0x20 /* SCSI bus high impedance */
+#define CTEST4_700_SLBE 0x10 /* SCSI loopback enabled */
+#define CTEST4_800_SRTM 0x10 /* Shadow Register Test Mode */
+#define CTEST4_700_SFWR 0x08 /* SCSI FIFO write enable,
+ * redirects writes from SODL
+ * to the SCSI FIFO.
+ */
+#define CTEST4_800_MPEE 0x08 /* Enable parity checking
+ during master cycles on PCI
+ bus */
+
+/*
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO. Normal operation is zero, otherwise
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2 0x04
+#define CTEST4_FBL1 0x02
+#define CTEST4_FBL0 0x01
+#define CTEST4_FBL_MASK 0x07
+#define CTEST4_FBL_0 0x04 /* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1 0x05 /* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2 0x06 /* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3 0x07 /* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE (CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700 (0x19^bE) /* Chip test 5 rw */
+#define CTEST5_REG_800 (0x22^bE) /* Chip test 5 rw */
+/*
+ * Clock Address Incrementor. When set, it increments the
+ * DNAD register to the next bus size boundary. It automatically
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK 0x80
+/*
+ * Clock Byte Counter. When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK 0x40
+/*
+ * Reset SCSI Offset. Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT). This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs. The offset should
+ * be cleared when a synchronous transfer fails. When written, it is
+ * automatically cleared after the SCSI synchronous offset counter is
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF 0x20
+/*
+ * Master Control for Set or Reset pulses. When 1, causes the low
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 0x10
+#define CTEST5_DDIR 0x08 /* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP 0x04 /* End of process */
+#define CTEST5_700_DREQ 0x02 /* Data request */
+#define CTEST5_700_DACK 0x01 /* Data acknowledge */
+
+/*
+ * Chip test 6 rw - writing to this register writes to the byte
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700 (0x1a^bE)
+#define CTEST6_REG_800 (0x23^bE)
+
+#define CTEST7_REG (0x1b^bE) /* Chip test 7 rw */
+#define CTEST7_10_CDIS 0x80 /* Cache burst disable */
+#define CTEST7_10_SC1 0x40 /* Snoop control bits */
+#define CTEST7_10_SC0 0x20
+#define CTEST7_10_SC_MASK 0x60
+#define CTEST7_STD 0x10 /* Selection timeout disable */
+#define CTEST7_DFP 0x08 /* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1 0x02 /* Transfer type */
+#define CTEST7_DIFF 0x01 /* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG 0x1c /* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG (0x20^bE) /* DMA FIFO rw */
+/*
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_BO6 0x40
+#define DFIFO_BO5 0x20
+#define DFIFO_BO4 0x10
+#define DFIFO_BO3 0x08
+#define DFIFO_BO2 0x04
+#define DFIFO_BO1 0x02
+#define DFIFO_BO0 0x01
+#define DFIFO_10_BO_MASK 0x7f /* 7 bit counter */
+
+/*
+ * Interrupt status rw
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700 (0x21^bE)
+#define ISTAT_REG_800 (0x14^bE)
+#define ISTAT_ABRT 0x80 /* Software abort, write
+ *1 to abort, wait for interrupt. */
+#define ISTAT_10_SRST 0x40 /* software reset */
+#define ISTAT_10_SIGP 0x20 /* signal script */
+#define ISTAT_CON 0x08 /* 1 when connected */
+#define ISTAT_800_INTF 0x04 /* Interrupt on the fly */
+#define ISTAT_700_PRE 0x04 /* Pointer register empty.
+ * Set to 1 when DSPS and DSP
+ * registers are empty in pipeline
+ * mode, always set otherwise.
+ */
+#define ISTAT_SIP 0x02 /* SCSI interrupt pending from
+ * SCSI portion of SIOP see
+ * SSTAT0
+ */
+#define ISTAT_DIP 0x01 /* DMA interrupt pending
+ * see DSTAT
+ */
+
+#define CTEST8_REG (0x22^bE) /* Chip test 8 rw */
+#define CTEST8_10_V3 0x80 /* Chip revision */
+#define CTEST8_10_V2 0x40
+#define CTEST8_10_V1 0x20
+#define CTEST8_10_V0 0x10
+#define CTEST8_10_V_MASK 0xf0
+#define CTEST8_10_FLF 0x08 /* Flush FIFOs */
+#define CTEST8_10_CLF 0x04 /* Clear FIFOs */
+#define CTEST8_10_FM 0x02 /* Fetch pin mode */
+#define CTEST8_10_SM 0x01 /* Snoop pin mode */
+
+
+#define LCRC_REG_10 (0x23^bE)
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register. Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+
+#define DBC_REG 0x24
+/*
+ * For Block Move Instructions, DBC is a 24 bit quantity representing
+ * the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows :
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE (1 << 19) /* Jump when true */
+#define DBC_TCI_COMPARE_DATA (1 << 18) /* Compare data */
+#define DBC_TCI_COMPARE_PHASE (1 << 17) /* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID (1 << 16) /* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK 0xff00 /* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT 8
+#define DBC_TCI_DATA_MASK 0xff /* Data to be compared */
+#define DBC_TCI_DATA_SHIFT 0
+
+#define DBC_RWRI_IMMEDIATE_MASK 0xff00 /* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8 /* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK 0x3f0000 /* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG (0x27^bE)
+#define DCMD_TYPE_MASK 0xc0 /* Masks off type */
+#define DCMD_TYPE_BMI 0x00 /* Indicates a Block Move instruction */
+#define DCMD_BMI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_BMI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_BMI_MSG 0x04 /* instruction */
+
+#define DCMD_BMI_OP_MASK 0x18 /* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T 0x00 /* MOVE */
+#define DCMD_BMI_OP_MOVE_I 0x08 /* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT 0x20 /* Indirect addressing */
+
+#define DCMD_TYPE_TCI 0x80 /* Indicates a Transfer Control
+ instruction */
+#define DCMD_TCI_IO 0x01 /* I/O, CD, and MSG bits selecting */
+#define DCMD_TCI_CD 0x02 /* the phase for the block MOVE */
+#define DCMD_TCI_MSG 0x04 /* instruction */
+#define DCMD_TCI_OP_MASK 0x38 /* mask for opcode */
+#define DCMD_TCI_OP_JUMP 0x00 /* JUMP */
+#define DCMD_TCI_OP_CALL 0x08 /* CALL */
+#define DCMD_TCI_OP_RETURN 0x10 /* RETURN */
+#define DCMD_TCI_OP_INT 0x18 /* INT */
+
+#define DCMD_TYPE_RWRI 0x40 /* Indicates I/O or register Read/Write
+ instruction */
+#define DCMD_RWRI_OPC_MASK 0x38 /* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE 0x28 /* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ 0x30 /* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY 0x38 /* Modify in place */
+
+#define DCMD_RWRI_OP_MASK 0x07
+#define DCMD_RWRI_OP_MOVE 0x00
+#define DCMD_RWRI_OP_SHL 0x01
+#define DCMD_RWRI_OP_OR 0x02
+#define DCMD_RWRI_OP_XOR 0x03
+#define DCMD_RWRI_OP_AND 0x04
+#define DCMD_RWRI_OP_SHR 0x05
+#define DCMD_RWRI_OP_ADD 0x06
+#define DCMD_RWRI_OP_ADDC 0x07
+
+#define DCMD_TYPE_MMI 0xc0 /* Indicates a Memory Move instruction
+ (three words) */
+
+
+#define DNAD_REG 0x28 /* through 0x2b DMA next address for
+ data */
+#define DSP_REG 0x2c /* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG 0x30 /* through 0x33 DMA SCRIPTS pointer
+ save rw */
+#define DMODE_BL1 0x80 /* Burst length bits */
+#define DMODE_BL0 0x40
+#define DMODE_BL_MASK 0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2 0x00 /* 2 transfer */
+#define DMODE_BL_4 0x40 /* 4 transfers */
+#define DMODE_BL_8 0x80 /* 8 transfers */
+#define DMODE_BL_16 0xc0 /* 16 transfers */
+
+#define DMODE_10_BL_1 0x00 /* 1 transfer */
+#define DMODE_10_BL_2 0x40 /* 2 transfers */
+#define DMODE_10_BL_4 0x80 /* 4 transfers */
+#define DMODE_10_BL_8 0xc0 /* 8 transfers */
+#define DMODE_10_FC2 0x20 /* Driven to FC2 pin */
+#define DMODE_10_FC1 0x10 /* Driven to FC1 pin */
+#define DMODE_710_PD 0x08 /* Program/data on FC0 pin */
+#define DMODE_710_UO 0x02 /* User prog. output */
+
+#define DMODE_MAN 0x01 /* Manual start mode,
+ * requires a 1 to be written
+ * to the start DMA bit in the DCNTL
+ * register to run scripts
+ */
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800 0x34 /* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10 0x34 /* through 0x37 scratch rw */
+
+#define DMODE_REG (0x38^bE) /* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM 0x20 /* Source IO = 1 */
+#define DMODE_800_DIOM 0x10 /* Destination IO = 1 */
+#define DMODE_800_ERL 0x08 /* Enable Read Line */
+
+#define DIEN_REG (0x39^bE) /* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE 0x40 /* Master data parity error */
+#define DIEN_800_BF 0x20 /* BUS fault */
+#define DIEN_700_BF 0x20 /* BUS fault */
+#define DIEN_ABRT 0x10 /* Enable aborted interrupt */
+#define DIEN_SSI 0x08 /* Enable single step interrupt */
+#define DIEN_SIR 0x04 /* Enable SCRIPTS INT command
+ * interrupt
+ */
+#define DIEN_700_WTD 0x02 /* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC 0x01 /* Enable illegal instruction
+ * interrupt
+ */
+#define DIEN_800_IID 0x01 /* Same meaning, different name */
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG (0x3a^bE)
+
+/* DMA control rw */
+#define DCNTL_REG (0x3b^bE)
+#define DCNTL_700_CF1 0x80 /* Clock divisor bits */
+#define DCNTL_700_CF0 0x40
+#define DCNTL_700_CF_MASK 0xc0
+/* Clock divisors Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2 0x00 /* 2.0 37.51-50.00 */
+#define DCNTL_700_CF_1_5 0x40 /* 1.5 25.01-37.50 */
+#define DCNTL_700_CF_1 0x80 /* 1.0 16.67-25.00 */
+#define DCNTL_700_CF_3 0xc0 /* 3.0 50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16 0x20 /* Load scripts 16 bits at a time */
+#define DCNTL_SSM 0x10 /* Single step mode */
+#define DCNTL_700_LLM 0x08 /* Low level mode, can only be set
+ * after selection */
+#define DCNTL_800_IRQM 0x08 /* Totem pole IRQ pin */
+#define DCNTL_STD 0x04 /* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
+#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME16x */
+
+#define SCRATCHB_REG_800 0x5c /* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10 0x3c /* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800 (0x41^bE)
+#define SIEN1_800_STO 0x04 /* selection/reselection timeout */
+#define SIEN1_800_GEN 0x02 /* general purpose timer */
+#define SIEN1_800_HTH 0x01 /* handshake to handshake */
+
+#define SIST1_REG_800 (0x43^bE)
+#define SIST1_800_STO 0x04 /* selection/reselection timeout */
+#define SIST1_800_GEN 0x02 /* general purpose timer */
+#define SIST1_800_HTH 0x01 /* handshake to handshake */
+
+#define SLPAR_REG_800 (0x44^bE) /* Parity */
+
+#define MACNTL_REG_800 (0x46^bE) /* Memory access control */
+#define MACNTL_800_TYP3 0x80
+#define MACNTL_800_TYP2 0x40
+#define MACNTL_800_TYP1 0x20
+#define MACNTL_800_TYP0 0x10
+#define MACNTL_800_DWR 0x08
+#define MACNTL_800_DRD 0x04
+#define MACNTL_800_PSCPT 0x02
+#define MACNTL_800_SCPTS 0x01
+
+#define GPCNTL_REG_800 (0x47^bE) /* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800 (0x48^bE) /* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK 0xf0 /* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT 4
+#define STIME0_800_SEL_MASK 0x0f /* Selection timeout */
+#define STIME0_800_SEL_SHIFT 0
+
+#define STIME1_REG_800 (0x49^bE)
+#define STIME1_800_GEN_MASK 0x0f /* General purpose timer */
+
+#define RESPID_REG_800 (0x4a^bE) /* Response ID, bit fielded. 8
+ bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800 (0x4c^bE)
+#define STEST0_800_SLT 0x08 /* Selection response logic test */
+#define STEST0_800_ART 0x04 /* Arbitration priority encoder test */
+#define STEST0_800_SOZ 0x02 /* Synchronous offset zero */
+#define STEST0_800_SOM 0x01 /* Synchronous offset maximum */
+
+#define STEST1_REG_800 (0x4d^bE)
+#define STEST1_800_SCLK 0x80 /* Disable SCSI clock */
+
+#define STEST2_REG_800 (0x4e^bE)
+#define STEST2_800_SCE 0x80 /* Enable SOCL/SODL */
+#define STEST2_800_ROF 0x40 /* Reset SCSI sync offset */
+#define STEST2_800_SLB 0x10 /* Enable SCSI loopback mode */
+#define STEST2_800_SZM 0x08 /* SCSI high impedance mode */
+#define STEST2_800_EXT 0x02 /* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW 0x01 /* SCSI low level mode */
+
+#define STEST3_REG_800 (0x4f^bE)
+#define STEST3_800_TE 0x80 /* Enable active negation */
+#define STEST3_800_STR 0x40 /* SCSI FIFO test read */
+#define STEST3_800_HSC 0x20 /* Halt SCSI clock */
+#define STEST3_800_DSI 0x10 /* Disable single initiator response */
+#define STEST3_800_TTM 0x04 /* Time test mode */
+#define STEST3_800_CSF 0x02 /* Clear SCSI FIFO */
+#define STEST3_800_STW 0x01 /* SCSI FIFO test write */
+
+#define ISTAT_REG ISTAT_REG_700
+#define SCRATCH_REG SCRATCHB_REG_10
+
+#ifdef MEM_MAPPED
+#define NCR_read8(address) \
+ (unsigned int)readb((u32)(host->base) + ((u32)(address)))
+
+#define NCR_read32(address) \
+ (unsigned int) readl((u32)(host->base) + (u32)(address))
+
+#define NCR_write8(address,value) \
+ { DEB(DEB_REGS, printk("NCR: %02x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+ *(volatile unsigned char *) \
+ ((u32)(host->base) + (u32)(address)) = (value); }
+
+#define NCR_write32(address,value) \
+ { DEB(DEB_REGS, printk("NCR: %08x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+ *(volatile unsigned long *) \
+ ((u32)(host->base) + (u32)(address)) = (value); }
+#else
+#define NCR_read8(address) \
+ inb((u32)(host->base) + (address))
+
+#define NCR_read32(address) \
+ inl((u32)(host->base) + (address))
+
+#define NCR_write8(address,value) \
+ { DEB(DEB_REGS, printk("NCR: %02x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+ outb((value), (u32)(host->base) + (u32)(address)); }
+
+#define NCR_write32(address,value) \
+ { DEB(DEB_REGS, printk("NCR: %08x => %08x\n", (u32)(value), ((u32)(host->base) + (u32)(address)))); \
+ outl((value), (u32)(host->base) + (u32)(address)); }
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value) \
+ for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
+ (u32)); ++i) { \
+ (script)[A_##symbol##_used[i] - (offset)] += (value); \
+ DEB(DEB_FIXUP, printk("scsi%d: %s reference %d at 0x%x in %s is now 0x%x\n",\
+ host->host_no, #symbol, i, A_##symbol##_used[i] - \
+ (int)(offset), #script, (script)[A_##symbol##_used[i] - \
+ (offset)])); \
+ }
+
+#endif
+#endif
diff --git a/drivers/scsi/sim710.scr b/drivers/scsi/sim710.scr
new file mode 100644
index 000000000..60893a662
--- /dev/null
+++ b/drivers/scsi/sim710.scr
@@ -0,0 +1,554 @@
+/*
+ * sim710.scr - Copyright (C) 1999 Richard Hirst
+ */
+
+/* Offsets from DSA, allow 128 elements of scatter/gather */
+
+ABSOLUTE dsa_select = 0
+ABSOLUTE dsa_msgout = 8
+ABSOLUTE dsa_cmnd = 16
+ABSOLUTE dsa_status = 24
+ABSOLUTE dsa_msgin = 32
+ABSOLUTE dsa_datain = 40 /* 8 * 128 = 1024 bytes */
+ABSOLUTE dsa_dataout = 1064 /* 8 * 128 = 1024 bytes */
+ABSOLUTE dsa_size = 2088
+
+ABSOLUTE reselected_identify = 0
+ABSOLUTE msgin_buf = 0
+
+/* Interrupt values passed back to driver */
+
+ABSOLUTE int_bad_extmsg1a = 0xab930000
+ABSOLUTE int_bad_extmsg1b = 0xab930001
+ABSOLUTE int_bad_extmsg2a = 0xab930002
+ABSOLUTE int_bad_extmsg2b = 0xab930003
+ABSOLUTE int_bad_extmsg3a = 0xab930004
+ABSOLUTE int_bad_extmsg3b = 0xab930005
+ABSOLUTE int_bad_msg1 = 0xab930006
+ABSOLUTE int_bad_msg2 = 0xab930007
+ABSOLUTE int_bad_msg3 = 0xab930008
+ABSOLUTE int_cmd_bad_phase = 0xab930009
+ABSOLUTE int_cmd_complete = 0xab93000a
+ABSOLUTE int_data_bad_phase = 0xab93000b
+ABSOLUTE int_msg_sdtr1 = 0xab93000c
+ABSOLUTE int_msg_sdtr2 = 0xab93000d
+ABSOLUTE int_msg_sdtr3 = 0xab93000e
+ABSOLUTE int_no_msgout1 = 0xab93000f
+ABSOLUTE int_no_msgout2 = 0xab930010
+ABSOLUTE int_no_msgout3 = 0xab930011
+ABSOLUTE int_not_cmd_complete = 0xab930012
+ABSOLUTE int_sel_no_ident = 0xab930013
+ABSOLUTE int_sel_not_cmd = 0xab930014
+ABSOLUTE int_status_not_msgin = 0xab930015
+ABSOLUTE int_resel_not_msgin = 0xab930016
+ABSOLUTE int_reselected = 0xab930017
+ABSOLUTE int_selected = 0xab930018
+ABSOLUTE int_disc1 = 0xab930019
+ABSOLUTE int_disc2 = 0xab93001a
+ABSOLUTE int_disc3 = 0xab93001b
+ABSOLUTE int_not_rej = 0xab93001c
+
+
+/* Bit field settings used to record status in SCRATCH */
+
+ABSOLUTE had_select = 0x01
+ABSOLUTE had_msgout = 0x02
+ABSOLUTE had_cmdout = 0x04
+ABSOLUTE had_datain = 0x08
+ABSOLUTE had_dataout = 0x10
+ABSOLUTE had_status = 0x20
+ABSOLUTE had_msgin = 0x40
+ABSOLUTE had_extmsg = 0x80
+
+
+/* These scripts are heavily based on the examples in the NCR 53C710
+ * Programmer's Guide (Preliminary).
+ */
+
+ENTRY do_select
+do_select:
+ CLEAR TARGET
+ MOVE SCRATCH0 & 0 TO SCRATCH0
+ ; Enable selection timer
+ MOVE CTEST7 & 0xef TO CTEST7
+ SELECT ATN FROM dsa_select, reselect
+ JUMP get_status, WHEN STATUS
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+ MOVE SCRATCH0 | had_select TO SCRATCH0
+ INT int_sel_no_ident, IF NOT MSG_OUT
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+ MOVE FROM dsa_msgout, when MSG_OUT
+ENTRY done_ident
+done_ident:
+ JUMP get_status, IF STATUS
+redo_msgin1:
+ JUMP get_msgin1, WHEN MSG_IN
+ INT int_sel_not_cmd, IF NOT CMD
+ENTRY resume_cmd
+resume_cmd:
+ MOVE SCRATCH0 | had_cmdout TO SCRATCH0
+ MOVE FROM dsa_cmnd, WHEN CMD
+ENTRY resume_pmm
+resume_pmm:
+redo_msgin2:
+ JUMP get_msgin2, WHEN MSG_IN
+ JUMP get_status, IF STATUS
+ JUMP input_data, IF DATA_IN
+ JUMP output_data, IF DATA_OUT
+ INT int_cmd_bad_phase
+
+get_status:
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+ MOVE FROM dsa_status, WHEN STATUS
+ INT int_status_not_msgin, WHEN NOT MSG_IN
+ MOVE FROM dsa_msgin, WHEN MSG_IN
+ INT int_not_cmd_complete, IF NOT 0x00
+ CLEAR ACK
+ENTRY wait_disc_complete
+wait_disc_complete:
+ WAIT DISCONNECT
+ INT int_cmd_complete
+
+input_data:
+ MOVE SCRATCH0 | had_datain TO SCRATCH0
+ENTRY patch_input_data
+patch_input_data:
+ JUMP 0
+ MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
+ MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
+ JUMP end_data_trans
+
+output_data:
+ MOVE SCRATCH0 | had_dataout TO SCRATCH0
+ENTRY patch_output_data
+patch_output_data:
+ JUMP 0
+ MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
+ MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
+ENTRY end_data_trans
+end_data_trans:
+redo_msgin3:
+ JUMP get_status, WHEN STATUS
+ JUMP get_msgin3, WHEN MSG_IN
+ INT int_data_bad_phase
+
+get_msgin1:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+ MOVE 1, msgin_buf, WHEN MSG_IN
+ JUMP ext_msg1, IF 0x01 ; Extended Message
+ JUMP ignore_msg1, IF 0x02 ; Save Data Pointers
+ JUMP ignore_msg1, IF 0x03 ; Save Restore Pointers
+ JUMP disc1, IF 0x04 ; Disconnect
+ INT int_bad_msg1
+ignore_msg1:
+ CLEAR ACK
+ JUMP redo_msgin1
+ext_msg1:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+ CLEAR ACK
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+ JUMP ext_msg1a, IF 0x03
+ INT int_bad_extmsg1a
+ext_msg1a:
+ CLEAR ACK
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+ JUMP ext_msg1b, IF 0x01 ; Must be SDTR
+ INT int_bad_extmsg1b
+ext_msg1b:
+ CLEAR ACK
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+ INT int_msg_sdtr1
+disc1:
+ CLEAR ACK
+ENTRY wait_disc1
+wait_disc1:
+ WAIT DISCONNECT
+ INT int_disc1
+ENTRY resume_msgin1a
+resume_msgin1a:
+ CLEAR ACK
+ JUMP redo_msgin1
+ENTRY resume_msgin1b
+resume_msgin1b:
+ SET ATN
+ CLEAR ACK
+ INT int_no_msgout1, WHEN NOT MSG_OUT
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+ MOVE FROM dsa_msgout, when MSG_OUT
+ JUMP redo_msgin1
+
+get_msgin2:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+ MOVE 1, msgin_buf, WHEN MSG_IN
+ JUMP ext_msg2, IF 0x01 ; Extended Message
+ JUMP ignore_msg2, IF 0x02 ; Save Data Pointers
+ JUMP ignore_msg2, IF 0x03 ; Save Restore Pointers
+ JUMP disc2, IF 0x04 ; Disconnect
+ INT int_bad_msg2
+ignore_msg2:
+ CLEAR ACK
+ JUMP redo_msgin2
+ext_msg2:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+ CLEAR ACK
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+ JUMP ext_msg2a, IF 0x03
+ INT int_bad_extmsg2a
+ext_msg2a:
+ CLEAR ACK
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+ JUMP ext_msg2b, IF 0x01 ; Must be SDTR
+ INT int_bad_extmsg2b
+ext_msg2b:
+ CLEAR ACK
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+ INT int_msg_sdtr2
+disc2:
+ CLEAR ACK
+ENTRY wait_disc2
+wait_disc2:
+ WAIT DISCONNECT
+ INT int_disc2
+ENTRY resume_msgin2a
+resume_msgin2a:
+ CLEAR ACK
+ JUMP redo_msgin2
+ENTRY resume_msgin2b
+resume_msgin2b:
+ SET ATN
+ CLEAR ACK
+ INT int_no_msgout2, WHEN NOT MSG_OUT
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+ MOVE FROM dsa_msgout, when MSG_OUT
+ JUMP redo_msgin2
+
+get_msgin3:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+ MOVE 1, msgin_buf, WHEN MSG_IN
+ JUMP ext_msg3, IF 0x01 ; Extended Message
+ JUMP ignore_msg3, IF 0x02 ; Save Data Pointers
+ JUMP ignore_msg3, IF 0x03 ; Save Restore Pointers
+ JUMP disc3, IF 0x04 ; Disconnect
+ INT int_bad_msg3
+ignore_msg3:
+ CLEAR ACK
+ JUMP redo_msgin3
+ext_msg3:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+ CLEAR ACK
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+ JUMP ext_msg3a, IF 0x03
+ INT int_bad_extmsg3a
+ext_msg3a:
+ CLEAR ACK
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+ JUMP ext_msg3b, IF 0x01 ; Must be SDTR
+ INT int_bad_extmsg3b
+ext_msg3b:
+ CLEAR ACK
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+ INT int_msg_sdtr3
+disc3:
+ CLEAR ACK
+ENTRY wait_disc3
+wait_disc3:
+ WAIT DISCONNECT
+ INT int_disc3
+ENTRY resume_msgin3a
+resume_msgin3a:
+ CLEAR ACK
+ JUMP redo_msgin3
+ENTRY resume_msgin3b
+resume_msgin3b:
+ SET ATN
+ CLEAR ACK
+ INT int_no_msgout3, WHEN NOT MSG_OUT
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+ MOVE FROM dsa_msgout, when MSG_OUT
+ JUMP redo_msgin3
+
+ENTRY resume_rej_ident
+resume_rej_ident:
+ CLEAR ATN
+ MOVE 1, msgin_buf, WHEN MSG_IN
+ INT int_not_rej, IF NOT 0x07 ; Reject
+ CLEAR ACK
+ JUMP done_ident
+
+ENTRY reselect
+reselect:
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+ WAIT RESELECT resel_err
+ INT int_resel_not_msgin, WHEN NOT MSG_IN
+ MOVE 1, reselected_identify, WHEN MSG_IN
+ INT int_reselected
+resel_err:
+ MOVE CTEST2 & 0x40 TO SFBR
+ JUMP selected, IF 0x00
+ MOVE SFBR & 0 TO SFBR
+ENTRY patch_new_dsa
+patch_new_dsa:
+ MOVE SFBR | 0x11 TO DSA0
+ MOVE SFBR | 0x22 TO DSA1
+ MOVE SFBR | 0x33 TO DSA2
+ MOVE SFBR | 0x44 TO DSA3
+ JUMP do_select
+
+selected:
+ INT int_selected
+
diff --git a/drivers/scsi/sim710_d.h b/drivers/scsi/sim710_d.h
new file mode 100644
index 000000000..22e046478
--- /dev/null
+++ b/drivers/scsi/sim710_d.h
@@ -0,0 +1,2360 @@
+u32 SCRIPT[] = {
+/*
+
+
+
+
+
+
+ABSOLUTE dsa_select = 0
+ABSOLUTE dsa_msgout = 8
+ABSOLUTE dsa_cmnd = 16
+ABSOLUTE dsa_status = 24
+ABSOLUTE dsa_msgin = 32
+ABSOLUTE dsa_datain = 40
+ABSOLUTE dsa_dataout = 1064
+ABSOLUTE dsa_size = 2088
+
+ABSOLUTE reselected_identify = 0
+ABSOLUTE msgin_buf = 0
+
+
+
+ABSOLUTE int_bad_extmsg1a = 0xab930000
+ABSOLUTE int_bad_extmsg1b = 0xab930001
+ABSOLUTE int_bad_extmsg2a = 0xab930002
+ABSOLUTE int_bad_extmsg2b = 0xab930003
+ABSOLUTE int_bad_extmsg3a = 0xab930004
+ABSOLUTE int_bad_extmsg3b = 0xab930005
+ABSOLUTE int_bad_msg1 = 0xab930006
+ABSOLUTE int_bad_msg2 = 0xab930007
+ABSOLUTE int_bad_msg3 = 0xab930008
+ABSOLUTE int_cmd_bad_phase = 0xab930009
+ABSOLUTE int_cmd_complete = 0xab93000a
+ABSOLUTE int_data_bad_phase = 0xab93000b
+ABSOLUTE int_msg_sdtr1 = 0xab93000c
+ABSOLUTE int_msg_sdtr2 = 0xab93000d
+ABSOLUTE int_msg_sdtr3 = 0xab93000e
+ABSOLUTE int_no_msgout1 = 0xab93000f
+ABSOLUTE int_no_msgout2 = 0xab930010
+ABSOLUTE int_no_msgout3 = 0xab930011
+ABSOLUTE int_not_cmd_complete = 0xab930012
+ABSOLUTE int_sel_no_ident = 0xab930013
+ABSOLUTE int_sel_not_cmd = 0xab930014
+ABSOLUTE int_status_not_msgin = 0xab930015
+ABSOLUTE int_resel_not_msgin = 0xab930016
+ABSOLUTE int_reselected = 0xab930017
+ABSOLUTE int_selected = 0xab930018
+ABSOLUTE int_disc1 = 0xab930019
+ABSOLUTE int_disc2 = 0xab93001a
+ABSOLUTE int_disc3 = 0xab93001b
+ABSOLUTE int_not_rej = 0xab93001c
+
+
+
+
+ABSOLUTE had_select = 0x01
+ABSOLUTE had_msgout = 0x02
+ABSOLUTE had_cmdout = 0x04
+ABSOLUTE had_datain = 0x08
+ABSOLUTE had_dataout = 0x10
+ABSOLUTE had_status = 0x20
+ABSOLUTE had_msgin = 0x40
+ABSOLUTE had_extmsg = 0x80
+
+
+
+
+
+
+ENTRY do_select
+do_select:
+ CLEAR TARGET
+
+at 0x00000000 : */ 0x60000200,0x00000000,
+/*
+ MOVE SCRATCH0 & 0 TO SCRATCH0
+
+at 0x00000002 : */ 0x7c340000,0x00000000,
+/*
+ ; Enable selection timer
+ MOVE CTEST7 & 0xef TO CTEST7
+
+at 0x00000004 : */ 0x7c1bef00,0x00000000,
+/*
+ SELECT ATN FROM dsa_select, reselect
+
+at 0x00000006 : */ 0x43000000,0x00000c48,
+/*
+ JUMP get_status, WHEN STATUS
+
+at 0x00000008 : */ 0x830b0000,0x000000a0,
+/*
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x0000000a : */ 0x7a1b1000,0x00000000,
+/*
+ MOVE SCRATCH0 | had_select TO SCRATCH0
+
+at 0x0000000c : */ 0x7a340100,0x00000000,
+/*
+ INT int_sel_no_ident, IF NOT MSG_OUT
+
+at 0x0000000e : */ 0x9e020000,0xab930013,
+/*
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000010 : */ 0x7a340200,0x00000000,
+/*
+ MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000012 : */ 0x1e000000,0x00000008,
+/*
+ENTRY done_ident
+done_ident:
+ JUMP get_status, IF STATUS
+
+at 0x00000014 : */ 0x830a0000,0x000000a0,
+/*
+redo_msgin1:
+ JUMP get_msgin1, WHEN MSG_IN
+
+at 0x00000016 : */ 0x870b0000,0x00000920,
+/*
+ INT int_sel_not_cmd, IF NOT CMD
+
+at 0x00000018 : */ 0x9a020000,0xab930014,
+/*
+ENTRY resume_cmd
+resume_cmd:
+ MOVE SCRATCH0 | had_cmdout TO SCRATCH0
+
+at 0x0000001a : */ 0x7a340400,0x00000000,
+/*
+ MOVE FROM dsa_cmnd, WHEN CMD
+
+at 0x0000001c : */ 0x1a000000,0x00000010,
+/*
+ENTRY resume_pmm
+resume_pmm:
+redo_msgin2:
+ JUMP get_msgin2, WHEN MSG_IN
+
+at 0x0000001e : */ 0x870b0000,0x00000a20,
+/*
+ JUMP get_status, IF STATUS
+
+at 0x00000020 : */ 0x830a0000,0x000000a0,
+/*
+ JUMP input_data, IF DATA_IN
+
+at 0x00000022 : */ 0x810a0000,0x000000e0,
+/*
+ JUMP output_data, IF DATA_OUT
+
+at 0x00000024 : */ 0x800a0000,0x000004f8,
+/*
+ INT int_cmd_bad_phase
+
+at 0x00000026 : */ 0x98080000,0xab930009,
+/*
+
+get_status:
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000028 : */ 0x7a1b1000,0x00000000,
+/*
+ MOVE FROM dsa_status, WHEN STATUS
+
+at 0x0000002a : */ 0x1b000000,0x00000018,
+/*
+ INT int_status_not_msgin, WHEN NOT MSG_IN
+
+at 0x0000002c : */ 0x9f030000,0xab930015,
+/*
+ MOVE FROM dsa_msgin, WHEN MSG_IN
+
+at 0x0000002e : */ 0x1f000000,0x00000020,
+/*
+ INT int_not_cmd_complete, IF NOT 0x00
+
+at 0x00000030 : */ 0x98040000,0xab930012,
+/*
+ CLEAR ACK
+
+at 0x00000032 : */ 0x60000040,0x00000000,
+/*
+ENTRY wait_disc_complete
+wait_disc_complete:
+ WAIT DISCONNECT
+
+at 0x00000034 : */ 0x48000000,0x00000000,
+/*
+ INT int_cmd_complete
+
+at 0x00000036 : */ 0x98080000,0xab93000a,
+/*
+
+input_data:
+ MOVE SCRATCH0 | had_datain TO SCRATCH0
+
+at 0x00000038 : */ 0x7a340800,0x00000000,
+/*
+ENTRY patch_input_data
+patch_input_data:
+ JUMP 0
+
+at 0x0000003a : */ 0x80080000,0x00000000,
+/*
+ MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
+
+at 0x0000003c : */ 0x19000000,0x00000028,
+/*
+ MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
+
+at 0x0000003e : */ 0x19000000,0x00000030,
+/*
+ MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
+
+at 0x00000040 : */ 0x19000000,0x00000038,
+/*
+ MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
+
+at 0x00000042 : */ 0x19000000,0x00000040,
+/*
+ MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
+
+at 0x00000044 : */ 0x19000000,0x00000048,
+/*
+ MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
+
+at 0x00000046 : */ 0x19000000,0x00000050,
+/*
+ MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
+
+at 0x00000048 : */ 0x19000000,0x00000058,
+/*
+ MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
+
+at 0x0000004a : */ 0x19000000,0x00000060,
+/*
+ MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
+
+at 0x0000004c : */ 0x19000000,0x00000068,
+/*
+ MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
+
+at 0x0000004e : */ 0x19000000,0x00000070,
+/*
+ MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
+
+at 0x00000050 : */ 0x19000000,0x00000078,
+/*
+ MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
+
+at 0x00000052 : */ 0x19000000,0x00000080,
+/*
+ MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
+
+at 0x00000054 : */ 0x19000000,0x00000088,
+/*
+ MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
+
+at 0x00000056 : */ 0x19000000,0x00000090,
+/*
+ MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
+
+at 0x00000058 : */ 0x19000000,0x00000098,
+/*
+ MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
+
+at 0x0000005a : */ 0x19000000,0x000000a0,
+/*
+ MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
+
+at 0x0000005c : */ 0x19000000,0x000000a8,
+/*
+ MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
+
+at 0x0000005e : */ 0x19000000,0x000000b0,
+/*
+ MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
+
+at 0x00000060 : */ 0x19000000,0x000000b8,
+/*
+ MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
+
+at 0x00000062 : */ 0x19000000,0x000000c0,
+/*
+ MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
+
+at 0x00000064 : */ 0x19000000,0x000000c8,
+/*
+ MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
+
+at 0x00000066 : */ 0x19000000,0x000000d0,
+/*
+ MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
+
+at 0x00000068 : */ 0x19000000,0x000000d8,
+/*
+ MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
+
+at 0x0000006a : */ 0x19000000,0x000000e0,
+/*
+ MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
+
+at 0x0000006c : */ 0x19000000,0x000000e8,
+/*
+ MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
+
+at 0x0000006e : */ 0x19000000,0x000000f0,
+/*
+ MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
+
+at 0x00000070 : */ 0x19000000,0x000000f8,
+/*
+ MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
+
+at 0x00000072 : */ 0x19000000,0x00000100,
+/*
+ MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
+
+at 0x00000074 : */ 0x19000000,0x00000108,
+/*
+ MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
+
+at 0x00000076 : */ 0x19000000,0x00000110,
+/*
+ MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
+
+at 0x00000078 : */ 0x19000000,0x00000118,
+/*
+ MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
+
+at 0x0000007a : */ 0x19000000,0x00000120,
+/*
+ MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
+
+at 0x0000007c : */ 0x19000000,0x00000128,
+/*
+ MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
+
+at 0x0000007e : */ 0x19000000,0x00000130,
+/*
+ MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
+
+at 0x00000080 : */ 0x19000000,0x00000138,
+/*
+ MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
+
+at 0x00000082 : */ 0x19000000,0x00000140,
+/*
+ MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
+
+at 0x00000084 : */ 0x19000000,0x00000148,
+/*
+ MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
+
+at 0x00000086 : */ 0x19000000,0x00000150,
+/*
+ MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
+
+at 0x00000088 : */ 0x19000000,0x00000158,
+/*
+ MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
+
+at 0x0000008a : */ 0x19000000,0x00000160,
+/*
+ MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
+
+at 0x0000008c : */ 0x19000000,0x00000168,
+/*
+ MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
+
+at 0x0000008e : */ 0x19000000,0x00000170,
+/*
+ MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
+
+at 0x00000090 : */ 0x19000000,0x00000178,
+/*
+ MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
+
+at 0x00000092 : */ 0x19000000,0x00000180,
+/*
+ MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
+
+at 0x00000094 : */ 0x19000000,0x00000188,
+/*
+ MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
+
+at 0x00000096 : */ 0x19000000,0x00000190,
+/*
+ MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
+
+at 0x00000098 : */ 0x19000000,0x00000198,
+/*
+ MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
+
+at 0x0000009a : */ 0x19000000,0x000001a0,
+/*
+ MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
+
+at 0x0000009c : */ 0x19000000,0x000001a8,
+/*
+ MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
+
+at 0x0000009e : */ 0x19000000,0x000001b0,
+/*
+ MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
+
+at 0x000000a0 : */ 0x19000000,0x000001b8,
+/*
+ MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
+
+at 0x000000a2 : */ 0x19000000,0x000001c0,
+/*
+ MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
+
+at 0x000000a4 : */ 0x19000000,0x000001c8,
+/*
+ MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
+
+at 0x000000a6 : */ 0x19000000,0x000001d0,
+/*
+ MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
+
+at 0x000000a8 : */ 0x19000000,0x000001d8,
+/*
+ MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
+
+at 0x000000aa : */ 0x19000000,0x000001e0,
+/*
+ MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
+
+at 0x000000ac : */ 0x19000000,0x000001e8,
+/*
+ MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
+
+at 0x000000ae : */ 0x19000000,0x000001f0,
+/*
+ MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
+
+at 0x000000b0 : */ 0x19000000,0x000001f8,
+/*
+ MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
+
+at 0x000000b2 : */ 0x19000000,0x00000200,
+/*
+ MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
+
+at 0x000000b4 : */ 0x19000000,0x00000208,
+/*
+ MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
+
+at 0x000000b6 : */ 0x19000000,0x00000210,
+/*
+ MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
+
+at 0x000000b8 : */ 0x19000000,0x00000218,
+/*
+ MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
+
+at 0x000000ba : */ 0x19000000,0x00000220,
+/*
+ MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
+
+at 0x000000bc : */ 0x19000000,0x00000228,
+/*
+ MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
+
+at 0x000000be : */ 0x19000000,0x00000230,
+/*
+ MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
+
+at 0x000000c0 : */ 0x19000000,0x00000238,
+/*
+ MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
+
+at 0x000000c2 : */ 0x19000000,0x00000240,
+/*
+ MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
+
+at 0x000000c4 : */ 0x19000000,0x00000248,
+/*
+ MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
+
+at 0x000000c6 : */ 0x19000000,0x00000250,
+/*
+ MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
+
+at 0x000000c8 : */ 0x19000000,0x00000258,
+/*
+ MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
+
+at 0x000000ca : */ 0x19000000,0x00000260,
+/*
+ MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
+
+at 0x000000cc : */ 0x19000000,0x00000268,
+/*
+ MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
+
+at 0x000000ce : */ 0x19000000,0x00000270,
+/*
+ MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
+
+at 0x000000d0 : */ 0x19000000,0x00000278,
+/*
+ MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
+
+at 0x000000d2 : */ 0x19000000,0x00000280,
+/*
+ MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
+
+at 0x000000d4 : */ 0x19000000,0x00000288,
+/*
+ MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
+
+at 0x000000d6 : */ 0x19000000,0x00000290,
+/*
+ MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
+
+at 0x000000d8 : */ 0x19000000,0x00000298,
+/*
+ MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
+
+at 0x000000da : */ 0x19000000,0x000002a0,
+/*
+ MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
+
+at 0x000000dc : */ 0x19000000,0x000002a8,
+/*
+ MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
+
+at 0x000000de : */ 0x19000000,0x000002b0,
+/*
+ MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
+
+at 0x000000e0 : */ 0x19000000,0x000002b8,
+/*
+ MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
+
+at 0x000000e2 : */ 0x19000000,0x000002c0,
+/*
+ MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
+
+at 0x000000e4 : */ 0x19000000,0x000002c8,
+/*
+ MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
+
+at 0x000000e6 : */ 0x19000000,0x000002d0,
+/*
+ MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
+
+at 0x000000e8 : */ 0x19000000,0x000002d8,
+/*
+ MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
+
+at 0x000000ea : */ 0x19000000,0x000002e0,
+/*
+ MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
+
+at 0x000000ec : */ 0x19000000,0x000002e8,
+/*
+ MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
+
+at 0x000000ee : */ 0x19000000,0x000002f0,
+/*
+ MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
+
+at 0x000000f0 : */ 0x19000000,0x000002f8,
+/*
+ MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
+
+at 0x000000f2 : */ 0x19000000,0x00000300,
+/*
+ MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
+
+at 0x000000f4 : */ 0x19000000,0x00000308,
+/*
+ MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
+
+at 0x000000f6 : */ 0x19000000,0x00000310,
+/*
+ MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
+
+at 0x000000f8 : */ 0x19000000,0x00000318,
+/*
+ MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
+
+at 0x000000fa : */ 0x19000000,0x00000320,
+/*
+ MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
+
+at 0x000000fc : */ 0x19000000,0x00000328,
+/*
+ MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
+
+at 0x000000fe : */ 0x19000000,0x00000330,
+/*
+ MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
+
+at 0x00000100 : */ 0x19000000,0x00000338,
+/*
+ MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
+
+at 0x00000102 : */ 0x19000000,0x00000340,
+/*
+ MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
+
+at 0x00000104 : */ 0x19000000,0x00000348,
+/*
+ MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
+
+at 0x00000106 : */ 0x19000000,0x00000350,
+/*
+ MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
+
+at 0x00000108 : */ 0x19000000,0x00000358,
+/*
+ MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
+
+at 0x0000010a : */ 0x19000000,0x00000360,
+/*
+ MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
+
+at 0x0000010c : */ 0x19000000,0x00000368,
+/*
+ MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
+
+at 0x0000010e : */ 0x19000000,0x00000370,
+/*
+ MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
+
+at 0x00000110 : */ 0x19000000,0x00000378,
+/*
+ MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
+
+at 0x00000112 : */ 0x19000000,0x00000380,
+/*
+ MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
+
+at 0x00000114 : */ 0x19000000,0x00000388,
+/*
+ MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
+
+at 0x00000116 : */ 0x19000000,0x00000390,
+/*
+ MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
+
+at 0x00000118 : */ 0x19000000,0x00000398,
+/*
+ MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
+
+at 0x0000011a : */ 0x19000000,0x000003a0,
+/*
+ MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
+
+at 0x0000011c : */ 0x19000000,0x000003a8,
+/*
+ MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
+
+at 0x0000011e : */ 0x19000000,0x000003b0,
+/*
+ MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
+
+at 0x00000120 : */ 0x19000000,0x000003b8,
+/*
+ MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
+
+at 0x00000122 : */ 0x19000000,0x000003c0,
+/*
+ MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
+
+at 0x00000124 : */ 0x19000000,0x000003c8,
+/*
+ MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
+
+at 0x00000126 : */ 0x19000000,0x000003d0,
+/*
+ MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
+
+at 0x00000128 : */ 0x19000000,0x000003d8,
+/*
+ MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
+
+at 0x0000012a : */ 0x19000000,0x000003e0,
+/*
+ MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
+
+at 0x0000012c : */ 0x19000000,0x000003e8,
+/*
+ MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
+
+at 0x0000012e : */ 0x19000000,0x000003f0,
+/*
+ MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
+
+at 0x00000130 : */ 0x19000000,0x000003f8,
+/*
+ MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
+
+at 0x00000132 : */ 0x19000000,0x00000400,
+/*
+ MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
+
+at 0x00000134 : */ 0x19000000,0x00000408,
+/*
+ MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
+
+at 0x00000136 : */ 0x19000000,0x00000410,
+/*
+ MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
+
+at 0x00000138 : */ 0x19000000,0x00000418,
+/*
+ MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
+
+at 0x0000013a : */ 0x19000000,0x00000420,
+/*
+ JUMP end_data_trans
+
+at 0x0000013c : */ 0x80080000,0x00000908,
+/*
+
+output_data:
+ MOVE SCRATCH0 | had_dataout TO SCRATCH0
+
+at 0x0000013e : */ 0x7a341000,0x00000000,
+/*
+ENTRY patch_output_data
+patch_output_data:
+ JUMP 0
+
+at 0x00000140 : */ 0x80080000,0x00000000,
+/*
+ MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
+
+at 0x00000142 : */ 0x18000000,0x00000428,
+/*
+ MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
+
+at 0x00000144 : */ 0x18000000,0x00000430,
+/*
+ MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
+
+at 0x00000146 : */ 0x18000000,0x00000438,
+/*
+ MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
+
+at 0x00000148 : */ 0x18000000,0x00000440,
+/*
+ MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
+
+at 0x0000014a : */ 0x18000000,0x00000448,
+/*
+ MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
+
+at 0x0000014c : */ 0x18000000,0x00000450,
+/*
+ MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
+
+at 0x0000014e : */ 0x18000000,0x00000458,
+/*
+ MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
+
+at 0x00000150 : */ 0x18000000,0x00000460,
+/*
+ MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
+
+at 0x00000152 : */ 0x18000000,0x00000468,
+/*
+ MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
+
+at 0x00000154 : */ 0x18000000,0x00000470,
+/*
+ MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
+
+at 0x00000156 : */ 0x18000000,0x00000478,
+/*
+ MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
+
+at 0x00000158 : */ 0x18000000,0x00000480,
+/*
+ MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
+
+at 0x0000015a : */ 0x18000000,0x00000488,
+/*
+ MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
+
+at 0x0000015c : */ 0x18000000,0x00000490,
+/*
+ MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
+
+at 0x0000015e : */ 0x18000000,0x00000498,
+/*
+ MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
+
+at 0x00000160 : */ 0x18000000,0x000004a0,
+/*
+ MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
+
+at 0x00000162 : */ 0x18000000,0x000004a8,
+/*
+ MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
+
+at 0x00000164 : */ 0x18000000,0x000004b0,
+/*
+ MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
+
+at 0x00000166 : */ 0x18000000,0x000004b8,
+/*
+ MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
+
+at 0x00000168 : */ 0x18000000,0x000004c0,
+/*
+ MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
+
+at 0x0000016a : */ 0x18000000,0x000004c8,
+/*
+ MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
+
+at 0x0000016c : */ 0x18000000,0x000004d0,
+/*
+ MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
+
+at 0x0000016e : */ 0x18000000,0x000004d8,
+/*
+ MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
+
+at 0x00000170 : */ 0x18000000,0x000004e0,
+/*
+ MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
+
+at 0x00000172 : */ 0x18000000,0x000004e8,
+/*
+ MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
+
+at 0x00000174 : */ 0x18000000,0x000004f0,
+/*
+ MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
+
+at 0x00000176 : */ 0x18000000,0x000004f8,
+/*
+ MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
+
+at 0x00000178 : */ 0x18000000,0x00000500,
+/*
+ MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
+
+at 0x0000017a : */ 0x18000000,0x00000508,
+/*
+ MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
+
+at 0x0000017c : */ 0x18000000,0x00000510,
+/*
+ MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
+
+at 0x0000017e : */ 0x18000000,0x00000518,
+/*
+ MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
+
+at 0x00000180 : */ 0x18000000,0x00000520,
+/*
+ MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
+
+at 0x00000182 : */ 0x18000000,0x00000528,
+/*
+ MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
+
+at 0x00000184 : */ 0x18000000,0x00000530,
+/*
+ MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
+
+at 0x00000186 : */ 0x18000000,0x00000538,
+/*
+ MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
+
+at 0x00000188 : */ 0x18000000,0x00000540,
+/*
+ MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
+
+at 0x0000018a : */ 0x18000000,0x00000548,
+/*
+ MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
+
+at 0x0000018c : */ 0x18000000,0x00000550,
+/*
+ MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
+
+at 0x0000018e : */ 0x18000000,0x00000558,
+/*
+ MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
+
+at 0x00000190 : */ 0x18000000,0x00000560,
+/*
+ MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
+
+at 0x00000192 : */ 0x18000000,0x00000568,
+/*
+ MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
+
+at 0x00000194 : */ 0x18000000,0x00000570,
+/*
+ MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
+
+at 0x00000196 : */ 0x18000000,0x00000578,
+/*
+ MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
+
+at 0x00000198 : */ 0x18000000,0x00000580,
+/*
+ MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
+
+at 0x0000019a : */ 0x18000000,0x00000588,
+/*
+ MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
+
+at 0x0000019c : */ 0x18000000,0x00000590,
+/*
+ MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
+
+at 0x0000019e : */ 0x18000000,0x00000598,
+/*
+ MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
+
+at 0x000001a0 : */ 0x18000000,0x000005a0,
+/*
+ MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
+
+at 0x000001a2 : */ 0x18000000,0x000005a8,
+/*
+ MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
+
+at 0x000001a4 : */ 0x18000000,0x000005b0,
+/*
+ MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
+
+at 0x000001a6 : */ 0x18000000,0x000005b8,
+/*
+ MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
+
+at 0x000001a8 : */ 0x18000000,0x000005c0,
+/*
+ MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
+
+at 0x000001aa : */ 0x18000000,0x000005c8,
+/*
+ MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
+
+at 0x000001ac : */ 0x18000000,0x000005d0,
+/*
+ MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
+
+at 0x000001ae : */ 0x18000000,0x000005d8,
+/*
+ MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
+
+at 0x000001b0 : */ 0x18000000,0x000005e0,
+/*
+ MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
+
+at 0x000001b2 : */ 0x18000000,0x000005e8,
+/*
+ MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
+
+at 0x000001b4 : */ 0x18000000,0x000005f0,
+/*
+ MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
+
+at 0x000001b6 : */ 0x18000000,0x000005f8,
+/*
+ MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
+
+at 0x000001b8 : */ 0x18000000,0x00000600,
+/*
+ MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
+
+at 0x000001ba : */ 0x18000000,0x00000608,
+/*
+ MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
+
+at 0x000001bc : */ 0x18000000,0x00000610,
+/*
+ MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
+
+at 0x000001be : */ 0x18000000,0x00000618,
+/*
+ MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
+
+at 0x000001c0 : */ 0x18000000,0x00000620,
+/*
+ MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
+
+at 0x000001c2 : */ 0x18000000,0x00000628,
+/*
+ MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
+
+at 0x000001c4 : */ 0x18000000,0x00000630,
+/*
+ MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
+
+at 0x000001c6 : */ 0x18000000,0x00000638,
+/*
+ MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
+
+at 0x000001c8 : */ 0x18000000,0x00000640,
+/*
+ MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
+
+at 0x000001ca : */ 0x18000000,0x00000648,
+/*
+ MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
+
+at 0x000001cc : */ 0x18000000,0x00000650,
+/*
+ MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
+
+at 0x000001ce : */ 0x18000000,0x00000658,
+/*
+ MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
+
+at 0x000001d0 : */ 0x18000000,0x00000660,
+/*
+ MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
+
+at 0x000001d2 : */ 0x18000000,0x00000668,
+/*
+ MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
+
+at 0x000001d4 : */ 0x18000000,0x00000670,
+/*
+ MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
+
+at 0x000001d6 : */ 0x18000000,0x00000678,
+/*
+ MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
+
+at 0x000001d8 : */ 0x18000000,0x00000680,
+/*
+ MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
+
+at 0x000001da : */ 0x18000000,0x00000688,
+/*
+ MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
+
+at 0x000001dc : */ 0x18000000,0x00000690,
+/*
+ MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
+
+at 0x000001de : */ 0x18000000,0x00000698,
+/*
+ MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
+
+at 0x000001e0 : */ 0x18000000,0x000006a0,
+/*
+ MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
+
+at 0x000001e2 : */ 0x18000000,0x000006a8,
+/*
+ MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
+
+at 0x000001e4 : */ 0x18000000,0x000006b0,
+/*
+ MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
+
+at 0x000001e6 : */ 0x18000000,0x000006b8,
+/*
+ MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
+
+at 0x000001e8 : */ 0x18000000,0x000006c0,
+/*
+ MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
+
+at 0x000001ea : */ 0x18000000,0x000006c8,
+/*
+ MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
+
+at 0x000001ec : */ 0x18000000,0x000006d0,
+/*
+ MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
+
+at 0x000001ee : */ 0x18000000,0x000006d8,
+/*
+ MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
+
+at 0x000001f0 : */ 0x18000000,0x000006e0,
+/*
+ MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
+
+at 0x000001f2 : */ 0x18000000,0x000006e8,
+/*
+ MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
+
+at 0x000001f4 : */ 0x18000000,0x000006f0,
+/*
+ MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
+
+at 0x000001f6 : */ 0x18000000,0x000006f8,
+/*
+ MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
+
+at 0x000001f8 : */ 0x18000000,0x00000700,
+/*
+ MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
+
+at 0x000001fa : */ 0x18000000,0x00000708,
+/*
+ MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
+
+at 0x000001fc : */ 0x18000000,0x00000710,
+/*
+ MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
+
+at 0x000001fe : */ 0x18000000,0x00000718,
+/*
+ MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
+
+at 0x00000200 : */ 0x18000000,0x00000720,
+/*
+ MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
+
+at 0x00000202 : */ 0x18000000,0x00000728,
+/*
+ MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
+
+at 0x00000204 : */ 0x18000000,0x00000730,
+/*
+ MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
+
+at 0x00000206 : */ 0x18000000,0x00000738,
+/*
+ MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
+
+at 0x00000208 : */ 0x18000000,0x00000740,
+/*
+ MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
+
+at 0x0000020a : */ 0x18000000,0x00000748,
+/*
+ MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
+
+at 0x0000020c : */ 0x18000000,0x00000750,
+/*
+ MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
+
+at 0x0000020e : */ 0x18000000,0x00000758,
+/*
+ MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
+
+at 0x00000210 : */ 0x18000000,0x00000760,
+/*
+ MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
+
+at 0x00000212 : */ 0x18000000,0x00000768,
+/*
+ MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
+
+at 0x00000214 : */ 0x18000000,0x00000770,
+/*
+ MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
+
+at 0x00000216 : */ 0x18000000,0x00000778,
+/*
+ MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
+
+at 0x00000218 : */ 0x18000000,0x00000780,
+/*
+ MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
+
+at 0x0000021a : */ 0x18000000,0x00000788,
+/*
+ MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
+
+at 0x0000021c : */ 0x18000000,0x00000790,
+/*
+ MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
+
+at 0x0000021e : */ 0x18000000,0x00000798,
+/*
+ MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
+
+at 0x00000220 : */ 0x18000000,0x000007a0,
+/*
+ MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
+
+at 0x00000222 : */ 0x18000000,0x000007a8,
+/*
+ MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
+
+at 0x00000224 : */ 0x18000000,0x000007b0,
+/*
+ MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
+
+at 0x00000226 : */ 0x18000000,0x000007b8,
+/*
+ MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
+
+at 0x00000228 : */ 0x18000000,0x000007c0,
+/*
+ MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
+
+at 0x0000022a : */ 0x18000000,0x000007c8,
+/*
+ MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
+
+at 0x0000022c : */ 0x18000000,0x000007d0,
+/*
+ MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
+
+at 0x0000022e : */ 0x18000000,0x000007d8,
+/*
+ MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
+
+at 0x00000230 : */ 0x18000000,0x000007e0,
+/*
+ MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
+
+at 0x00000232 : */ 0x18000000,0x000007e8,
+/*
+ MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
+
+at 0x00000234 : */ 0x18000000,0x000007f0,
+/*
+ MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
+
+at 0x00000236 : */ 0x18000000,0x000007f8,
+/*
+ MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
+
+at 0x00000238 : */ 0x18000000,0x00000800,
+/*
+ MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
+
+at 0x0000023a : */ 0x18000000,0x00000808,
+/*
+ MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
+
+at 0x0000023c : */ 0x18000000,0x00000810,
+/*
+ MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
+
+at 0x0000023e : */ 0x18000000,0x00000818,
+/*
+ MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
+
+at 0x00000240 : */ 0x18000000,0x00000820,
+/*
+ENTRY end_data_trans
+end_data_trans:
+redo_msgin3:
+ JUMP get_status, WHEN STATUS
+
+at 0x00000242 : */ 0x830b0000,0x000000a0,
+/*
+ JUMP get_msgin3, WHEN MSG_IN
+
+at 0x00000244 : */ 0x870b0000,0x00000b20,
+/*
+ INT int_data_bad_phase
+
+at 0x00000246 : */ 0x98080000,0xab93000b,
+/*
+
+get_msgin1:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x00000248 : */ 0x7a344000,0x00000000,
+/*
+ MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000024a : */ 0x0f000001,0x00000000,
+/*
+ JUMP ext_msg1, IF 0x01 ; Extended Message
+
+at 0x0000024c : */ 0x800c0001,0x00000968,
+/*
+ JUMP ignore_msg1, IF 0x02 ; Save Data Pointers
+
+at 0x0000024e : */ 0x800c0002,0x00000958,
+/*
+ JUMP ignore_msg1, IF 0x03 ; Save Restore Pointers
+
+at 0x00000250 : */ 0x800c0003,0x00000958,
+/*
+ JUMP disc1, IF 0x04 ; Disconnect
+
+at 0x00000252 : */ 0x800c0004,0x000009c8,
+/*
+ INT int_bad_msg1
+
+at 0x00000254 : */ 0x98080000,0xab930006,
+/*
+ignore_msg1:
+ CLEAR ACK
+
+at 0x00000256 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin1
+
+at 0x00000258 : */ 0x80080000,0x00000058,
+/*
+ext_msg1:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x0000025a : */ 0x7a348000,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x0000025c : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x0000025e : */ 0x0f000001,0x00000001,
+/*
+ JUMP ext_msg1a, IF 0x03
+
+at 0x00000260 : */ 0x800c0003,0x00000990,
+/*
+ INT int_bad_extmsg1a
+
+at 0x00000262 : */ 0x98080000,0xab930000,
+/*
+ext_msg1a:
+ CLEAR ACK
+
+at 0x00000264 : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x00000266 : */ 0x0f000001,0x00000002,
+/*
+ JUMP ext_msg1b, IF 0x01 ; Must be SDTR
+
+at 0x00000268 : */ 0x800c0001,0x000009b0,
+/*
+ INT int_bad_extmsg1b
+
+at 0x0000026a : */ 0x98080000,0xab930001,
+/*
+ext_msg1b:
+ CLEAR ACK
+
+at 0x0000026c : */ 0x60000040,0x00000000,
+/*
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x0000026e : */ 0x0f000002,0x00000003,
+/*
+ INT int_msg_sdtr1
+
+at 0x00000270 : */ 0x98080000,0xab93000c,
+/*
+disc1:
+ CLEAR ACK
+
+at 0x00000272 : */ 0x60000040,0x00000000,
+/*
+ENTRY wait_disc1
+wait_disc1:
+ WAIT DISCONNECT
+
+at 0x00000274 : */ 0x48000000,0x00000000,
+/*
+ INT int_disc1
+
+at 0x00000276 : */ 0x98080000,0xab930019,
+/*
+ENTRY resume_msgin1a
+resume_msgin1a:
+ CLEAR ACK
+
+at 0x00000278 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin1
+
+at 0x0000027a : */ 0x80080000,0x00000058,
+/*
+ENTRY resume_msgin1b
+resume_msgin1b:
+ SET ATN
+
+at 0x0000027c : */ 0x58000008,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x0000027e : */ 0x60000040,0x00000000,
+/*
+ INT int_no_msgout1, WHEN NOT MSG_OUT
+
+at 0x00000280 : */ 0x9e030000,0xab93000f,
+/*
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000282 : */ 0x7a340200,0x00000000,
+/*
+ MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000284 : */ 0x1e000000,0x00000008,
+/*
+ JUMP redo_msgin1
+
+at 0x00000286 : */ 0x80080000,0x00000058,
+/*
+
+get_msgin2:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x00000288 : */ 0x7a344000,0x00000000,
+/*
+ MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000028a : */ 0x0f000001,0x00000000,
+/*
+ JUMP ext_msg2, IF 0x01 ; Extended Message
+
+at 0x0000028c : */ 0x800c0001,0x00000a68,
+/*
+ JUMP ignore_msg2, IF 0x02 ; Save Data Pointers
+
+at 0x0000028e : */ 0x800c0002,0x00000a58,
+/*
+ JUMP ignore_msg2, IF 0x03 ; Save Restore Pointers
+
+at 0x00000290 : */ 0x800c0003,0x00000a58,
+/*
+ JUMP disc2, IF 0x04 ; Disconnect
+
+at 0x00000292 : */ 0x800c0004,0x00000ac8,
+/*
+ INT int_bad_msg2
+
+at 0x00000294 : */ 0x98080000,0xab930007,
+/*
+ignore_msg2:
+ CLEAR ACK
+
+at 0x00000296 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin2
+
+at 0x00000298 : */ 0x80080000,0x00000078,
+/*
+ext_msg2:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x0000029a : */ 0x7a348000,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x0000029c : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x0000029e : */ 0x0f000001,0x00000001,
+/*
+ JUMP ext_msg2a, IF 0x03
+
+at 0x000002a0 : */ 0x800c0003,0x00000a90,
+/*
+ INT int_bad_extmsg2a
+
+at 0x000002a2 : */ 0x98080000,0xab930002,
+/*
+ext_msg2a:
+ CLEAR ACK
+
+at 0x000002a4 : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002a6 : */ 0x0f000001,0x00000002,
+/*
+ JUMP ext_msg2b, IF 0x01 ; Must be SDTR
+
+at 0x000002a8 : */ 0x800c0001,0x00000ab0,
+/*
+ INT int_bad_extmsg2b
+
+at 0x000002aa : */ 0x98080000,0xab930003,
+/*
+ext_msg2b:
+ CLEAR ACK
+
+at 0x000002ac : */ 0x60000040,0x00000000,
+/*
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002ae : */ 0x0f000002,0x00000003,
+/*
+ INT int_msg_sdtr2
+
+at 0x000002b0 : */ 0x98080000,0xab93000d,
+/*
+disc2:
+ CLEAR ACK
+
+at 0x000002b2 : */ 0x60000040,0x00000000,
+/*
+ENTRY wait_disc2
+wait_disc2:
+ WAIT DISCONNECT
+
+at 0x000002b4 : */ 0x48000000,0x00000000,
+/*
+ INT int_disc2
+
+at 0x000002b6 : */ 0x98080000,0xab93001a,
+/*
+ENTRY resume_msgin2a
+resume_msgin2a:
+ CLEAR ACK
+
+at 0x000002b8 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin2
+
+at 0x000002ba : */ 0x80080000,0x00000078,
+/*
+ENTRY resume_msgin2b
+resume_msgin2b:
+ SET ATN
+
+at 0x000002bc : */ 0x58000008,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x000002be : */ 0x60000040,0x00000000,
+/*
+ INT int_no_msgout2, WHEN NOT MSG_OUT
+
+at 0x000002c0 : */ 0x9e030000,0xab930010,
+/*
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x000002c2 : */ 0x7a340200,0x00000000,
+/*
+ MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x000002c4 : */ 0x1e000000,0x00000008,
+/*
+ JUMP redo_msgin2
+
+at 0x000002c6 : */ 0x80080000,0x00000078,
+/*
+
+get_msgin3:
+ MOVE SCRATCH0 | had_msgin TO SCRATCH0
+
+at 0x000002c8 : */ 0x7a344000,0x00000000,
+/*
+ MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x000002ca : */ 0x0f000001,0x00000000,
+/*
+ JUMP ext_msg3, IF 0x01 ; Extended Message
+
+at 0x000002cc : */ 0x800c0001,0x00000b68,
+/*
+ JUMP ignore_msg3, IF 0x02 ; Save Data Pointers
+
+at 0x000002ce : */ 0x800c0002,0x00000b58,
+/*
+ JUMP ignore_msg3, IF 0x03 ; Save Restore Pointers
+
+at 0x000002d0 : */ 0x800c0003,0x00000b58,
+/*
+ JUMP disc3, IF 0x04 ; Disconnect
+
+at 0x000002d2 : */ 0x800c0004,0x00000bc8,
+/*
+ INT int_bad_msg3
+
+at 0x000002d4 : */ 0x98080000,0xab930008,
+/*
+ignore_msg3:
+ CLEAR ACK
+
+at 0x000002d6 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin3
+
+at 0x000002d8 : */ 0x80080000,0x00000908,
+/*
+ext_msg3:
+ MOVE SCRATCH0 | had_extmsg TO SCRATCH0
+
+at 0x000002da : */ 0x7a348000,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x000002dc : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 1, WHEN MSG_IN
+
+at 0x000002de : */ 0x0f000001,0x00000001,
+/*
+ JUMP ext_msg3a, IF 0x03
+
+at 0x000002e0 : */ 0x800c0003,0x00000b90,
+/*
+ INT int_bad_extmsg3a
+
+at 0x000002e2 : */ 0x98080000,0xab930004,
+/*
+ext_msg3a:
+ CLEAR ACK
+
+at 0x000002e4 : */ 0x60000040,0x00000000,
+/*
+ MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002e6 : */ 0x0f000001,0x00000002,
+/*
+ JUMP ext_msg3b, IF 0x01 ; Must be SDTR
+
+at 0x000002e8 : */ 0x800c0001,0x00000bb0,
+/*
+ INT int_bad_extmsg3b
+
+at 0x000002ea : */ 0x98080000,0xab930005,
+/*
+ext_msg3b:
+ CLEAR ACK
+
+at 0x000002ec : */ 0x60000040,0x00000000,
+/*
+ MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002ee : */ 0x0f000002,0x00000003,
+/*
+ INT int_msg_sdtr3
+
+at 0x000002f0 : */ 0x98080000,0xab93000e,
+/*
+disc3:
+ CLEAR ACK
+
+at 0x000002f2 : */ 0x60000040,0x00000000,
+/*
+ENTRY wait_disc3
+wait_disc3:
+ WAIT DISCONNECT
+
+at 0x000002f4 : */ 0x48000000,0x00000000,
+/*
+ INT int_disc3
+
+at 0x000002f6 : */ 0x98080000,0xab93001b,
+/*
+ENTRY resume_msgin3a
+resume_msgin3a:
+ CLEAR ACK
+
+at 0x000002f8 : */ 0x60000040,0x00000000,
+/*
+ JUMP redo_msgin3
+
+at 0x000002fa : */ 0x80080000,0x00000908,
+/*
+ENTRY resume_msgin3b
+resume_msgin3b:
+ SET ATN
+
+at 0x000002fc : */ 0x58000008,0x00000000,
+/*
+ CLEAR ACK
+
+at 0x000002fe : */ 0x60000040,0x00000000,
+/*
+ INT int_no_msgout3, WHEN NOT MSG_OUT
+
+at 0x00000300 : */ 0x9e030000,0xab930011,
+/*
+ MOVE SCRATCH0 | had_msgout TO SCRATCH0
+
+at 0x00000302 : */ 0x7a340200,0x00000000,
+/*
+ MOVE FROM dsa_msgout, when MSG_OUT
+
+at 0x00000304 : */ 0x1e000000,0x00000008,
+/*
+ JUMP redo_msgin3
+
+at 0x00000306 : */ 0x80080000,0x00000908,
+/*
+
+ENTRY resume_rej_ident
+resume_rej_ident:
+ CLEAR ATN
+
+at 0x00000308 : */ 0x60000008,0x00000000,
+/*
+ MOVE 1, msgin_buf, WHEN MSG_IN
+
+at 0x0000030a : */ 0x0f000001,0x00000000,
+/*
+ INT int_not_rej, IF NOT 0x07 ; Reject
+
+at 0x0000030c : */ 0x98040007,0xab93001c,
+/*
+ CLEAR ACK
+
+at 0x0000030e : */ 0x60000040,0x00000000,
+/*
+ JUMP done_ident
+
+at 0x00000310 : */ 0x80080000,0x00000050,
+/*
+
+ENTRY reselect
+reselect:
+ ; Disable selection timer
+ MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000312 : */ 0x7a1b1000,0x00000000,
+/*
+ WAIT RESELECT resel_err
+
+at 0x00000314 : */ 0x50000000,0x00000c70,
+/*
+ INT int_resel_not_msgin, WHEN NOT MSG_IN
+
+at 0x00000316 : */ 0x9f030000,0xab930016,
+/*
+ MOVE 1, reselected_identify, WHEN MSG_IN
+
+at 0x00000318 : */ 0x0f000001,0x00000000,
+/*
+ INT int_reselected
+
+at 0x0000031a : */ 0x98080000,0xab930017,
+/*
+resel_err:
+ MOVE CTEST2 & 0x40 TO SFBR
+
+at 0x0000031c : */ 0x74164000,0x00000000,
+/*
+ JUMP selected, IF 0x00
+
+at 0x0000031e : */ 0x800c0000,0x00000cb0,
+/*
+ MOVE SFBR & 0 TO SFBR
+
+at 0x00000320 : */ 0x7c080000,0x00000000,
+/*
+ENTRY patch_new_dsa
+patch_new_dsa:
+ MOVE SFBR | 0x11 TO DSA0
+
+at 0x00000322 : */ 0x6a101100,0x00000000,
+/*
+ MOVE SFBR | 0x22 TO DSA1
+
+at 0x00000324 : */ 0x6a112200,0x00000000,
+/*
+ MOVE SFBR | 0x33 TO DSA2
+
+at 0x00000326 : */ 0x6a123300,0x00000000,
+/*
+ MOVE SFBR | 0x44 TO DSA3
+
+at 0x00000328 : */ 0x6a134400,0x00000000,
+/*
+ JUMP do_select
+
+at 0x0000032a : */ 0x80080000,0x00000000,
+/*
+
+selected:
+ INT int_selected
+
+at 0x0000032c : */ 0x98080000,0xab930018,
+};
+
+#define A_dsa_cmnd 0x00000010
+u32 A_dsa_cmnd_used[] = {
+ 0x0000001d,
+};
+
+#define A_dsa_datain 0x00000028
+u32 A_dsa_datain_used[] = {
+ 0x0000003d,
+ 0x0000003f,
+ 0x00000041,
+ 0x00000043,
+ 0x00000045,
+ 0x00000047,
+ 0x00000049,
+ 0x0000004b,
+ 0x0000004d,
+ 0x0000004f,
+ 0x00000051,
+ 0x00000053,
+ 0x00000055,
+ 0x00000057,
+ 0x00000059,
+ 0x0000005b,
+ 0x0000005d,
+ 0x0000005f,
+ 0x00000061,
+ 0x00000063,
+ 0x00000065,
+ 0x00000067,
+ 0x00000069,
+ 0x0000006b,
+ 0x0000006d,
+ 0x0000006f,
+ 0x00000071,
+ 0x00000073,
+ 0x00000075,
+ 0x00000077,
+ 0x00000079,
+ 0x0000007b,
+ 0x0000007d,
+ 0x0000007f,
+ 0x00000081,
+ 0x00000083,
+ 0x00000085,
+ 0x00000087,
+ 0x00000089,
+ 0x0000008b,
+ 0x0000008d,
+ 0x0000008f,
+ 0x00000091,
+ 0x00000093,
+ 0x00000095,
+ 0x00000097,
+ 0x00000099,
+ 0x0000009b,
+ 0x0000009d,
+ 0x0000009f,
+ 0x000000a1,
+ 0x000000a3,
+ 0x000000a5,
+ 0x000000a7,
+ 0x000000a9,
+ 0x000000ab,
+ 0x000000ad,
+ 0x000000af,
+ 0x000000b1,
+ 0x000000b3,
+ 0x000000b5,
+ 0x000000b7,
+ 0x000000b9,
+ 0x000000bb,
+ 0x000000bd,
+ 0x000000bf,
+ 0x000000c1,
+ 0x000000c3,
+ 0x000000c5,
+ 0x000000c7,
+ 0x000000c9,
+ 0x000000cb,
+ 0x000000cd,
+ 0x000000cf,
+ 0x000000d1,
+ 0x000000d3,
+ 0x000000d5,
+ 0x000000d7,
+ 0x000000d9,
+ 0x000000db,
+ 0x000000dd,
+ 0x000000df,
+ 0x000000e1,
+ 0x000000e3,
+ 0x000000e5,
+ 0x000000e7,
+ 0x000000e9,
+ 0x000000eb,
+ 0x000000ed,
+ 0x000000ef,
+ 0x000000f1,
+ 0x000000f3,
+ 0x000000f5,
+ 0x000000f7,
+ 0x000000f9,
+ 0x000000fb,
+ 0x000000fd,
+ 0x000000ff,
+ 0x00000101,
+ 0x00000103,
+ 0x00000105,
+ 0x00000107,
+ 0x00000109,
+ 0x0000010b,
+ 0x0000010d,
+ 0x0000010f,
+ 0x00000111,
+ 0x00000113,
+ 0x00000115,
+ 0x00000117,
+ 0x00000119,
+ 0x0000011b,
+ 0x0000011d,
+ 0x0000011f,
+ 0x00000121,
+ 0x00000123,
+ 0x00000125,
+ 0x00000127,
+ 0x00000129,
+ 0x0000012b,
+ 0x0000012d,
+ 0x0000012f,
+ 0x00000131,
+ 0x00000133,
+ 0x00000135,
+ 0x00000137,
+ 0x00000139,
+ 0x0000013b,
+};
+
+#define A_dsa_dataout 0x00000428
+u32 A_dsa_dataout_used[] = {
+ 0x00000143,
+ 0x00000145,
+ 0x00000147,
+ 0x00000149,
+ 0x0000014b,
+ 0x0000014d,
+ 0x0000014f,
+ 0x00000151,
+ 0x00000153,
+ 0x00000155,
+ 0x00000157,
+ 0x00000159,
+ 0x0000015b,
+ 0x0000015d,
+ 0x0000015f,
+ 0x00000161,
+ 0x00000163,
+ 0x00000165,
+ 0x00000167,
+ 0x00000169,
+ 0x0000016b,
+ 0x0000016d,
+ 0x0000016f,
+ 0x00000171,
+ 0x00000173,
+ 0x00000175,
+ 0x00000177,
+ 0x00000179,
+ 0x0000017b,
+ 0x0000017d,
+ 0x0000017f,
+ 0x00000181,
+ 0x00000183,
+ 0x00000185,
+ 0x00000187,
+ 0x00000189,
+ 0x0000018b,
+ 0x0000018d,
+ 0x0000018f,
+ 0x00000191,
+ 0x00000193,
+ 0x00000195,
+ 0x00000197,
+ 0x00000199,
+ 0x0000019b,
+ 0x0000019d,
+ 0x0000019f,
+ 0x000001a1,
+ 0x000001a3,
+ 0x000001a5,
+ 0x000001a7,
+ 0x000001a9,
+ 0x000001ab,
+ 0x000001ad,
+ 0x000001af,
+ 0x000001b1,
+ 0x000001b3,
+ 0x000001b5,
+ 0x000001b7,
+ 0x000001b9,
+ 0x000001bb,
+ 0x000001bd,
+ 0x000001bf,
+ 0x000001c1,
+ 0x000001c3,
+ 0x000001c5,
+ 0x000001c7,
+ 0x000001c9,
+ 0x000001cb,
+ 0x000001cd,
+ 0x000001cf,
+ 0x000001d1,
+ 0x000001d3,
+ 0x000001d5,
+ 0x000001d7,
+ 0x000001d9,
+ 0x000001db,
+ 0x000001dd,
+ 0x000001df,
+ 0x000001e1,
+ 0x000001e3,
+ 0x000001e5,
+ 0x000001e7,
+ 0x000001e9,
+ 0x000001eb,
+ 0x000001ed,
+ 0x000001ef,
+ 0x000001f1,
+ 0x000001f3,
+ 0x000001f5,
+ 0x000001f7,
+ 0x000001f9,
+ 0x000001fb,
+ 0x000001fd,
+ 0x000001ff,
+ 0x00000201,
+ 0x00000203,
+ 0x00000205,
+ 0x00000207,
+ 0x00000209,
+ 0x0000020b,
+ 0x0000020d,
+ 0x0000020f,
+ 0x00000211,
+ 0x00000213,
+ 0x00000215,
+ 0x00000217,
+ 0x00000219,
+ 0x0000021b,
+ 0x0000021d,
+ 0x0000021f,
+ 0x00000221,
+ 0x00000223,
+ 0x00000225,
+ 0x00000227,
+ 0x00000229,
+ 0x0000022b,
+ 0x0000022d,
+ 0x0000022f,
+ 0x00000231,
+ 0x00000233,
+ 0x00000235,
+ 0x00000237,
+ 0x00000239,
+ 0x0000023b,
+ 0x0000023d,
+ 0x0000023f,
+ 0x00000241,
+};
+
+#define A_dsa_msgin 0x00000020
+u32 A_dsa_msgin_used[] = {
+ 0x0000002f,
+};
+
+#define A_dsa_msgout 0x00000008
+u32 A_dsa_msgout_used[] = {
+ 0x00000013,
+ 0x00000285,
+ 0x000002c5,
+ 0x00000305,
+};
+
+#define A_dsa_select 0x00000000
+u32 A_dsa_select_used[] = {
+ 0x00000006,
+};
+
+#define A_dsa_size 0x00000828
+u32 A_dsa_size_used[] = {
+};
+
+#define A_dsa_status 0x00000018
+u32 A_dsa_status_used[] = {
+ 0x0000002b,
+};
+
+#define A_had_cmdout 0x00000004
+u32 A_had_cmdout_used[] = {
+ 0x0000001a,
+};
+
+#define A_had_datain 0x00000008
+u32 A_had_datain_used[] = {
+ 0x00000038,
+};
+
+#define A_had_dataout 0x00000010
+u32 A_had_dataout_used[] = {
+ 0x0000013e,
+};
+
+#define A_had_extmsg 0x00000080
+u32 A_had_extmsg_used[] = {
+ 0x0000025a,
+ 0x0000029a,
+ 0x000002da,
+};
+
+#define A_had_msgin 0x00000040
+u32 A_had_msgin_used[] = {
+ 0x00000248,
+ 0x00000288,
+ 0x000002c8,
+};
+
+#define A_had_msgout 0x00000002
+u32 A_had_msgout_used[] = {
+ 0x00000010,
+ 0x00000282,
+ 0x000002c2,
+ 0x00000302,
+};
+
+#define A_had_select 0x00000001
+u32 A_had_select_used[] = {
+ 0x0000000c,
+};
+
+#define A_had_status 0x00000020
+u32 A_had_status_used[] = {
+};
+
+#define A_int_bad_extmsg1a 0xab930000
+u32 A_int_bad_extmsg1a_used[] = {
+ 0x00000263,
+};
+
+#define A_int_bad_extmsg1b 0xab930001
+u32 A_int_bad_extmsg1b_used[] = {
+ 0x0000026b,
+};
+
+#define A_int_bad_extmsg2a 0xab930002
+u32 A_int_bad_extmsg2a_used[] = {
+ 0x000002a3,
+};
+
+#define A_int_bad_extmsg2b 0xab930003
+u32 A_int_bad_extmsg2b_used[] = {
+ 0x000002ab,
+};
+
+#define A_int_bad_extmsg3a 0xab930004
+u32 A_int_bad_extmsg3a_used[] = {
+ 0x000002e3,
+};
+
+#define A_int_bad_extmsg3b 0xab930005
+u32 A_int_bad_extmsg3b_used[] = {
+ 0x000002eb,
+};
+
+#define A_int_bad_msg1 0xab930006
+u32 A_int_bad_msg1_used[] = {
+ 0x00000255,
+};
+
+#define A_int_bad_msg2 0xab930007
+u32 A_int_bad_msg2_used[] = {
+ 0x00000295,
+};
+
+#define A_int_bad_msg3 0xab930008
+u32 A_int_bad_msg3_used[] = {
+ 0x000002d5,
+};
+
+#define A_int_cmd_bad_phase 0xab930009
+u32 A_int_cmd_bad_phase_used[] = {
+ 0x00000027,
+};
+
+#define A_int_cmd_complete 0xab93000a
+u32 A_int_cmd_complete_used[] = {
+ 0x00000037,
+};
+
+#define A_int_data_bad_phase 0xab93000b
+u32 A_int_data_bad_phase_used[] = {
+ 0x00000247,
+};
+
+#define A_int_disc1 0xab930019
+u32 A_int_disc1_used[] = {
+ 0x00000277,
+};
+
+#define A_int_disc2 0xab93001a
+u32 A_int_disc2_used[] = {
+ 0x000002b7,
+};
+
+#define A_int_disc3 0xab93001b
+u32 A_int_disc3_used[] = {
+ 0x000002f7,
+};
+
+#define A_int_msg_sdtr1 0xab93000c
+u32 A_int_msg_sdtr1_used[] = {
+ 0x00000271,
+};
+
+#define A_int_msg_sdtr2 0xab93000d
+u32 A_int_msg_sdtr2_used[] = {
+ 0x000002b1,
+};
+
+#define A_int_msg_sdtr3 0xab93000e
+u32 A_int_msg_sdtr3_used[] = {
+ 0x000002f1,
+};
+
+#define A_int_no_msgout1 0xab93000f
+u32 A_int_no_msgout1_used[] = {
+ 0x00000281,
+};
+
+#define A_int_no_msgout2 0xab930010
+u32 A_int_no_msgout2_used[] = {
+ 0x000002c1,
+};
+
+#define A_int_no_msgout3 0xab930011
+u32 A_int_no_msgout3_used[] = {
+ 0x00000301,
+};
+
+#define A_int_not_cmd_complete 0xab930012
+u32 A_int_not_cmd_complete_used[] = {
+ 0x00000031,
+};
+
+#define A_int_not_rej 0xab93001c
+u32 A_int_not_rej_used[] = {
+ 0x0000030d,
+};
+
+#define A_int_resel_not_msgin 0xab930016
+u32 A_int_resel_not_msgin_used[] = {
+ 0x00000317,
+};
+
+#define A_int_reselected 0xab930017
+u32 A_int_reselected_used[] = {
+ 0x0000031b,
+};
+
+#define A_int_sel_no_ident 0xab930013
+u32 A_int_sel_no_ident_used[] = {
+ 0x0000000f,
+};
+
+#define A_int_sel_not_cmd 0xab930014
+u32 A_int_sel_not_cmd_used[] = {
+ 0x00000019,
+};
+
+#define A_int_selected 0xab930018
+u32 A_int_selected_used[] = {
+ 0x0000032d,
+};
+
+#define A_int_status_not_msgin 0xab930015
+u32 A_int_status_not_msgin_used[] = {
+ 0x0000002d,
+};
+
+#define A_msgin_buf 0x00000000
+u32 A_msgin_buf_used[] = {
+ 0x0000024b,
+ 0x0000025f,
+ 0x00000267,
+ 0x0000026f,
+ 0x0000028b,
+ 0x0000029f,
+ 0x000002a7,
+ 0x000002af,
+ 0x000002cb,
+ 0x000002df,
+ 0x000002e7,
+ 0x000002ef,
+ 0x0000030b,
+};
+
+#define A_reselected_identify 0x00000000
+u32 A_reselected_identify_used[] = {
+ 0x00000319,
+};
+
+#define Ent_do_select 0x00000000
+#define Ent_done_ident 0x00000050
+#define Ent_end_data_trans 0x00000908
+#define Ent_patch_input_data 0x000000e8
+#define Ent_patch_new_dsa 0x00000c88
+#define Ent_patch_output_data 0x00000500
+#define Ent_reselect 0x00000c48
+#define Ent_resume_cmd 0x00000068
+#define Ent_resume_msgin1a 0x000009e0
+#define Ent_resume_msgin1b 0x000009f0
+#define Ent_resume_msgin2a 0x00000ae0
+#define Ent_resume_msgin2b 0x00000af0
+#define Ent_resume_msgin3a 0x00000be0
+#define Ent_resume_msgin3b 0x00000bf0
+#define Ent_resume_pmm 0x00000078
+#define Ent_resume_rej_ident 0x00000c20
+#define Ent_wait_disc1 0x000009d0
+#define Ent_wait_disc2 0x00000ad0
+#define Ent_wait_disc3 0x00000bd0
+#define Ent_wait_disc_complete 0x000000d0
+u32 LABELPATCHES[] = {
+ 0x00000007,
+ 0x00000009,
+ 0x00000015,
+ 0x00000017,
+ 0x0000001f,
+ 0x00000021,
+ 0x00000023,
+ 0x00000025,
+ 0x0000013d,
+ 0x00000243,
+ 0x00000245,
+ 0x0000024d,
+ 0x0000024f,
+ 0x00000251,
+ 0x00000253,
+ 0x00000259,
+ 0x00000261,
+ 0x00000269,
+ 0x0000027b,
+ 0x00000287,
+ 0x0000028d,
+ 0x0000028f,
+ 0x00000291,
+ 0x00000293,
+ 0x00000299,
+ 0x000002a1,
+ 0x000002a9,
+ 0x000002bb,
+ 0x000002c7,
+ 0x000002cd,
+ 0x000002cf,
+ 0x000002d1,
+ 0x000002d3,
+ 0x000002d9,
+ 0x000002e1,
+ 0x000002e9,
+ 0x000002fb,
+ 0x00000307,
+ 0x00000311,
+ 0x00000315,
+ 0x0000031f,
+ 0x0000032b,
+};
+
+struct {
+ u32 offset;
+ void *address;
+} EXTERNAL_PATCHES[] = {
+};
+
+u32 INSTRUCTIONS = 407;
+u32 PATCHES = 42;
+u32 EXTERNAL_PATCHES_LEN = 0;
diff --git a/drivers/scsi/sim710_u.h b/drivers/scsi/sim710_u.h
new file mode 100644
index 000000000..e660a847d
--- /dev/null
+++ b/drivers/scsi/sim710_u.h
@@ -0,0 +1,67 @@
+#undef A_dsa_cmnd
+#undef A_dsa_datain
+#undef A_dsa_dataout
+#undef A_dsa_msgin
+#undef A_dsa_msgout
+#undef A_dsa_select
+#undef A_dsa_size
+#undef A_dsa_status
+#undef A_had_cmdout
+#undef A_had_datain
+#undef A_had_dataout
+#undef A_had_extmsg
+#undef A_had_msgin
+#undef A_had_msgout
+#undef A_had_select
+#undef A_had_status
+#undef A_int_bad_extmsg1a
+#undef A_int_bad_extmsg1b
+#undef A_int_bad_extmsg2a
+#undef A_int_bad_extmsg2b
+#undef A_int_bad_extmsg3a
+#undef A_int_bad_extmsg3b
+#undef A_int_bad_msg1
+#undef A_int_bad_msg2
+#undef A_int_bad_msg3
+#undef A_int_cmd_bad_phase
+#undef A_int_cmd_complete
+#undef A_int_data_bad_phase
+#undef A_int_disc1
+#undef A_int_disc2
+#undef A_int_disc3
+#undef A_int_msg_sdtr1
+#undef A_int_msg_sdtr2
+#undef A_int_msg_sdtr3
+#undef A_int_no_msgout1
+#undef A_int_no_msgout2
+#undef A_int_no_msgout3
+#undef A_int_not_cmd_complete
+#undef A_int_not_rej
+#undef A_int_resel_not_msgin
+#undef A_int_reselected
+#undef A_int_sel_no_ident
+#undef A_int_sel_not_cmd
+#undef A_int_selected
+#undef A_int_status_not_msgin
+#undef A_msgin_buf
+#undef A_reselected_identify
+#undef Ent_do_select
+#undef Ent_done_ident
+#undef Ent_end_data_trans
+#undef Ent_patch_input_data
+#undef Ent_patch_new_dsa
+#undef Ent_patch_output_data
+#undef Ent_reselect
+#undef Ent_resume_cmd
+#undef Ent_resume_msgin1a
+#undef Ent_resume_msgin1b
+#undef Ent_resume_msgin2a
+#undef Ent_resume_msgin2b
+#undef Ent_resume_msgin3a
+#undef Ent_resume_msgin3b
+#undef Ent_resume_pmm
+#undef Ent_resume_rej_ident
+#undef Ent_wait_disc1
+#undef Ent_wait_disc2
+#undef Ent_wait_disc3
+#undef Ent_wait_disc_complete
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index 80696413e..4479532b6 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
@@ -55,7 +55,7 @@
*/
/*
-** April 2 1999, sym53c8xx version 1.3c
+** Sep 10 1999, sym53c8xx 1.5e
**
** Supported SCSI features:
** Synchronous data transfers
@@ -64,13 +64,14 @@
** Tagged command queuing
** SCSI Parity checking
**
-** Supported NCR chips:
+** Supported NCR/SYMBIOS chips:
** 53C810A (8 bits, Fast 10, no rom BIOS)
** 53C825A (Wide, Fast 10, on-board rom BIOS)
** 53C860 (8 bits, Fast 20, no rom BIOS)
** 53C875 (Wide, Fast 20, on-board rom BIOS)
** 53C876 (Wide, Fast 20 Dual, on-board rom BIOS)
** 53C895 (Wide, Fast 40, on-board rom BIOS)
+** 53C895A (Wide, Fast 40, on-board rom BIOS)
** 53C896 (Wide, Fast 40 Dual, on-board rom BIOS)
**
** Other features:
@@ -82,7 +83,7 @@
/*
** Name and version of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.3c"
+#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5e"
/* #define DEBUG_896R1 */
#define SCSI_NCR_OPTIMIZE_896
@@ -109,8 +110,10 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
#endif
#include <linux/delay.h>
#include <linux/signal.h>
@@ -130,13 +133,13 @@
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
#include <linux/init.h>
-#else
-#ifndef __initdata
-#define __initdata
#endif
+
#ifndef __init
#define __init
#endif
+#ifndef __initdata
+#define __initdata
#endif
#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
@@ -314,26 +317,34 @@ static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
#endif
/*
-** TAGS are actually limited to 64 tags/lun.
-** We need to deal with power of 2, for alignment constraints.
+** TAGS are actually unlimited (256 tags/lun).
+** But Linux only supports 255. :)
*/
-#if SCSI_NCR_MAX_TAGS > 64
-#undef SCSI_NCR_MAX_TAGS
-#define SCSI_NCR_MAX_TAGS (64)
+#if SCSI_NCR_MAX_TAGS > 255
+#define MAX_TAGS 255
+#else
+#define MAX_TAGS SCSI_NCR_MAX_TAGS
#endif
-#define NO_TAG (255)
-
/*
-** Choose appropriate type for tag bitmap.
-*/
-#if SCSI_NCR_MAX_TAGS > 32
-typedef u_int64 tagmap_t;
+** Since the ncr chips only have a 8 bit ALU, we try to be clever
+** about offset calculation in the TASK TABLE per LUN that is an
+** array of DWORDS = 4 bytes.
+*/
+#if MAX_TAGS > (512/4)
+#define MAX_TASKS (1024/4)
+#elif MAX_TAGS > (256/4)
+#define MAX_TASKS (512/4)
#else
-typedef u_int32 tagmap_t;
+#define MAX_TASKS (256/4)
#endif
/*
+** This one means 'NO TAG for this job'
+*/
+#define NO_TAG (256)
+
+/*
** Number of targets supported by the driver.
** n permits target numbers 0..n-1.
** Default is 16, meaning targets #0..#15.
@@ -354,7 +365,7 @@ typedef u_int32 tagmap_t;
*/
#ifdef SCSI_NCR_MAX_LUN
-#define MAX_LUN SCSI_NCR_MAX_LUN
+#define MAX_LUN 64
#else
#define MAX_LUN (1)
#endif
@@ -377,51 +388,34 @@ typedef u_int32 tagmap_t;
#ifdef SCSI_NCR_CAN_QUEUE
#define MAX_START (SCSI_NCR_CAN_QUEUE + 4)
#else
-#define MAX_START (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+** We donnot want to allocate more than 1 PAGE for the
+** the start queue and the done queue. We hard-code entry
+** size to 8 in order to let cpp do the checking.
+** Allows 512-4=508 pending IOs for i386 but Linux seems for
+** now not able to provide the driver with this amount of IOs.
+*/
+#if MAX_START > PAGE_SIZE/8
+#undef MAX_START
+#define MAX_START (PAGE_SIZE/8)
#endif
/*
** The maximum number of segments a transfer is split into.
** We support up to 127 segments for both read and write.
-** Since we try to avoid phase mismatches by testing the PHASE
-** before each MOV, the both DATA_IN and DATA_OUT scripts do
-** not fit in the 4K on-chip RAM. For this reason, the data
-** scripts are broken into 2 sub-scripts.
-** 80 (MAX_SCATTERL) segments are moved from a sub-script
-** in on-chip RAM. This makes data transfers shorter than
-** 80k (assuming 1k fs) as fast as possible.
-** The 896 allows to handle phase mismatches from SCRIPTS.
-** So, for this chip, we use a simple array of MOV's.
-** Perhaps, using a simple array of MOV's and going with
-** the phase mismatch interrupt is also the best solution
-** for the 895 in Ultra2-mode, since the PHASE test + MOV
-** latency may be enough to fill the SCSI offset for very
-** fast disks like the Cheatah Wide LVD and so, may waste
-** SCSI BUS bandwitch.
*/
#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
-
-#ifdef SCSI_NCR_OPTIMIZE_896
#define SCR_SG_SIZE (2)
-#define MAX_SCATTERL MAX_SCATTER
-#define MAX_SCATTERH 0
-#else
-#if (MAX_SCATTER > 80)
-#define SCR_SG_SIZE (4)
-#define MAX_SCATTERL 80
-#define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL)
-#else
-#define MAX_SCATTERL MAX_SCATTER
-#define MAX_SCATTERH 0
-#endif
-#endif /* SCSI_NCR_OPTIMIZE_896 */
/*
** Io mapped or memory mapped.
*/
-#if defined(SCSI_NCR_IOMAPPED)
+#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
#define NCR_IOMAPPED
#endif
@@ -464,17 +458,14 @@ typedef u_int32 tagmap_t;
#define DEBUG_ALLOC (0x0001)
#define DEBUG_PHASE (0x0002)
-#define DEBUG_POLL (0x0004)
#define DEBUG_QUEUE (0x0008)
#define DEBUG_RESULT (0x0010)
-#define DEBUG_SCATTER (0x0020)
+#define DEBUG_POINTER (0x0020)
#define DEBUG_SCRIPT (0x0040)
#define DEBUG_TINY (0x0080)
#define DEBUG_TIMING (0x0100)
#define DEBUG_NEGO (0x0200)
#define DEBUG_TAGS (0x0400)
-#define DEBUG_FREEZE (0x0800)
-#define DEBUG_RESTART (0x1000)
/*
** Enable/Disable debug messages.
@@ -569,12 +560,19 @@ spinlock_t sym53c8xx_lock;
#endif
#ifdef __sparc__
-#define pcivtobus(p) ((p) & pci_dvma_mask)
-#else /* __sparc__ */
-#define pcivtobus(p) (p)
+# define ioremap(base, size) ((u_long) __va(base))
+# define iounmap(vaddr)
+# define pcivtobus(p) ((p) & pci_dvma_mask)
+# define memcpy_to_pci(a, b, c) memcpy_toio((u_long) (a), (b), (c))
+#elif defined(__alpha__)
+# define pcivtobus(p) ((p) & 0xfffffffful)
+# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
+#else /* others */
+# define pcivtobus(p) (p)
+# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c))
#endif
-#if !defined(NCR_IOMAPPED) || defined(__i386__)
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
static u_long __init remap_pci_mem(u_long base, u_long size)
{
u_long page_base = ((u_long) base) & PAGE_MASK;
@@ -589,7 +587,8 @@ static void __init unmap_pci_mem(u_long vaddr, u_long size)
if (vaddr)
iounmap((void *) (vaddr & PAGE_MASK));
}
-#endif /* !NCR_IOMAPPED || __i386__ */
+
+#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
/*
** Insert a delay in micro-seconds and milli-seconds.
@@ -760,7 +759,7 @@ static void *m_calloc(int size, char *name, int uflags)
NCR_UNLOCK_DRIVER(flags);
if (DEBUG_FLAGS & DEBUG_ALLOC)
- printk ("new %s[%d] @%p.\n", name, size, p);
+ printk ("new %-10s[%4d] @%p.\n", name, size, p);
if (p)
memset(p, 0, size);
@@ -775,13 +774,26 @@ static void m_free(void *ptr, int size, char *name)
u_long flags;
if (DEBUG_FLAGS & DEBUG_ALLOC)
- printk ("freeing %s[%d] @%p.\n", name, size, ptr);
+ printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
NCR_LOCK_DRIVER(flags);
__m_free(ptr, size);
NCR_UNLOCK_DRIVER(flags);
}
+static void ncr_print_hex(u_char *p, int n)
+{
+ while (n-- > 0)
+ printk (" %x", *p++);
+}
+
+static void ncr_printl_hex(char *label, u_char *p, int n)
+{
+ printk("%s", label);
+ ncr_print_hex(p, n);
+ printk (".\n");
+}
+
/*
** Transfer direction
**
@@ -831,34 +843,6 @@ static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
** This structure is initialized from linux config options.
** It can be overridden at boot-up by the boot command line.
*/
-#define SCSI_NCR_MAX_EXCLUDES 8
-struct ncr_driver_setup {
- u_char master_parity;
- u_char scsi_parity;
- u_char disconnection;
- u_char special_features;
- u_char ultra_scsi;
- u_char force_sync_nego;
- u_char reverse_probe;
- u_char pci_fix_up;
- u_char use_nvram;
- u_char verbose;
- u_char default_tags;
- u_short default_sync;
- u_short debug;
- u_char burst_max;
- u_char led_pin;
- u_char max_wide;
- u_char settle_delay;
- u_char diff_support;
- u_char irqm;
- u_char bus_check;
- u_char optimize;
- u_char recovery;
- u_int excludes[SCSI_NCR_MAX_EXCLUDES];
- char tag_ctrl[100];
-};
-
static struct ncr_driver_setup
driver_setup = SCSI_NCR_DRIVER_SETUP;
@@ -888,134 +872,7 @@ static void sym53c8xx_timeout(unsigned long np);
#define bootverbose (np->verbose)
#ifdef SCSI_NCR_NVRAM_SUPPORT
-/*
-** Symbios NvRAM data format
-*/
-#define SYMBIOS_NVRAM_SIZE 368
-#define SYMBIOS_NVRAM_ADDRESS 0x100
-
-struct Symbios_nvram {
-/* Header 6 bytes */
- u_short type; /* 0x0000 */
- u_short byte_count; /* excluding header/trailer */
- u_short checksum;
-
-/* Controller set up 20 bytes */
- u_char v_major; /* 0x00 */
- u_char v_minor; /* 0x30 */
- u_int32 boot_crc;
- u_short flags;
-#define SYMBIOS_SCAM_ENABLE (1)
-#define SYMBIOS_PARITY_ENABLE (1<<1)
-#define SYMBIOS_VERBOSE_MSGS (1<<2)
-#define SYMBIOS_CHS_MAPPING (1<<3)
-#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */
- u_short flags1;
-#define SYMBIOS_SCAN_HI_LO (1)
- u_short term_state;
-#define SYMBIOS_TERM_CANT_PROGRAM (0)
-#define SYMBIOS_TERM_ENABLED (1)
-#define SYMBIOS_TERM_DISABLED (2)
- u_short rmvbl_flags;
-#define SYMBIOS_RMVBL_NO_SUPPORT (0)
-#define SYMBIOS_RMVBL_BOOT_DEVICE (1)
-#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2)
- u_char host_id;
- u_char num_hba; /* 0x04 */
- u_char num_devices; /* 0x10 */
- u_char max_scam_devices; /* 0x04 */
- u_char num_valid_scam_devives; /* 0x00 */
- u_char rsvd;
-
-/* Boot order 14 bytes * 4 */
- struct Symbios_host{
- u_short type; /* 4:8xx / 0:nok */
- u_short device_id; /* PCI device id */
- u_short vendor_id; /* PCI vendor id */
- u_char bus_nr; /* PCI bus number */
- u_char device_fn; /* PCI device/function number << 3*/
- u_short word8;
- u_short flags;
-#define SYMBIOS_INIT_SCAN_AT_BOOT (1)
- u_short io_port; /* PCI io_port address */
- } host[4];
-
-/* Targets 8 bytes * 16 */
- struct Symbios_target {
- u_char flags;
-#define SYMBIOS_DISCONNECT_ENABLE (1)
-#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1)
-#define SYMBIOS_SCAN_LUNS (1<<2)
-#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3)
- u_char rsvd;
- u_char bus_width; /* 0x08/0x10 */
- u_char sync_offset;
- u_short sync_period; /* 4*period factor */
- u_short timeout;
- } target[16];
-/* Scam table 8 bytes * 4 */
- struct Symbios_scam {
- u_short id;
- u_short method;
-#define SYMBIOS_SCAM_DEFAULT_METHOD (0)
-#define SYMBIOS_SCAM_DONT_ASSIGN (1)
-#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2)
-#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3)
- u_short status;
-#define SYMBIOS_SCAM_UNKNOWN (0)
-#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1)
-#define SYMBIOS_SCAM_ID_NOT_SET (2)
-#define SYMBIOS_SCAM_ID_VALID (3)
- u_char target_id;
- u_char rsvd;
- } scam[4];
-
- u_char spare_devices[15*8];
- u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
-};
-typedef struct Symbios_nvram Symbios_nvram;
-typedef struct Symbios_host Symbios_host;
-typedef struct Symbios_target Symbios_target;
-typedef struct Symbios_scam Symbios_scam;
-
-/*
-** Tekram NvRAM data format.
-*/
-#define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_NVRAM_ADDRESS 0
-
-struct Tekram_nvram {
- struct Tekram_target {
- u_char flags;
-#define TEKRAM_PARITY_CHECK (1)
-#define TEKRAM_SYNC_NEGO (1<<1)
-#define TEKRAM_DISCONNECT_ENABLE (1<<2)
-#define TEKRAM_START_CMD (1<<3)
-#define TEKRAM_TAGGED_COMMANDS (1<<4)
-#define TEKRAM_WIDE_NEGO (1<<5)
- u_char sync_index;
- u_short word2;
- } target[16];
- u_char host_id;
- u_char flags;
-#define TEKRAM_MORE_THAN_2_DRIVES (1)
-#define TEKRAM_DRIVES_SUP_1GB (1<<1)
-#define TEKRAM_RESET_ON_POWER_ON (1<<2)
-#define TEKRAM_ACTIVE_NEGATION (1<<3)
-#define TEKRAM_IMMEDIATE_SEEK (1<<4)
-#define TEKRAM_SCAN_LUNS (1<<5)
-#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; 1: boot device; 2:all */
- u_char boot_delay_index;
- u_char max_tags_index;
- u_short flags1;
-#define TEKRAM_F2_F6_ENABLED (1)
- u_short spare[29];
-};
-typedef struct Tekram_nvram Tekram_nvram;
-typedef struct Tekram_target Tekram_target;
-
static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-
#endif /* SCSI_NCR_NVRAM_SUPPORT */
/*
@@ -1282,36 +1139,38 @@ typedef struct {
#define SIR_BAD_STATUS (1)
#define SIR_SEL_ATN_NO_MSG_OUT (2)
-#define SIR_NEGO_SYNC (3)
-#define SIR_NEGO_WIDE (4)
+#define SIR_MSG_RECEIVED (3)
+#define SIR_MSG_WEIRD (4)
#define SIR_NEGO_FAILED (5)
#define SIR_NEGO_PROTO (6)
-#define SIR_REJECT_RECEIVED (7)
+#define SIR_SCRIPT_STOPPED (7)
#define SIR_REJECT_TO_SEND (8)
-#define SIR_IGN_RESIDUE (9)
-#define SIR_MISSING_SAVE (10)
+#define SIR_SWIDE_OVERRUN (9)
+#define SIR_SODL_UNDERRUN (10)
#define SIR_RESEL_NO_MSG_IN (11)
#define SIR_RESEL_NO_IDENTIFY (12)
#define SIR_RESEL_BAD_LUN (13)
-#define SIR_UNUSED_14 (14)
+#define SIR_TARGET_SELECTED (14)
#define SIR_RESEL_BAD_I_T_L (15)
#define SIR_RESEL_BAD_I_T_L_Q (16)
-#define SIR_UNUSED_17 (17)
+#define SIR_ABORT_SENT (17)
#define SIR_RESEL_ABORTED (18)
#define SIR_MSG_OUT_DONE (19)
-#define SIR_MAX (19)
+#define SIR_AUTO_SENSE_DONE (20)
+#define SIR_DUMMY_INTERRUPT (21)
+#define SIR_MAX (21)
/*==========================================================
**
-** Extended error codes.
+** Extended error bits.
** xerr_status field of struct ccb.
**
**==========================================================
*/
-#define XE_OK (0)
-#define XE_EXTRA_DATA (1) /* unexpected data phase */
-#define XE_BAD_PHASE (2) /* illegal phase (4/5) */
+#define XE_EXTRA_DATA (1) /* unexpected data phase */
+#define XE_BAD_PHASE (2) /* illegal phase (4/5) */
+#define XE_PARITY_ERR (4) /* unrecovered SCSI parity error */
/*==========================================================
**
@@ -1334,9 +1193,6 @@ typedef struct {
*/
#define QUIRK_AUTOSAVE (0x01)
-#define QUIRK_NOMSG (0x02)
-#define QUIRK_NOSYNC (0x10)
-#define QUIRK_NOWIDE16 (0x20)
/*==========================================================
**
@@ -1400,6 +1256,8 @@ struct usrcmd {
#define UC_SETFLAG 15
#define UC_CLEARPROF 16
#define UC_SETVERBOSE 17
+#define UC_RESETDEV 18
+#define UC_CLEARDEV 19
#define UF_TRACE (0x01)
#define UF_NODISC (0x02)
@@ -1443,8 +1301,11 @@ struct tcb {
*/
u_int32 *luntbl; /* lcbs bus address table */
u_int32 b_luntbl; /* bus address of this table */
- lcb_p lp[MAX_LUN]; /* The lcb's of this tcb */
-
+ u_int32 b_lun0; /* bus address of lun0 */
+ lcb_p l0p; /* lcb of LUN #0 (normal case) */
+#if MAX_LUN > 1
+ lcb_p *lmp; /* Other lcb's [1..MAX_LUN] */
+#endif
/*----------------------------------------------------------------
** Target capabilities.
**----------------------------------------------------------------
@@ -1453,6 +1314,12 @@ struct tcb {
u_char inq_byte7; /* Contains these capabilities */
/*----------------------------------------------------------------
+ ** Some flags.
+ **----------------------------------------------------------------
+ */
+ u_char to_reset; /* This target is to be reset */
+
+ /*----------------------------------------------------------------
** Pointer to the ccb used for negotiation.
** Prevent from starting a negotiation for all queued commands
** when tagged command queuing is enabled.
@@ -1488,8 +1355,8 @@ struct tcb {
*/
u_char usrsync;
u_char usrwide;
- u_char usrtags;
u_char usrflag;
+ u_short usrtags;
};
/*========================================================================
@@ -1526,11 +1393,11 @@ struct lcb {
*/
XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */
XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */
- u_char busyccbs; /* CCBs busy for this lun */
- u_char queuedccbs; /* CCBs queued to the controller*/
- u_char queuedepth; /* Queue depth for this lun */
- u_char scdev_depth; /* SCSI device queue depth */
- u_char maxnxs; /* Max possible nexuses */
+ u_short busyccbs; /* CCBs busy for this lun */
+ u_short queuedccbs; /* CCBs queued to the controller*/
+ u_short queuedepth; /* Queue depth for this lun */
+ u_short scdev_depth; /* SCSI device queue depth */
+ u_short maxnxs; /* Max possible nexuses */
/*----------------------------------------------------------------
** Control of tagged command queuing.
@@ -1538,22 +1405,23 @@ struct lcb {
** This avoids using a loop for tag allocation.
**----------------------------------------------------------------
*/
- u_char ia_tag; /* Tag allocation index */
- u_char if_tag; /* Tag release index */
- u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer */
+ u_short ia_tag; /* Tag allocation index */
+ u_short if_tag; /* Tag release index */
+ u_char *cb_tags; /* Circular tags buffer */
+ u_char inq_byte7; /* Store unit CmdQ capability */
u_char usetags; /* Command queuing is active */
- u_char maxtags; /* Max NR of tags asked by user */
- u_char numtags; /* Current number of tags */
- u_char inq_byte7; /* Store unit CmdQ capabitility */
+ u_char to_clear; /* User wants to clear all tasks*/
+ u_short maxtags; /* Max NR of tags asked by user */
+ u_short numtags; /* Current number of tags */
/*----------------------------------------------------------------
** QUEUE FULL and ORDERED tag control.
**----------------------------------------------------------------
*/
u_short num_good; /* Nr of GOOD since QUEUE FULL */
- tagmap_t tags_umap; /* Used tags bitmap */
- tagmap_t tags_smap; /* Tags in use at 'tag_stime' */
- u_long tags_stime; /* Last time we set smap=umap */
+ u_short tags_sum[2]; /* Tags sum counters */
+ u_char tags_si; /* Current index to tags sum */
+ u_long tags_stime; /* Last time we switch tags_sum */
};
/*========================================================================
@@ -1641,6 +1509,18 @@ struct head {
};
/*
+** LUN control block lookup.
+** We use a direct pointer for LUN #0, and a table of pointers
+** which is only allocated for devices that support LUN(s) > 0.
+*/
+#if MAX_LUN <= 1
+#define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0
+#else
+#define ncr_lp(np, tp, lun) \
+ (!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0
+#endif
+
+/*
** The status bytes are used by the host and the script processor.
**
** The last four bytes (status[4]) are copied to the scratchb register
@@ -1683,10 +1563,14 @@ struct head {
#define HF_IN_PM1 (1u<<1)
#define HF_ACT_PM (1u<<2)
#define HF_DP_SAVED (1u<<3)
-#define HF_PAR_ERR (1u<<4)
+#define HF_AUTO_SENSE (1u<<4)
#define HF_DATA_ST (1u<<5)
#define HF_PM_TO_C (1u<<6)
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define HF_HINT_IARB (1u<<7)
+#endif
+
/*
** First four bytes (script)
*/
@@ -1731,6 +1615,7 @@ struct dsb {
struct scr_tblsel select;
struct scr_tblmove smsg ;
+ struct scr_tblmove smsg_ext ;
struct scr_tblmove cmd ;
struct scr_tblmove sense ;
struct scr_tblmove data [MAX_SCATTER];
@@ -1744,6 +1629,12 @@ struct dsb {
struct pm_ctx pm0;
struct pm_ctx pm1;
+ /*
+ ** Extra bytes count transferred
+ ** in case of data overrun.
+ */
+ u_int32 extra_bytes;
+
#ifdef SCSI_NCR_PROFILE_SUPPORT
/*
** Disconnection counter
@@ -1774,8 +1665,8 @@ struct ccb {
**----------------------------------------------------------------
*/
Scsi_Cmnd *cmd; /* SCSI command */
- u_long tlimit; /* Deadline for this job */
int data_len; /* Total data length */
+ int segments; /* Number of SG segments */
/*----------------------------------------------------------------
** Message areas.
@@ -1791,21 +1682,34 @@ struct ccb {
u_char scsi_smsg2[8];
/*----------------------------------------------------------------
+ ** Saved info for auto-sense
+ **----------------------------------------------------------------
+ */
+ u_char sv_scsi_status;
+ u_char sv_xerr_status;
+
+ /*----------------------------------------------------------------
** Other fields.
**----------------------------------------------------------------
*/
u_long p_ccb; /* BUS address of this CCB */
u_char sensecmd[6]; /* Sense command */
- u_char tag; /* Tag for this transfer */
- /* 255 means no tag */
+ u_char to_abort; /* This CCB is to be aborted */
+ u_short tag; /* Tag for this transfer */
+ /* NO_TAG means no tag */
+ u_char tags_si; /* Lun tags sum index (0,1) */
+
u_char target;
u_char lun;
- u_char queued;
- u_char auto_sense;
+ u_short queued;
ccb_p link_ccb; /* Host adapter CCB chain */
ccb_p link_ccbh; /* Host adapter CCB hash chain */
XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */
u_int32 startp; /* Initial data pointer */
+ u_int32 lastp0; /* Initial 'lastp' */
+ int ext_sg; /* Extreme data pointer, used */
+ int ext_ofs; /* to calculate the residual. */
+ int resid;
};
#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1899,11 +1803,15 @@ struct ncb {
** Virtual and physical bus addresses of the chip.
**----------------------------------------------------------------
*/
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
u_long base_va; /* MMIO base virtual address */
+ u_long base2_va; /* On-chip RAM virtual address */
+#endif
u_long base_ba; /* MMIO base bus address */
u_long base_io; /* IO space base address */
u_long base_ws; /* (MM)IO window size */
- u_long base2_ba; /* On-chip RAM bus address. */
+ u_long base2_ba; /* On-chip RAM bus address */
+ u_long base2_ws; /* On-chip RAM window size */
u_int irq; /* IRQ number */
volatile /* Pointer to volatile for */
struct ncr_reg *reg; /* memory mapped IO. */
@@ -1912,7 +1820,7 @@ struct ncb {
** SCRIPTS virtual and physical bus addresses.
** 'script' is loaded in the on-chip RAM if present.
** 'scripth' stays in main memory for all chips except the
- ** 53C896 that provides 8K on-chip RAM.
+ ** 53C895A and 53C896 that provide 8K on-chip RAM.
**----------------------------------------------------------------
*/
struct script *script0; /* Copies of script and scripth */
@@ -2004,6 +1912,24 @@ struct ncb {
XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */
/*----------------------------------------------------------------
+ ** IMMEDIATE ARBITRATION (IARB) control.
+ ** We keep track in 'last_cp' of the last CCB that has been
+ ** queued to the SCRIPTS processor and clear 'last_cp' when
+ ** this CCB completes. If last_cp is not zero at the moment
+ ** we queue a new CCB, we set a flag in 'last_cp' that is
+ ** used by the SCRIPTS as a hint for setting IARB.
+ ** We donnot set more than 'iarb_max' consecutive hints for
+ ** IARB in order to leave devices a chance to reselect.
+ ** By the way, any non zero value of 'iarb_max' is unfair. :)
+ **----------------------------------------------------------------
+ */
+#ifdef SCSI_NCR_IARB_SUPPORT
+ struct ccb *last_cp; /* Last queud CCB used for IARB */
+ u_short iarb_max; /* Max. # consecutive IARB hints*/
+ u_short iarb_count; /* Actual # of these hints */
+#endif
+
+ /*----------------------------------------------------------------
** We need the LCB in order to handle disconnections and
** to count active CCBs for task management. So, we use
** a unique CCB for LUNs we donnot have the LCB yet.
@@ -2019,6 +1945,17 @@ struct ncb {
int (*scatter) (ccb_p, Scsi_Cmnd *);
/*----------------------------------------------------------------
+ ** Command abort handling.
+ ** We need to synchronize tightly with the SCRIPTS
+ ** processor in order to handle things correctly.
+ **----------------------------------------------------------------
+ */
+ u_char abrt_msg[4]; /* Message to send buffer */
+ struct scr_tblmove abrt_tbl; /* Table for the MOV of it */
+ struct scr_tblsel abrt_sel; /* Sync params for selection */
+ u_char istat_sem; /* Tells the chip to stop (SEM) */
+
+ /*----------------------------------------------------------------
** Fields that should be removed or changed.
**----------------------------------------------------------------
*/
@@ -2053,34 +1990,53 @@ struct ncb {
/*
** Script fragments which are loaded into the on-chip RAM
-** of 825A, 875, 876, 895 and 896 chips.
+** of 825A, 875, 876, 895, 895A and 896 chips.
*/
struct script {
- ncrcmd start [ 10];
+ ncrcmd start [ 18];
ncrcmd getjob_begin [ 4];
ncrcmd getjob_end [ 4];
- ncrcmd select [ 4];
+ ncrcmd select [ 8];
ncrcmd wf_sel_done [ 2];
ncrcmd send_ident [ 2];
- ncrcmd select2 [ 6];
+#ifdef SCSI_NCR_IARB_SUPPORT
+ ncrcmd select2 [ 8];
+#else
+ ncrcmd select2 [ 2];
+#endif
ncrcmd command [ 2];
- ncrcmd dispatch [ 26];
+ ncrcmd dispatch [ 28];
ncrcmd sel_no_cmd [ 10];
ncrcmd init [ 6];
ncrcmd clrack [ 4];
- ncrcmd databreak [ 2];
+ ncrcmd disp_msg_in [ 2];
+ ncrcmd disp_status [ 4];
+ ncrcmd datai_done [ 16];
+ ncrcmd datao_done [ 10];
+ ncrcmd ign_i_w_r_msg [ 4];
#ifdef SCSI_NCR_PROFILE_SUPPORT
ncrcmd dataphase [ 4];
#else
ncrcmd dataphase [ 2];
#endif
- ncrcmd status [ 8];
ncrcmd msg_in [ 2];
- ncrcmd msg_in2 [ 16];
- ncrcmd msg_bad [ 6];
+ ncrcmd msg_in2 [ 10];
+#ifdef SCSI_NCR_IARB_SUPPORT
+ ncrcmd status [ 14];
+#else
+ ncrcmd status [ 10];
+#endif
ncrcmd complete [ 8];
- ncrcmd complete2 [ 6];
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+ ncrcmd complete2 [ 12];
+#else
+ ncrcmd complete2 [ 10];
+#endif
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+ ncrcmd done [ 18];
+#else
ncrcmd done [ 14];
+#endif
ncrcmd done_end [ 2];
ncrcmd save_dp [ 8];
ncrcmd restore_dp [ 4];
@@ -2089,57 +2045,64 @@ struct script {
#else
ncrcmd disconnect [ 20];
#endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+ ncrcmd idle [ 4];
+#else
ncrcmd idle [ 2];
+#endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+ ncrcmd ungetjob [ 6];
+#else
ncrcmd ungetjob [ 4];
+#endif
ncrcmd reselect [ 4];
- ncrcmd reselected [ 44];
+ ncrcmd reselected [ 48];
+#if MAX_TASKS*4 > 512
+ ncrcmd resel_tag [ 16];
+#elif MAX_TASKS*4 > 256
+ ncrcmd resel_tag [ 10];
+#else
ncrcmd resel_tag [ 6];
+#endif
ncrcmd resel_go [ 6];
ncrcmd resel_notag [ 4];
ncrcmd resel_dsa [ 8];
- ncrcmd data_in [MAX_SCATTERL * SCR_SG_SIZE];
+ ncrcmd data_in [MAX_SCATTER * SCR_SG_SIZE];
ncrcmd data_in2 [ 4];
- ncrcmd data_out [MAX_SCATTERL * SCR_SG_SIZE];
+ ncrcmd data_out [MAX_SCATTER * SCR_SG_SIZE];
ncrcmd data_out2 [ 4];
ncrcmd pm0_data [ 16];
ncrcmd pm1_data [ 16];
-
- /* Data area */
- ncrcmd saved_dsa [ 1];
- ncrcmd done_pos [ 1];
- ncrcmd startpos [ 1];
- ncrcmd targtbl [ 1];
};
/*
** Script fragments which stay in main memory for all chips
-** except for the 896 that support 8K on-chip RAM.
+** except for the 895A and 896 that support 8K on-chip RAM.
*/
struct scripth {
ncrcmd start64 [ 2];
- ncrcmd select_no_atn [ 4];
+ ncrcmd sel_for_abort [ 18];
+ ncrcmd sel_for_abort_1 [ 2];
+ ncrcmd select_no_atn [ 8];
ncrcmd wf_sel_done_no_atn [ 4];
- ncrcmd cancel [ 4];
- ncrcmd msg_reject [ 8];
- ncrcmd msg_ign_residue [ 24];
- ncrcmd msg_extended [ 10];
- ncrcmd msg_ext_2 [ 10];
- ncrcmd msg_wdtr [ 14];
+
+ ncrcmd msg_in_etc [ 14];
+ ncrcmd msg_received [ 4];
+ ncrcmd msg_weird_seen [ 4];
+ ncrcmd msg_extended [ 20];
+ ncrcmd msg_bad [ 6];
+ ncrcmd msg_weird [ 4];
+ ncrcmd msg_weird1 [ 8];
+
+ ncrcmd wdtr_resp [ 6];
ncrcmd send_wdtr [ 4];
- ncrcmd msg_ext_3 [ 10];
- ncrcmd msg_sdtr [ 14];
+ ncrcmd sdtr_resp [ 6];
ncrcmd send_sdtr [ 4];
ncrcmd nego_bad_phase [ 4];
ncrcmd msg_out_abort [ 12];
ncrcmd msg_out [ 6];
ncrcmd msg_out_done [ 4];
- ncrcmd no_data [ 16];
-#if MAX_SCATTERH != 0
- ncrcmd hdata_in [MAX_SCATTERH * SCR_SG_SIZE];
- ncrcmd hdata_in2 [ 2];
- ncrcmd hdata_out [MAX_SCATTERH * SCR_SG_SIZE];
- ncrcmd hdata_out2 [ 2];
-#endif
+ ncrcmd no_data [ 28];
ncrcmd abort_resel [ 16];
ncrcmd resend_ident [ 4];
ncrcmd ident_break [ 4];
@@ -2156,22 +2119,39 @@ struct scripth {
ncrcmd pm_handle [ 20];
ncrcmd pm_handle1 [ 4];
ncrcmd pm_save [ 4];
- ncrcmd pm0_save [ 10];
- ncrcmd pm1_save [ 10];
+ ncrcmd pm0_save [ 14];
+ ncrcmd pm1_save [ 14];
+
+ /* SWIDE handling */
+ ncrcmd swide_ma_32 [ 4];
+ ncrcmd swide_ma_64 [ 6];
+ ncrcmd swide_scr_64 [ 26];
+ ncrcmd swide_scr_64_1 [ 12];
+ ncrcmd swide_com_64 [ 6];
+ ncrcmd swide_common [ 10];
+ ncrcmd swide_fin_32 [ 24];
/* Data area */
+ ncrcmd zero [ 1];
+ ncrcmd scratch [ 1];
+ ncrcmd scratch1 [ 1];
ncrcmd pm0_data_addr [ 1];
ncrcmd pm1_data_addr [ 1];
+ ncrcmd saved_dsa [ 1];
+ ncrcmd saved_drs [ 1];
+ ncrcmd done_pos [ 1];
+ ncrcmd startpos [ 1];
+ ncrcmd targtbl [ 1];
/* End of data area */
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
ncrcmd start_ram [ 1];
ncrcmd script0_ba [ 4];
-
ncrcmd start_ram64 [ 3];
ncrcmd script0_ba64 [ 3];
ncrcmd scripth0_ba64 [ 6];
ncrcmd ram_seg64 [ 1];
-
+#endif
ncrcmd snooptest [ 6];
ncrcmd snoopend [ 2];
};
@@ -2195,6 +2175,7 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln);
static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln,
u_char *inq_data);
static void ncr_getclock (ncb_p np, int mult);
+static u_int ncr_getpciclock (ncb_p np);
static void ncr_selectclock (ncb_p np, u_char scntl3);
static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln);
static void ncr_init (ncb_p np, int reset, char * msg, u_long code);
@@ -2204,8 +2185,8 @@ static void ncr_int_ma (ncb_p np);
static void ncr_int_sir (ncb_p np);
static void ncr_int_sto (ncb_p np);
static void ncr_int_udc (ncb_p np);
-static u_long ncr_lookup (char* id);
-static void ncr_negotiate (struct ncb* np, struct tcb* tp);
+static void ncr_negotiate (ncb_p np, tcb_p tp);
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
#ifdef SCSI_NCR_PROFILE_SUPPORT
static void ncb_profile (ncb_p np, ccb_p cp);
#endif
@@ -2219,6 +2200,7 @@ 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);
static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack);
static int ncr_show_msg (u_char * msg);
+static void ncr_print_msg (ccb_p cp, char *label, u_char * msg);
static int ncr_snooptest (ncb_p np);
static void ncr_timeout (ncb_p np);
static void ncr_wakeup (ncb_p np, u_long code);
@@ -2228,6 +2210,7 @@ static void ncr_put_start_queue(ncb_p np, ccb_p cp);
static void ncr_soft_reset (ncb_p np);
static void ncr_start_reset (ncb_p np);
static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
+static int ncr_compute_residual (ncb_p np, ccb_p cp);
#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np);
@@ -2328,6 +2311,25 @@ static struct script script0 __initdata = {
*/
SCR_FROM_REG (ctest2),
0,
+
+ /*
+ ** Stop here if the C code wants to perform
+ ** some error recovery procedure manually.
+ ** (Indicate this by setting SEM in ISTAT)
+ */
+ SCR_FROM_REG (istat),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (SEM, SEM)),
+ 16,
+ /*
+ ** Report to the C code the next position in
+ ** the start queue the SCRIPTS will schedule.
+ */
+ SCR_LOAD_ABS (scratcha, 4),
+ PADDRH (startpos),
+ SCR_INT,
+ SIR_SCRIPT_STOPPED,
+
/*
** Start the next job.
**
@@ -2343,14 +2345,14 @@ static struct script script0 __initdata = {
** and the the next queue position points to the next JOB.
*/
SCR_LOAD_ABS (scratcha, 4),
- PADDR (startpos),
+ PADDRH (startpos),
SCR_LOAD_ABS (dsa, 4),
- PADDR (startpos),
+ PADDRH (startpos),
SCR_LOAD_REL (temp, 4),
4,
}/*-------------------------< GETJOB_BEGIN >------------------*/,{
SCR_STORE_ABS (temp, 4),
- PADDR (startpos),
+ PADDRH (startpos),
SCR_LOAD_REL (dsa, 4),
0,
}/*-------------------------< GETJOB_END >--------------------*/,{
@@ -2407,6 +2409,19 @@ static struct script script0 __initdata = {
** So we have to wait immediately for the next phase
** or the selection to complete or time-out.
*/
+
+ /*
+ ** load the savep (saved pointer) into
+ ** the actual data pointer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct ccb, phys.header.savep),
+ /*
+ ** Initialize the status registers
+ */
+ SCR_LOAD_REL (scr0, 4),
+ offsetof (struct ccb, phys.header.status),
+
}/*-------------------------< WF_SEL_DONE >----------------------*/,{
SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
SIR_SEL_ATN_NO_MSG_OUT,
@@ -2419,17 +2434,18 @@ static struct script script0 __initdata = {
SCR_MOVE_TBL ^ SCR_MSG_OUT,
offsetof (struct dsb, smsg),
}/*-------------------------< SELECT2 >----------------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
/*
- ** load the savep (saved pointer) into
- ** the actual data pointer.
- */
- SCR_LOAD_REL (temp, 4),
- offsetof (struct ccb, phys.header.savep),
- /*
- ** Initialize the status registers
+ ** Set IMMEDIATE ARBITRATION if we have been given
+ ** a hint to do so. (Some job to do after this one).
*/
- SCR_LOAD_REL (scr0, 4),
- offsetof (struct ccb, phys.header.status),
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
/*
** Anticipate the COMMAND phase.
** This is the PHASE we expect at this point.
@@ -2465,7 +2481,9 @@ static struct script script0 __initdata = {
/*
** Discard one illegal phase byte, if required.
*/
- SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+ SCR_LOAD_REL (scratcha, 1),
+ offsetof (struct ccb, xerr_status),
+ SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE),
0,
SCR_STORE_REL (scratcha, 1),
offsetof (struct ccb, xerr_status),
@@ -2517,7 +2535,7 @@ static struct script script0 __initdata = {
SCR_FROM_REG (sstat0),
0,
SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
- -8,
+ -16,
SCR_JUMP,
PADDR (start),
}/*-------------------------< CLRACK >----------------------*/,{
@@ -2529,37 +2547,115 @@ static struct script script0 __initdata = {
SCR_JUMP,
PADDR (dispatch),
-}/*-------------------------< DATABREAK >-------------------*/,{
+}/*-------------------------< DISP_MSG_IN >----------------------*/,{
/*
- ** Jump to dispatcher.
+ ** Anticipate MSG_IN phase then STATUS phase.
+ **
+ ** May spare 2 SCRIPTS instructions when we have
+ ** completed the OUTPUT of the data and the device
+ ** goes directly to STATUS phase.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR (msg_in),
+
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+ /*
+ ** Anticipate STATUS phase.
+ **
+ ** Does spare 3 SCRIPTS instructions when we have
+ ** completed the INPUT of the data.
*/
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+ PADDR (status),
SCR_JUMP,
PADDR (dispatch),
-}/*-------------------------< DATAPHASE >------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
- SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+}/*-------------------------< DATAI_DONE >-------------------*/,{
+ /*
+ ** If the SWIDE is not full, jump to dispatcher.
+ ** We anticipate a STATUS phase.
+ ** If we get later an IGNORE WIDE RESIDUE, we
+ ** will alias it as a MODIFY DP (-1).
+ */
+ SCR_FROM_REG (scntl2),
0,
-#endif
- SCR_RETURN,
- 0,
-
-}/*-------------------------< STATUS >--------------------*/,{
+ SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+ PADDR (disp_status),
/*
- ** get the status
+ ** The SWIDE is full.
+ ** Clear this condition.
*/
- SCR_MOVE_ABS (1) ^ SCR_STATUS,
- NADDR (scratch),
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
/*
- ** save status to scsi_status.
- ** mark as complete.
+ ** Since the device is required to send any
+ ** IGNORE WIDE RESIDUE message prior to any
+ ** other information, we just snoop the SCSI
+ ** BUS to check for such a message.
*/
- SCR_TO_REG (SS_REG),
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDR (disp_status),
+ SCR_FROM_REG (sbdl),
0,
- SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ PADDR (disp_status),
+ /*
+ ** We have been ODD at the end of the transfer,
+ ** but the device hasn't be so.
+ ** Signal a DATA OVERRUN condition to the C code.
+ */
+ SCR_INT,
+ SIR_SWIDE_OVERRUN,
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< DATAO_DONE >-------------------*/,{
+ /*
+ ** If the SODL is not full jump to dispatcher.
+ ** We anticipate a MSG IN phase or a STATUS phase.
+ */
+ SCR_FROM_REG (scntl2),
0,
+ SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+ PADDR (disp_msg_in),
+ /*
+ ** The SODL is full, clear this condition.
+ */
+ SCR_REG_REG (scntl2, SCR_OR, WSS),
+ 0,
+ /*
+ ** And signal a DATA UNDERRUN condition
+ ** to the C code.
+ */
+ SCR_INT,
+ SIR_SODL_UNDERRUN,
SCR_JUMP,
PADDR (dispatch),
+
+}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
+ /*
+ ** We jump here from the phase mismatch interrupt,
+ ** When we have a SWIDE and the device has presented
+ ** a IGNORE WIDE RESIDUE message on the BUS.
+ ** We just have to throw away this message and then
+ ** to jump to dispatcher.
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ NADDR (scratch),
+ /*
+ ** Clear ACK and jump to dispatcher.
+ */
+ SCR_JUMP,
+ PADDR (clrack),
+
+}/*-------------------------< DATAPHASE >------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+ SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+ 0,
+#endif
+ SCR_RETURN,
+ 0,
+
}/*-------------------------< MSG_IN >--------------------*/,{
/*
** Get the first byte of the message.
@@ -2571,7 +2667,8 @@ static struct script script0 __initdata = {
NADDR (msgin[0]),
}/*-------------------------< MSG_IN2 >--------------------*/,{
/*
- ** Handle this message.
+ ** Check first against 1 byte messages
+ ** that we handle from SCRIPTS.
*/
SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
PADDR (complete),
@@ -2581,31 +2678,47 @@ static struct script script0 __initdata = {
PADDR (save_dp),
SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
PADDR (restore_dp),
- SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
- PADDRH (msg_extended),
- SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
- PADDR (clrack),
- SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
- PADDRH (msg_reject),
- SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
- PADDRH (msg_ign_residue),
/*
- ** Rest of the messages left as
- ** an exercise ...
- **
- ** Unimplemented messages:
- ** fall through to MSG_BAD.
+ ** We handle all other messages from the
+ ** C code, so no need to waste on-chip RAM
+ ** for those ones.
*/
-}/*-------------------------< MSG_BAD >------------------*/,{
+ SCR_JUMP,
+ PADDRH (msg_in_etc),
+
+}/*-------------------------< STATUS >--------------------*/,{
/*
- ** unimplemented message - reject it.
+ ** get the status
*/
- SCR_INT,
- SIR_REJECT_TO_SEND,
- SCR_SET (SCR_ATN),
+ SCR_MOVE_ABS (1) ^ SCR_STATUS,
+ NADDR (scratch),
+#ifdef SCSI_NCR_IARB_SUPPORT
+ /*
+ ** If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
+ ** since we may have to tamper the start queue from
+ ** the C code.
+ */
+ SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+ 8,
+ SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+ 0,
+#endif
+ /*
+ ** save status to scsi_status.
+ ** mark as complete.
+ */
+ SCR_TO_REG (SS_REG),
0,
+ SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+ 0,
+ /*
+ ** Anticipate the MESSAGE PHASE for
+ ** the TASK COMPLETE message.
+ */
+ SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+ PADDR (msg_in),
SCR_JUMP,
- PADDR (clrack),
+ PADDR (dispatch),
}/*-------------------------< COMPLETE >-----------------*/,{
/*
@@ -2642,6 +2755,18 @@ static struct script script0 __initdata = {
SCR_STORE_REL (scr0, 4),
offsetof (struct ccb, phys.header.status),
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+ /*
+ ** Some bridges may reorder DMA writes to memory.
+ ** We donnot want the CPU to deal with completions
+ ** without all the posted write having been flushed
+ ** to memory. This DUMMY READ should flush posted
+ ** buffers prior to the CPU having to deal with
+ ** completions.
+ */
+ SCR_LOAD_REL (scr0, 4), /* DUMMY READ */
+ offsetof (struct ccb, phys.header.status),
+#endif
/*
** If command resulted in not GOOD status,
** call the C code if needed.
@@ -2651,7 +2776,35 @@ static struct script script0 __initdata = {
SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
PADDRH (bad_status),
+ /*
+ ** If we performed an auto-sense, call
+ ** the C code to synchronyze task aborts
+ ** with UNIT ATTENTION conditions.
+ */
+ SCR_FROM_REG (HF_REG),
+ 0,
+ SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)),
+ SIR_AUTO_SENSE_DONE,
+
}/*------------------------< DONE >-----------------*/,{
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+ /*
+ ** It seems that some bridges flush everything
+ ** when the INTR line is raised. For these ones,
+ ** we can just ensure that the INTR line will be
+ ** raised before each completion. So, if it happens
+ ** that we have been faster that the CPU, we just
+ ** have to synchronize with it. A dummy programmed
+ ** interrupt will do the trick.
+ ** Note that we overlap at most 1 IO with the CPU
+ ** in this situation and that the IRQ line must not
+ ** be shared.
+ */
+ SCR_FROM_REG (istat),
+ 0,
+ SCR_INT ^ IFTRUE (MASK (INTF, INTF)),
+ SIR_DUMMY_INTERRUPT,
+#endif
/*
** Copy the DSA to the DONE QUEUE and
** signal completion to the host.
@@ -2660,11 +2813,11 @@ static struct script script0 __initdata = {
** the completed CCB will be lost.
*/
SCR_STORE_ABS (dsa, 4),
- PADDR (saved_dsa),
+ PADDRH (saved_dsa),
SCR_LOAD_ABS (dsa, 4),
- PADDR (done_pos),
+ PADDRH (done_pos),
SCR_LOAD_ABS (scratcha, 4),
- PADDR(saved_dsa),
+ PADDRH (saved_dsa),
SCR_STORE_REL (scratcha, 4),
0,
/*
@@ -2679,7 +2832,7 @@ static struct script script0 __initdata = {
SCR_INT_FLY,
0,
SCR_STORE_ABS (temp, 4),
- PADDR (done_pos),
+ PADDRH (done_pos),
}/*------------------------< DONE_END >-----------------*/,{
SCR_JUMP,
PADDR (start),
@@ -2791,7 +2944,20 @@ static struct script script0 __initdata = {
*/
SCR_NO_OP,
0,
+#ifdef SCSI_NCR_IARB_SUPPORT
+ SCR_JUMPR,
+ 8,
+#endif
}/*-------------------------< UNGETJOB >-----------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
+ /*
+ ** Set IMMEDIATE ARBITRATION, for the next time.
+ ** This will give us better chance to win arbitration
+ ** for the job we just wanted to do.
+ */
+ SCR_REG_REG (scntl1, SCR_OR, IARB),
+ 0,
+#endif
/*
** We are not able to restart the SCRIPTS if we are
** interrupted and these instruction haven't been
@@ -2801,7 +2967,7 @@ static struct script script0 __initdata = {
SCR_LOAD_REG (dsa, 0xff),
0,
SCR_STORE_ABS (scratcha, 4),
- PADDR (startpos),
+ PADDRH (startpos),
}/*-------------------------< RESELECT >--------------------*/,{
/*
** make the host status invalid.
@@ -2834,7 +3000,7 @@ static struct script script0 __initdata = {
** load the target control block address
*/
SCR_LOAD_ABS (dsa, 4),
- PADDR (targtbl),
+ PADDRH (targtbl),
SCR_SFBR_REG (dsa, SCR_SHL, 0),
0,
SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2870,12 +3036,13 @@ static struct script script0 __initdata = {
/*
** It is an IDENTIFY message,
** Load the LUN control block address.
- ** Avoid nasty address calculation if LUN #0.
+ ** If LUN 0, avoid a PCI BUS ownership by loading
+ ** directly 'b_lun0' from the TCB.
*/
+ SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
+ 48,
SCR_LOAD_REL (dsa, 4),
offsetof(struct tcb, b_luntbl),
- SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
- 24,
SCR_SFBR_REG (dsa, SCR_SHL, 0),
0,
SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2884,6 +3051,14 @@ static struct script script0 __initdata = {
0,
SCR_LOAD_REL (dsa, 4),
0,
+ SCR_JUMPR,
+ 8,
+ /*
+ ** LUN 0 special case (but usual one :))
+ */
+ SCR_LOAD_REL (dsa, 4),
+ offsetof(struct tcb, b_lun0),
+
/*
** Load the reselect task action for this LUN.
** Load the tasks DSA array for this LUN.
@@ -2914,6 +3089,23 @@ static struct script script0 __initdata = {
*/
SCR_REG_SFBR (sidl, SCR_SHL, 0),
0,
+#if MAX_TASKS*4 > 512
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 2),
+ 0,
+ SCR_REG_REG (sfbr, SCR_SHL, 0),
+ 0,
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#elif MAX_TASKS*4 > 256
+ SCR_JUMPR ^ IFFALSE (CARRYSET),
+ 8,
+ SCR_REG_REG (dsa1, SCR_OR, 1),
+ 0,
+#endif
/*
** Retrieve the DSA of this task.
** JUMP indirectly to the restart point of the CCB.
@@ -2966,13 +3158,11 @@ static struct script script0 __initdata = {
}/*-------------------------< DATA_IN >--------------------*/,{
/*
** Because the size depends on the
-** #define MAX_SCATTERL parameter,
+** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** ##===========< i=0; i<MAX_SCATTERL >=========
-** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** || PADDR (databreak),
-** || SCR_MOVE_TBL ^ SCR_DATA_IN,
+** ##===========< i=0; i<MAX_SCATTER >=========
+** || SCR_CHMOV_TBL ^ SCR_DATA_IN,
** || offsetof (struct dsb, data[ i]),
** ##==========================================
**
@@ -2981,19 +3171,17 @@ static struct script script0 __initdata = {
0
}/*-------------------------< DATA_IN2 >-------------------*/,{
SCR_CALL,
- PADDR (databreak),
+ PADDR (datai_done),
SCR_JUMP,
PADDRH (no_data),
}/*-------------------------< DATA_OUT >--------------------*/,{
/*
** Because the size depends on the
-** #define MAX_SCATTERL parameter,
+** #define MAX_SCATTER parameter,
** it is filled in at runtime.
**
-** ##===========< i=0; i<MAX_SCATTERL >=========
-** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-** || PADDR (databreak),
-** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
+** ##===========< i=0; i<MAX_SCATTER >=========
+** || SCR_CHMOV_TBL ^ SCR_DATA_OUT,
** || offsetof (struct dsb, data[ i]),
** ##==========================================
**
@@ -3002,7 +3190,7 @@ static struct script script0 __initdata = {
0
}/*-------------------------< DATA_OUT2 >-------------------*/,{
SCR_CALL,
- PADDR (databreak),
+ PADDR (datao_done),
SCR_JUMP,
PADDRH (no_data),
@@ -3019,11 +3207,11 @@ static struct script script0 __initdata = {
*/
SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
16,
- SCR_MOVE_TBL ^ SCR_DATA_IN,
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct ccb, phys.pm0.sg),
SCR_JUMPR,
8,
- SCR_MOVE_TBL ^ SCR_DATA_OUT,
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
offsetof (struct ccb, phys.pm0.sg),
/*
** Clear the flag that told we were in
@@ -3053,11 +3241,11 @@ static struct script script0 __initdata = {
*/
SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
16,
- SCR_MOVE_TBL ^ SCR_DATA_IN,
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct ccb, phys.pm1.sg),
SCR_JUMPR,
8,
- SCR_MOVE_TBL ^ SCR_DATA_OUT,
+ SCR_CHMOV_TBL ^ SCR_DATA_OUT,
offsetof (struct ccb, phys.pm1.sg),
/*
** Clear the flag that told we were in
@@ -3074,27 +3262,76 @@ static struct script script0 __initdata = {
offsetof (struct ccb, phys.pm1.ret),
SCR_RETURN,
0,
-
-}/*-------------------------< SAVED_DSA >-------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< DONE_POS >--------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< STARTPOS >--------------------*/,{
- SCR_DATA_ZERO,
-}/*-------------------------< TARGTBL >---------------------*/,{
- SCR_DATA_ZERO,
-}/*--------------------------------------------------------*/
+}/*---------------------------------------------------------*/
};
static struct scripth scripth0 __initdata = {
/*------------------------< START64 >-----------------------*/{
/*
- ** SCRIPT entry point for the 896.
+ ** SCRIPT entry point for the 895A and the 896.
** For now, there is no specific stuff for that
** chip at this point, but this may come.
*/
SCR_JUMP,
PADDR (init),
+
+}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
+ /*
+ ** We are jumped here by the C code, if we have
+ ** some target to reset or some disconnected
+ ** job to abort. Since error recovery is a serious
+ ** busyness, we will really reset the SCSI BUS, if
+ ** case of a SCSI interrupt occuring in this path.
+ */
+
+ /*
+ ** Set initiator mode.
+ */
+ SCR_CLR (SCR_TRG),
+ 0,
+ /*
+ ** And try to select this target.
+ */
+ SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel),
+ PADDR (reselect),
+
+ /*
+ ** Wait for the selection to complete or
+ ** the selection to time out.
+ */
+ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+ -8,
+ /*
+ ** Call the C code.
+ */
+ SCR_INT,
+ SIR_TARGET_SELECTED,
+ /*
+ ** The C code should let us continue here.
+ ** Send the 'kiss of death' message.
+ ** We expect an immediate disconnect once
+ ** the target has eaten the message.
+ */
+ SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+ 0,
+ SCR_MOVE_TBL ^ SCR_MSG_OUT,
+ offsetof (struct ncb, abrt_tbl),
+ SCR_CLR (SCR_ACK|SCR_ATN),
+ 0,
+ SCR_WAIT_DISC,
+ 0,
+ /*
+ ** Tell the C code that we are done.
+ */
+ SCR_INT,
+ SIR_ABORT_SENT,
+}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
+ /*
+ ** Jump at scheduler.
+ */
+ SCR_JUMP,
+ PADDR (start),
+
}/*------------------------< SELECT_NO_ATN >-----------------*/,{
/*
** Set Initiator mode.
@@ -3105,6 +3342,18 @@ static struct scripth scripth0 __initdata = {
0,
SCR_SEL_TBL ^ offsetof (struct dsb, select),
PADDR (ungetjob),
+ /*
+ ** load the savep (saved pointer) into
+ ** the actual data pointer.
+ */
+ SCR_LOAD_REL (temp, 4),
+ offsetof (struct ccb, phys.header.savep),
+ /*
+ ** Initialize the status registers
+ */
+ SCR_LOAD_REL (scr0, 4),
+ offsetof (struct ccb, phys.header.status),
+
}/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
/*
** Wait immediately for the next phase or
@@ -3115,129 +3364,111 @@ static struct scripth scripth0 __initdata = {
SCR_JUMP,
PADDR (select2),
-}/*-------------------------< CANCEL >------------------------*/,{
+}/*-------------------------< MSG_IN_ETC >--------------------*/,{
/*
- ** Load the host status.
+ ** If it is an EXTENDED (variable size message)
+ ** Handle it.
*/
- SCR_LOAD_REG (HS_REG, HS_ABORTED),
- 0,
- SCR_JUMP,
- PADDR (complete2),
-
-}/*-------------------------< MSG_REJECT >---------------*/,{
+ SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+ PADDRH (msg_extended),
/*
- ** If a negotiation was in progress,
- ** negotiation failed.
- ** Otherwise just make host log this message
+ ** Let the C code handle any other
+ ** 1 byte message.
*/
- SCR_FROM_REG (HS_REG),
+ SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+ PADDRH (msg_received),
+ SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+ PADDRH (msg_received),
+ /*
+ ** We donnot handle 2 bytes messages from SCRIPTS.
+ ** So, let the C code deal with these ones too.
+ */
+ SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+ PADDRH (msg_weird_seen),
+ SCR_CLR (SCR_ACK),
0,
- SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
- SIR_REJECT_RECEIVED,
- SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
- SIR_NEGO_FAILED,
+ SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+ NADDR (msgin[1]),
SCR_JUMP,
- PADDR (clrack),
+ PADDRH (msg_received),
+
+}/*-------------------------< MSG_RECEIVED >--------------------*/,{
+ SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */
+ 0,
+ SCR_INT,
+ SIR_MSG_RECEIVED,
+
+}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
+ SCR_LOAD_REL (scratcha1, 4), /* DUMMY READ */
+ 0,
+ SCR_INT,
+ SIR_MSG_WEIRD,
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+}/*-------------------------< MSG_EXTENDED >--------------------*/,{
/*
- ** Terminate cycle
+ ** Clear ACK and get the next byte
+ ** assumed to be the message length.
*/
SCR_CLR (SCR_ACK),
0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get residue size.
- */
SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
NADDR (msgin[1]),
/*
- ** Size is 0 .. ignore message.
+ ** Try to catch some unlikely situations as 0 length
+ ** or too large the length.
*/
SCR_JUMP ^ IFTRUE (DATA (0)),
- PADDR (clrack),
- /*
- ** Size is not 1 .. have to interrupt.
- */
- SCR_JUMPR ^ IFFALSE (DATA (1)),
- 40,
- /*
- ** Check for residue byte in swide register
- */
- SCR_FROM_REG (scntl2),
+ PADDRH (msg_weird_seen),
+ SCR_TO_REG (scratcha),
0,
- SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
- 16,
+ SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+ 0,
+ SCR_JUMP ^ IFTRUE (CARRYSET),
+ PADDRH (msg_weird_seen),
/*
- ** There IS data in the swide register.
- ** Discard it.
+ ** We donnot handle extended messages from SCRIPTS.
+ ** Read the amount of data correponding to the
+ ** message length and call the C code.
*/
- SCR_REG_REG (scntl2, SCR_OR, WSR),
+ SCR_STORE_REL (scratcha, 1),
+ offsetof (struct dsb, smsg_ext.size),
+ SCR_CLR (SCR_ACK),
0,
+ SCR_MOVE_TBL ^ SCR_MSG_IN,
+ offsetof (struct dsb, smsg_ext),
SCR_JUMP,
- PADDR (clrack),
+ PADDRH (msg_received),
+
+}/*-------------------------< MSG_BAD >------------------*/,{
/*
- ** Load again the size to the sfbr register.
+ ** unimplemented message - reject it.
*/
- SCR_FROM_REG (scratcha),
- 0,
SCR_INT,
- SIR_IGN_RESIDUE,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
+ 0,
SCR_JUMP,
PADDR (clrack),
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
+}/*-------------------------< MSG_WEIRD >--------------------*/,{
/*
- ** Terminate cycle
+ ** weird message received
+ ** ignore all MSG IN phases and reject it.
*/
- SCR_CLR (SCR_ACK),
+ SCR_INT,
+ SIR_REJECT_TO_SEND,
+ SCR_SET (SCR_ATN),
0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get length.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[1]),
- /*
- */
- SCR_JUMP ^ IFTRUE (DATA (3)),
- PADDRH (msg_ext_3),
- SCR_JUMP ^ IFFALSE (DATA (2)),
- PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
+}/*-------------------------< MSG_WEIRD1 >--------------------*/,{
SCR_CLR (SCR_ACK),
0,
SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
PADDR (dispatch),
- /*
- ** get extended message code.
- */
SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[2]),
- SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
- PADDRH (msg_wdtr),
- /*
- ** unknown extended message
- */
+ NADDR (scratch),
SCR_JUMP,
- PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get data bus width
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[3]),
- /*
- ** let the host do the real work.
- */
- SCR_INT,
- SIR_NEGO_WIDE,
+ PADDRH (msg_weird1),
+}/*-------------------------< WDTR_RESP >----------------*/,{
/*
** let the target fetch our answer.
*/
@@ -3257,39 +3488,7 @@ static struct scripth scripth0 __initdata = {
SCR_JUMP,
PADDRH (msg_out_done),
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get extended message code.
- */
- SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
- NADDR (msgin[2]),
- SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
- PADDRH (msg_sdtr),
- /*
- ** unknown extended message
- */
- SCR_JUMP,
- PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
- SCR_CLR (SCR_ACK),
- 0,
- SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
- PADDR (dispatch),
- /*
- ** get period and offset
- */
- SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
- NADDR (msgin[3]),
- /*
- ** let the host do the real work.
- */
- SCR_INT,
- SIR_NEGO_SYNC,
+}/*-------------------------< SDTR_RESP >-------------*/,{
/*
** let the target fetch our answer.
*/
@@ -3372,7 +3571,9 @@ static struct scripth scripth0 __initdata = {
** or in the wrong direction.
** Remember that in extended error.
*/
- SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+ SCR_LOAD_REL (scratcha, 1),
+ offsetof (struct ccb, xerr_status),
+ SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
0,
SCR_STORE_REL (scratcha, 1),
offsetof (struct ccb, xerr_status),
@@ -3388,57 +3589,28 @@ static struct scripth scripth0 __initdata = {
SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
NADDR (scratch),
/*
+ ** Count this byte.
+ ** This will allow to return a positive
+ ** residual to user.
+ */
+ SCR_LOAD_REL (scratcha, 4),
+ offsetof (struct ccb, phys.extra_bytes),
+ SCR_REG_REG (scratcha, SCR_ADD, 0x01),
+ 0,
+ SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+ 0,
+ SCR_STORE_REL (scratcha, 4),
+ offsetof (struct ccb, phys.extra_bytes),
+ /*
** .. and repeat as required.
*/
SCR_CALL,
- PADDR (databreak),
+ PADDR (dispatch),
SCR_JUMP,
PADDRH (no_data),
-#if MAX_SCATTERH != 0
-
-}/*-------------------------< HDATA_IN >-------------------*/,{
-/*
-** Because the size depends on the
-** #define MAX_SCATTERH parameter,
-** it is filled in at runtime.
-**
-** ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-** || PADDR (databreak),
-** || SCR_MOVE_TBL ^ SCR_DATA_IN,
-** || offsetof (struct dsb, data[ i]),
-** ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_IN2 >------------------*/,{
- SCR_JUMP,
- PADDR (data_in),
-
-}/*-------------------------< HDATA_OUT >-------------------*/,{
-/*
-** Because the size depends on the
-** #define MAX_SCATTERH parameter,
-** it is filled in at runtime.
-**
-** ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-** || PADDR (databreak),
-** || SCR_MOVE_TBL ^ SCR_DATA_OUT,
-** || offsetof (struct dsb, data[ i]),
-** ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_OUT2 >------------------*/,{
- SCR_JUMP,
- PADDR (data_out),
-
-#endif /* MAX_SCATTERH */
-
}/*-------------------------< ABORT_RESEL >----------------*/,{
SCR_SET (SCR_ATN),
0,
@@ -3482,10 +3654,10 @@ static struct scripth scripth0 __initdata = {
SCR_JUMP,
PADDR (select2),
}/*-------------------------< SDATA_IN >-------------------*/,{
- SCR_MOVE_TBL ^ SCR_DATA_IN,
+ SCR_CHMOV_TBL ^ SCR_DATA_IN,
offsetof (struct dsb, sense),
SCR_CALL,
- PADDR (databreak),
+ PADDR (dispatch),
SCR_JUMP,
PADDRH (no_data),
@@ -3588,7 +3760,7 @@ static struct scripth scripth0 __initdata = {
** call the C code.
*/
SCR_LOAD_ABS (scratcha, 4),
- PADDR (startpos),
+ PADDRH (startpos),
SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
SIR_BAD_STATUS,
SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
@@ -3690,6 +3862,17 @@ static struct scripth scripth0 __initdata = {
SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
PADDRH (pm1_save),
}/*-------------------------< PM0_SAVE >-------------------*/,{
+ SCR_STORE_REL (ia, 4),
+ offsetof(struct ccb, phys.pm0.ret),
+ /*
+ ** If WSR bit is set, either UA and RBC may
+ ** have to be changed whatever the device wants
+ ** to ignore this residue ot not.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+ PADDRH (swide_scr_64),
/*
** Save the remaining byte count, the updated
** address and the return address.
@@ -3698,16 +3881,25 @@ static struct scripth scripth0 __initdata = {
offsetof(struct ccb, phys.pm0.sg.size),
SCR_STORE_REL (ua, 4),
offsetof(struct ccb, phys.pm0.sg.addr),
- SCR_STORE_REL (ia, 4),
- offsetof(struct ccb, phys.pm0.ret),
/*
** Set the current pointer at the PM0 DATA mini-script.
*/
SCR_LOAD_ABS (temp, 4),
PADDRH (pm0_data_addr),
SCR_JUMP,
- PADDR (databreak),
+ PADDR (dispatch),
}/*-------------------------< PM1_SAVE >-------------------*/,{
+ SCR_STORE_REL (ia, 4),
+ offsetof(struct ccb, phys.pm1.ret),
+ /*
+ ** If WSR bit is set, either UA and RBC may
+ ** have been changed whatever the device wants
+ ** to ignore this residue or not.
+ */
+ SCR_FROM_REG (scntl2),
+ 0,
+ SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+ PADDRH (swide_scr_64),
/*
** Save the remaining byte count, the updated
** address and the return address.
@@ -3716,19 +3908,237 @@ static struct scripth scripth0 __initdata = {
offsetof(struct ccb, phys.pm1.sg.size),
SCR_STORE_REL (ua, 4),
offsetof(struct ccb, phys.pm1.sg.addr),
- SCR_STORE_REL (ia, 4),
- offsetof(struct ccb, phys.pm1.ret),
/*
** Set the current pointer at the PM1 DATA mini-script.
*/
SCR_LOAD_ABS (temp, 4),
PADDRH (pm1_data_addr),
SCR_JUMP,
- PADDR (databreak),
+ PADDR (dispatch),
+
+}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
+ /*
+ ** Handling of the SWIDE for 32 bit chips.
+ **
+ ** We jump here from the C code with SCRATCHA
+ ** containing the address to write the SWIDE.
+ ** - Save 32 bit address in <scratch>.
+ */
+ SCR_STORE_ABS (scratcha, 4),
+ PADDRH (scratch),
+ SCR_JUMP,
+ PADDRH (swide_common),
+}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
+ /*
+ ** Handling of the SWIDE for 64 bit chips when the
+ ** hardware handling of phase mismatch is disabled.
+ **
+ ** We jump here from the C code with SCRATCHA
+ ** containing the address to write the SWIDE and
+ ** SBR containing bit 32..39 of this address.
+ ** - Save 32 bit address in <scratch>.
+ ** - Move address bit 32..39 to SFBR.
+ */
+ SCR_STORE_ABS (scratcha, 4),
+ PADDRH (scratch),
+ SCR_FROM_REG (sbr),
+ 0,
+ SCR_JUMP,
+ PADDRH (swide_com_64),
+}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
+ /*
+ ** Handling of the SWIDE for 64 bit chips when
+ ** hardware phase mismatch is enabled.
+ ** We are entered with a SCR_CALL from PMO_SAVE
+ ** and PM1_SAVE sub-scripts.
+ **
+ ** Snoop the SCSI BUS in case of the device
+ ** willing to ignore this residue.
+ ** If it does, we must only increment the RBC,
+ ** since this register does reflect all bytes
+ ** received from the SCSI BUS including the SWIDE.
+ */
+ SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+ PADDRH (swide_scr_64_1),
+ SCR_FROM_REG (sbdl),
+ 0,
+ SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+ PADDRH (swide_scr_64_1),
+ SCR_REG_REG (rbc, SCR_ADD, 1),
+ 0,
+ SCR_REG_REG (rbc1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (rbc2, SCR_ADDC, 0),
+ 0,
+ /*
+ ** Save UA and RBC, since the PM0/1_SAVE
+ ** sub-scripts haven't moved them to the
+ ** context yet and the below MOV may just
+ ** change their value.
+ */
+ SCR_STORE_ABS (ua, 4),
+ PADDRH (scratch),
+ SCR_STORE_ABS (rbc, 4),
+ PADDRH (scratch1),
+ /*
+ ** Throw away the IGNORE WIDE RESIDUE message.
+ ** since we just did take care of it.
+ */
+ SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+ NADDR (scratch),
+ SCR_CLR (SCR_ACK),
+ 0,
+ /*
+ ** Restore UA and RBC registers and return.
+ */
+ SCR_LOAD_ABS (ua, 4),
+ PADDRH (scratch),
+ SCR_LOAD_ABS (rbc, 4),
+ PADDRH (scratch1),
+ SCR_RETURN,
+ 0,
+}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
+ /*
+ ** We must grab the SWIDE and move it to
+ ** memory.
+ **
+ ** - Save UA (32 bit address) in <scratch>.
+ ** - Move address bit 32..39 to SFBR.
+ ** - Increment UA (updated address).
+ */
+ SCR_STORE_ABS (ua, 4),
+ PADDRH (scratch),
+ SCR_FROM_REG (rbc3),
+ 0,
+ SCR_REG_REG (ua, SCR_ADD, 1),
+ 0,
+ SCR_REG_REG (ua1, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (ua2, SCR_ADDC, 0),
+ 0,
+ SCR_REG_REG (ua3, SCR_ADDC, 0),
+ 0,
+}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
+ /*
+ ** - Save DRS.
+ ** - Load DRS with address bit 32..39 of the
+ ** location to write the SWIDE.
+ ** SFBR has been loaded with these bits.
+ ** (Look above).
+ */
+ SCR_STORE_ABS (drs, 4),
+ PADDRH (saved_drs),
+ SCR_LOAD_ABS (drs, 4),
+ PADDRH (zero),
+ SCR_TO_REG (drs),
+ 0,
+}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
+ /*
+ ** - Save current DSA
+ ** - Load DSA with bit 0..31 of the memory
+ ** location to write the SWIDE.
+ */
+ SCR_STORE_ABS (dsa, 4),
+ PADDRH (saved_dsa),
+ SCR_LOAD_ABS (dsa, 4),
+ PADDRH (scratch),
+ /*
+ ** Move the SWIDE to memory.
+ ** Clear the WSR bit.
+ */
+ SCR_STORE_REL (swide, 1),
+ 0,
+ SCR_REG_REG (scntl2, SCR_OR, WSR),
+ 0,
+ /*
+ ** Restore the original DSA.
+ */
+ SCR_LOAD_ABS (dsa, 4),
+ PADDRH (saved_dsa),
+}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
+ /*
+ ** For 32 bit chip, the following SCRIPTS
+ ** instruction is patched with a JUMP to dispatcher.
+ ** (Look into the C code).
+ */
+ SCR_LOAD_ABS (drs, 4),
+ PADDRH (saved_drs),
+ /*
+ ** 64 bit chip only.
+ ** If PM handling from SCRIPTS, we are just
+ ** a helper for the C code, so jump to
+ ** dispatcher now.
+ */
+ SCR_FROM_REG (ccntl0),
+ 0,
+ SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
+ PADDR (dispatch),
+ /*
+ ** 64 bit chip with hardware PM handling enabled.
+ **
+ ** Since we are paranoid:), we donnot want
+ ** a SWIDE followed by a CHMOV(1) to lead to
+ ** a CHMOV(0) in our PM context.
+ ** We check against such a condition.
+ ** Also does the C code.
+ */
+ SCR_FROM_REG (rbc),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ SCR_FROM_REG (rbc1),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ SCR_FROM_REG (rbc2),
+ 0,
+ SCR_RETURN ^ IFFALSE (DATA (0)),
+ 0,
+ /*
+ ** If we are there, RBC(0..23) is zero,
+ ** and we just have to load the current
+ ** DATA SCRIPTS address (register TEMP)
+ ** with the IA and go to dispatch.
+ ** No PM context is needed.
+ */
+ SCR_STORE_ABS (ia, 4),
+ PADDRH (scratch),
+ SCR_LOAD_ABS (temp, 4),
+ PADDRH (scratch),
+ SCR_JUMP,
+ PADDR (dispatch),
+
+}/*-------------------------< ZERO >------------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >---------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH1 >--------------------*/,{
+ SCR_DATA_ZERO,
}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
SCR_DATA_ZERO,
}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DSA >-------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DRS >-------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >--------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >--------------------*/,{
+ SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >---------------------*/,{
+ SCR_DATA_ZERO,
+
+
+/*
+** We may use MEMORY MOVE instructions to load the on chip-RAM,
+** if it happens that mapping PCI memory is not possible.
+** But writing the RAM from the CPU is the preferred method,
+** since PCI 2.2 seems to disallow PCI self-mastering.
+*/
+
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+
}/*-------------------------< START_RAM >-------------------*/,{
/*
** Load the script into on-chip RAM,
@@ -3743,7 +4153,7 @@ static struct scripth scripth0 __initdata = {
}/*-------------------------< START_RAM64 >--------------------*/,{
/*
- ** Load the RAM and start for 64 bit PCI (896).
+ ** Load the RAM and start for 64 bit PCI (895A,896).
** Both scripts (script and scripth) are loaded into
** the RAM which is 8K (4K for 825A/875/895).
** We also need to load some 32-63 bit segments
@@ -3768,6 +4178,9 @@ static struct scripth scripth0 __initdata = {
PADDRH (start64),
}/*-------------------------< RAM_SEG64 >--------------------*/,{
0,
+
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+
}/*-------------------------< SNOOPTEST >-------------------*/,{
/*
** Read the variable.
@@ -3801,50 +4214,17 @@ void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
int i;
ncrcmd *p;
-#if MAX_SCATTERH != 0
- p = scrh->hdata_in;
- for (i=0; i<MAX_SCATTERH; i++) {
-#if SCR_SG_SIZE == 4
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (databreak);
-#endif
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
-#endif
-
p = scr->data_in;
- for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if SCR_SG_SIZE == 4
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
- *p++ =PADDR (databreak);
-#endif
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+ for (i=0; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
*p++ =offsetof (struct dsb, data[i]);
};
- assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
-#if MAX_SCATTERH != 0
- p = scrh->hdata_out;
- for (i=0; i<MAX_SCATTERH; i++) {
-#if SCR_SG_SIZE == 4
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (databreak);
-#endif
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
- *p++ =offsetof (struct dsb, data[i]);
- };
- assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
-#endif
+ assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
p = scr->data_out;
- for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if SCR_SG_SIZE == 4
- *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
- *p++ =PADDR (databreak);
-#endif
- *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+ for (i=0; i<MAX_SCATTER; i++) {
+ *p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
*p++ =offsetof (struct dsb, data[i]);
};
@@ -3860,7 +4240,8 @@ void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
**==========================================================
*/
-static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
+static void __init
+ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
{
ncrcmd opcode, new, old, tmp1, tmp2;
ncrcmd *start, *end;
@@ -3950,11 +4331,22 @@ static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,in
case 0x0:
/*
- ** MOVE (absolute address)
+ ** MOVE/CHMOV (absolute address)
*/
+ if (!(np->features & FE_WIDE))
+ dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
relocs = 1;
break;
+ case 0x1:
+ /*
+ ** MOVE/CHMOV (table indirect)
+ */
+ if (!(np->features & FE_WIDE))
+ dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+ relocs = 0;
+ break;
+
case 0x8:
/*
** JUMP / CALL
@@ -4016,6 +4408,7 @@ static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,in
}
/* fall through */
default:
+ new = 0; /* For 'cc' not to complain */
panic("ncr_script_copy_and_bind: "
"weird relocation %x\n", old);
break;
@@ -4083,9 +4476,16 @@ static u_long div_10M[] =
** Prepare io register values used by ncr_init() according
** to selected and supported features.
**
-** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128
-** transfers. 32,64,128 are only supported by 825A, 875, 895
-** and 896 chips.
+** NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
+** 128 transfers. All chips support at least 16 transfers bursts.
+** The 825A, 875 and 895 chips support bursts of up to 128
+** transfers and the 895A and 896 support bursts of up to 64
+** transfers. All other chips support up to 16 transfers bursts.
+**
+** For PCI 32 bit data transfers each transfer is a DWORD (4 bytes).
+** It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
+** Only the 896 is able to perform 64 bit data transfers.
+**
** We use log base 2 (burst length) as internal code, with
** value 0 meaning "burst disabled".
**
@@ -4128,8 +4528,8 @@ static inline void ncr_init_burst(ncb_p np, u_char bc)
** Get target set-up from Symbios format NVRAM.
*/
-static void __init
- ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
+static void __init
+ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
{
tcb_p tp = &np->target[target];
Symbios_target *tn = &nvram->target[target];
@@ -4137,7 +4537,7 @@ static void __init
tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
tp->usrtags =
- (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+ (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
tp->usrflag |= UF_NODISC;
@@ -4150,7 +4550,7 @@ static void __init
*/
static void __init
- ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
+ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
{
tcb_p tp = &np->target[target];
struct Tekram_target *tn = &nvram->target[target];
@@ -4261,7 +4661,7 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
np->maxsync = period > 2540 ? 254 : period / 10;
/*
- ** 64 bit (53C896) ?
+ ** 64 bit (53C895A or 53C896) ?
*/
if (np->features & FE_64BIT)
#if BITS_PER_LONG > 32
@@ -4271,8 +4671,8 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
#endif
/*
- ** Phase mismatch handled by SCRIPTS (53C896) ?
- */
+ ** Phase mismatch handled by SCRIPTS (53C895A or 53C896) ?
+ */
if (np->features & FE_NOPM)
np->rv_ccntl0 |= (ENPMJ);
@@ -4383,28 +4783,50 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
ncr_init_burst(np, burst_max);
/*
- ** Set differential mode and LED support.
- ** Ignore these features for boards known to use a
- ** specific GPIO wiring (Tekram only for now) and
- ** for the 896 that drives the LED directly.
- ** Probe initial setting of GPREG and GPCNTL for
- ** other ones.
- */
- if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+ ** Set SCSI BUS mode.
+ **
+ ** - ULTRA2 chips (895/895A/896) report the current
+ ** BUS mode through the STEST4 IO register.
+ ** - For previous generation chips (825/825A/875),
+ ** user has to tell us how to check against HVD,
+ ** since a 100% safe algorithm is not possible.
+ */
+ np->scsi_mode = SMODE_SE;
+ if (np->features & FE_ULTRA2)
+ np->scsi_mode = (np->sv_stest4 & SMODE);
+ else if (np->features & FE_DIFF) {
switch(driver_setup.diff_support) {
- case 3:
+ case 4: /* Trust previous settings if present, then GPIO3 */
+ if (np->sv_scntl3) {
+ if (np->sv_stest2 & 0x20)
+ np->scsi_mode = SMODE_HVD;
+ break;
+ }
+ case 3: /* SYMBIOS controllers report HVD through GPIO3 */
+ if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+ break;
if (INB(nc_gpreg) & 0x08)
+ break;
+ case 2: /* Set HVD unconditionally */
+ np->scsi_mode = SMODE_HVD;
+ case 1: /* Trust previous settings for HVD */
+ if (np->sv_stest2 & 0x20)
+ np->scsi_mode = SMODE_HVD;
break;
- case 2:
- np->rv_stest2 |= 0x20;
- break;
- case 1:
- np->rv_stest2 |= (np->sv_stest2 & 0x20);
- break;
- default:
+ default:/* Don't care about HVD */
break;
}
}
+ if (np->scsi_mode == SMODE_HVD)
+ np->rv_stest2 |= 0x20;
+
+ /*
+ ** Set LED support from SCRIPTS.
+ ** Ignore this feature for boards known to use a
+ ** specific GPIO wiring and for the 895A or 896
+ ** that drive the LED directly.
+ ** Also probe initial setting of GPIO0 as output.
+ */
if ((driver_setup.led_pin ||
(nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
!(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
@@ -4457,7 +4879,7 @@ static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
#endif
tp->usrsync = driver_setup.default_sync;
tp->usrwide = driver_setup.max_wide;
- tp->usrtags = SCSI_NCR_MAX_TAGS;
+ tp->usrtags = MAX_TAGS;
if (!driver_setup.disconnection)
np->target[i].usrflag = UF_NODISC;
}
@@ -4587,7 +5009,8 @@ void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
** start the timer daemon.
*/
-static int __init ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
+static int __init
+ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
{
struct host_data *host_data;
ncb_p np = 0;
@@ -4758,6 +5181,19 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
(void) ncr_prepare_setting(np, nvram);
/*
+ ** Check the PCI clock frequency.
+ ** Must be done after prepare_setting since it
+ ** destroys STEST1 that is used to probe for
+ ** the clock doubler.
+ */
+ i = (int) ncr_getpciclock(np);
+ if (i > 37000) {
+ printk(KERN_ERR "%s: PCI clock seems too high (%u KHz).\n",
+ ncr_name(np), i);
+ goto attach_error;
+ }
+
+ /*
** Patch script to physical addresses
*/
ncr_script_fill (&script0, &scripth0);
@@ -4769,17 +5205,36 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
if (np->base2_ba) {
np->p_script = pcivtobus(np->base2_ba);
if (np->features & FE_RAM8K) {
+ np->base2_ws = 8192;
np->p_scripth = np->p_script + 4096;
#if BITS_PER_LONG > 32
np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32);
#endif
}
+ else
+ np->base2_ws = 4096;
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+ np->base2_va = remap_pci_mem(np->base2_ba, np->base2_ws);
+ if (!np->base2_va) {
+ printk(KERN_ERR "%s: can't map PCI MEMORY region\n",
+ ncr_name(np));
+ goto attach_error;
+ }
+#endif
}
ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
/*
+ ** If not 64 bit chip, patch some places in SCRIPTS.
+ */
+ if (!(np->features & FE_64BIT)) {
+ np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
+ np->scripth0->swide_fin_32[1] =
+ cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch));
+ }
+ /*
** Patch some variables in SCRIPTS
*/
np->scripth0->pm0_data_addr[0] =
@@ -4787,11 +5242,12 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
np->scripth0->pm1_data_addr[0] =
cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data));
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
np->scripth0->script0_ba[0] = cpu_to_scr(vtobus(np->script0));
np->scripth0->script0_ba64[0] = cpu_to_scr(vtobus(np->script0));
np->scripth0->scripth0_ba64[0] = cpu_to_scr(vtobus(np->scripth0));
np->scripth0->ram_seg64[0] = np->scr_ram_seg;
-
+#endif
/*
** Prepare the idle and invalid task actions.
*/
@@ -4827,10 +5283,11 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
/*
** Prepare the target bus address array.
*/
- np->script0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
+ 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->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
+ np->target[i].b_lun0 = cpu_to_scr(vtobus(&np->resel_badlun));
}
/*
@@ -4846,6 +5303,23 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
}
+#ifdef SCSI_NCR_IARB_SUPPORT
+ /*
+ ** If user does not want to use IMMEDIATE ARBITRATION
+ ** when we are reselected while attempting to arbitrate,
+ ** patch the SCRIPTS accordingly with a SCRIPT NO_OP.
+ */
+ if (!(driver_setup.iarb & 1))
+ np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+ /*
+ ** If user wants IARB to be set when we win arbitration
+ ** and have other jobs, compute the max number of consecutive
+ ** settings of IARB hint before we leave devices a chance to
+ ** arbitrate for reselection.
+ */
+ np->iarb_max = (driver_setup.iarb >> 4);
+#endif
+
/*
** DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5.
*/
@@ -4890,14 +5364,20 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
/*
** Install the interrupt handler.
+ ** If we synchonize the C code with SCRIPTS on interrupt,
+ ** we donnot want to share the INTR line at all.
*/
if (request_irq(device->slot.irq, sym53c8xx_intr,
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+ ((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
+#else
((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) |
#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
#else
0,
#endif
+#endif
NAME53C8XX, np)) {
printk(KERN_ERR "%s: request irq %d failure\n",
ncr_name(np), device->slot.irq);
@@ -4957,8 +5437,9 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
** and return success.
*/
instance->max_channel = 0;
+ instance->this_id = np->myaddr;
instance->max_id = np->maxwide ? 16 : 8;
- instance->max_lun = SCSI_NCR_MAX_LUN;
+ instance->max_lun = MAX_LUN;
#ifndef NCR_IOMAPPED
instance->base = (char *) np->reg;
#endif
@@ -4967,6 +5448,9 @@ printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n
instance->io_port = np->base_io;
instance->n_io_port = np->base_ws;
instance->dma_channel = 0;
+ instance->cmd_per_lun = MAX_TAGS;
+ instance->can_queue = (MAX_START-4);
+
instance->select_queue_depths = sym53c8xx_select_queue_depths;
NCR_UNLOCK_NCB(np, flags);
@@ -5002,9 +5486,11 @@ static void ncr_free_resources(ncb_p np)
free_irq(np->irq, np);
if (np->base_io)
release_region(np->base_io, np->base_ws);
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
if (np->base_va)
unmap_pci_mem(np->base_va, np->base_ws);
+ if (np->base2_va)
+ unmap_pci_mem(np->base2_va, np->base2_ws);
#endif
if (np->scripth0)
m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH");
@@ -5026,13 +5512,19 @@ static void ncr_free_resources(ncb_p np)
for (target = 0; target < MAX_TARGET ; target++) {
tp = &np->target[target];
for (lun = 0 ; lun < MAX_LUN ; lun++) {
- lp = tp->lp[lun];
+ lp = ncr_lp(np, tp, lun);
if (!lp)
continue;
if (lp->tasktbl != &lp->tasktbl_0)
- m_free(lp->tasktbl, 256, "TASKTBL");
+ m_free(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");
}
+#if MAX_LUN > 1
+ if (tp->lmp)
+ m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP");
+#endif
}
m_free(np, sizeof(*np), "NCB");
@@ -5074,6 +5566,81 @@ static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd)
}
}
+/*==========================================================
+**
+**
+** Prepare the next negotiation message if needed.
+**
+** Fill in the part of message buffer that contains the
+** negotiation and the nego_status field of the CCB.
+** Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
+{
+ tcb_p tp = &np->target[cp->target];
+ int msglen = 0;
+ int nego = 0;
+
+ if (tp->inq_done) {
+
+ /*
+ ** negotiate wide transfers ?
+ */
+
+ if (!tp->widedone) {
+ if (tp->inq_byte7 & INQ7_WIDE16) {
+ nego = NS_WIDE;
+ } else
+ tp->widedone=1;
+ };
+
+ /*
+ ** negotiate synchronous transfers?
+ */
+
+ if (!nego && !tp->period) {
+ if (tp->inq_byte7 & INQ7_SYNC) {
+ nego = NS_SYNC;
+ } else {
+ tp->period =0xffff;
+ PRINT_TARGET(np, cp->target);
+ printk ("target did not report SYNC.\n");
+ };
+ };
+ };
+
+ switch (nego) {
+ case NS_SYNC:
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 3;
+ msgptr[msglen++] = M_X_SYNC_REQ;
+ msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+ msgptr[msglen++] = tp->maxoffs;
+ break;
+ case NS_WIDE:
+ msgptr[msglen++] = M_EXTENDED;
+ msgptr[msglen++] = 2;
+ msgptr[msglen++] = M_X_WIDE_REQ;
+ msgptr[msglen++] = tp->usrwide;
+ break;
+ };
+
+ cp->nego_status = nego;
+
+ if (nego) {
+ tp->nego_cp = cp;
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, nego == NS_WIDE ?
+ "wide msgout":"sync_msgout", msgptr);
+ };
+ };
+
+ return msglen;
+}
/*==========================================================
**
@@ -5088,12 +5655,12 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
{
/* Scsi_Device *device = cmd->device; */
tcb_p tp = &np->target[cmd->target];
- lcb_p lp = tp->lp[cmd->lun];
+ lcb_p lp = ncr_lp(np, tp, cmd->lun);
ccb_p cp;
int segments;
- u_char nego, idmsg, *msgptr;
- u_int msglen;
+ u_char idmsg, *msgptr;
+ u_int msglen;
int direction;
u_int32 lastp, goalp;
@@ -5138,9 +5705,10 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**
**----------------------------------------------------
*/
- if (np->settle_time && cmd->timeout_per_command >= HZ &&
- np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
- np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+ if (np->settle_time && cmd->timeout_per_command >= HZ) {
+ u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+ if (ktime_dif(np->settle_time, tlimit) > 0)
+ np->settle_time = tlimit;
}
if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -5166,52 +5734,6 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
cp->phys.num_disc = 0;
#endif
- /*---------------------------------------------------
- **
- ** negotiation required?
- **
- **---------------------------------------------------
- */
-
- nego = 0;
-
- if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) {
-
- /*
- ** negotiate wide transfers ?
- */
-
- if (!tp->widedone) {
- if (tp->inq_byte7 & INQ7_WIDE16) {
- nego = NS_WIDE;
- } else
- tp->widedone=1;
- };
-
- /*
- ** negotiate synchronous transfers?
- */
-
- if (!nego && !tp->period) {
- if (tp->inq_byte7 & INQ7_SYNC) {
- nego = NS_SYNC;
- } else {
- tp->period =0xffff;
- PRINT_TARGET(np, cp->target);
- printk ("target did not report SYNC.\n");
- };
- };
-
- /*
- ** remember nego is pending for the target.
- ** Avoid to start a nego for all queued commands
- ** when tagged command queuing is enabled.
- */
-
- if (nego)
- tp->nego_cp = cp;
- };
-
/*----------------------------------------------------
**
** Build the identify / tag / sdtr message
@@ -5235,16 +5757,16 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
** Force ordered tag if necessary to avoid timeouts
** and to preserve interactivity.
*/
- if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
- if (lp->tags_smap) {
+ if (lp && ktime_exp(lp->tags_stime)) {
+ lp->tags_si = !(lp->tags_si);
+ if (lp->tags_sum[lp->tags_si]) {
order = M_ORDERED_TAG;
- if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){
+ if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){
PRINT_ADDR(cmd);
printk("ordered tag forced.\n");
}
}
- lp->tags_stime = jiffies;
- lp->tags_smap = lp->tags_umap;
+ lp->tags_stime = ktime_get(3*HZ);
}
if (order == 0) {
@@ -5263,41 +5785,19 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
}
msgptr[msglen++] = order;
/*
- ** Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
- ** since we may have to deal with devices that have
- ** problems with #TAG 0 or too great #TAG numbers.
+ ** For less than 128 tags, actual tags are numbered
+ ** 1,3,5,..2*MAXTAGS+1,since we may have to deal
+ ** with devices that have problems with #TAG 0 or too
+ ** great #TAG numbers. For more tags (up to 256),
+ ** we use directly our tag number.
*/
+#if MAX_TASKS > (512/4)
+ msgptr[msglen++] = cp->tag;
+#else
msgptr[msglen++] = (cp->tag << 1) + 1;
+#endif
}
- switch (nego) {
- case NS_SYNC:
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 3;
- msgptr[msglen++] = M_X_SYNC_REQ;
- msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
- msgptr[msglen++] = tp->maxoffs;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("sync msgout: ");
- ncr_show_msg (&cp->scsi_smsg [msglen-5]);
- printk (".\n");
- };
- break;
- case NS_WIDE:
- msgptr[msglen++] = M_EXTENDED;
- msgptr[msglen++] = 2;
- msgptr[msglen++] = M_X_WIDE_REQ;
- msgptr[msglen++] = tp->usrwide;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("wide msgout: ");
- ncr_show_msg (&cp->scsi_smsg [msglen-4]);
- printk (".\n");
- };
- break;
- };
-
cp->host_flags = 0;
/*----------------------------------------------------
@@ -5307,7 +5807,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
**----------------------------------------------------
*/
- segments = np->scatter (cp, cp->cmd);
+ cp->segments = segments = np->scatter (cp, cp->cmd);
if (segments < 0) {
ncr_free_ccb(np, cp);
@@ -5357,16 +5857,8 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
*/
if (direction & XFER_OUT) {
goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-#if MAX_SCATTERH != 0
- if (segments <= MAX_SCATTERL)
- lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
- else {
- lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
- lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
- }
-#else
lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
+
/*
** If actual data direction is unknown, save pointers
** in header. The SCRIPTS will swap them to current
@@ -5383,16 +5875,7 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
*/
if (direction & XFER_IN) {
goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
-#if MAX_SCATTERH != 0
- if (segments <= MAX_SCATTERL)
- lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
- else {
- lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
- lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
- }
-#else
lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
}
/*
@@ -5411,8 +5894,26 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
/*
** Save the initial data pointer in order to be able
** to redo the command.
+ ** We also have to save the initial lastp, since it
+ ** will be changed to DATA_IO if we don't know the data
+ ** direction and the device completes the command with
+ ** QUEUE FULL status (without entering the data phase).
*/
cp->startp = cp->phys.header.savep;
+ cp->lastp0 = cp->phys.header.lastp;
+
+ /*---------------------------------------------------
+ **
+ ** negotiation required?
+ **
+ ** (nego_status is filled by ncr_prepare_nego())
+ **
+ **---------------------------------------------------
+ */
+
+ cp->nego_status = 0;
+ if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp)
+ msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
/*----------------------------------------------------
**
@@ -5439,24 +5940,30 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
/*
** message
*/
- cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
- cp->phys.smsg.size = cpu_to_scr(msglen);
+ cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+ cp->phys.smsg.size = cpu_to_scr(msglen);
/*
** command
*/
- cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0]));
- cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
+ cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0]));
+ cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len);
/*
** status
*/
- cp->actualquirks = tp->quirks;
- cp->host_status = nego ? HS_NEGOTIATE : HS_BUSY;
- cp->scsi_status = S_ILLEGAL;
+ cp->actualquirks = tp->quirks;
+ cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+ cp->scsi_status = S_ILLEGAL;
+ cp->xerr_status = 0;
+ cp->phys.extra_bytes = 0;
- cp->xerr_status = XE_OK;
- cp->nego_status = nego;
+ /*
+ ** extreme data pointer.
+ ** shall be positive, so -1 is lower than lowest.:)
+ */
+ cp->ext_sg = -1;
+ cp->ext_ofs = 0;
/*----------------------------------------------------
**
@@ -5469,17 +5976,10 @@ static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
** activate this job.
*/
- /* Compute a time limit greater than the middle-level driver one */
- if (cmd->timeout_per_command > 0)
- cp->tlimit = jiffies + cmd->timeout_per_command + HZ;
- else
- cp->tlimit = jiffies + 86400 * HZ;/* No timeout=24 hours */
-
/*
** insert next CCBs into start queue.
** 2 max at a time is enough to flush the CCB wait queue.
*/
- cp->auto_sense = 0;
if (lp)
ncr_start_next_ccb(np, lp, 2);
else
@@ -5525,6 +6025,24 @@ static void ncr_put_start_queue(ncb_p np, ccb_p cp)
{
u_short qidx;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ /*
+ ** If the previously queued CCB is not yet done,
+ ** set the IARB hint. The SCRIPTS will go with IARB
+ ** for this job when starting the previous one.
+ ** We leave devices a chance to win arbitration by
+ ** not using more than 'iarb_max' consecutive
+ ** immediate arbitrations.
+ */
+ if (np->last_cp && np->iarb_count < np->iarb_max) {
+ np->last_cp->host_flags |= HF_HINT_IARB;
+ ++np->iarb_count;
+ }
+ else
+ np->iarb_count = 0;
+ np->last_cp = cp;
+#endif
+
/*
** insert into start queue.
*/
@@ -5546,7 +6064,7 @@ static void ncr_put_start_queue(ncb_p np, ccb_p cp)
** Wake it up.
*/
MEMORY_BARRIER();
- OUTB (nc_istat, SIGP);
+ OUTB (nc_istat, SIGP|np->istat_sem);
}
@@ -5593,7 +6111,6 @@ static void ncr_soft_reset(ncb_p np)
**
**
** Start reset process.
-** If reset in progress do nothing.
** The interrupt handler will reinitialize the chip.
** The timeout handler will wait for settle_time before
** clearing it and so resuming command processing.
@@ -5603,17 +6120,15 @@ static void ncr_soft_reset(ncb_p np)
*/
static void ncr_start_reset(ncb_p np)
{
- if (!np->settle_time) {
- (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
- }
- }
+ (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+}
static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
{
u_int32 term;
int retv = 0;
- np->settle_time = jiffies + settle_delay * HZ;
+ np->settle_time = ktime_get(settle_delay * HZ);
if (bootverbose > 1)
printk("%s: resetting, "
@@ -5747,8 +6262,6 @@ static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd)
{
/* Scsi_Device *device = cmd->device; */
ccb_p cp;
- int found;
- int retv;
/*
* First, look for the scsi command in the waiting list
@@ -5762,58 +6275,41 @@ static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd)
/*
* Then, look in the wakeup list
*/
- for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) {
+ for (cp=np->ccbc; cp; cp=cp->link_ccb) {
/*
** look for the ccb of this command.
*/
if (cp->host_status == HS_IDLE) continue;
- if (cp->cmd == cmd) {
- found = 1;
+ if (cp->cmd == cmd)
break;
- }
}
- if (!found) {
+ if (!cp) {
return SCSI_ABORT_NOT_RUNNING;
}
- if (np->settle_time) {
- return SCSI_ABORT_SNOOZE;
- }
-
/*
- ** If the CCB is active, patch schedule jumps for the
- ** script to abort the command.
+ ** Keep track we have to abort this job.
*/
+ cp->to_abort = 1;
- cp->tlimit = 0;
- switch(cp->host_status) {
- case HS_BUSY:
- case HS_NEGOTIATE:
- printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
- cp->phys.header.go.start =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
- retv = SCSI_ABORT_PENDING;
- break;
- case HS_DISCONNECT:
- cp->phys.header.go.restart =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
- retv = SCSI_ABORT_PENDING;
- break;
- default:
- retv = SCSI_ABORT_NOT_RUNNING;
- break;
-
- }
+ /*
+ ** Tell the SCRIPTS processor to stop
+ ** and synchronize with us.
+ */
+ np->istat_sem = SEM;
/*
** If there are no requests, the script
** processor will sleep on SEL_WAIT_RESEL.
** Let's wake it up, since it may have to work.
*/
- OUTB (nc_istat, SIGP);
+ OUTB (nc_istat, SIGP|SEM);
- return retv;
+ /*
+ ** Tell user we are working for him.
+ */
+ return SCSI_ABORT_PENDING;
}
/*==========================================================
@@ -5917,7 +6413,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
cmd = cp->cmd;
cp->cmd = NULL;
tp = &np->target[cp->target];
- lp = tp->lp[cp->lun];
+ lp = ncr_lp(np, tp, cp->lun);
/*
** We donnot queue more than 1 ccb per target
@@ -5928,41 +6424,47 @@ void ncr_complete (ncb_p np, ccb_p cp)
if (cp == tp->nego_cp)
tp->nego_cp = 0;
+#ifdef SCSI_NCR_IARB_SUPPORT
/*
- ** If auto-sense performed, change scsi status.
+ ** We just complete the last queued CCB.
+ ** Clear this info that is no more relevant.
*/
- if (cp->auto_sense) {
- cp->scsi_status = cp->auto_sense;
- }
+ if (cp == np->last_cp)
+ np->last_cp = 0;
+#endif
/*
- ** Check for parity errors.
+ ** If auto-sense performed, change scsi status,
+ ** Otherwise, compute the residual.
*/
-
- if (cp->host_flags & HF_PAR_ERR) {
- PRINT_ADDR(cmd);
- printk ("unrecovered SCSI parity error.\n");
- if (cp->host_status==HS_COMPLETE)
- cp->host_status = HS_FAIL;
+ if (cp->host_flags & HF_AUTO_SENSE) {
+ cp->scsi_status = cp->sv_scsi_status;
+ cp->xerr_status = cp->sv_xerr_status;
+ }
+ else {
+ cp->resid = 0;
+ if (cp->phys.header.lastp != cp->phys.header.goalp)
+ cp->resid = ncr_compute_residual(np, cp);
}
/*
** Check for extended errors.
*/
- if (cp->xerr_status != XE_OK) {
- PRINT_ADDR(cmd);
- switch (cp->xerr_status) {
- case XE_EXTRA_DATA:
+ if (cp->xerr_status) {
+ if (cp->xerr_status & XE_PARITY_ERR) {
+ PRINT_ADDR(cp->cmd);
+ printk ("unrecovered SCSI parity error.\n");
+ }
+ if (cp->xerr_status & XE_EXTRA_DATA) {
+ PRINT_ADDR(cp->cmd);
printk ("extraneous data discarded.\n");
- break;
- case XE_BAD_PHASE:
+ }
+ if (cp->xerr_status & XE_BAD_PHASE) {
+ PRINT_ADDR(cp->cmd);
printk ("illegal scsi phase (4/5).\n");
- break;
- default:
- printk ("extended error %d.\n", cp->xerr_status);
- break;
}
+
if (cp->host_status==HS_COMPLETE)
cp->host_status = HS_FAIL;
}
@@ -5971,10 +6473,13 @@ void ncr_complete (ncb_p np, ccb_p cp)
** Print out any error for debugging purpose.
*/
if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
- if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+ if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD ||
+ cp->resid) {
PRINT_ADDR(cmd);
- printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
- cmd->cmnd[0], cp->host_status, cp->scsi_status);
+ printk ("ERROR: cmd=%x host_status=%x scsi_status=%x "
+ "data_len=%d residual=%d\n",
+ cmd->cmnd[0], cp->host_status, cp->scsi_status,
+ cp->data_len, -cp->resid);
}
}
@@ -5992,13 +6497,6 @@ void ncr_complete (ncb_p np, ccb_p cp)
SetScsiResult(cmd, DID_OK, cp->scsi_status);
/*
- ** @RESID@
- ** Could dig out the correct value for resid,
- ** but it would be quite complicated.
- */
- /* if (cp->phys.header.lastp != cp->phys.header.goalp) */
-
- /*
** Allocate the lcb if not yet.
*/
if (!lp)
@@ -6038,12 +6536,8 @@ void ncr_complete (ncb_p np, ccb_p cp)
SetScsiResult(cmd, DID_OK, S_CHECK_COND);
if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
- u_char * p = (u_char*) & cmd->sense_buffer;
- int i;
PRINT_ADDR(cmd);
- printk ("sense data:");
- for (i=0; i<14; i++) printk (" %x", *p++);
- printk (".\n");
+ ncr_printl_hex("sense data:", cmd->sense_buffer, 14);
}
} else if ((cp->host_status == HS_COMPLETE)
@@ -6078,6 +6572,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
SetScsiResult(cmd, DID_ABORT, cp->scsi_status);
} else {
+ int did_status;
/*
** Other protocol messes
@@ -6086,7 +6581,11 @@ void ncr_complete (ncb_p np, ccb_p cp)
printk ("COMMAND FAILED (%x %x) @%p.\n",
cp->host_status, cp->scsi_status, cp);
- SetScsiResult(cmd, DID_ERROR, cp->scsi_status);
+ did_status = DID_ERROR;
+ if (cp->xerr_status & XE_PARITY_ERR)
+ did_status = DID_PARITY;
+
+ SetScsiResult(cmd, did_status, cp->scsi_status);
}
/*
@@ -6094,12 +6593,9 @@ void ncr_complete (ncb_p np, ccb_p cp)
*/
if (tp->usrflag & UF_TRACE) {
- u_char * p;
- int i;
PRINT_ADDR(cmd);
printk (" CMD:");
- p = (u_char*) &cmd->cmnd[0];
- for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
+ ncr_print_hex(cmd->cmnd, cmd->cmd_len);
if (cp->host_status==HS_COMPLETE) {
switch (cp->scsi_status) {
@@ -6108,9 +6604,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
break;
case S_CHECK_COND:
printk (" SENSE:");
- p = (u_char*) &cmd->sense_buffer;
- for (i=0; i<14; i++)
- printk (" %x", *p++);
+ ncr_print_hex(cmd->sense_buffer, 14);
break;
default:
printk (" STAT: %x\n", cp->scsi_status);
@@ -6250,7 +6744,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
** Start at first entry.
*/
np->squeueput = 0;
- np->script0->startpos[0] = cpu_to_scr(phys);
+ np->scripth0->startpos[0] = cpu_to_scr(phys);
/*
** Clear Done Queue
@@ -6265,7 +6759,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
/*
** Start at first entry.
*/
- np->script0->done_pos[0] = cpu_to_scr(phys);
+ np->scripth0->done_pos[0] = cpu_to_scr(phys);
np->dqueueget = 0;
/*
@@ -6313,7 +6807,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
np->rv_ccntl0 |= DPR;
/*
- ** If 64 bit (53C896) enable 40 bit address table
+ ** If 64 bit (53C895A or 53C896) enable 40 bit address table
** indirect addressing for MOVE.
*/
@@ -6322,7 +6816,7 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
}
/*
- ** If phase mismatch handled by scripts (53C896),
+ ** If phase mismatch handled by scripts (53C895A or 53C896),
** set PM jump addresses.
*/
@@ -6370,6 +6864,8 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
for (i=0;i<MAX_TARGET;i++) {
tcb_p tp = &np->target[i];
+ tp->to_reset = 0;
+
tp->sval = 0;
tp->wval = np->rv_scntl3;
@@ -6390,21 +6886,41 @@ void ncr_init (ncb_p np, int reset, char * msg, u_long code)
}
/*
- ** Start script processor.
+ ** Download SCSI SCRIPTS to on-chip RAM if present,
+ ** and start script processor.
+ ** We do the download preferently from the CPU.
+ ** For platforms that may not support PCI memory mapping,
+ ** we use a simple SCRIPTS that performs MEMORY MOVEs.
*/
MEMORY_BARRIER();
if (np->base2_ba) {
if (bootverbose)
printk ("%s: Downloading SCSI SCRIPTS.\n",
ncr_name(np));
- if (np->features & FE_RAM8K)
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+ if (np->base2_ws == 8192)
phys = NCB_SCRIPTH0_PHYS (np, start_ram64);
else
phys = NCB_SCRIPTH_PHYS (np, start_ram);
+#else
+ if (np->base2_ws == 8192) {
+ memcpy_to_pci(np->base2_va + 4096,
+ np->scripth0, sizeof(struct scripth));
+ OUTL (nc_mmws, np->scr_ram_seg);
+ OUTL (nc_mmrs, np->scr_ram_seg);
+ OUTL (nc_sfs, np->scr_ram_seg);
+ phys = NCB_SCRIPTH_PHYS (np, start64);
+ }
+ else
+ phys = NCB_SCRIPT_PHYS (np, init);
+ memcpy_to_pci(np->base2_va, np->script0, sizeof(struct script));
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
}
else
phys = NCB_SCRIPT_PHYS (np, init);
+ np->istat_sem = 0;
+
OUTL (nc_dsa, vtobus(np));
OUTL (nc_dsp, phys);
}
@@ -6609,7 +7125,11 @@ static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
/*
** Bells and whistles ;-)
+ ** Donnot announce negotiations due to auto-sense,
+ ** unless user really want us to be verbose. :)
*/
+ if (bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+ goto next;
PRINT_TARGET(np, target);
if (sxfer & 0x01f) {
unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
@@ -6634,7 +7154,7 @@ static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
} else
printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+next:
/*
** set actual value and sync_status
** patch ALL ccbs of this target.
@@ -6705,8 +7225,8 @@ static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack)
static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
{
tcb_p tp = &np->target[tn];
- lcb_p lp = tp->lp[ln];
- u_char reqtags, maxdepth;
+ lcb_p lp = ncr_lp(np, tp, ln);
+ u_short reqtags, maxdepth;
/*
** Just in case ...
@@ -6800,35 +7320,12 @@ static void ncr_usercmd (ncb_p np)
{
u_char t;
tcb_p tp;
+ int ln;
+ u_long size;
switch (np->user.cmd) {
-
case 0: return;
- case UC_SETSYNC:
- for (t=0; t<MAX_TARGET; t++) {
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- tp->usrsync = np->user.data;
- ncr_negotiate (np, tp);
- };
- break;
-
- case UC_SETTAGS:
- for (t=0; t<MAX_TARGET; t++) {
- int ln;
- if (!((np->user.target>>t)&1)) continue;
- np->target[t].usrtags = np->user.data;
- for (ln = 0; ln < MAX_LUN; ln++) {
- lcb_p lp = np->target[t].lp[ln];
- if (!lp)
- continue;
- lp->maxtags = lp->numtags = np->user.data;
- ncr_setup_tags (np, t, ln);
- }
- };
- break;
-
case UC_SETDEBUG:
#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = np->user.data;
@@ -6843,31 +7340,73 @@ static void ncr_usercmd (ncb_p np)
np->verbose = np->user.data;
break;
- case UC_SETWIDE:
- for (t=0; t<MAX_TARGET; t++) {
- u_long size;
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- size = np->user.data;
- if (size > np->maxwide) size=np->maxwide;
- tp->usrwide = size;
- ncr_negotiate (np, tp);
- };
- break;
-
- case UC_SETFLAG:
- for (t=0; t<MAX_TARGET; t++) {
- if (!((np->user.target>>t)&1)) continue;
- tp = &np->target[t];
- tp->usrflag = np->user.data;
- };
- break;
-
#ifdef SCSI_NCR_PROFILE_SUPPORT
case UC_CLEARPROF:
bzero(&np->profile, sizeof(np->profile));
break;
#endif
+ default:
+ /*
+ ** We assume that other commands apply to targets.
+ ** This should always be the case and avoid the below
+ ** 4 lines to be repeated 5 times.
+ */
+ for (t = 0; t < MAX_TARGET; t++) {
+ if (!((np->user.target >> t) & 1))
+ continue;
+ tp = &np->target[t];
+
+ switch (np->user.cmd) {
+
+ case UC_SETSYNC:
+ tp->usrsync = np->user.data;
+ ncr_negotiate (np, tp);
+ break;
+
+ case UC_SETWIDE:
+ size = np->user.data;
+ if (size > np->maxwide)
+ size=np->maxwide;
+ tp->usrwide = size;
+ ncr_negotiate (np, tp);
+ break;
+
+ case UC_SETTAGS:
+ tp->usrtags = np->user.data;
+ for (ln = 0; ln < MAX_LUN; ln++) {
+ lcb_p lp;
+ lp = ncr_lp(np, tp, ln);
+ if (!lp)
+ continue;
+ lp->numtags = np->user.data;
+ lp->maxtags = lp->numtags;
+ ncr_setup_tags (np, t, ln);
+ }
+ break;
+
+ case UC_RESETDEV:
+ tp->to_reset = 1;
+ np->istat_sem = SEM;
+ OUTB (nc_istat, SIGP|SEM);
+ break;
+
+ case UC_CLEARDEV:
+ for (ln = 0; ln < MAX_LUN; ln++) {
+ lcb_p lp;
+ lp = ncr_lp(np, tp, ln);
+ if (lp)
+ lp->to_clear = 1;
+ }
+ np->istat_sem = SEM;
+ OUTB (nc_istat, SIGP|SEM);
+ break;
+
+ case UC_SETFLAG:
+ tp->usrflag = np->user.data;
+ break;
+ }
+ }
+ break;
}
np->user.cmd=0;
}
@@ -6889,7 +7428,7 @@ static void ncr_usercmd (ncb_p np)
static void ncr_timeout (ncb_p np)
{
- u_long thistime = jiffies;
+ u_long thistime = ktime_get(0);
/*
** If release process in progress, let's go
@@ -6902,7 +7441,11 @@ static void ncr_timeout (ncb_p np)
return;
}
- np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
+ np->timer.expires = ktime_get((HZ+9)/10);
+#else
+ np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+#endif
add_timer(&np->timer);
/*
@@ -6926,7 +7469,19 @@ static void ncr_timeout (ncb_p np)
np->lasttime = thistime;
}
-#ifdef SCSI_NCR_BROKEN_INTR
+#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+ /*
+ ** Some way-broken PCI bridges may lead to
+ ** completions being lost when the clearing
+ ** of the INTFLY flag by the CPU occurs
+ ** concurrently with the chip raising this flag.
+ ** If this ever happen, lost completions will
+ ** be reaped here.
+ */
+ ncr_wakeup_done(np);
+#endif
+
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
if (INB(nc_istat) & (INTF|SIP|DIP)) {
/*
@@ -6936,7 +7491,7 @@ static void ncr_timeout (ncb_p np)
ncr_exception (np);
if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
}
-#endif /* SCSI_NCR_BROKEN_INTR */
+#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */
}
/*==========================================================
@@ -6963,7 +7518,7 @@ static void ncr_timeout (ncb_p np)
** dsp: script adress (relative to start of script).
** dbc: first word of script command.
**
-** First 16 register of the chip:
+** First 24 register of the chip:
** r0..rf
**
**==========================================================
@@ -7012,7 +7567,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat)
}
printk ("%s: regdump:", ncr_name(np));
- for (i=0; i<16;i++)
+ for (i=0; i<24;i++)
printk (" %02x", (unsigned)INB_OFF(i));
printk (".\n");
}
@@ -7119,7 +7674,7 @@ void ncr_exception (ncb_p np)
** with my 895 that unfortunately suffers of the MA int.).
*/
if (driver_setup.optimize & 1) {
- OUTB(nc_istat, (INTF | SIGP));
+ OUTB(nc_istat, (INTF | SIGP | np->istat_sem));
if (ncr_wakeup_done (np)) {
#ifdef SCSI_NCR_PROFILE_SUPPORT
++np->profile.num_fly;
@@ -7131,10 +7686,17 @@ void ncr_exception (ncb_p np)
/*
** interrupt on the fly ?
+ **
+ ** For bridges that donnot flush posted writes
+ ** in the reverse direction on read, a dummy read
+ ** may help not to miss completions.
*/
istat = INB (nc_istat);
if (istat & INTF) {
- OUTB (nc_istat, (istat & SIGP) | INTF);
+ OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+ istat = INB (nc_istat); /* DUMMY READ */
+#endif
if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
(void)ncr_wakeup_done (np);
#ifdef SCSI_NCR_PROFILE_SUPPORT
@@ -7252,8 +7814,8 @@ void ncr_exception (ncb_p np)
** Reset everything.
**=========================================================
*/
- if (jiffies - np->regtime > 10*HZ) {
- np->regtime = jiffies;
+ if (ktime_exp(np->regtime)) {
+ np->regtime = ktime_get(10*HZ);
for (i = 0; i<sizeof(np->regdump); i++)
((char*)&np->regdump)[i] = INB_OFF(i);
np->regdump.nc_dstat = dstat;
@@ -7315,17 +7877,9 @@ static void ncr_recover_scsi_int (ncb_p np, u_char hsts)
{
u_int32 dsp = INL (nc_dsp);
u_int32 dsa = INL (nc_dsa);
- u_char scntl1 = INB (nc_scntl1);
ccb_p cp = ncr_ccb_from_dsa(np, dsa);
/*
- ** If we are connected to the SCSI BUS, we only
- ** can reset the BUS.
- */
- if (scntl1 & ISCON)
- goto reset_all;
-
- /*
** If we haven't been interrupted inside the SCRIPTS
** critical pathes, we can safely restart the SCRIPTS
** and trust the DSA value if it matches a CCB.
@@ -7334,6 +7888,8 @@ static void ncr_recover_scsi_int (ncb_p np, u_char hsts)
dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) &&
(!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) &&
dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) &&
+ (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) &&
+ dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) &&
(!(dsp > NCB_SCRIPT_PHYS (np, done) &&
dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) {
if (cp) {
@@ -7377,7 +7933,6 @@ void ncr_int_sto (ncb_p np)
if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 ||
- dsp == NCB_SCRIPTH_PHYS (np, wf_sel_done_no_atn) + 8 ||
!(driver_setup.recovery & 1))
ncr_recover_scsi_int(np, HS_SEL_TIMEOUT);
else
@@ -7429,7 +7984,7 @@ static void ncr_int_sbmc (ncb_p np)
** Suspend command processing for 1 second and
** reinitialize all except the chip.
*/
- np->settle_time = jiffies + HZ;
+ np->settle_time = ktime_get(1*HZ);
ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
}
@@ -7455,8 +8010,8 @@ static void ncr_int_sbmc (ncb_p np)
** The chip will then interrupt with both PAR and MA
** conditions set.
**
-** - A phase mismatch occurs before the MOV finished
-** and phase errors are to be handled by SCRIPTS (896).
+** - A phase mismatch occurs before the MOV finished and
+** phase errors are to be handled by SCRIPTS (895A or 896).
** The chip will load the DSP with the phase mismatch
** JUMP address and interrupt the host processor.
**
@@ -7472,6 +8027,7 @@ static void ncr_int_par (ncb_p np, u_short sist)
u_char sbcl = INB (nc_sbcl);
u_char cmd = dbc >> 24;
int phase = cmd & 7;
+ ccb_p cp = ncr_ccb_from_dsa(np, dsa);
printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
ncr_name(np), hsts, dbc, sbcl);
@@ -7491,7 +8047,7 @@ static void ncr_int_par (ncb_p np, u_short sist)
** If the nexus is not clearly identified, reset the bus.
** We will try to do better later.
*/
- if (!ncr_ccb_from_dsa(np, dsa))
+ if (!cp)
goto reset_all;
/*
@@ -7504,7 +8060,7 @@ static void ncr_int_par (ncb_p np, u_short sist)
/*
** Keep track of the parity error.
*/
- OUTONB (HF_PRT, HF_PAR_ERR);
+ cp->xerr_status |= XE_PARITY_ERR;
/*
** Prepare the message to send to the device.
@@ -7528,7 +8084,7 @@ static void ncr_int_par (ncb_p np, u_short sist)
/* No phase mismatch occurred */
else {
OUTL (nc_temp, dsp);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
}
}
else
@@ -7590,8 +8146,9 @@ static void ncr_int_ma (ncb_p np)
/*
** Donnot take into account dma fifo and various buffers in
- ** DATA IN phase since the chip flushes everything before
+ ** INPUT phase since the chip flushes everything before
** raising the MA interrupt for interrupted INPUT phases.
+ ** For DATA IN phase, we will check for the SWIDE later.
*/
if ((cmd & 7) != 1) {
u_int32 dfifo;
@@ -7633,7 +8190,7 @@ static void ncr_int_ma (ncb_p np)
*/
OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */
OUTB (nc_stest3, TE|CSF); /* scsi fifo */
- };
+ }
/*
** log the information
@@ -7732,8 +8289,8 @@ static void ncr_int_ma (ncb_p np)
**
** Look at the PM_SAVE SCRIPT if you want to understand
** this stuff. The equivalent code is implemented in
- ** SCRIPTS for the 896 that is able to handle PM from
- ** the SCRIPTS processor.
+ ** SCRIPTS for the 895A and 896 that are able to handle
+ ** PM from the SCRIPTS processor.
*/
hflags0 = INB (HF_PRT);
@@ -7770,6 +8327,53 @@ static void ncr_int_ma (ncb_p np)
pm->sg.size = cpu_to_scr(rest);
pm->ret = cpu_to_scr(nxtdsp);
+ /*
+ ** If we have a SWIDE,
+ ** - prepare the address to write the SWIDE from SCRIPTS,
+ ** - compute the SCRIPTS address to restart from,
+ ** - move current data pointer context by one byte.
+ */
+ nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+ if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
+ (INB (nc_scntl2) & WSR)) {
+ /*
+ ** Hmmm... The device may want to also ignore
+ ** this residue but it must send immediately the
+ ** appropriate message. We snoop the SCSI BUS
+ ** and will just throw away this message from
+ ** SCRIPTS if the SWIDE is to be ignored.
+ */
+ if ((INB (nc_sbcl) & 7) == 7 &&
+ INB (nc_sbdl) == M_IGN_RESIDUE) {
+ nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg);
+ }
+ /*
+ ** We must grab the SWIDE.
+ ** We will use some complex SCRIPTS for that.
+ */
+ else {
+ OUTL (nc_scratcha, pm->sg.addr);
+ nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32);
+ if (np->features & FE_64BIT) {
+ OUTB (nc_sbr, (pm->sg.size >> 24));
+ nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64);
+ }
+ /*
+ ** Adjust our data pointer context.
+ */
+ ++pm->sg.addr;
+ --pm->sg.size;
+ /*
+ ** Hmmm... Could it be possible that a SWIDE that
+ ** is followed by a 1 byte CHMOV would lead to
+ ** a CHMOV(0). Anyway, we handle it by just
+ ** skipping context that would attempt a CHMOV(0).
+ */
+ if (!pm->sg.size)
+ newcmd = pm->ret;
+ }
+ }
+
if (DEBUG_FLAGS & DEBUG_PHASE) {
PRINT_ADDR(cp->cmd);
printk ("PM %x %x %x / %x %x %x.\n",
@@ -7780,12 +8384,11 @@ static void ncr_int_ma (ncb_p np)
}
/*
- ** fake the return address (to the patch).
- ** and restart script processor at dispatcher.
+ ** Restart the SCRIPTS processor.
*/
OUTL (nc_temp, newcmd);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+ OUTL (nc_dsp, nxtdsp);
return;
/*
@@ -7889,6 +8492,10 @@ reset_all:
** requeue the CCB that failed in front of the LUN queue.
** I just hope this not to be performed too often. :)
**
+** If we are using IMMEDIATE ARBITRATION, we clear the
+** IARB hint for every commands we encounter in order not
+** to be stuck with a won arbitration and no job to queue
+** to a device.
**----------------------------------------------------------
*/
@@ -7896,11 +8503,12 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
{
Scsi_Cmnd *cmd = cp->cmd;
tcb_p tp = &np->target[cp->target];
- lcb_p lp = tp->lp[cp->lun];
+ lcb_p lp = ncr_lp(np, tp, cp->lun);
ccb_p cp2;
int busyccbs = 1;
u_int32 startp;
u_char s_status = INB (SS_PRT);
+ int msglen;
/*
** Remove all CCBs queued to the chip for that LUN and put
@@ -7923,6 +8531,11 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
continue;
if (cp2->target != cp->target || cp2->lun != cp->lun)
continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ cp2->host_flags &= ~HF_HINT_IARB;
+ if (cp2 == np->last_cp)
+ np->last_cp = 0;
+#endif
xpt_remque(&cp2->link_ccbq);
xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq);
--lp->queuedccbs;
@@ -7935,11 +8548,21 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
** Requeue the interrupted CCB in front of
** the LUN CCB wait queue.
*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+ cp->host_flags &= ~HF_HINT_IARB;
+ if (cp == np->last_cp)
+ np->last_cp = 0;
+#endif
xpt_remque(&cp->link_ccbq);
xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq);
--lp->queuedccbs;
cp->queued = 0;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ if (np->last_cp)
+ np->last_cp->host_flags &= ~HF_HINT_IARB;
+#endif
+
/*
** Repair the startqueue if necessary.
*/
@@ -7992,10 +8615,13 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
/*
** Repair the offending CCB.
*/
- cp->phys.header.savep = cp->startp;
- cp->host_status = HS_BUSY;
- cp->scsi_status = S_ILLEGAL;
- cp->host_flags &= HF_PM_TO_C;
+ cp->phys.header.savep = cp->startp;
+ cp->phys.header.lastp = cp->lastp0;
+ cp->host_status = HS_BUSY;
+ cp->scsi_status = S_ILLEGAL;
+ cp->xerr_status = 0;
+ cp->phys.extra_bytes = 0;
+ cp->host_flags &= HF_PM_TO_C;
break;
@@ -8004,12 +8630,20 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
/*
** If we were requesting sense, give up.
*/
- if (cp->auto_sense) {
+ if (cp->host_flags & HF_AUTO_SENSE) {
ncr_complete(np, cp);
break;
}
/*
+ ** Save SCSI status and extended error.
+ ** Compute the data residual now.
+ */
+ cp->sv_scsi_status = cp->scsi_status;
+ cp->sv_xerr_status = cp->xerr_status;
+ cp->resid = ncr_compute_residual(np, cp);
+
+ /*
** Device returned CHECK CONDITION status.
** Prepare all needed data strutures for getting
** sense data.
@@ -8019,8 +8653,29 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
** identify message
*/
cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun;
+ msglen = 1;
+
+ /*
+ ** If we are currently using anything different from
+ ** async. 8 bit data transfers with that target,
+ ** start a negotiation, since the device may want
+ ** to report us a UNIT ATTENTION condition due to
+ ** a cause we currently ignore, and we donnot want
+ ** to be stuck with WIDE and/or SYNC data transfer.
+ **
+ ** cp->nego_status is filled by ncr_prepare_nego().
+ */
+ ncr_negotiate(np, tp);
+ cp->nego_status = 0;
+ if ((tp->wval & EWS) || (tp->sval & 0x1f))
+ msglen +=
+ ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+
+ /*
+ ** Message table indirect structure.
+ */
cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
- cp->phys.smsg.size = cpu_to_scr(1);
+ cp->phys.smsg.size = cpu_to_scr(msglen);
/*
** sense command
@@ -8038,6 +8693,7 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
/*
** 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 =
@@ -8046,30 +8702,22 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
/*
** requeue the command.
*/
- startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
+ startp = NCB_SCRIPTH_PHYS (np, sdata_in);
- cp->phys.header.savep = startp;
- cp->phys.header.goalp = startp + 24;
- cp->phys.header.lastp = startp;
- cp->phys.header.wgoalp = startp + 24;
- cp->phys.header.wlastp = startp;
+ cp->phys.header.savep = cpu_to_scr(startp);
+ cp->phys.header.goalp = cpu_to_scr(startp + 16);
+ cp->phys.header.lastp = cpu_to_scr(startp);
+ cp->phys.header.wgoalp = cpu_to_scr(startp + 16);
+ cp->phys.header.wlastp = cpu_to_scr(startp);
- cp->host_status = HS_BUSY;
+ cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
cp->scsi_status = S_ILLEGAL;
- cp->host_flags = 0;
- cp->auto_sense = s_status;
+ cp->host_flags = HF_AUTO_SENSE;
cp->phys.header.go.start =
cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
/*
- ** Select without ATN for quirky devices.
- */
- if (tp->quirks & QUIRK_NOMSG)
- cp->phys.header.go.start =
- cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
-
- /*
** If lp not yet allocated, requeue the command.
*/
if (!lp)
@@ -8086,12 +8734,718 @@ static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
return;
}
+/*----------------------------------------------------------
+**
+** After a device has accepted some management message
+** as BUS DEVICE RESET, ABORT TASK, etc ..., or when
+** a device signals a UNIT ATTENTION condition, some
+** tasks are thrown away by the device. We are required
+** to reflect that on our tasks list since the device
+** will never complete these tasks.
+**
+** This function completes all disconnected CCBs for a
+** given target that matches the following criteria:
+** - lun=-1 means any logical UNIT otherwise a given one.
+** - task=-1 means any task, otherwise a given one.
+**----------------------------------------------------------
+*/
+static int ncr_clear_tasks(ncb_p np, u_char hsts,
+ int target, int lun, int task)
+{
+ int i = 0;
+ ccb_p cp;
+
+ for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+ if (cp->host_status != HS_DISCONNECT)
+ continue;
+ if (cp->target != target)
+ continue;
+ if (lun != -1 && cp->lun != lun)
+ continue;
+ if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task)
+ continue;
+ cp->host_status = hsts;
+ cp->scsi_status = S_ILLEGAL;
+ ncr_complete(np, cp);
+ ++i;
+ }
+ return i;
+}
/*==========================================================
**
+** ncr chip handler for TASKS recovery.
**
-** ncr chip exception handler for programmed interrupts.
+**==========================================================
+**
+** We cannot safely abort a command, while the SCRIPTS
+** processor is running, since we just would be in race
+** with it.
+**
+** As long as we have tasks to abort, we keep the SEM
+** bit set in the ISTAT. When this bit is set, the
+** SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED)
+** each time it enters the scheduler.
+**
+** If we have to reset a target, clear tasks of a unit,
+** or to perform the abort of a disconnected job, we
+** restart the SCRIPTS for selecting the target. Once
+** selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
+** If it loses arbitration, the SCRIPTS will interrupt again
+** the next time it will enter its scheduler, and so on ...
+**
+** On SIR_TARGET_SELECTED, we scan for the more
+** appropriate thing to do:
+**
+** - If nothing, we just sent a M_ABORT message to the
+** target to get rid of the useless SCSI bus ownership.
+** According to the specs, no tasks shall be affected.
+** - If the target is to be reset, we send it a M_RESET
+** message.
+** - If a logical UNIT is to be cleared , we send the
+** IDENTIFY(lun) + M_ABORT.
+** - If an untagged task is to be aborted, we send the
+** IDENTIFY(lun) + M_ABORT.
+** - If a tagged task is to be aborted, we send the
+** IDENTIFY(lun) + task attributes + M_ABORT_TAG.
+**
+** Once our 'kiss of death' :) message has been accepted
+** by the target, the SCRIPTS interrupts again
+** (SIR_ABORT_SENT). On this interrupt, we complete
+** all the CCBs that should have been aborted by the
+** target according to our message.
+**
+**----------------------------------------------------------
+*/
+static void ncr_sir_task_recovery(ncb_p np, int num)
+{
+ ccb_p cp;
+ tcb_p tp;
+ int target=-1, lun=-1, task;
+ int i, k;
+ u_char *p;
+
+ switch(num) {
+ /*
+ ** The SCRIPTS processor stopped before starting
+ ** the next command in order to allow us to perform
+ ** some task recovery.
+ */
+ case SIR_SCRIPT_STOPPED:
+
+ /*
+ ** Do we have any target to reset or unit to clear ?
+ */
+ for (i = 0 ; i < MAX_TARGET ; i++) {
+ tp = &np->target[i];
+ if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) {
+ target = i;
+ break;
+ }
+ if (!tp->lmp)
+ continue;
+ for (k = 1 ; k < MAX_LUN ; k++) {
+ if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+ target = i;
+ break;
+ }
+ }
+ if (target != -1)
+ break;
+ }
+
+ /*
+ ** If not, look at the CCB list for any
+ ** disconnected CCB to be aborted.
+ */
+ if (target == -1) {
+ for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+ if (cp->host_status != HS_DISCONNECT)
+ continue;
+ if (cp->to_abort) {
+ target = cp->target;
+ break;
+ }
+ }
+ }
+
+ /*
+ ** If some target is to be selected,
+ ** prepare and start the selection.
+ */
+ if (target != -1) {
+ tp = &np->target[target];
+ 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_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
+ return;
+ }
+
+ /*
+ ** Nothing is to be selected, so we donnot need
+ ** to synchronize with the SCRIPTS anymore.
+ ** Remove the SEM flag from the ISTAT.
+ */
+ np->istat_sem = 0;
+ OUTB (nc_istat, SIGP);
+
+ /*
+ ** Now look at CCBs to abort that haven't started yet.
+ ** Remove all those CCBs from the start queue and
+ ** complete them with appropriate status.
+ ** Btw, the SCRIPTS processor is still stopped, so
+ ** we are not in race.
+ */
+ for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+ if (cp->host_status != HS_BUSY &&
+ cp->host_status != HS_NEGOTIATE)
+ continue;
+ if (!cp->to_abort)
+ continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ /*
+ ** If we are using IMMEDIATE ARBITRATION, we donnot
+ ** want to cancel the last queued CCB, since the
+ ** SCRIPTS may have anticipated the selection.
+ */
+ if (cp == np->last_cp) {
+ cp->to_abort = 0;
+ continue;
+ }
+#endif
+ /*
+ ** Compute index of next position in the start
+ ** queue the SCRIPTS will schedule.
+ */
+ i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+
+ /*
+ ** Remove the job from the start queue.
+ */
+ k = -1;
+ while (1) {
+ if (i == np->squeueput)
+ break;
+ if (k == -1) { /* Not found yet */
+ if (cp == ncr_ccb_from_dsa(np,
+ scr_to_cpu(np->squeue[i])))
+ k = i; /* Found */
+ }
+ else {
+ /*
+ ** Once found, we have to move
+ ** back all jobs by 1 position.
+ */
+ np->squeue[k] = np->squeue[i];
+ k += 2;
+ if (k >= MAX_START*2)
+ k = 0;
+ }
+
+ i += 2;
+ if (i >= MAX_START*2)
+ i = 0;
+ }
+ assert(k != -1);
+ if (k != 1) {
+ np->squeue[k] = np->squeue[i]; /* Idle task */
+ cp->host_status = HS_ABORTED;
+ cp->scsi_status = S_ILLEGAL;
+ ncr_complete(np, cp);
+ }
+ }
+ break;
+ /*
+ ** The SCRIPTS processor has selected a target
+ ** we may have some manual recovery to perform for.
+ */
+ case SIR_TARGET_SELECTED:
+ target = (INB (nc_sdid) & 0xf);
+ tp = &np->target[target];
+
+ np->abrt_tbl.addr = vtobus(np->abrt_msg);
+
+ /*
+ ** If the target is to be reset, prepare a
+ ** M_RESET message and clear the to_reset flag
+ ** since we donnot expect this operation to fail.
+ */
+ if (tp->to_reset) {
+ np->abrt_msg[0] = M_RESET;
+ np->abrt_tbl.size = 1;
+ tp->to_reset = 0;
+ break;
+ }
+
+ /*
+ ** Otherwise, look for some logical unit to be cleared.
+ */
+ if (tp->l0p && tp->l0p->to_clear)
+ lun = 0;
+ else if (tp->lmp) {
+ for (k = 1 ; k < MAX_LUN ; k++) {
+ if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+ lun = k;
+ break;
+ }
+ }
+ }
+
+ /*
+ ** If a logical unit is to be cleared, prepare
+ ** an IDENTIFY(lun) + ABORT MESSAGE.
+ */
+ if (lun != -1) {
+ lcb_p lp = ncr_lp(np, tp, lun);
+ lp->to_clear = 0; /* We donnot expect to fail here */
+ np->abrt_msg[0] = M_IDENTIFY | lun;
+ np->abrt_msg[1] = M_ABORT;
+ np->abrt_tbl.size = 2;
+ break;
+ }
+
+ /*
+ ** Otherwise, look for some disconnected job to
+ ** abort for this target.
+ */
+ for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+ if (cp->host_status != HS_DISCONNECT)
+ continue;
+ if (cp->target != target)
+ continue;
+ if (cp->to_abort)
+ break;
+ }
+
+ /*
+ ** If we have none, probably since the device has
+ ** completed the command before we won abitration,
+ ** send a M_ABORT message without IDENTIFY.
+ ** According to the specs, the device must just
+ ** disconnect the BUS and not abort any task.
+ */
+ if (!cp) {
+ np->abrt_msg[0] = M_ABORT;
+ np->abrt_tbl.size = 1;
+ break;
+ }
+
+ /*
+ ** We have some task to abort.
+ ** Set the IDENTIFY(lun)
+ */
+ np->abrt_msg[0] = M_IDENTIFY | cp->lun;
+
+ /*
+ ** If we want to abort an untagged command, we
+ ** will send a IDENTIFY + M_ABORT.
+ ** Otherwise (tagged command), we will send
+ ** a IDENTITFY + task attributes + ABORT TAG.
+ */
+ if (cp->tag == NO_TAG) {
+ np->abrt_msg[1] = M_ABORT;
+ np->abrt_tbl.size = 2;
+ }
+ else {
+ np->abrt_msg[1] = cp->scsi_smsg[1];
+ np->abrt_msg[2] = cp->scsi_smsg[2];
+ np->abrt_msg[3] = M_ABORT_TAG;
+ np->abrt_tbl.size = 4;
+ }
+ cp->to_abort = 0; /* We donnot expect to fail here */
+ break;
+
+ /*
+ ** The target has accepted our message and switched
+ ** to BUS FREE phase as we expected.
+ */
+ case SIR_ABORT_SENT:
+ target = (INB (nc_sdid) & 0xf);
+ tp = &np->target[target];
+
+ /*
+ ** If we didn't abort anything, leave here.
+ */
+ if (np->abrt_msg[0] == M_ABORT)
+ break;
+
+ /*
+ ** If we sent a M_RESET, then a hardware reset has
+ ** been performed by the target.
+ ** - Reset everything to async 8 bit
+ ** - Tell ourself to negotiate next time :-)
+ ** - Prepare to clear all disconnected CCBs for
+ ** this target from our task list (lun=task=-1)
+ */
+ lun = -1;
+ task = -1;
+ if (np->abrt_msg[0] == M_RESET) {
+ tp->sval = 0;
+ tp->wval = np->rv_scntl3;
+ ncr_set_sync_wide_status(np, target);
+ ncr_negotiate(np, tp);
+ }
+
+ /*
+ ** Otherwise, check for the LUN and TASK(s)
+ ** concerned by the cancelation.
+ ** If it is not ABORT_TAG then it is CLEAR_QUEUE
+ ** or an ABORT message :-)
+ */
+ else {
+ lun = np->abrt_msg[0] & 0x3f;
+ if (np->abrt_msg[1] == M_ABORT_TAG)
+ task = np->abrt_msg[2];
+ }
+
+ /*
+ ** Complete all the CCBs the device should have
+ ** aborted due to our 'kiss of death' message.
+ */
+ (void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task);
+ break;
+
+ /*
+ ** We have performed a auto-sense that succeeded.
+ ** If the device reports a UNIT ATTENTION condition
+ ** due to a RESET condition, we must complete all
+ ** disconnect CCBs for this unit since the device
+ ** shall have thrown them away.
+ ** Since I haven't time to guess what the specs are
+ ** expecting for other UNIT ATTENTION conditions, I
+ ** decided to only care about RESET conditions. :)
+ */
+ case SIR_AUTO_SENSE_DONE:
+ cp = ncr_ccb_from_dsa(np, INL (nc_dsa));
+ p = &cp->cmd->sense_buffer[0];
+
+ if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
+ break;
+ (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+ break;
+ }
+
+ /*
+ ** Print to the log the message we intend to send.
+ */
+ if (num == SIR_TARGET_SELECTED) {
+ PRINT_TARGET(np, target);
+ ncr_printl_hex("control msgout:", np->abrt_msg,
+ np->abrt_tbl.size);
+ np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
+ }
+
+ /*
+ ** Let the SCRIPTS processor continue.
+ */
+ OUTONB (nc_dcntl, (STD|NOCOM));
+}
+
+
+/*==========================================================
+**
+** Gérard's alchemy:) that deals with with the data
+** pointer for both MDP and the residual calculation.
+**
+**==========================================================
+**
+** I didn't want to bloat the code by more than 200
+** lignes for the handling of both MDP and the residual.
+** This has been achieved by using a data pointer
+** representation consisting in an index in the data
+** array (dp_sg) and a negative offset (dp_ofs) that
+** have the following meaning:
+**
+** - dp_sg = MAX_SCATTER
+** we are at the end of the data script.
+** - dp_sg < MAX_SCATTER
+** dp_sg points to the next entry of the scatter array
+** we want to transfer.
+** - dp_ofs < 0
+** dp_ofs represents the residual of bytes of the
+** previous entry scatter entry we will send first.
+** - dp_ofs = 0
+** no residual to send first.
+**
+** The function ncr_evaluate_dp() accepts an arbitray
+** offset (basically from the MDP message) and returns
+** the corresponding values of dp_sg and dp_ofs.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs)
+{
+ u_int32 dp_scr;
+ int dp_ofs, dp_sg, dp_sgmin;
+ int tmp;
+ struct pm_ctx *pm;
+
+ /*
+ ** Compute the resulted data pointer in term of a script
+ ** address within some DATA script and a signed byte offset.
+ */
+ dp_scr = scr;
+ dp_ofs = *ofs;
+ if (dp_scr == NCB_SCRIPT_PHYS (np, pm0_data))
+ pm = &cp->phys.pm0;
+ else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data))
+ pm = &cp->phys.pm1;
+ else
+ pm = 0;
+
+ if (pm) {
+ dp_scr = pm->ret;
+ dp_ofs -= pm->sg.size;
+ }
+
+ /*
+ ** Deduce the index of the sg entry.
+ ** Keep track of the index of the first valid entry.
+ ** If result is dp_sg = MAX_SCATTER, then we are at the
+ ** end of the data.
+ */
+ tmp = scr_to_cpu(cp->phys.header.goalp);
+ dp_sg = MAX_SCATTER - (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4);
+ dp_sgmin = MAX_SCATTER - cp->segments;
+
+ /*
+ ** Move to the sg entry the data pointer belongs to.
+ **
+ ** If we are inside the data area, we expect result to be:
+ **
+ ** Either,
+ ** dp_ofs = 0 and dp_sg is the index of the sg entry
+ ** the data pointer belongs to (or the end of the data)
+ ** Or,
+ ** dp_ofs < 0 and dp_sg is the index of the sg entry
+ ** the data pointer belongs to + 1.
+ */
+ if (dp_ofs < 0) {
+ int n;
+ while (dp_sg > dp_sgmin) {
+ --dp_sg;
+ tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+ n = dp_ofs + (tmp & 0xffffff);
+ if (n > 0) {
+ ++dp_sg;
+ break;
+ }
+ dp_ofs = n;
+ }
+ }
+ else if (dp_ofs > 0) {
+ while (dp_sg < MAX_SCATTER) {
+ ++dp_sg;
+ tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+ dp_ofs -= (tmp & 0xffffff);
+ if (dp_ofs <= 0)
+ break;
+ }
+ }
+
+ /*
+ ** Make sure the data pointer is inside the data area.
+ ** If not, return some error.
+ */
+ if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
+ goto out_err;
+ else if (dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0))
+ goto out_err;
+
+ /*
+ ** Save the extreme pointer if needed.
+ */
+ if (dp_sg > cp->ext_sg ||
+ (dp_sg == cp->ext_sg && dp_ofs < cp->ext_ofs)) {
+ cp->ext_sg = dp_sg;
+ cp->ext_ofs = dp_ofs;
+ }
+
+ /*
+ ** Return data.
+ */
+ *ofs = dp_ofs;
+ return dp_sg;
+
+out_err:
+ return -1;
+}
+
+/*==========================================================
+**
+** ncr chip handler for MODIFY DATA POINTER MESSAGE
+**
+**==========================================================
+**
+** We also call this function on IGNORE WIDE RESIDUE
+** messages that do not match a SWIDE full condition.
+** Btw, we assume in that situation that such a message
+** is equivalent to a MODIFY DATA POINTER (offset=-1).
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs)
+{
+ int dp_ofs = ofs;
+ u_int32 dp_scr = INL (nc_temp);
+ u_int32 dp_ret;
+ u_char hflags;
+ int dp_sg;
+ struct pm_ctx *pm;
+
+ /*
+ ** Not supported for auto_sense;
+ */
+ if (cp->host_flags & HF_AUTO_SENSE)
+ goto out_reject;
+
+ /*
+ ** Apply our alchemy:) (see comments in ncr_evaluate_dp()),
+ ** to the resulted data pointer.
+ */
+ dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs);
+ if (dp_sg < 0)
+ goto out_reject;
+
+ /*
+ ** And our alchemy:) allows to easily calculate the data
+ ** script address we want to return for the next data phase.
+ */
+ dp_ret = cpu_to_scr(cp->phys.header.goalp);
+ dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4);
+
+ /*
+ ** If offset / scatter entry is zero we donnot need
+ ** a context for the new current data pointer.
+ */
+ if (dp_ofs == 0) {
+ dp_scr = dp_ret;
+ goto out_ok;
+ }
+
+ /*
+ ** Get a context for the new current data pointer.
+ */
+ hflags = INB (HF_PRT);
+
+ if (hflags & HF_DP_SAVED)
+ hflags ^= HF_ACT_PM;
+
+ if (!(hflags & HF_ACT_PM)) {
+ pm = &cp->phys.pm0;
+ dp_scr = NCB_SCRIPT_PHYS (np, pm0_data);
+ }
+ else {
+ pm = &cp->phys.pm1;
+ dp_scr = NCB_SCRIPT_PHYS (np, pm1_data);
+ }
+
+ hflags &= ~(HF_DP_SAVED);
+
+ OUTB (HF_PRT, hflags);
+
+ /*
+ ** Set up the new current data pointer.
+ ** ofs < 0 there, and for the next data phase, we
+ ** want to transfer part of the data of the sg entry
+ ** corresponding to index dp_sg-1 prior to returning
+ ** to the main data script.
+ */
+ pm->ret = cpu_to_scr(dp_ret);
+ pm->sg.addr = cp->phys.data[dp_sg-1].addr + dp_ofs;
+ pm->sg.size = cp->phys.data[dp_sg-1].size - dp_ofs;
+
+out_ok:
+ OUTL (nc_temp, dp_scr);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+ return;
+
+out_reject:
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+}
+
+
+/*==========================================================
**
+** ncr chip calculation of the data residual.
+**
+**==========================================================
+**
+** As I used to say, the requirement of data residual
+** in SCSI is broken, useless and cannot be achieved
+** without huge complexity.
+** But most OSes and even the official CAM require it.
+** When stupidity happens to be so widely spread inside
+** a community, it gets hard to convince.
+**
+** Anyway, I don't care, since I am not going to use
+** any software that considers this data residual as
+** a relevant information. :)
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_compute_residual(ncb_p np, ccb_p cp)
+{
+ int dp_sg, dp_sgmin, resid, tmp;
+ int dp_ofs = 0;
+
+ /*
+ ** Should have been checked by the caller.
+ */
+ if (cp->phys.header.lastp == cp->phys.header.goalp)
+ return 0;
+
+ /*
+ ** If the last data pointer is data_io (direction
+ ** unknown), then no data transfer should have
+ ** taken place.
+ */
+ if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io))
+ return -cp->data_len;
+
+ /*
+ ** If the device asked for more data than available,
+ ** return a positive residual value.
+ */
+ if (cp->phys.extra_bytes)
+ return scr_to_cpu(cp->phys.extra_bytes);
+
+ /*
+ ** Evaluate the pointer saved on message COMPLETE.
+ ** According to our alchemy:), the extreme data
+ ** pointer will also be updated if needed.
+ ** On error, assume no data transferred (this may
+ ** happen if the data direction is unknown).
+ */
+ tmp = cpu_to_scr(cp->phys.header.lastp);
+ if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0)
+ return -cp->data_len;
+
+ /*
+ ** We are now full comfortable in the computation
+ ** of the data residual (2's complement).
+ */
+ dp_sgmin = MAX_SCATTER - cp->segments;
+ resid = cp->ext_ofs;
+ for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) {
+ tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+ resid -= (tmp & 0xffffff);
+ }
+
+ /*
+ ** Hopefully, the result is not too wrong.
+ */
+ return resid;
+}
+
+/*==========================================================
+**
+** Print out the containt of a SCSI message.
**
**==========================================================
*/
@@ -8113,80 +9467,22 @@ static int ncr_show_msg (u_char * msg)
return (1);
}
-
-void ncr_int_sir (ncb_p np)
+static void ncr_print_msg (ccb_p cp, char *label, u_char *msg)
{
- u_char scntl3;
- u_char chg, ofs, per, fak, wide;
- u_char num = INB (nc_dsps);
- ccb_p cp=0;
- u_long dsa = INL (nc_dsa);
- u_char target = INB (nc_sdid) & 0x0f;
- tcb_p tp = &np->target[target];
-
- if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+ if (cp)
+ PRINT_ADDR(cp->cmd);
+ if (label)
+ printk ("%s: ", label);
- switch (num) {
- case SIR_SEL_ATN_NO_MSG_OUT:
- /*
- ** The device didn't go to MSG OUT phase after having
- ** been selected with ATN. We donnot want to handle
- ** that.
- */
- printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
- ncr_name (np), target);
- goto out_stuck;
- case SIR_RESEL_NO_MSG_IN:
- case SIR_RESEL_NO_IDENTIFY:
- /*
- ** If devices reselecting without sending an IDENTIFY
- ** message still exist, this should help.
- ** We just assume lun=0, 1 CCB, no tag.
- */
- if (tp->lp[0]) {
- OUTL (nc_dsa, scr_to_cpu(tp->lp[0]->tasktbl[0]));
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
- return;
- }
- case SIR_RESEL_BAD_LUN:
- np->msgout[0] = M_RESET;
- goto out;
- case SIR_RESEL_BAD_I_T_L:
- np->msgout[0] = M_ABORT;
- goto out;
- case SIR_RESEL_BAD_I_T_L_Q:
- np->msgout[0] = M_ABORT_TAG;
- goto out;
- case SIR_RESEL_ABORTED:
- np->lastmsg = np->msgout[0];
- np->msgout[0] = M_NOOP;
- printk ("%s:%d: message %d sent on bad reselection.\n",
- ncr_name (np), target, np->lastmsg);
- goto out;
- case SIR_MSG_OUT_DONE:
- np->lastmsg = np->msgout[0];
- np->msgout[0] = M_NOOP;
- /* Should we really care of that */
- if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR)
- OUTOFFB (HF_PRT, HF_PAR_ERR);
- goto out;
- case SIR_BAD_STATUS:
- cp = ncr_ccb_from_dsa(np, dsa);
- if (!cp)
- goto out;
- ncr_sir_to_redo(np, num, cp);
- return;
- default:
- /*
- ** lookup the ccb
- */
- cp = ncr_ccb_from_dsa(np, dsa);
- if (!cp)
- goto out;
- }
+ (void) ncr_show_msg (msg);
+ printk (".\n");
+}
- switch (num) {
-/*-----------------------------------------------------------------------------
+/*===================================================================
+**
+** Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
+**
+**===================================================================
**
** Was Sie schon immer ueber transfermode negotiation wissen wollten ...
**
@@ -8199,8 +9495,8 @@ void ncr_int_sir (ncb_p np)
** The host status field is set to HS_NEGOTIATE to mark this
** situation.
**
-** If the target doesn't answer this message immidiately
-** (as required by the standard), the SIR_NEGO_FAIL interrupt
+** If the target doesn't answer this message immediately
+** (as required by the standard), the SIR_NEGO_FAILED interrupt
** will be raised eventually.
** The handler removes the HS_NEGOTIATE status, and sets the
** negotiated value to the default (async / nowide).
@@ -8218,375 +9514,532 @@ void ncr_int_sir (ncb_p np)
**
** If the target doesn't fetch the answer (no message out phase),
** we assume the negotiation has failed, and fall back to default
-** settings.
+** settings (SIR_NEGO_PROTO interrupt).
**
** When we set the values, we adjust them in all ccbs belonging
** to this target, in the controller's register, and in the "phys"
** field of the controller's struct ncb.
**
-** Possible cases: hs sir msg_in value send goto
-** We try to negotiate:
-** -> target doesnt't msgin NEG FAIL noop defa. - dispatch
-** -> target rejected our msg NEG FAIL reject defa. - dispatch
-** -> target answered (ok) NEG SYNC sdtr set - clrack
-** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad
-** -> target answered (ok) NEG WIDE wdtr set - clrack
-** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad
-** -> any other msgin NEG FAIL noop defa. - dispatch
-**
-** Target tries to negotiate:
-** -> incoming message --- SYNC sdtr set SDTR -
-** -> incoming message --- WIDE wdtr set WDTR -
-** We sent our answer:
-** -> target doesn't msgout --- PROTO ? defa. - dispatch
-**
-**-----------------------------------------------------------------------------
+**---------------------------------------------------------------------
*/
- case SIR_NEGO_FAILED:
- /*-------------------------------------------------------
- **
- ** Negotiation failed.
- ** Target doesn't send an answer message,
- ** or target rejected our message.
- **
- ** Remove negotiation request.
- **
- **-------------------------------------------------------
- */
- OUTB (HS_PRT, HS_BUSY);
-
- /* fall through */
-
- case SIR_NEGO_PROTO:
- /*-------------------------------------------------------
- **
- ** Negotiation failed.
- ** Target doesn't fetch the answer message.
- **
- **-------------------------------------------------------
- */
-
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("negotiation failed sir=%x status=%x.\n",
- num, cp->nego_status);
- };
-
- /*
- ** any error in negotiation:
- ** fall back to default mode.
- */
- switch (cp->nego_status) {
-
- case NS_SYNC:
- ncr_setsync (np, cp, 0, 0xe0);
- break;
-
- case NS_WIDE:
- ncr_setwide (np, cp, 0, 0);
- break;
-
- };
- np->msgin [0] = M_NOOP;
- np->msgout[0] = M_NOOP;
- cp->nego_status = 0;
- break;
+/*==========================================================
+**
+** ncr chip handler for SYNCHRONOUS DATA TRANSFER
+** REQUEST (SDTR) message.
+**
+**==========================================================
+**
+** Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+ u_char scntl3;
+ u_char chg, ofs, per, fak;
- case SIR_NEGO_SYNC:
- /*
- ** Synchronous request message received.
- */
+ /*
+ ** Synchronous request message received.
+ */
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("sync msgin: ");
- (void) ncr_show_msg (np->msgin);
- printk (".\n");
- };
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "sync msg in", np->msgin);
+ };
- /*
- ** get requested values.
- */
+ /*
+ ** get requested values.
+ */
- chg = 0;
- per = np->msgin[3];
- ofs = np->msgin[4];
- if (ofs==0) per=255;
+ chg = 0;
+ per = np->msgin[3];
+ ofs = np->msgin[4];
+ if (ofs==0) per=255;
- /*
- ** if target sends SDTR message,
- ** it CAN transfer synch.
- */
+ /*
+ ** if target sends SDTR message,
+ ** it CAN transfer synch.
+ */
- if (ofs)
- tp->inq_byte7 |= INQ7_SYNC;
+ if (ofs)
+ tp->inq_byte7 |= INQ7_SYNC;
- /*
- ** check values against driver limits.
- */
+ /*
+ ** check values against driver limits.
+ */
- if (per < np->minsync)
- {chg = 1; per = np->minsync;}
- if (per < tp->minsync)
- {chg = 1; per = tp->minsync;}
- if (ofs > tp->maxoffs)
- {chg = 1; ofs = tp->maxoffs;}
+ if (per < np->minsync)
+ {chg = 1; per = np->minsync;}
+ if (per < tp->minsync)
+ {chg = 1; per = tp->minsync;}
+ if (ofs > tp->maxoffs)
+ {chg = 1; ofs = tp->maxoffs;}
- /*
- ** Check against controller limits.
- */
+ /*
+ ** Check against controller limits.
+ */
+ fak = 7;
+ scntl3 = 0;
+ if (ofs != 0) {
+ ncr_getsync(np, per, &fak, &scntl3);
+ if (fak > 7) {
+ chg = 1;
+ ofs = 0;
+ }
+ }
+ if (ofs == 0) {
fak = 7;
+ per = 0;
scntl3 = 0;
- if (ofs != 0) {
- ncr_getsync(np, per, &fak, &scntl3);
- if (fak > 7) {
- chg = 1;
- ofs = 0;
- }
- }
- if (ofs == 0) {
- fak = 7;
- per = 0;
- scntl3 = 0;
- tp->minsync = 0;
- }
-
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
- per, scntl3, ofs, fak, chg);
- }
+ tp->minsync = 0;
+ }
- if (INB (HS_PRT) == HS_NEGOTIATE) {
- OUTB (HS_PRT, HS_BUSY);
- switch (cp->nego_status) {
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->cmd);
+ printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+ per, scntl3, ofs, fak, chg);
+ }
- case NS_SYNC:
+ if (INB (HS_PRT) == HS_NEGOTIATE) {
+ OUTB (HS_PRT, HS_BUSY);
+ switch (cp->nego_status) {
+ case NS_SYNC:
+ /*
+ ** This was an answer message
+ */
+ if (chg) {
/*
- ** This was an answer message
+ ** Answer wasn't acceptable.
*/
- if (chg) {
- /*
- ** Answer wasn't acceptable.
- */
- ncr_setsync (np, cp, 0, 0xe0);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
- } else {
- /*
- ** Answer is ok.
- */
- ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
- };
- return;
-
- case NS_WIDE:
- ncr_setwide (np, cp, 0, 0);
- break;
+ ncr_setsync (np, cp, 0, 0xe0);
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ } else {
+ /*
+ ** Answer is ok.
+ */
+ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
};
+ return;
+
+ case NS_WIDE:
+ ncr_setwide (np, cp, 0, 0);
+ break;
};
+ };
- /*
- ** It was a request. Set value and
- ** prepare an answer message
- */
+ /*
+ ** It was a request. Set value and
+ ** prepare an answer message
+ */
- ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+ ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
- np->msgout[0] = M_EXTENDED;
- np->msgout[1] = 3;
- np->msgout[2] = M_X_SYNC_REQ;
- np->msgout[3] = per;
- np->msgout[4] = ofs;
+ np->msgout[0] = M_EXTENDED;
+ np->msgout[1] = 3;
+ np->msgout[2] = M_X_SYNC_REQ;
+ np->msgout[3] = per;
+ np->msgout[4] = ofs;
- cp->nego_status = NS_SYNC;
+ cp->nego_status = NS_SYNC;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("sync msgout: ");
- (void) ncr_show_msg (np->msgout);
- printk (".\n");
- }
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "sync msgout", np->msgout);
+ }
- if (!ofs) {
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
- return;
- }
- np->msgin [0] = M_NOOP;
+ np->msgin [0] = M_NOOP;
- break;
+ if (!ofs)
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ else
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp));
+}
- case SIR_NEGO_WIDE:
- /*
- ** Wide request message received.
- */
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("wide msgin: ");
- (void) ncr_show_msg (np->msgin);
- printk (".\n");
- };
+/*==========================================================
+**
+** ncr chip handler for WIDE DATA TRANSFER REQUEST
+** (WDTR) message.
+**
+**==========================================================
+**
+** Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+ u_char chg, wide;
- /*
- ** get requested values.
- */
+ /*
+ ** Wide request message received.
+ */
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "wide msgin", np->msgin);
+ };
- chg = 0;
- wide = np->msgin[3];
+ /*
+ ** get requested values.
+ */
- /*
- ** if target sends WDTR message,
- ** it CAN transfer wide.
- */
+ chg = 0;
+ wide = np->msgin[3];
- if (wide)
- tp->inq_byte7 |= INQ7_WIDE16;
+ /*
+ ** if target sends WDTR message,
+ ** it CAN transfer wide.
+ */
- /*
- ** check values against driver limits.
- */
+ if (wide)
+ tp->inq_byte7 |= INQ7_WIDE16;
- if (wide > tp->usrwide)
- {chg = 1; wide = tp->usrwide;}
+ /*
+ ** check values against driver limits.
+ */
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("wide: wide=%d chg=%d.\n", wide, chg);
- }
+ if (wide > tp->usrwide)
+ {chg = 1; wide = tp->usrwide;}
- if (INB (HS_PRT) == HS_NEGOTIATE) {
- OUTB (HS_PRT, HS_BUSY);
- switch (cp->nego_status) {
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ PRINT_ADDR(cp->cmd);
+ printk ("wide: wide=%d chg=%d.\n", wide, chg);
+ }
- case NS_WIDE:
+ if (INB (HS_PRT) == HS_NEGOTIATE) {
+ OUTB (HS_PRT, HS_BUSY);
+ switch (cp->nego_status) {
+ case NS_WIDE:
+ /*
+ ** This was an answer message
+ */
+ if (chg) {
/*
- ** This was an answer message
+ ** Answer wasn't acceptable.
*/
- if (chg) {
- /*
- ** Answer wasn't acceptable.
- */
- ncr_setwide (np, cp, 0, 1);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
- } else {
- /*
- ** Answer is ok.
- */
- ncr_setwide (np, cp, wide, 1);
- OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
- };
- return;
-
- case NS_SYNC:
- ncr_setsync (np, cp, 0, 0xe0);
- break;
+ ncr_setwide (np, cp, 0, 1);
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ } else {
+ /*
+ ** Answer is ok.
+ */
+ ncr_setwide (np, cp, wide, 1);
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
};
+ return;
+
+ case NS_SYNC:
+ ncr_setsync (np, cp, 0, 0xe0);
+ break;
};
+ };
- /*
- ** It was a request, set value and
- ** prepare an answer message
- */
+ /*
+ ** It was a request, set value and
+ ** prepare an answer message
+ */
- ncr_setwide (np, cp, wide, 1);
+ ncr_setwide (np, cp, wide, 1);
- np->msgout[0] = M_EXTENDED;
- np->msgout[1] = 2;
- np->msgout[2] = M_X_WIDE_REQ;
- np->msgout[3] = wide;
+ np->msgout[0] = M_EXTENDED;
+ np->msgout[1] = 2;
+ np->msgout[2] = M_X_WIDE_REQ;
+ np->msgout[3] = wide;
- np->msgin [0] = M_NOOP;
+ np->msgin [0] = M_NOOP;
- cp->nego_status = NS_WIDE;
+ cp->nego_status = NS_WIDE;
- if (DEBUG_FLAGS & DEBUG_NEGO) {
- PRINT_ADDR(cp->cmd);
- printk ("wide msgout: ");
- (void) ncr_show_msg (np->msgin);
- printk (".\n");
- }
- break;
+ if (DEBUG_FLAGS & DEBUG_NEGO) {
+ ncr_print_msg(cp, "wide msgout", np->msgout);
+ }
-/*--------------------------------------------------------------------
-**
-** Processing of special messages
-**
-**--------------------------------------------------------------------
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
+}
+
+/*
+** Reset SYNC or WIDE to default settings.
+** Called when a negotiation does not succeed either
+** on rejection or on protocol error.
*/
+static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp)
+{
+ /*
+ ** any error in negotiation:
+ ** fall back to default mode.
+ */
+ switch (cp->nego_status) {
- case SIR_REJECT_RECEIVED:
- /*-----------------------------------------------
- **
- ** We received a M_REJECT message.
- **
- **-----------------------------------------------
- */
+ case NS_SYNC:
+ ncr_setsync (np, cp, 0, 0xe0);
+ break;
- PRINT_ADDR(cp->cmd);
- printk ("M_REJECT received (%x:%x).\n",
- (unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
+ case NS_WIDE:
+ ncr_setwide (np, cp, 0, 0);
break;
- case SIR_REJECT_TO_SEND:
- /*-----------------------------------------------
- **
- ** We received an unknown message
- **
- **-----------------------------------------------
- */
+ };
+ np->msgin [0] = M_NOOP;
+ np->msgout[0] = M_NOOP;
+ cp->nego_status = 0;
+}
+
+/*==========================================================
+**
+** ncr chip handler for MESSAGE REJECT received for
+** a WIDE or SYNCHRONOUS negotiation.
+**
+**==========================================================
+**
+** Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp)
+{
+ ncr_nego_default(np, tp, cp);
+ OUTB (HS_PRT, HS_BUSY);
+}
- PRINT_ADDR(cp->cmd);
- printk ("M_REJECT to send for ");
- (void) ncr_show_msg (np->msgin);
- printk (".\n");
- np->msgout[0] = M_REJECT;
- break;
-/*--------------------------------------------------------------------
+/*==========================================================
+**
**
-** Processing of special messages
+** ncr chip exception handler for programmed interrupts.
**
-**--------------------------------------------------------------------
+**
+**==========================================================
*/
- case SIR_IGN_RESIDUE:
- /*-----------------------------------------------
- **
- ** We received an IGNORE RESIDUE message,
- ** which couldn't be handled by the script.
- **
- **-----------------------------------------------
- */
+void ncr_int_sir (ncb_p np)
+{
+ u_char num = INB (nc_dsps);
+ u_long dsa = INL (nc_dsa);
+ ccb_p cp = ncr_ccb_from_dsa(np, dsa);
+ u_char target = INB (nc_sdid) & 0x0f;
+ tcb_p tp = &np->target[target];
+ int tmp;
- PRINT_ADDR(cp->cmd);
- printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
- break;
-#if 0
- case SIR_MISSING_SAVE:
- /*-----------------------------------------------
- **
- ** We received an DISCONNECT message,
- ** but the datapointer wasn't saved before.
- **
- **-----------------------------------------------
- */
+ if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
- PRINT_ADDR(cp->cmd);
- printk ("M_DISCONNECT received, but datapointer not saved: "
- "data=%x save=%x goal=%x.\n",
- (unsigned) INL (nc_temp),
- (unsigned) scr_to_cpu(np->header.savep),
- (unsigned) scr_to_cpu(np->header.goalp));
- break;
+ switch (num) {
+ /*
+ ** See comments in the SCRIPTS code.
+ */
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+ case SIR_DUMMY_INTERRUPT:
+ goto out;
#endif
+ /*
+ ** The C code is currently trying to recover from something.
+ ** Typically, user want to abort some command.
+ */
+ case SIR_SCRIPT_STOPPED:
+ case SIR_TARGET_SELECTED:
+ case SIR_ABORT_SENT:
+ ncr_sir_task_recovery(np, num);
+ return;
+ /*
+ ** The device didn't go to MSG OUT phase after having
+ ** been selected with ATN. We donnot want to handle
+ ** that.
+ */
+ case SIR_SEL_ATN_NO_MSG_OUT:
+ printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
+ ncr_name (np), target);
+ goto out_stuck;
+ /*
+ ** The device didn't switch to MSG IN phase after
+ ** having reseleted the initiator.
+ */
+ case SIR_RESEL_NO_MSG_IN:
+ /*
+ ** After reselection, the device sent a message that wasn't
+ ** an IDENTIFY.
+ */
+ case SIR_RESEL_NO_IDENTIFY:
+ /*
+ ** If devices reselecting without sending an IDENTIFY
+ ** message still exist, this should help.
+ ** We just assume lun=0, 1 CCB, no tag.
+ */
+ if (tp->l0p) {
+ OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+ return;
+ }
+ /*
+ ** The device reselected a LUN we donnot know of.
+ */
+ case SIR_RESEL_BAD_LUN:
+ np->msgout[0] = M_RESET;
+ goto out;
+ /*
+ ** The device reselected for an untagged nexus and we
+ ** haven't any.
+ */
+ case SIR_RESEL_BAD_I_T_L:
+ np->msgout[0] = M_ABORT;
+ goto out;
+ /*
+ ** The device reselected for a tagged nexus that we donnot
+ ** have.
+ */
+ case SIR_RESEL_BAD_I_T_L_Q:
+ np->msgout[0] = M_ABORT_TAG;
+ goto out;
+ /*
+ ** The SCRIPTS let us know that the device has grabbed
+ ** our message and will abort the job.
+ */
+ case SIR_RESEL_ABORTED:
+ np->lastmsg = np->msgout[0];
+ np->msgout[0] = M_NOOP;
+ printk ("%s:%d: message %x sent on bad reselection.\n",
+ ncr_name (np), target, np->lastmsg);
+ goto out;
+ /*
+ ** The SCRIPTS let us know that a message has been
+ ** successfully sent to the device.
+ */
+ case SIR_MSG_OUT_DONE:
+ np->lastmsg = np->msgout[0];
+ np->msgout[0] = M_NOOP;
+ /* Should we really care of that */
+ if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
+ if (cp)
+ cp->xerr_status &= ~XE_PARITY_ERR;
+ }
+ goto out;
+ /*
+ ** The device didn't send a GOOD SCSI status.
+ ** We may have some work to do prior to allow
+ ** the SCRIPTS processor to continue.
+ */
+ case SIR_BAD_STATUS:
+ if (!cp)
+ goto out;
+ ncr_sir_to_redo(np, num, cp);
+ return;
+ /*
+ ** We are asked by the SCRIPTS to prepare a
+ ** REJECT message.
+ */
+ case SIR_REJECT_TO_SEND:
+ ncr_print_msg(cp, "M_REJECT to send for ", np->msgin);
+ np->msgout[0] = M_REJECT;
+ goto out;
+ /*
+ ** We have been ODD at the end of a DATA IN
+ ** transfer and the device didn't send a
+ ** IGNORE WIDE RESIDUE message.
+ ** It is a data overrun condition.
+ */
+ case SIR_SWIDE_OVERRUN:
+ if (cp)
+ cp->xerr_status |= XE_EXTRA_DATA;
+ goto out;
+ /*
+ ** We have been ODD at the end of a DATA OUT
+ ** transfer.
+ ** It is a data underrun condition.
+ */
+ case SIR_SODL_UNDERRUN:
+ if (cp)
+ cp->xerr_status |= XE_EXTRA_DATA;
+ goto out;
+ /*
+ ** We received a message.
+ */
+ case SIR_MSG_RECEIVED:
+ if (!cp)
+ goto out_stuck;
+ switch (np->msgin [0]) {
+ /*
+ ** We received an extended message.
+ ** We handle MODIFY DATA POINTER, SDTR, WDTR
+ ** and reject all other extended messages.
+ */
+ case M_EXTENDED:
+ switch (np->msgin [2]) {
+ case M_X_MODIFY_DP:
+ if (DEBUG_FLAGS & DEBUG_POINTER)
+ ncr_print_msg(cp,"modify DP",np->msgin);
+ tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) +
+ (np->msgin[5]<<8) + (np->msgin[6]);
+ ncr_modify_dp(np, tp, cp, tmp);
+ return;
+ case M_X_SYNC_REQ:
+ ncr_sync_nego(np, tp, cp);
+ return;
+ case M_X_WIDE_REQ:
+ ncr_wide_nego(np, tp, cp);
+ return;
+ default:
+ goto out_reject;
+ }
+ break;
+ /*
+ ** We received a 1/2 byte message not handled from SCRIPTS.
+ ** We are only expecting MESSAGE REJECT and IGNORE WIDE
+ ** RESIDUE messages that haven't been anticipated by
+ ** SCRIPTS on SWIDE full condition. Unanticipated IGNORE
+ ** WIDE RESIDUE messages are aliased as MODIFY DP (-1).
+ */
+ case M_IGN_RESIDUE:
+ if (DEBUG_FLAGS & DEBUG_POINTER)
+ ncr_print_msg(cp,"ign wide residue", np->msgin);
+ ncr_modify_dp(np, tp, cp, -1);
+ return;
+ case M_REJECT:
+ if (INB (HS_PRT) == HS_NEGOTIATE)
+ ncr_nego_rejected(np, tp, cp);
+ else {
+ PRINT_ADDR(cp->cmd);
+ printk ("M_REJECT received (%x:%x).\n",
+ scr_to_cpu(np->lastmsg), np->msgout[0]);
+ }
+ goto out_clrack;
+ break;
+ default:
+ goto out_reject;
+ }
+ break;
+ /*
+ ** We received an unknown message.
+ ** Ignore all MSG IN phases and reject it.
+ */
+ case SIR_MSG_WEIRD:
+ ncr_print_msg(cp, "WEIRD message received", np->msgin);
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird));
+ return;
+ /*
+ ** Negotiation failed.
+ ** Target does not send us the reply.
+ ** Remove the HS_NEGOTIATE status.
+ */
+ case SIR_NEGO_FAILED:
+ OUTB (HS_PRT, HS_BUSY);
+ /*
+ ** Negotiation failed.
+ ** Target does not want answer message.
+ */
+ case SIR_NEGO_PROTO:
+ ncr_nego_default(np, tp, cp);
+ goto out;
};
out:
OUTONB (nc_dcntl, (STD|NOCOM));
+ return;
+out_reject:
+ OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+ return;
+out_clrack:
+ OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+ return;
out_stuck:
}
+
/*==========================================================
**
**
@@ -8599,8 +10052,8 @@ out_stuck:
static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
{
tcb_p tp = &np->target[tn];
- lcb_p lp = tp->lp[ln];
- u_char tag = NO_TAG;
+ lcb_p lp = ncr_lp(np, tp, ln);
+ u_short tag = NO_TAG;
XPT_QUEHEAD *qp;
ccb_p cp = (ccb_p) 0;
@@ -8644,9 +10097,10 @@ static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
if (lp->busyccbs < lp->maxnxs) {
tag = lp->cb_tags[lp->ia_tag];
++lp->ia_tag;
- if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+ if (lp->ia_tag == MAX_TAGS)
lp->ia_tag = 0;
- lp->tags_umap |= (((tagmap_t) 1) << tag);
+ cp->tags_si = lp->tags_si;
+ ++lp->tags_sum[cp->tags_si];
}
else
goto out_free;
@@ -8663,6 +10117,7 @@ static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
/*
** Remember all informations needed to free this CCB.
*/
+ cp->to_abort = 0;
cp->tag = tag;
cp->target = tn;
cp->lun = ln;
@@ -8691,7 +10146,7 @@ out_free:
static void ncr_free_ccb (ncb_p np, ccb_p cp)
{
tcb_p tp = &np->target[cp->target];
- lcb_p lp = tp->lp[cp->lun];
+ lcb_p lp = ncr_lp(np, tp, cp->lun);
if (DEBUG_FLAGS & DEBUG_TAGS) {
PRINT_LUN(np, cp->target, cp->lun);
@@ -8706,10 +10161,9 @@ static void ncr_free_ccb (ncb_p np, ccb_p cp)
if (lp) {
if (cp->tag != NO_TAG) {
lp->cb_tags[lp->if_tag++] = cp->tag;
- if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+ if (lp->if_tag == MAX_TAGS)
lp->if_tag = 0;
- lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
- lp->tags_smap &= lp->tags_umap;
+ --lp->tags_sum[cp->tags_si];
lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q);
} else {
lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l);
@@ -8770,6 +10224,11 @@ static ccb_p ncr_alloc_ccb(ncb_p np)
cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l));
/*
+ ** Initilialyze some other fields.
+ */
+ cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
+
+ /*
** Chain into wakeup list and free ccb queue.
*/
cp->link_ccb = np->ccbc;
@@ -8820,25 +10279,6 @@ static ccb_p ncr_ccb_from_dsa(ncb_p np, u_long dsa)
*/
static void ncr_init_tcb (ncb_p np, u_char tn)
{
- tcb_p tp = &np->target[tn];
-
- /*
- ** Already bone.
- */
- if (tp->luntbl)
- return;
- /*
- ** Allocate the lcb bus address array.
- */
- tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
- if (!tp->luntbl)
- return;
-
- /*
- ** Compute the bus address of this table.
- */
- tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
-
/*
** Check some alignments required by the chip.
*/
@@ -8858,7 +10298,7 @@ static void ncr_init_tcb (ncb_p np, u_char tn)
static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
{
tcb_p tp = &np->target[tn];
- lcb_p lp = tp->lp[ln];
+ lcb_p lp = ncr_lp(np, tp, ln);
/*
** Already done, return.
@@ -8870,21 +10310,46 @@ static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
** Initialize the target control block if not yet.
*/
ncr_init_tcb(np, tn);
- if (!tp->luntbl)
- goto fail;
/*
- ** Allocate the lcb.
+ ** Allocate the lcb bus address array.
+ ** Compute the bus address of this table.
*/
- lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
- if (!lp)
- goto fail;
- tp->lp[ln] = lp;
+ if (ln && !tp->luntbl) {
+ int i;
+
+ tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
+ if (!tp->luntbl)
+ goto fail;
+ for (i = 0 ; i < 64 ; i++)
+ tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+ tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
+ }
+
+ /*
+ ** 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);
+ if (!tp->lmp)
+ goto fail;
+ }
/*
+ ** Allocate the lcb.
** Make it available to the chip.
*/
- tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+ lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
+ if (!lp)
+ goto fail;
+ if (ln) {
+ tp->lmp[ln] = lp;
+ tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+ }
+ else {
+ tp->l0p = lp;
+ tp->b_lun0 = cpu_to_scr(vtobus(lp));
+ }
/*
** Initialize the CCB queue headers.
@@ -8924,7 +10389,7 @@ fail:
static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
{
tcb_p tp = &np->target[tn];
- lcb_p lp = tp->lp[ln];
+ lcb_p lp = ncr_lp(np, tp, ln);
u_char inq_byte7;
int i;
@@ -8934,14 +10399,16 @@ static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
goto fail;
+#if 0 /* No more used. Left here as provision */
/*
- ** Get device quirks from a speciality table.
+ ** Get device quirks.
*/
- tp->quirks = ncr_lookup (inq_data);
+ tp->quirks = 0;
if (tp->quirks && bootverbose) {
PRINT_LUN(np, tn, ln);
printk ("quirks=%x.\n", tp->quirks);
}
+#endif
/*
** Evaluate trustable target/unit capabilities.
@@ -8984,18 +10451,23 @@ 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(256, "TASKTBL", MEMO_WARN);
+ lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN);
if (!lp->tasktbl) {
lp->tasktbl = &lp->tasktbl_0;
goto fail;
}
lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl));
- for (i = 0 ; i < 64 ; i++)
+ for (i = 0 ; i < MAX_TASKS ; i++)
lp->tasktbl[i] = cpu_to_scr(np->p_notask);
- for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+
+ lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN);
+ if (!lp->cb_tags)
+ goto fail;
+ for (i = 0 ; i < MAX_TAGS ; i++)
lp->cb_tags[i] = i;
- lp->maxnxs = SCSI_NCR_MAX_TAGS;
- lp->tags_stime = jiffies;
+
+ lp->maxnxs = MAX_TAGS;
+ lp->tags_stime = ktime_get(3*HZ);
}
/*
@@ -9043,7 +10515,7 @@ fail:
/*
** For 64 bit systems, we use the 8 upper bits of the size field
** to provide bus address bits 32-39 to the SCRIPTS processor.
-** This allows the 896 to access up to 1 tera-bytes of memory.
+** This allows the 895A and 896 to address up to 1 TB of memory.
** For 32 bit chips on 64 bit systems, we must be provided with
** memory addresses that fit into the first 32 bit bus address
** range and so, this does not matter and we expect an error from
@@ -9325,62 +10797,6 @@ static void ncb_profile (ncb_p np, ccb_p cp)
/*==========================================================
**
-**
-** Device lookup.
-**
-** @GENSCSI@ should be integrated to scsiconf.c
-**
-**
-**==========================================================
-*/
-
-struct table_entry {
- char * manufacturer;
- char * model;
- char * version;
- u_long info;
-};
-
-static struct table_entry device_tab[] =
-{
-#if 0
- {"", "", "", QUIRK_NOMSG},
-#endif
- {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
- {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
- {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
- {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
- {"", "", "", 0} /* catch all: must be last entry. */
-};
-
-static u_long ncr_lookup(char * id)
-{
- struct table_entry * p = device_tab;
- char *d, *r, c;
-
- for (;;p++) {
-
- d = id+8;
- r = p->manufacturer;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- d = id+16;
- r = p->model;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- d = id+32;
- r = p->version;
- while ((c=*r++)) if (c!=*d++) break;
- if (c) continue;
-
- return (p->info);
- }
-}
-
-/*==========================================================
-**
** Determine the ncr's clock frequency.
** This is essential for the negotiation
** of the synchronous transfer rate.
@@ -9395,7 +10811,7 @@ static u_long ncr_lookup(char * id)
** do not have a clock doubler and so are provided with a
** 80 MHz clock. All other fast20 boards incorporate a doubler
** and so should be delivered with a 40 MHz clock.
-** The recent fast40 chips (895/896) use a 40 Mhz base clock
+** The recent fast40 chips (895/896/895A) use a 40 Mhz base clock
** and provide a clock quadrupler (160 Mhz). The code below
** tries to deal as cleverly as possible with all this stuff.
**
@@ -9436,7 +10852,8 @@ static void ncr_selectclock(ncb_p np, u_char scntl3)
*/
static unsigned __init ncrgetfreq (ncb_p np, int gen)
{
- unsigned ms = 0;
+ unsigned int ms = 0;
+ unsigned int f;
/*
* Measure GEN timer delay in order
@@ -9453,7 +10870,6 @@ static unsigned __init ncrgetfreq (ncb_p np, int gen)
* performed trust the higher delay
* (lower frequency returned).
*/
- OUTB (nc_stest1, 0); /* make sure clock doubler is OFF */
OUTW (nc_sien , 0); /* mask all scsi interrupts */
(void) INW (nc_sist); /* clear pending scsi interrupt */
OUTB (nc_dien , 0); /* mask all dma interrupts */
@@ -9471,12 +10887,28 @@ static unsigned __init ncrgetfreq (ncb_p np, int gen)
*/
OUTB (nc_scntl3, 0);
- if (bootverbose >= 2)
- printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
/*
* adjust for prescaler, and convert into KHz
*/
- return ms ? ((1 << gen) * 4340) / ms : 0;
+ f = ms ? ((1 << gen) * 4340) / ms : 0;
+
+ if (bootverbose >= 2)
+ printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
+ ncr_name(np), gen, ms, f);
+
+ return f;
+}
+
+static unsigned __init ncr_getfreq (ncb_p np)
+{
+ u_int f1, f2;
+ int gen = 11;
+
+ (void) ncrgetfreq (np, gen); /* throw away first result */
+ f1 = ncrgetfreq (np, gen);
+ f2 = ncrgetfreq (np, gen);
+ if (f1 > f2) f1 = f2; /* trust lower result */
+ return f1;
}
/*
@@ -9492,7 +10924,7 @@ static void __init ncr_getclock (ncb_p np, int mult)
f1 = 40000;
/*
- ** True with 875/895/896 with clock multiplier selected
+ ** True with 875/895/896/895A with clock multiplier selected
*/
if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
if (bootverbose >= 2)
@@ -9506,16 +10938,11 @@ static void __init ncr_getclock (ncb_p np, int mult)
** Otherwise trust scntl3 BIOS setting.
*/
if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
- unsigned f2;
-
- (void) ncrgetfreq (np, 11); /* throw away first result */
- f1 = ncrgetfreq (np, 11);
- f2 = ncrgetfreq (np, 11);
+ OUTB (nc_stest1, 0); /* make sure doubler is OFF */
+ f1 = ncr_getfreq (np);
if (bootverbose)
- printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
-
- if (f1 > f2) f1 = f2; /* trust lower result */
+ printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1);
if (f1 < 45000) f1 = 40000;
else if (f1 < 55000) f1 = 50000;
@@ -9541,6 +10968,21 @@ static void __init ncr_getclock (ncb_p np, int mult)
np->clock_khz = f1;
}
+/*
+ * Get/probe PCI clock frequency
+ */
+static u_int __init ncr_getpciclock (ncb_p np)
+{
+ static u_int f = 0;
+
+ if (!f) {
+ OUTB (nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */
+ f = ncr_getfreq (np);
+ OUTB (nc_stest1, 0);
+ }
+ return f;
+}
+
/*===================== LINUX ENTRY POINTS SECTION ==========================*/
#ifndef uchar
@@ -9592,6 +11034,11 @@ static void __init ncr_getclock (ncb_p np, int mult)
#define OPT_SAFE_SETUP 22
#define OPT_USE_NVRAM 23
#define OPT_EXCLUDE 24
+#define OPT_HOST_ID 25
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB 26
+#endif
static char setup_token[] __initdata =
"tags:" "mpar:"
@@ -9606,7 +11053,11 @@ static char setup_token[] __initdata =
"buschk:" "optim:"
"recovery:"
"safe:" "nvram:"
- "excl:";
+ "excl:" "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+ "iarb:"
+#endif
+ ; /* DONNOT REMOVE THIS ';' */
#ifdef MODULE
#define ARG_SEP ' '
@@ -9631,7 +11082,7 @@ static int __init get_setup_token(char *p)
}
-void __init sym53c8xx_setup(char *str, int *ints)
+int __init sym53c8xx_setup(char *str)
{
#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
char *cur = str;
@@ -9736,6 +11187,14 @@ void __init sym53c8xx_setup(char *str, int *ints)
if (xi < SCSI_NCR_MAX_EXCLUDES)
driver_setup.excludes[xi++] = val;
break;
+ case OPT_HOST_ID:
+ driver_setup.host_id = val;
+ break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+ case OPT_IARB:
+ driver_setup.iarb = val;
+ break;
+#endif
default:
printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
break;
@@ -9745,8 +11204,15 @@ void __init sym53c8xx_setup(char *str, int *ints)
++cur;
}
#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+ return 0;
}
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sym53c8xx=", sym53c8xx_setup);
+#endif
+#endif
+
static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
uchar bus, uchar device_fn, ncr_device *device);
@@ -9893,7 +11359,7 @@ int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
#if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
if (sym53c8xx)
- sym53c8xx_setup(sym53c8xx, (int *) 0);
+ sym53c8xx_setup(sym53c8xx);
#endif
#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
ncr_debug = driver_setup.debug;
@@ -9945,8 +11411,16 @@ if (sym53c8xx)
continue;
}
++index;
+ /* Some HW as the HP LH4 may report twice PCI devices */
+ for (i = 0; i < count ; i++) {
+ if (devtbl[i].slot.bus == bus &&
+ devtbl[i].slot.device_fn == device_fn)
+ break;
+ }
+ if (i != count) /* Ignore this device if we already have it */
+ continue;
devp = &devtbl[count];
- devp->host_id = 255;
+ devp->host_id = driver_setup.host_id;
devp->attach_done = 0;
if (sym53c8xx_pci_init(tpnt, bus, device_fn, devp)) {
continue;
@@ -10050,7 +11524,7 @@ next:
**===================================================================
*/
#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-static int __init
+static int __init
pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
{
u_int32 tmp;
@@ -10067,18 +11541,27 @@ pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
}
return offset;
}
-#else /* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-static int __init
+#elif LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init
pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
{
- /* FIXME! This is just unbelieably horrible backwards compatibility code */
- struct resource *res = pdev->resource + index;
-
- *base = res->start | (res->flags & 0xf);
- if ((res->flags & 0x7) == 0x4) {
+ *base = pdev->base_address[index++];
+ if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+ *base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
++index;
}
- return index+1;
+ return index;
+}
+#else /* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
+static int __init
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+ *base = pdev->resource[index].start;
+ if ((pdev->resource[index].flags & 0x7) == 0x4)
+ ++index;
+ return ++index;
}
#endif
@@ -10094,6 +11577,7 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
u_short vendor_id, device_id, command;
u_char cache_line_size, latency_timer;
u_char suggested_cache_line_size = 0;
+ u_char pci_fix_up;
u_char revision;
#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
struct pci_dev *pdev;
@@ -10173,18 +11657,18 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
if (revision > ncr_chip_table[i].revision_id)
continue;
if (!(ncr_chip_table[i].features & FE_LDSTR))
- continue;
+ break;
chip = &device->chip;
memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
chip->revision_id = revision;
break;
}
-#if defined(__i386__)
/*
** Ignore Symbios chips controlled by SISL RAID controller.
** This controller sets value 0x52414944 at RAM end - 16.
*/
+#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
unsigned int ram_size, ram_val;
u_long ram_ptr;
@@ -10206,7 +11690,7 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
}
}
}
-#endif
+#endif /* i386 and PCI MEMORY accessible */
if (!chip) {
printk(NAME53C8XX ": not initializing, device not supported\n");
@@ -10267,6 +11751,9 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
** coherent with hardware and software resource identifications.
** This is fairly simple, but seems still too complex for Sparc.
*/
+ base = __pa(base);
+ base_2 = __pa(base_2);
+
if (!cache_line_size)
suggested_cache_line_size = 16;
@@ -10290,9 +11777,16 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
/*
** Check availability of IO space, memory space.
** Enable master capability if not yet.
+ **
+ ** We shouldn't have to care about the IO region when
+ ** we are using MMIO. But calling check_region() from
+ ** both the ncr53c8xx and the sym53c8xx drivers prevents
+ ** from attaching devices from the both drivers.
+ ** If you have a better idea, let me know.
*/
-#ifdef NCR_IOMAPPED
- if (!(command & PCI_COMMAND_IO) || !(io_port & 1)) {
+/* #ifdef NCR_IOMAPPED */
+#if 1
+ if (!(command & PCI_COMMAND_IO)) {
printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
(long) io_port);
io_port = 0;
@@ -10307,7 +11801,8 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
base &= PCI_BASE_ADDRESS_MEM_MASK;
base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef NCR_IOMAPPED
+/* #ifdef NCR_IOMAPPED */
+#if 1
if (io_port && check_region (io_port, 128)) {
printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
(long) io_port);
@@ -10315,7 +11810,8 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
}
if (!io_port)
return -1;
-#else
+#endif
+#ifndef NCR_IOMAPPED
if (!base) {
printk(NAME53C8XX ": MMIO base address disabled.\n");
return -1;
@@ -10354,11 +11850,24 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
if (!driver_setup.max_wide)
chip->features &= ~FE_WIDE;
+ /*
+ ** Some features are required to be enabled in order to
+ ** work around some chip problems. :) ;)
+ ** (ITEM 12 of a DEL about the 896 I haven't yet).
+ ** We must ensure the chip will use WRITE AND INVALIDATE.
+ ** The revision number limit is for now arbitrary.
+ */
+ pci_fix_up = driver_setup.pci_fix_up;
+ if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) {
+ chip->features |= (FE_WRIE | FE_CLSE);
+ pci_fix_up |= 3; /* Force appropriate PCI fix-up */
+ }
+
#ifdef SCSI_NCR_PCI_FIX_UP_SUPPORT
/*
** Try to fix up PCI config according to wished features.
*/
- if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) &&
+ if ((pci_fix_up & 1) && (chip->features & FE_CLSE) &&
!cache_line_size && suggested_cache_line_size) {
cache_line_size = suggested_cache_line_size;
pcibios_write_config_byte(bus, device_fn,
@@ -10367,7 +11876,7 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
cache_line_size);
}
- if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+ if ((pci_fix_up & 2) && cache_line_size &&
(chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n");
command |= PCI_COMMAND_INVALIDATE;
@@ -10379,7 +11888,7 @@ static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
** (latency timer >= burst length + 6, we add 10 to be quite sure)
*/
- if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+ if ((pci_fix_up & 4) && chip->burst_max) {
uchar lt = (1 << chip->burst_max) + 6 + 10;
if (latency_timer < lt) {
latency_timer = lt;
@@ -10532,7 +12041,7 @@ static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
np = ((struct host_data *) host->hostdata)->ncb;
tp = &np->target[device->id];
- lp = tp->lp[device->lun];
+ lp = ncr_lp(np, tp, device->lun);
/*
** Select queue depth from driver setup.
@@ -10548,8 +12057,8 @@ static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de
device->queue_depth = numtags;
if (device->queue_depth < 2)
device->queue_depth = 2;
- if (device->queue_depth > SCSI_NCR_MAX_TAGS)
- device->queue_depth = SCSI_NCR_MAX_TAGS;
+ if (device->queue_depth > MAX_TAGS)
+ device->queue_depth = MAX_TAGS;
/*
** Since the queue depth is not tunable under Linux,
@@ -10973,8 +12482,14 @@ static int ncr_user_command(ncb_p np, char *buffer, int length)
uc->cmd = UC_SETDEBUG;
else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0)
uc->cmd = UC_SETFLAG;
+ else if ((arg_len = is_keyword(ptr, len, "resetdev")) != 0)
+ uc->cmd = UC_RESETDEV;
+ else if ((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
+ uc->cmd = UC_CLEARDEV;
+#ifdef SCSI_NCR_PROFILE_SUPPORT
else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
uc->cmd = UC_CLEARPROF;
+#endif
else
arg_len = 0;
@@ -10991,6 +12506,8 @@ printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
case UC_SETTAGS:
case UC_SETWIDE:
case UC_SETFLAG:
+ case UC_RESETDEV:
+ case UC_CLEARDEV:
SKIP_SPACES(1);
if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
ptr += arg_len; len -= arg_len;
@@ -11034,14 +12551,12 @@ printk("ncr_user_command: data=%ld\n", uc->data);
uc->data |= DEBUG_ALLOC;
else if ((arg_len = is_keyword(ptr, len, "phase")))
uc->data |= DEBUG_PHASE;
- else if ((arg_len = is_keyword(ptr, len, "poll")))
- uc->data |= DEBUG_POLL;
else if ((arg_len = is_keyword(ptr, len, "queue")))
uc->data |= DEBUG_QUEUE;
else if ((arg_len = is_keyword(ptr, len, "result")))
uc->data |= DEBUG_RESULT;
- else if ((arg_len = is_keyword(ptr, len, "scatter")))
- uc->data |= DEBUG_SCATTER;
+ else if ((arg_len = is_keyword(ptr, len, "pointer")))
+ uc->data |= DEBUG_POINTER;
else if ((arg_len = is_keyword(ptr, len, "script")))
uc->data |= DEBUG_SCRIPT;
else if ((arg_len = is_keyword(ptr, len, "tiny")))
@@ -11052,10 +12567,6 @@ printk("ncr_user_command: data=%ld\n", uc->data);
uc->data |= DEBUG_NEGO;
else if ((arg_len = is_keyword(ptr, len, "tags")))
uc->data |= DEBUG_TAGS;
- else if ((arg_len = is_keyword(ptr, len, "freeze")))
- uc->data |= DEBUG_FREEZE;
- else if ((arg_len = is_keyword(ptr, len, "restart")))
- uc->data |= DEBUG_RESTART;
else
return -EINVAL;
ptr += arg_len; len -= arg_len;
@@ -11167,7 +12678,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
(u_long) np->reg);
#endif
copy_info(&info, " Synchronous period factor %d, ", (int) np->minsync);
- copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+ copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
if (driver_setup.debug || driver_setup.verbose > 1) {
copy_info(&info, " Debug flags 0x%x, ", driver_setup.debug);
@@ -11350,8 +12861,8 @@ static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
nvram_stop(np, &gpreg);
#ifdef SCSI_NCR_DEBUG_NVRAM
-printk("sym53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
- nvram->start_marker,
+printk("sym53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+ nvram->type,
nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
nvram->byte_count, sizeof(*nvram) - 12,
@@ -11375,7 +12886,8 @@ out:
/*
* Read Symbios NvRAM data and compute checksum.
*/
-static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
+static u_short __init
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
{
int x;
u_short csum;
@@ -11404,7 +12916,8 @@ static void __init nvram_start(ncr_slot *np, u_char *gpreg)
* WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
* GPIO0 must already be set as an output
*/
-static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
{
int x;
@@ -11418,7 +12931,8 @@ static void __init nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write
* READ a byte from the NVRAM and then send an ACK to say we have got it,
* GPIO0 must already be set as an input
*/
-static void __init nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
{
int x;
u_char read_bit;
@@ -11436,7 +12950,8 @@ static void __init nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_d
* Output an ACK to the NVRAM after reading,
* change GPIO0 to output and when done back to an input
*/
-static void __init nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
{
OUTB (nc_gpcntl, *gpcntl & 0xfe);
nvram_doBit(np, 0, write_bit, gpreg);
@@ -11447,7 +12962,8 @@ static void __init nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg,
* Input an ACK from NVRAM after writing,
* change GPIO0 to input and when done back to an output
*/
-static void __init nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+static void __init
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
{
OUTB (nc_gpcntl, *gpcntl | 0x01);
nvram_doBit(np, read_bit, 1, gpreg);
@@ -11458,7 +12974,8 @@ static void __init nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg,
* Read or write a bit to the NVRAM,
* read if GPIO0 input else write if GPIO0 output
*/
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+static void __init
+nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
{
nvram_setBit(np, write_bit, gpreg, SET_BIT);
nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11480,7 +12997,8 @@ static void __init nvram_stop(ncr_slot *np, u_char *gpreg)
/*
* Set/clear data/clock bit in GPIO0
*/
-static void __init nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+static void __init
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
{
UDELAY (5);
switch (bit_mode){
@@ -11566,7 +13084,8 @@ static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
/*
* Read Tekram NvRAM data and compute checksum.
*/
-static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
+static u_short __init
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
{
u_char read_bit;
u_short csum;
@@ -11591,7 +13110,8 @@ static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_c
/*
* Send read command and address to NVRAM
*/
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
+static void __init
+Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
{
int x;
@@ -11605,7 +13125,8 @@ static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char
/*
* READ a byte from the NVRAM
*/
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+static void __init
+Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
{
int x;
u_char read_bit;
@@ -11624,7 +13145,8 @@ static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *g
/*
* Read bit from NVRAM
*/
-static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+static void __init
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
{
UDELAY (2);
Tnvram_Clk(np, gpreg);
@@ -11634,7 +13156,8 @@ static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg
/*
* Write bit to GPIO0
*/
-static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+static void __init
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
{
if (write_bit & 0x01)
*gpreg |= 0x02;
diff --git a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h
index 5bdd608e9..4e39980c4 100644
--- a/drivers/scsi/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx.h
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
diff --git a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h
index 3b30e1bb5..0ec18fc2d 100644
--- a/drivers/scsi/sym53c8xx_defs.h
+++ b/drivers/scsi/sym53c8xx_defs.h
@@ -1,7 +1,7 @@
/******************************************************************************
** High Performance device driver for the Symbios 53C896 controller.
**
-** Copyright (C) 1998 Gerard Roudier <groudier@club-internet.fr>
+** Copyright (C) 1998-1999 Gerard Roudier <groudier@club-internet.fr>
**
** This driver also supports all the Symbios 53C8XX controller family,
** except 53C810 revisions < 16, 53C825 revisions < 16 and all
@@ -137,13 +137,13 @@
#define SCSI_NCR_MAX_SYNC (40)
/*
- * Allow tags from 2 to 64, default 8
+ * Allow tags from 2 to 256, default 8
*/
#ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS
#if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
#define SCSI_NCR_MAX_TAGS (2)
-#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64
-#define SCSI_NCR_MAX_TAGS (64)
+#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 256
+#define SCSI_NCR_MAX_TAGS (256)
#else
#define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS
#endif
@@ -175,6 +175,13 @@
#endif
/*
+ * Immediate arbitration
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IARB)
+#define SCSI_NCR_IARB_SUPPORT
+#endif
+
+/*
* Sync transfer frequency at startup.
* Allow from 5Mhz to 40Mhz default 20 Mhz.
*/
@@ -238,7 +245,7 @@
*/
#ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
#define SCSI_NCR_SETUP_LED_PIN (1)
-#define SCSI_NCR_SETUP_DIFF_SUPPORT (3)
+#define SCSI_NCR_SETUP_DIFF_SUPPORT (4)
#else
#define SCSI_NCR_SETUP_LED_PIN (0)
#define SCSI_NCR_SETUP_DIFF_SUPPORT (0)
@@ -250,6 +257,57 @@
#define SCSI_NCR_SETUP_SETTLE_TIME (2)
/*
+** Bridge quirks work-around option defaulted to 1.
+*/
+#ifndef SCSI_NCR_PCIQ_WORK_AROUND_OPT
+#define SCSI_NCR_PCIQ_WORK_AROUND_OPT 1
+#endif
+
+/*
+** Work-around common bridge misbehaviour.
+**
+** - Do not flush posted writes in the opposite
+** direction on read.
+** - May reorder DMA writes to memory.
+**
+** This option should not affect performances
+** significantly, so it is the default.
+*/
+#if SCSI_NCR_PCIQ_WORK_AROUND_OPT == 1
+#define SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+
+/*
+** Same as option 1, but also deal with
+** misconfigured interrupts.
+**
+** - Edge triggerred instead of level sensitive.
+** - No interrupt line connected.
+** - IRQ number misconfigured.
+**
+** If no interrupt is delivered, the driver will
+** catch the interrupt conditions 10 times per
+** second. No need to say that this option is
+** not recommended.
+*/
+#elif SCSI_NCR_PCIQ_WORK_AROUND_OPT == 2
+#define SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+#define SCSI_NCR_PCIQ_BROKEN_INTR
+
+/*
+** Some bridge designers decided to flush
+** everything prior to deliver the interrupt.
+** This option tries to deal with such a
+** behaviour.
+*/
+#elif SCSI_NCR_PCIQ_WORK_AROUND_OPT == 3
+#define SCSI_NCR_PCIQ_SYNC_ON_INTR
+#endif
+
+/*
** Other parameters not configurable with "make config"
** Avoid to change these constants, unless you know what you are doing.
*/
@@ -258,20 +316,20 @@
#define SCSI_NCR_MAX_SCATTER (127)
#define SCSI_NCR_MAX_TARGET (16)
-/* No need to use a too large adapter queue */
-#if SCSI_NCR_MAX_TAGS <= 32
-#define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS)
-#else
-#define SCSI_NCR_CAN_QUEUE (250)
-#endif
-
+/*
+** Compute some desirable value for CAN_QUEUE
+** and CMD_PER_LUN.
+** The driver will use lower values if these
+** ones appear to be too large.
+*/
+#define SCSI_NCR_CAN_QUEUE (8*SCSI_NCR_MAX_TAGS + 2*SCSI_NCR_MAX_TARGET)
#define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS)
-#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER)
+#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER)
#define SCSI_NCR_TIMER_INTERVAL (HZ)
#if 1 /* defined CONFIG_SCSI_MULTI_LUN */
-#define SCSI_NCR_MAX_LUN (8)
+#define SCSI_NCR_MAX_LUN (16)
#else
#define SCSI_NCR_MAX_LUN (1)
#endif
@@ -279,6 +337,18 @@
#ifndef HOSTS_C
/*
+** These simple macros limit expression involving
+** kernel time values (jiffies) to some that have
+** chance not to be too much incorrect. :-)
+*/
+#define ktime_get(o) (jiffies + (u_long) o)
+#define ktime_exp(b) ((long)(jiffies) - (long)(b) >= 0)
+#define ktime_dif(a, b) ((long)(a) - (long)(b))
+/* These ones are not used in this driver */
+#define ktime_add(a, o) ((a) + (u_long)(o))
+#define ktime_sub(a, o) ((a) - (u_long)(o))
+
+/*
** IO functions definition for big/little endian support.
** For now, the NCR is only supported in little endian addressing mode,
** and big endian byte ordering is only supported for the PPC.
@@ -384,6 +454,10 @@
#define PCI_DEVICE_ID_NCR_53C896 0xb
#endif
+#ifndef PCI_DEVICE_ID_NCR_53C895A
+#define PCI_DEVICE_ID_NCR_53C895A 0x12
+#endif
+
/*
** NCR53C8XX devices features table.
*/
@@ -391,31 +465,33 @@ typedef struct {
unsigned short device_id;
unsigned short revision_id;
char *name;
- unsigned char burst_max;
+ unsigned char burst_max; /* log-base-2 of max burst */
unsigned char offset_max;
unsigned char nr_divisor;
unsigned int features;
#define FE_LED0 (1<<0)
-#define FE_WIDE (1<<1)
-#define FE_ULTRA (1<<2)
-#define FE_ULTRA2 (1<<3)
-#define FE_DBLR (1<<4)
-#define FE_QUAD (1<<5)
-#define FE_ERL (1<<6)
-#define FE_CLSE (1<<7)
-#define FE_WRIE (1<<8)
-#define FE_ERMP (1<<9)
-#define FE_BOF (1<<10)
-#define FE_DFS (1<<11)
-#define FE_PFEN (1<<12)
-#define FE_LDSTR (1<<13)
-#define FE_RAM (1<<14)
-#define FE_CLK80 (1<<15)
-#define FE_RAM8K (1<<16)
-#define FE_64BIT (1<<17)
-#define FE_IO256 (1<<18)
-#define FE_NOPM (1<<19)
-#define FE_LEDC (1<<20)
+#define FE_WIDE (1<<1) /* Wide data transfers */
+#define FE_ULTRA (1<<2) /* Ultra speed 20Mtrans/sec */
+#define FE_ULTRA2 (1<<3) /* Ultra 2 - 40 Mtrans/sec */
+#define FE_DBLR (1<<4) /* Clock doubler present */
+#define FE_QUAD (1<<5) /* Clock quadrupler present */
+#define FE_ERL (1<<6) /* Enable read line */
+#define FE_CLSE (1<<7) /* Cache line size enable */
+#define FE_WRIE (1<<8) /* Write & Invalidate enable */
+#define FE_ERMP (1<<9) /* Enable read multiple */
+#define FE_BOF (1<<10) /* Burst opcode fetch */
+#define FE_DFS (1<<11) /* DMA fifo size */
+#define FE_PFEN (1<<12) /* Prefetch enable */
+#define FE_LDSTR (1<<13) /* Load/Store supported */
+#define FE_RAM (1<<14) /* On chip RAM present */
+#define FE_CLK80 (1<<15) /* Board clock is 80 MHz */
+#define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */
+#define FE_64BIT (1<<17) /* Supports 64-bit addressing */
+#define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */
+#define FE_NOPM (1<<19) /* Scripts handles phase mismatch */
+#define FE_LEDC (1<<20) /* Hardware control of LED */
+#define FE_DIFF (1<<21) /* Support Differential SCSI */
+
#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
@@ -449,35 +525,53 @@ typedef struct {
FE_WIDE|FE_ERL} \
, \
{PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \
- FE_WIDE|FE_ERL|FE_BOF} \
+ FE_WIDE|FE_ERL|FE_BOF|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, \
- FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \
FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \
, \
{PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|\
+ FE_RAM|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_DIFF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0x1f, "876", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_DIFF} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C875, 0x2f, "875E", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM} \
, \
{PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_DIFF} \
, \
{PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, \
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM} \
+ , \
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, \
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC} \
, \
- {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 7, 31, 7, \
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
- FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}\
+ {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a", 6, 31, 7, \
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| \
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC} \
}
/*
@@ -494,10 +588,47 @@ typedef struct {
PCI_DEVICE_ID_NCR_53C875J, \
PCI_DEVICE_ID_NCR_53C885, \
PCI_DEVICE_ID_NCR_53C895, \
- PCI_DEVICE_ID_NCR_53C896 \
+ PCI_DEVICE_ID_NCR_53C896, \
+ PCI_DEVICE_ID_NCR_53C895A \
}
/*
+** Driver setup structure.
+**
+** This structure is initialized from linux config options.
+** It can be overridden at boot-up by the boot command line.
+*/
+#define SCSI_NCR_MAX_EXCLUDES 8
+struct ncr_driver_setup {
+ u_char master_parity;
+ u_char scsi_parity;
+ u_char disconnection;
+ u_char special_features;
+ u_char ultra_scsi;
+ u_char force_sync_nego;
+ u_char reverse_probe;
+ u_char pci_fix_up;
+ u_char use_nvram;
+ u_char verbose;
+ u_char default_tags;
+ u_short default_sync;
+ u_short debug;
+ u_char burst_max;
+ u_char led_pin;
+ u_char max_wide;
+ u_char settle_delay;
+ u_char diff_support;
+ u_char irqm;
+ u_char bus_check;
+ u_char optimize;
+ u_char recovery;
+ u_char host_id;
+ u_short iarb;
+ u_int excludes[SCSI_NCR_MAX_EXCLUDES];
+ char tag_ctrl[100];
+};
+
+/*
** Initial setup.
** Can be overriden at startup by a command line.
*/
@@ -524,7 +655,9 @@ typedef struct {
0, \
1, \
0, \
- 0 \
+ 0, \
+ 255, \
+ 0x00 \
}
/*
@@ -555,9 +688,139 @@ typedef struct {
1, \
1, \
0, \
- 0 \
+ 0, \
+ 255 \
}
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+** Symbios NvRAM data format
+*/
+#define SYMBIOS_NVRAM_SIZE 368
+#define SYMBIOS_NVRAM_ADDRESS 0x100
+
+struct Symbios_nvram {
+/* Header 6 bytes */
+ u_short type; /* 0x0000 */
+ u_short byte_count; /* excluding header/trailer */
+ u_short checksum;
+
+/* Controller set up 20 bytes */
+ u_char v_major; /* 0x00 */
+ u_char v_minor; /* 0x30 */
+ u_int32 boot_crc;
+ u_short flags;
+#define SYMBIOS_SCAM_ENABLE (1)
+#define SYMBIOS_PARITY_ENABLE (1<<1)
+#define SYMBIOS_VERBOSE_MSGS (1<<2)
+#define SYMBIOS_CHS_MAPPING (1<<3)
+#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */
+ u_short flags1;
+#define SYMBIOS_SCAN_HI_LO (1)
+ u_short term_state;
+#define SYMBIOS_TERM_CANT_PROGRAM (0)
+#define SYMBIOS_TERM_ENABLED (1)
+#define SYMBIOS_TERM_DISABLED (2)
+ u_short rmvbl_flags;
+#define SYMBIOS_RMVBL_NO_SUPPORT (0)
+#define SYMBIOS_RMVBL_BOOT_DEVICE (1)
+#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2)
+ u_char host_id;
+ u_char num_hba; /* 0x04 */
+ u_char num_devices; /* 0x10 */
+ u_char max_scam_devices; /* 0x04 */
+ u_char num_valid_scam_devives; /* 0x00 */
+ u_char rsvd;
+
+/* Boot order 14 bytes * 4 */
+ struct Symbios_host{
+ u_short type; /* 4:8xx / 0:nok */
+ u_short device_id; /* PCI device id */
+ u_short vendor_id; /* PCI vendor id */
+ u_char bus_nr; /* PCI bus number */
+ u_char device_fn; /* PCI device/function number << 3*/
+ u_short word8;
+ u_short flags;
+#define SYMBIOS_INIT_SCAN_AT_BOOT (1)
+ u_short io_port; /* PCI io_port address */
+ } host[4];
+
+/* Targets 8 bytes * 16 */
+ struct Symbios_target {
+ u_char flags;
+#define SYMBIOS_DISCONNECT_ENABLE (1)
+#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1)
+#define SYMBIOS_SCAN_LUNS (1<<2)
+#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3)
+ u_char rsvd;
+ u_char bus_width; /* 0x08/0x10 */
+ u_char sync_offset;
+ u_short sync_period; /* 4*period factor */
+ u_short timeout;
+ } target[16];
+/* Scam table 8 bytes * 4 */
+ struct Symbios_scam {
+ u_short id;
+ u_short method;
+#define SYMBIOS_SCAM_DEFAULT_METHOD (0)
+#define SYMBIOS_SCAM_DONT_ASSIGN (1)
+#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2)
+#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3)
+ u_short status;
+#define SYMBIOS_SCAM_UNKNOWN (0)
+#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1)
+#define SYMBIOS_SCAM_ID_NOT_SET (2)
+#define SYMBIOS_SCAM_ID_VALID (3)
+ u_char target_id;
+ u_char rsvd;
+ } scam[4];
+
+ u_char spare_devices[15*8];
+ u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
+};
+typedef struct Symbios_nvram Symbios_nvram;
+typedef struct Symbios_host Symbios_host;
+typedef struct Symbios_target Symbios_target;
+typedef struct Symbios_scam Symbios_scam;
+
+/*
+** Tekram NvRAM data format.
+*/
+#define TEKRAM_NVRAM_SIZE 64
+#define TEKRAM_NVRAM_ADDRESS 0
+
+struct Tekram_nvram {
+ struct Tekram_target {
+ u_char flags;
+#define TEKRAM_PARITY_CHECK (1)
+#define TEKRAM_SYNC_NEGO (1<<1)
+#define TEKRAM_DISCONNECT_ENABLE (1<<2)
+#define TEKRAM_START_CMD (1<<3)
+#define TEKRAM_TAGGED_COMMANDS (1<<4)
+#define TEKRAM_WIDE_NEGO (1<<5)
+ u_char sync_index;
+ u_short word2;
+ } target[16];
+ u_char host_id;
+ u_char flags;
+#define TEKRAM_MORE_THAN_2_DRIVES (1)
+#define TEKRAM_DRIVES_SUP_1GB (1<<1)
+#define TEKRAM_RESET_ON_POWER_ON (1<<2)
+#define TEKRAM_ACTIVE_NEGATION (1<<3)
+#define TEKRAM_IMMEDIATE_SEEK (1<<4)
+#define TEKRAM_SCAN_LUNS (1<<5)
+#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; 1: boot device; 2:all */
+ u_char boot_delay_index;
+ u_char max_tags_index;
+ u_short flags1;
+#define TEKRAM_F2_F6_ENABLED (1)
+ u_short spare[29];
+};
+typedef struct Tekram_nvram Tekram_nvram;
+typedef struct Tekram_target Tekram_target;
+
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
+
/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
/*-----------------------------------------------------------------
@@ -573,6 +836,7 @@ struct ncr_reg {
/*01*/ u_char nc_scntl1; /* no reset */
#define ISCON 0x10 /* connected to scsi */
#define CRST 0x08 /* force reset */
+ #define IARB 0x02 /* immediate arbitration */
/*02*/ u_char nc_scntl2; /* no disconnect expected */
#define SDU 0x80 /* cmd: disconnect will raise error */
@@ -639,7 +903,10 @@ struct ncr_reg {
#define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */
#define LDSC 0x02 /* sta: disconnect & reconnect */
-/*10*/ u_int32 nc_dsa; /* --> Base page */
+/*10*/ u_char nc_dsa; /* --> Base page */
+/*11*/ u_char nc_dsa1;
+/*12*/ u_char nc_dsa2;
+/*13*/ u_char nc_dsa3;
/*14*/ u_char nc_istat; /* --> Main Command and status */
#define CABRT 0x80 /* cmd: abort current operation */
@@ -696,7 +963,7 @@ struct ncr_reg {
#define BOF 0x02 /* mod: burst op code fetch */
/*39*/ u_char nc_dien;
-/*3a*/ u_char nc_dwt;
+/*3a*/ u_char nc_sbr;
/*3b*/ u_char nc_dcntl; /* --> Script execution control */
#define CLSE 0x80 /* mod: cache line size enable */
@@ -736,6 +1003,7 @@ struct ncr_reg {
/*4c*/ u_char nc_stest0;
/*4d*/ u_char nc_stest1;
+ #define SCLK 0x80 /* Use the PCI clock as SCSI clock */
#define DBLEN 0x08 /* clock doubler running */
#define DBLSEL 0x04 /* clock doubler selected */
@@ -794,8 +1062,15 @@ struct ncr_reg {
/*c0*/ u_int32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */
/*c4*/ u_int32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */
-/*c8*/ u_int32 nc_rbc; /* Remaining Byte Count */
-/*cc*/ u_int32 nc_ua; /* Updated Address */
+/*c8*/ u_char nc_rbc; /* Remaining Byte Count */
+/*c9*/ u_char nc_rbc1; /* */
+/*ca*/ u_char nc_rbc2; /* */
+/*cb*/ u_char nc_rbc3; /* */
+
+/*cc*/ u_char nc_ua; /* Updated Address */
+/*cd*/ u_char nc_ua1; /* */
+/*ce*/ u_char nc_ua2; /* */
+/*cf*/ u_char nc_ua3; /* */
/*d0*/ u_int32 nc_esa; /* Entry Storage Address */
/*d4*/ u_char nc_ia; /* Instruction Address */
/*d5*/ u_char nc_ia1;
@@ -815,10 +1090,6 @@ struct ncr_reg {
#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
#define REG(r) REGJ (nc_, r)
-#ifndef TARGET_MODE
-#define TARGET_MODE 0
-#endif
-
typedef u_int32 ncrcmd;
/*-----------------------------------------------------------
@@ -855,9 +1126,15 @@ typedef u_int32 ncrcmd;
**-----------------------------------------------------------
*/
-#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul))
+#define OPC_MOVE 0x08000000
+
+#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_TBL (0x10000000 | OPC_MOVE)
+
+#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
+#define SCR_CHMOV_IND(l) ((0x20000000) | (l))
+#define SCR_CHMOV_TBL (0x10000000)
struct scr_tblmove {
u_int32 size;
@@ -870,7 +1147,7 @@ struct scr_tblmove {
**
**-----------------------------------------------------------
**
-** SEL_ABS | SCR_ID (0..7) [ | REL_JMP]
+** SEL_ABS | SCR_ID (0..15) [ | REL_JMP]
** <<alternate_address>>
**
** SEL_TBL | << dnad_offset>> [ | REL_JMP]
@@ -1104,7 +1381,7 @@ struct scr_tblsel {
** Conditions:
** WHEN (phase)
** IF (phase)
-** CARRY
+** CARRYSET
** DATA (data, mask)
**
**-----------------------------------------------------------
diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c
index 641467deb..3551de64b 100644
--- a/drivers/sgi/char/shmiq.c
+++ b/drivers/sgi/char/shmiq.c
@@ -1,4 +1,4 @@
-/* $Id: shmiq.c,v 1.13 1999/09/28 22:26:59 ralf Exp $
+/* $Id: shmiq.c,v 1.14 1999/10/09 00:01:31 ralf Exp $
*
* shmiq.c: shared memory input queue driver
* written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -118,7 +118,7 @@ shmiq_push_event (struct shmqevent *e)
s->tail = tail_next;
shmiqs [device].tail = tail_next;
if (shmiqs [device].fasync)
- kill_fasync (shmiqs [device].fasync, SIGIO);
+ kill_fasync (shmiqs [device].fasync, SIGIO, POLL_IN);
wake_up_interruptible (&shmiqs [device].proc_list);
}
diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c
index 90ccaf342..ec41d0b6a 100644
--- a/drivers/sound/esssolo1.c
+++ b/drivers/sound/esssolo1.c
@@ -58,6 +58,8 @@
* replaced current->state = x with set_current_state(x)
* 03.09.99 0.8 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
+ * 07.10.99 0.9 Fix initialization; complain if sequencer writes time out
+ * Revised resource grabbing for the FM synthesizer
*
*/
@@ -108,6 +110,7 @@
#define MPUBASE_EXTENT 4
#define GPBASE_EXTENT 4
+#define FMSYNTH_EXTENT 4
/* MIDI buffer sizes */
@@ -207,7 +210,7 @@ extern inline void write_seq(struct solo1_state *s, unsigned char data)
{
int i;
unsigned long flags;
-
+
/* the __cli stunt is to send the data within the command window */
for (i = 0; i < 0xffff; i++) {
__save_flags(flags);
@@ -219,6 +222,8 @@ extern inline void write_seq(struct solo1_state *s, unsigned char data)
}
__restore_flags(flags);
}
+ printk(KERN_ERR "esssolo1: write_seq timeout\n");
+ outb(data, s->sbbase+0xc);
}
extern inline int read_seq(struct solo1_state *s, unsigned char *data)
@@ -232,6 +237,7 @@ extern inline int read_seq(struct solo1_state *s, unsigned char *data)
*data = inb(s->sbbase+0xa);
return 1;
}
+ printk(KERN_ERR "esssolo1: read_seq timeout\n");
return 0;
}
@@ -1993,6 +1999,12 @@ static int solo1_dmfm_open(struct inode *inode, struct file *file)
return -ERESTARTSYS;
down(&s->open_sem);
}
+ if (check_region(s->sbbase, FMSYNTH_EXTENT)) {
+ up(&s->open_sem);
+ printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
+ return -EBUSY;
+ }
+ request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1");
/* init the stuff */
outb(1, s->sbbase);
outb(0x20, s->sbbase+1); /* enable waveforms */
@@ -2020,6 +2032,7 @@ static int solo1_dmfm_release(struct inode *inode, struct file *file)
outb(regb, s->sbbase+2);
outb(0, s->sbbase+3);
}
+ release_region(s->sbbase, FMSYNTH_EXTENT);
up(&s->open_sem);
wake_up(&s->open_wait);
MOD_DEC_USE_COUNT;
@@ -2113,14 +2126,14 @@ static int __init init_solo1(void)
s->gpbase = RSRCADDRESS(pcidev, 4);
s->irq = pcidev->irq;
if (check_region(s->iobase, IOBASE_EXTENT) ||
- check_region(s->sbbase+4, SBBASE_EXTENT-4) ||
+ check_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT) ||
check_region(s->ddmabase, DDMABASE_EXTENT) ||
check_region(s->mpubase, MPUBASE_EXTENT)) {
printk(KERN_ERR "solo1: io ports in use\n");
goto err_region;
}
request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1");
- request_region(s->sbbase+4, SBBASE_EXTENT-4, "ESS Solo1"); /* allow OPL3 synth module */
+ request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1");
request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1");
request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1");
if (request_irq(s->irq, solo1_interrupt, SA_SHIRQ, "ESS Solo1", s)) {
@@ -2147,6 +2160,10 @@ static int __init init_solo1(void)
if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0)
goto err_dev4;
/* initialize the chips */
+ if (!reset_ctrl(s)) {
+ printk(KERN_ERR "esssolo1: cannot reset controller\n");
+ goto err;
+ }
outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
/* initialize mixer regs */
@@ -2181,6 +2198,8 @@ static int __init init_solo1(void)
index++;
continue;
+ err:
+ unregister_sound_dsp(s->dev_dmfm);
err_dev4:
unregister_sound_dsp(s->dev_midi);
err_dev3:
@@ -2192,7 +2211,7 @@ static int __init init_solo1(void)
free_irq(s->irq, s);
err_irq:
release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+4, SBBASE_EXTENT-4);
+ release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
release_region(s->ddmabase, DDMABASE_EXTENT);
release_region(s->mpubase, MPUBASE_EXTENT);
err_region:
@@ -2222,7 +2241,7 @@ static void __exit cleanup_solo1(void)
pci_write_config_word(s->pcidev, 0x60, 0); /* turn off DDMA controller address space */
free_irq(s->irq, s);
release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+4, SBBASE_EXTENT-4);
+ release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
release_region(s->ddmabase, DDMABASE_EXTENT);
release_region(s->mpubase, MPUBASE_EXTENT);
unregister_sound_dsp(s->dev_audio);
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 04e688614..19a76c0bd 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -10,39 +10,43 @@ comment 'USB drivers - not for the faint of heart'
tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
if [ ! "$CONFIG_USB" = "n" ]; then
- dep_tristate 'UHCI (intel PIIX4 and others) support' CONFIG_USB_UHCI \
+comment 'USB Controllers'
+ dep_tristate ' UHCI (Intel PIIX4 and others) support' CONFIG_USB_UHCI \
$CONFIG_USB
- dep_tristate 'OHCI (compaq and some others) support' CONFIG_USB_OHCI \
+ dep_tristate ' OHCI (Compaq and some others) support' CONFIG_USB_OHCI \
$CONFIG_USB
- if [ "$CONFIG_USB_OHCI" != "n" ]; then
- bool ' Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG
- fi
- dep_tristate 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \
+ if [ "$CONFIG_USB_OHCI" != "n" ]; then
+ bool ' Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG
+ fi
+ dep_tristate ' OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \
CONFIG_USB_OHCI_HCD $CONFIG_USB
- if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then
- bool ' OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
- fi
+ if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then
+ bool ' OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
+ fi
- bool 'Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC
+comment 'Miscellaneous USB options'
+ bool ' Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC
+ if [ "$CONFIG_PROC_FS" != "n" ]; then
+ bool ' Preliminary /proc/bus/usb support' CONFIG_USB_PROC
+ fi
+ dep_tristate ' EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
- dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
- dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
- dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
- dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
- dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
- dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
- dep_tristate 'USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
- dep_tristate 'USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
- dep_tristate 'USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
- if [ "$CONFIG_USB_SCSI" != "n" ]; then
- dep_tristate ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
- fi
- dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
- dep_tristate 'USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
- if [ "$CONFIG_PROC_FS" != "n" ]; then
- bool 'Preliminary /proc/bus/usb support' CONFIG_USB_PROC
- fi
+comment 'USB Devices'
+ dep_tristate ' USB hub support (Required!)' CONFIG_USB_HUB $CONFIG_USB
+ dep_tristate ' USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+ dep_tristate ' USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
+ dep_tristate ' USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
+ dep_tristate ' USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
+ dep_tristate ' USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
+ dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+ dep_tristate ' USB Belkin and Peracom serial support' CONFIG_USB_SERIAL $CONFIG_USB
+ dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
+ dep_tristate ' USB SCSI Support' CONFIG_USB_SCSI $CONFIG_USB
+ if [ "$CONFIG_USB_SCSI" != "n" ]; then
+ bool ' USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG
+ fi
+ dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
fi
endmenu
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 0531c15bd..8d6006493 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -97,6 +97,15 @@ ifeq ($(CONFIG_USB_PRINTER),m)
MIX_OBJS += printer.o
endif
+ifeq ($(CONFIG_USB_SERIAL),y)
+ L_OBJS += serial.o
+endif
+
+ifeq ($(CONFIG_USB_SERIAL),m)
+ M_OBJS += serial.o
+ MIX_OBJS += serial.o
+endif
+
ifeq ($(CONFIG_USB_KBD),y)
L_OBJS += keyboard.o keymap.o
endif
diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci
index 921d9a9a3..22420779f 100644
--- a/drivers/usb/README.ohci
+++ b/drivers/usb/README.ohci
@@ -1,5 +1,17 @@
[This is the readme for ohci.c, ohci-debug.c and ohci.h]
+September 05, 1999 17:03:21
+
+I haven't updated this file in a while. I have started merging good
+ideas from the ohci-hcd driver into this code as well as simplifying
+the code where I can. Isochronous transfers still need to be ported
+over from ohci-hcd. Large control and bulk transfers should be
+working much better now.
+
+A big thanks goes to 3Com and APC for donating me a modem and UPS to
+test with! They aren't working with OHCI quite yet but we hope to
+change that soon.
+
June 23, 1999 00:31:20 PST
I now have bulk support in a reasonably working state. The only
diff --git a/drivers/usb/README.serial b/drivers/usb/README.serial
new file mode 100644
index 000000000..e67fb748a
--- /dev/null
+++ b/drivers/usb/README.serial
@@ -0,0 +1,35 @@
+This serial driver currently only works with the Belkin and Peracom USB
+Serial devices. It should also work for the Etek converter, but I do
+not know the vendor id, and device id of that device (if anyone does,
+please let me know.)
+
+The driver can handle enumerating the device, and sending and receiving
+data from the converter. However, since I do not have a spec for this
+device, and the raw dumps from the Win98 driver are confusing, no control
+signals are handled, and the data will most likely come through on a baud
+rate that you are not expecting.
+
+But I am working on figuring the control settings out. This release is to
+let others try it out, and give some feedback.
+
+The major number that the driver uses is 240 (in the local/experimental
+range.) It will stay there until some agreements are reached on how to
+handle the configuration problem that USB provides.
+
+To use the driver, create the following nodes:
+mknod /dev/ttyUSB0 c 240 0
+mknod /dev/ttyUSB1 c 240 1
+mknod /dev/ttyUSB2 c 240 2
+mknod /dev/ttyUSB3 c 240 3
+
+then plug in a device and use your friendly terminal program to see what
+happens.
+
+If anyone has any problems getting the device to enumerate, or data to
+flow through it, please contact me.
+
+
+
+greg k-h
+greg@kroah.com
+
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index 6560331fc..61830f720 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -1,7 +1,11 @@
/*
* USB Abstract Control Model based on Brad Keryan's USB busmouse driver
*
- * Armin Fuerst 5/8/1999
+ * Armin Fuerst 5/8/1999 <armin.please@put.your.email.here.!!!!>
+ *
+ * version 0.8: Fixed endianity bug, some cleanups. I really hate to have
+ * half of driver in form if (...) { info("x"); return y; }
+ * Pavel Machek <pavel@suse.de>
*
* version 0.7: Added usb flow control. Fixed bug in uhci.c (what idiot
* wrote this code? ...Oops that was me). Fixed module cleanup. Did some
@@ -63,8 +67,8 @@
#define NR_PORTS 3
#define ACM_MAJOR 166
-#define info(message); printk(message);
-//#define info(message);
+//#define info(message...); printk(message);
+#define info(message...);
#define CTRL_STAT_DTR 1
#define CTRL_STAT_RTS 2
@@ -94,6 +98,7 @@ struct acm_state {
unsigned ctrlinterval; //interval to poll from device
};
+#define ACM_READY (acm->present && acm->active)
//functions for various ACM requests
@@ -108,7 +113,7 @@ void Set_Control_Line_Status (unsigned int status,struct acm_state *acm)
dr.value = status;
dr.index = 0;
dr.length = 0;
- acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+ acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ);
acm->ctrlstate=status;
}
@@ -124,7 +129,7 @@ void Set_Line_Coding (unsigned int coding,struct acm_state *acm)
dr.value = coding;
dr.index = 0;
dr.length = 0;
- acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0);
+ acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev,0), &dr, NULL, 0, HZ);
acm->linecoding=coding;
}
@@ -139,20 +144,16 @@ static int acm_irq(int state, void *__buffer, int count, void *dev_id)
info("ACM_USB_IRQ\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
+ if (!acm->present)
return 0;
- }
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
+ if (!acm->active)
return 1;
- }
dr=__buffer;
data=__buffer;
data+=sizeof(dr);
-#if 1
+#if 0
printk("reqtype: %02X\n",dr->requesttype);
printk("request: %02X\n",dr->request);
printk("wValue: %02X\n",dr->value);
@@ -161,31 +162,26 @@ static int acm_irq(int state, void *__buffer, int count, void *dev_id)
#endif
switch(dr->request) {
- //Network connection
- case 0x00:
- printk("Network connection: ");
- if (dr->request==0) info("disconnected\n");
- if (dr->request==1) info("connected\n");
- break;
+ case 0x00: /* Network connection */
+ printk("Network connection: ");
+ if (dr->request==0) printk("disconnected\n");
+ if (dr->request==1) printk("connected\n");
+ break;
- //Response available
- case 0x01:
- printk("Response available\n");
- break;
+ case 0x01: /* Response available */
+ printk("Response available\n");
+ break;
- //Set serial line state
- case 0x20:
- printk("Set serial control line state\n");
- if ((dr->index==1)&&(dr->length==2)) {
- acm->ctrlstate=* ((unsigned short int *)data);
- printk("Serstate: %02X\n",acm->ctrlstate);
- }
- break;
+ case 0x20: /* Set serial line state */
+ printk("acm.c: Set serial control line state\n");
+ if ((dr->index==1)&&(dr->length==2)) {
+ acm->ctrlstate= data[0] || (data[1] << 16);
+ printk("Serstate: %02X\n",acm->ctrlstate);
+ }
+ break;
}
- //info("Done\n");
- //Continue transfer
- return 1;
+ return 1; /* Continue transfer */
}
static int acm_read_irq(int state, void *__buffer, int count, void *dev_id)
@@ -195,29 +191,20 @@ static int acm_read_irq(int state, void *__buffer, int count, void *dev_id)
unsigned char* data=__buffer;
int i;
- info("ACM_READ_IRQ\n");
-
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- //Stop transfer
- return 0;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
- //Stop transfer
- return 0;
+ info("ACM_READ_IRQ: state %d, %d bytes\n", state, count);
+ if (state) {
+ printk( "acm_read_irq: strange state received: %x\n", state );
+ return 1;
}
+
+ if (!ACM_READY)
+ return 0; /* stop transfer */
-// printk("%d %s\n",count,data);
- for (i=0;i<count;i++) {
- tty_insert_flip_char(tty,data[i],0);
- }
+ for (i=0;i<count;i++)
+ tty_insert_flip_char(tty,data[i],0);
tty_flip_buffer_push(tty);
-
- //info("Done\n");
- //Continue transfer
- return 1;
+
+ return 1; /* continue transfer */
}
static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
@@ -227,16 +214,8 @@ static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
info("ACM_WRITE_IRQ\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- //Stop transfer
- return 0;
- }
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
- //Stop transfer
- return 0;
- }
+ if (!ACM_READY)
+ return 0; /* stop transfer */
usb_terminate_bulk(acm->dev, acm->writetransfer);
acm->writing=0;
@@ -244,9 +223,7 @@ static int acm_write_irq(int state, void *__buffer, int count, void *dev_id)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
- //info("Done\n");
- //Stop transfer
- return 0;
+ return 0; /* stop tranfer */
}
/*TTY STUFF*/
@@ -260,22 +237,16 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
tty->driver_data=acm=&acm_state_table[MINOR(tty->device)-tty->driver.minor_start];
acm->tty=tty;
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
+ if (!acm->present)
return -EINVAL;
- }
- if (acm->active) {
- info ("ACM DEVICE ALREADY OPEN\n");
- return -EINVAL;
- }
- acm->active=1;
+ if (acm->active++)
+ return 0;
- /*Start reading from the device*/
+ /* Start reading from the device */
ret = usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm, &acm->ctrltransfer);
- if (ret) {
+ if (ret)
printk (KERN_WARNING "usb-acm: usb_request_irq failed (0x%x)\n", ret);
- }
acm->reading=1;
acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm);
@@ -289,15 +260,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
struct acm_state *acm = (struct acm_state *) tty->driver_data;
info("rs_close\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
+ if (!acm->present)
return;
- }
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
+ if (--acm->active)
return;
- }
Set_Control_Line_Status (0, acm);
@@ -309,9 +276,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
usb_terminate_bulk(acm->dev, acm->readtransfer);
acm->reading=0;
}
-// usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
-
- acm->active=0;
+// usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
}
static int rs_write(struct tty_struct * tty, int from_user,
@@ -322,15 +287,8 @@ static int rs_write(struct tty_struct * tty, int from_user,
info("rs_write\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- return -EINVAL;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
+ if (!ACM_READY)
return -EINVAL;
- }
if (acm->writing) {
info ("already writing\n");
@@ -339,14 +297,8 @@ static int rs_write(struct tty_struct * tty, int from_user,
written=(count>acm->writesize) ? acm->writesize : count;
- if (from_user) {
- //info("fromuser\n");
- copy_from_user(acm->writebuffer,buf,written);
- }
- else {
- //info("notfromuser\n");
- memcpy(acm->writebuffer,buf,written);
- }
+ if (from_user) copy_from_user(acm->writebuffer,buf,written);
+ else memcpy(acm->writebuffer,buf,written);
//start the transfer
acm->writing=1;
@@ -359,18 +311,8 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct acm_state *acm = (struct acm_state *) tty->driver_data;
- info("rs_put_char\n");
-
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- return;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
- return;
- }
-// printk("%c\n",ch);
+ printk( "acm: rs_put_char: Who called this unsupported routine?\n" );
+ BUG();
}
static int rs_write_room(struct tty_struct *tty)
@@ -379,42 +321,22 @@ static int rs_write_room(struct tty_struct *tty)
info("rs_write_room\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
+ if (!ACM_READY)
return -EINVAL;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
- return -EINVAL;
- }
- if (acm->writing) {
- return 0;
- }
- return acm->writesize;
+ return acm->writing ? 0 : acm->writesize;
}
static int rs_chars_in_buffer(struct tty_struct *tty)
{
struct acm_state *acm = (struct acm_state *) tty->driver_data;
- info("rs_chars_in_buffer\n");
+// info("rs_chars_in_buffer\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- return -EINVAL;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
+ if (!ACM_READY)
return -EINVAL;
- }
- if (acm->writing) {
- return acm->writesize;
- }
- return 0;
+ return acm->writing ? acm->writesize : 0;
}
static void rs_throttle(struct tty_struct * tty)
@@ -423,21 +345,12 @@ static void rs_throttle(struct tty_struct * tty)
info("rs_throttle\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
- return;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
+ if (!ACM_READY)
return;
- }
-
/*
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
*/
-
if (tty->termios->c_cflag & CRTSCTS)
Set_Control_Line_Status (acm->ctrlstate & ~CTRL_STAT_RTS, acm);
}
@@ -448,21 +361,12 @@ static void rs_unthrottle(struct tty_struct * tty)
info("rs_unthrottle\n");
- if (!acm->present) {
- info("NO ACM DEVICE REGISTERED\n");
+ if (!ACM_READY)
return;
- }
-
- if (!acm->active) {
- info ("ACM DEVICE NOT OPEN\n");
- return;
- }
-
/*
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
*/
-
if (tty->termios->c_cflag & CRTSCTS)
Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm);
}
@@ -521,7 +425,8 @@ static int acm_probe(struct usb_device *dev)
interface->bNumEndpoints != 2)
continue;
- if ((endpoint->bEndpointAddress & 0x80) == 0x80)
+ endpoint = &interface->endpoint[0];
+ if ((endpoint->bEndpointAddress & 0x80) != 0x80)
swapped = 1;
/*With a bulk input */
@@ -578,10 +483,8 @@ static void acm_disconnect(struct usb_device *dev)
info("acm_disconnect\n");
- if (!acm->present) {
- printk("device not present\n");
+ if (!acm->present)
return;
- }
printk("disconnecting\n");
@@ -593,7 +496,7 @@ static void acm_disconnect(struct usb_device *dev)
usb_terminate_bulk(acm->dev, acm->readtransfer);
acm->reading=0;
}
-// usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
+ usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
//BUG: What to do if a device is open?? Notify process or not allow cleanup?
acm->active=0;
acm->present=0;
@@ -643,9 +546,9 @@ int usb_acm_init(void)
acm_tty_driver.open = rs_open;
acm_tty_driver.close = rs_close;
acm_tty_driver.write = rs_write;
- acm_tty_driver.put_char = rs_put_char; //FUCKIN BUG IN DOKU!!!
+ acm_tty_driver.put_char = rs_put_char;
acm_tty_driver.flush_chars = NULL; //rs_flush_chars;
- acm_tty_driver.write_room = rs_write_room; //ANBOTHER FUCKIN BUG!!
+ acm_tty_driver.write_room = rs_write_room;
acm_tty_driver.ioctl = NULL; //rs_ioctl;
acm_tty_driver.set_termios = NULL; //rs_set_termios;
acm_tty_driver.set_ldisc = NULL;
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 8e25ae40b..291f424dc 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -1,25 +1,2540 @@
+/*****************************************************************************/
+
+/*
+ * audio.c -- USB Audio Class driver
+ *
+ * Copyright (C) 1999
+ * Alan Cox (alan@lxorguk.ukuu.org.uk)
+ * Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ * 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.
+ *
+ *
+ * 1999-09-07: Alan Cox
+ * Parsing Audio descriptor patch
+ * 1999-09-08: Thomas Sailer
+ * Added OSS compatible data io functions; both parts of the
+ * driver remain to be glued together
+ * 1999-09-10: Thomas Sailer
+ * Beautified the driver. Added sample format conversions.
+ * Still not properly glued with the parsing code.
+ * The parsing code seems to have its problems btw,
+ * Since it parses all available configs but doesn't
+ * store which iface/altsetting belongs to which config.
+ * 1999-09-20: Thomas Sailer
+ * Threw out Alan's parsing code and implemented my own one.
+ * You cannot reasonnably linearly parse audio descriptors,
+ * especially the AudioClass descriptors have to be considered
+ * pointer lists. Mixer parsing untested, due to lack of device.
+ * First stab at synch pipe implementation, the Dallas USB DAC
+ * wants to use an Asynch out pipe. usb_audio_state now basically
+ * only contains lists of mixer and wave devices. We can therefore
+ * now have multiple mixer/wave devices per USB device.
+ *
+ */
+
+/*
+ * Strategy:
+ *
+ * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
+ * are hoping to meet in the middle, just like tunnel diggers :)
+ * Alan tackles the descriptor parsing, Thomas the actual data IO and the
+ * OSS compatible interface.
+ *
+ * Data IO implementation issues
+ *
+ * A mmap'able ring buffer per direction is implemented, because
+ * almost every OSS app expects it. It is however impractical to
+ * transmit/receive USB data directly into and out of the ring buffer,
+ * due to alignment and synchronisation issues. Instead, the ring buffer
+ * feeds a constant time delay line that handles the USB issues.
+ *
+ * Now we first try to find an alternate setting that exactly matches
+ * the sample format requested by the user. If we find one, we do not
+ * need to perform any sample rate conversions. If there is no matching
+ * altsetting, we choose the closest one and perform sample format
+ * conversions. We never do sample rate conversion; these are too
+ * expensive to be performed in the kernel.
+ *
+ * Current status:
+ * - The IO code seems to work a couple of frames, but then gets
+ * UHCI into a "complaining" mode, i.e. uhci won't work again until
+ * removed and reloaded, it will not even notice disconnect/reconnect
+ * events.
+ * It seems to work more stably on OHCI-HCD.
+ *
+ * Generally: Due to the brokenness of the Audio Class spec
+ * it seems generally impossible to write a generic Audio Class driver,
+ * so a reasonable driver should implement the features that are actually
+ * used.
+ *
+ * Parsing implementation issues
+ *
+ * One cannot reasonably parse the AudioClass descriptors linearly.
+ * Therefore the current implementation features routines to look
+ * for a specific descriptor in the descriptor list.
+ *
+ * How does the parsing work? First, all interfaces are searched
+ * for an AudioControl class interface. If found, the config descriptor
+ * that belongs to the current configuration is fetched from the device.
+ * Then the HEADER descriptor is fetched. It contains a list of
+ * all AudioStreaming and MIDIStreaming devices. This list is then walked,
+ * and all AudioStreaming interfaces are classified into input and output
+ * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
+ * is currently not supported). The input & output list is then used
+ * to group inputs and outputs together and issued pairwise to the
+ * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
+ * are walked and issued to the mixer construction routine.
+ *
+ * The AudioStreaming parser simply enumerates all altsettings belonging
+ * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
+ * class specific descriptors to extract the sample format/sample rate
+ * data. Only sample format types PCM and PCM8 are supported right now, and
+ * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
+ * be the first endpoint of the interface, and the optional synchronisation
+ * isochronous endpoint the second one.
+ *
+ * Mixer construction works as follows: The various TERMINAL and UNIT
+ * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
+ * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
+ * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
+ * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
+ * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
+ * to determine "meaningful" OSS slider numbers, however we will see
+ * how well this works in practice. Other features are not used at the
+ * moment, they seem less often used. Also, it seems difficult at least
+ * to construct recording source switches from SELECTOR_UNITs, but
+ * since there are not many USB ADC's available, we leave that for later.
+ */
+
+/*****************************************************************************/
+
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/module.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
#include "usb.h"
+#include "audio.h"
+
#define AUDIO_DEBUG 1
-static int usb_audio_probe(struct usb_device *dev);
-static void usb_audio_disconnect(struct usb_device *dev);
-static LIST_HEAD(usb_audio_list);
+#define SND_DEV_DSP16 5
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Linked list of all audio devices...
+ */
+static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
+static DECLARE_MUTEX(open_sem);
+
+/*
+ * wait queue for processes wanting to open an USB audio device
+ */
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+#define MAXFORMATS MAX_ALT
+#define DMABUFSHIFT 17 /* 128k worth of DMA buffer */
+#define NRSGBUF (1U<<(DMABUFSHIFT-PAGE_SHIFT))
+
+/*
+ * This influences:
+ * - Latency
+ * - Interrupt rate
+ * - Synchronisation behaviour
+ * Don't touch this if you don't understand all of the above.
+ */
+#define DESCFRAMES 4
+
+#define MIXFLG_STEREOIN 1
+#define MIXFLG_STEREOOUT 2
+
+struct mixerchannel {
+ __u16 value;
+ __u16 osschannel; /* number of the OSS channel */
+ __s16 minval, maxval;
+ __u8 unitid;
+ __u8 selector;
+ __u8 chnum;
+ __u8 flags;
+};
+
+struct audioformat {
+ unsigned int format;
+ unsigned int sratelo;
+ unsigned int sratehi;
+ unsigned char altsetting;
+};
+
+struct dmabuf {
+ /* buffer data format */
+ unsigned int format;
+ unsigned int srate;
+ /* physical buffer */
+ unsigned char *sgbuf[NRSGBUF];
+ unsigned bufsize;
+ unsigned numfrag;
+ unsigned fragshift;
+ unsigned wrptr, rdptr;
+ unsigned total_bytes;
+ int count;
+ unsigned error; /* over/underrun */
+ wait_queue_head_t wait;
+ /* redundant, but makes calculations easier */
+ unsigned fragsize;
+ unsigned dmasize;
+ /* OSS stuff */
+ unsigned mapped:1;
+ unsigned ready:1;
+ unsigned ossfragshift;
+ int ossmaxfrags;
+ unsigned subdivision;
+};
+
+struct usb_audio_state;
+
+#define FLG_NEXTID 1
+#define FLG_ID0RUNNING 2
+#define FLG_ID1RUNNING 4
+#define FLG_SYNCNEXTID 8
+#define FLG_SYNC0RUNNING 16
+#define FLG_SYNC1RUNNING 32
+#define FLG_RUNNING 64
-struct usb_audio {
- struct usb_device *dev;
+struct usb_audiodev {
struct list_head list;
+ struct usb_audio_state *state;
+
+ /* soundcore stuff */
+ int dev_audio;
+
+ /* wave stuff */
+ mode_t open_mode;
+ spinlock_t lock; /* DMA buffer access spinlock */
+
+ struct usbin {
+ unsigned int interface; /* Interface number */
+ unsigned int format; /* USB data format */
+ unsigned int datapipe; /* the data input pipe */
+ unsigned int syncpipe; /* the synchronisation pipe - 0 for anything but adaptive IN mode */
+ unsigned int syncinterval; /* P for adaptive IN mode, 0 otherwise */
+ unsigned int freqn; /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+ unsigned int phase; /* phase accumulator */
+ unsigned int flags; /* see FLG_ defines */
+
+ struct usb_isoc_desc *dataiso[2]; /* ISO descriptors for the data endpoint */
+ unsigned char *data[2]; /* data pages associated with the ISO descriptors */
+
+ struct usb_isoc_desc *synciso[2]; /* ISO sync pipe descriptor if needed */
+ unsigned char *syncdata[2]; /* data page for sync data */
+
+ struct dmabuf dma;
+ } usbin;
+
+ struct usbout {
+ unsigned int interface; /* Interface number */
+ unsigned int format; /* USB data format */
+ unsigned int datapipe; /* the data input pipe */
+ unsigned int syncpipe; /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
+ unsigned int syncinterval; /* P for asynchronous OUT mode, 0 otherwise */
+ unsigned int freqn; /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+ unsigned int freqm; /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+ unsigned int phase; /* phase accumulator */
+ unsigned int flags; /* see FLG_ defines */
+
+ struct usb_isoc_desc *dataiso[2]; /* ISO descriptors for the data endpoint */
+ unsigned char *data[2]; /* data pages associated with the ISO descriptors */
+
+ struct usb_isoc_desc *synciso[2]; /* ISO sync pipe descriptor if needed */
+ unsigned char *syncdata[2]; /* data page for sync data */
+
+ struct dmabuf dma;
+ } usbout;
- void *irq_handle;
- unsigned int irqpipe;
+
+ unsigned int numfmtin, numfmtout;
+ struct audioformat fmtin[MAXFORMATS];
+ struct audioformat fmtout[MAXFORMATS];
+};
+
+struct usb_mixerdev {
+ struct list_head list;
+ struct usb_audio_state *state;
+
+ /* soundcore stuff */
+ int dev_mixer;
+
+ unsigned char iface; /* interface number of the AudioControl interface */
+
+ /* USB format descriptions */
+ unsigned int numch, modcnt;
+
+ /* mixch is last and gets allocated dynamically */
+ struct mixerchannel ch[0];
};
+struct usb_audio_state {
+ struct list_head audiodev;
+
+ /* USB device */
+ struct usb_device *usbdev;
+
+ struct list_head audiolist;
+ struct list_head mixerlist;
+
+ unsigned count; /* usage counter; NOTE: the usb stack is also considered a user */
+};
+
+/* private audio format extensions */
+#define AFMT_STEREO 0x80000000
+#define AFMT_ISSTEREO(x) ((x) & AFMT_STEREO)
+#define AFMT_IS16BIT(x) ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
+#define AFMT_BYTES(x) (1<<AFMT_BYTESSHFIT(x))
+
+/* --------------------------------------------------------------------- */
+
+extern inline unsigned ld2(unsigned int x)
+{
+ unsigned r = 0;
+
+ if (x >= 0x10000) {
+ x >>= 16;
+ r += 16;
+ }
+ if (x >= 0x100) {
+ x >>= 8;
+ r += 8;
+ }
+ if (x >= 0x10) {
+ x >>= 4;
+ r += 4;
+ }
+ if (x >= 4) {
+ x >>= 2;
+ r += 2;
+ }
+ if (x >= 2)
+ r++;
+ return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
+ * an application address space.
+ *
+ * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
+ * we now use an array of pointers to a single page each. This saves us the
+ * kernel page table manipulations, but we have to do a page table alike mechanism
+ * (though only one indirection) in software.
+ */
+
+static void dmabuf_release(struct dmabuf *db)
+{
+ unsigned int nr;
+ void *p;
+
+ for(nr = 0; nr < NRSGBUF; nr++) {
+ if (!(p = db->sgbuf[nr]))
+ continue;
+ mem_map_unreserve(MAP_NR(p));
+ free_page((unsigned long)p);
+ db->sgbuf[nr] = NULL;
+ }
+ db->mapped = db->ready = 0;
+}
+
+static int dmabuf_init(struct dmabuf *db)
+{
+ unsigned int nr, bytepersec, bufs;
+ void *p;
+
+ /* initialize some fields */
+ db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
+ /* calculate required buffer size */
+ bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
+ bufs = 1U << DMABUFSHIFT;
+ if (db->ossfragshift) {
+ if ((1000 << db->ossfragshift) < bytepersec)
+ db->fragshift = ld2(bytepersec/1000);
+ else
+ db->fragshift = db->ossfragshift;
+ } else {
+ db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+ if (db->fragshift < 3)
+ db->fragshift = 3;
+ }
+ db->numfrag = bufs >> db->fragshift;
+ while (db->numfrag < 4 && db->fragshift > 3) {
+ db->fragshift--;
+ db->numfrag = bufs >> db->fragshift;
+ }
+ db->fragsize = 1 << db->fragshift;
+ if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+ db->numfrag = db->ossmaxfrags;
+ db->dmasize = db->numfrag << db->fragshift;
+ for(nr = 0; nr < NRSGBUF; nr++) {
+ if (!db->sgbuf[nr]) {
+ p = (void *)get_free_page(GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ db->sgbuf[nr] = p;
+ mem_map_reserve(MAP_NR(p));
+ }
+ memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
+ if ((nr << PAGE_SHIFT) >= db->dmasize)
+ break;
+ }
+ db->bufsize = nr << PAGE_SHIFT;
+ db->ready = 1;
+ printk(KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
+ "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d\n",
+ bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
+ db->numfrag, db->dmasize, db->bufsize);
+ return 0;
+}
+
+static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
+{
+ unsigned int nr;
+
+ if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
+ return -EINVAL;
+ size >>= PAGE_SHIFT;
+ for(nr = 0; nr < size; nr++)
+ if (!db->sgbuf[nr])
+ return -EINVAL;
+ db->mapped = 1;
+ for(nr = 0; nr < size; nr++) {
+ if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
+ return -EAGAIN;
+ start += PAGE_SIZE;
+ }
+ return 0;
+}
+
+static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
+{
+ unsigned int pgrem, rem;
+
+ for (;;) {
+ if (size <= 0)
+ return;
+ pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
+ if (pgrem > size)
+ pgrem = size;
+ rem = db->dmasize - db->wrptr;
+ if (pgrem > rem)
+ pgrem = rem;
+ memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
+ size -= pgrem;
+ (char *)buffer += pgrem;
+ db->wrptr += pgrem;
+ if (db->wrptr >= db->dmasize)
+ db->wrptr = 0;
+ }
+}
+
+static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
+{
+ unsigned int pgrem, rem;
+
+ for (;;) {
+ if (size <= 0)
+ return;
+ pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
+ if (pgrem > size)
+ pgrem = size;
+ rem = db->dmasize - db->rdptr;
+ if (pgrem > rem)
+ pgrem = rem;
+ memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
+ size -= pgrem;
+ (char *)buffer += pgrem;
+ db->rdptr += pgrem;
+ if (db->rdptr >= db->dmasize)
+ db->rdptr = 0;
+ }
+}
+
+static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size)
+{
+ unsigned int pgrem, rem;
+
+ if (!db->ready || db->mapped)
+ return -EINVAL;
+ for (;;) {
+ if (size <= 0)
+ return 0;
+ pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+ if (pgrem > size)
+ pgrem = size;
+ rem = db->dmasize - ptr;
+ if (pgrem > rem)
+ pgrem = rem;
+ copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT);
+ size -= pgrem;
+ (char *)buffer += pgrem;
+ ptr += pgrem;
+ if (ptr >= db->dmasize)
+ ptr = 0;
+ }
+}
+
+static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size)
+{
+ unsigned int pgrem, rem;
+
+ if (!db->ready || db->mapped)
+ return -EINVAL;
+ for (;;) {
+ if (size <= 0)
+ return 0;
+ pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+ if (pgrem > size)
+ pgrem = size;
+ rem = db->dmasize - ptr;
+ if (pgrem > rem)
+ pgrem = rem;
+ copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT);
+ size -= pgrem;
+ (char *)buffer += pgrem;
+ ptr += pgrem;
+ if (ptr >= db->dmasize)
+ ptr = 0;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * USB I/O code. We do sample format conversion if necessary
+ */
+
+static void usbin_stop(struct usb_audiodev *as)
+{
+ struct usbin *u = &as->usbin;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&as->lock, flags);
+ u->flags &= ~FLG_RUNNING;
+ i = u->flags;
+ spin_unlock_irqrestore(&as->lock, flags);
+ while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+ schedule_timeout(1);
+ spin_lock_irqsave(&as->lock, flags);
+ i = u->flags;
+ spin_unlock_irqrestore(&as->lock, flags);
+ }
+ if (u->dataiso[0])
+ usb_free_isoc(u->dataiso[0]);
+ if (u->dataiso[1])
+ usb_free_isoc(u->dataiso[1]);
+ if (u->synciso[0])
+ usb_free_isoc(u->synciso[0]);
+ if (u->synciso[1])
+ usb_free_isoc(u->synciso[1]);
+ u->dataiso[0] = u->dataiso[1] = u->synciso[0] = u->synciso[1] = NULL;
+}
+
+static void usbin_release(struct usb_audiodev *as)
+{
+ struct usbin *u = &as->usbin;
+
+ usbin_stop(as);
+ if (u->data[0])
+ free_page((unsigned long)u->data[0]);
+ if (u->data[1])
+ free_page((unsigned long)u->data[1]);
+ if (u->syncdata[0])
+ free_page((unsigned long)u->syncdata[0]);
+ if (u->syncdata[1])
+ free_page((unsigned long)u->syncdata[1]);
+ u->data[0] = u->data[1] = u->syncdata[0] = u->syncdata[1] = NULL;
+}
+
+static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
+{
+ union {
+ __s16 s[64];
+ unsigned char b[0];
+ } tmp;
+ unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
+ __s16 *sp, *sp2, s;
+ unsigned char *bp;
+
+ ufmtsh = AFMT_BYTESSHIFT(u->format);
+ dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+ maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+ while (samples > 0) {
+ scnt = samples;
+ if (scnt > maxs)
+ scnt = maxs;
+ cnt = scnt;
+ if (AFMT_ISSTEREO(u->format))
+ cnt <<= 1;
+ sp = tmp.s + cnt;
+ switch (u->format & ~AFMT_STEREO) {
+ case AFMT_U8:
+ for (bp = buffer+cnt, i = 0; i < cnt; i++) {
+ bp--;
+ sp--;
+ *sp = (*bp ^ 0x80) << 8;
+ }
+ break;
+
+ case AFMT_S8:
+ for (bp = buffer+cnt, i = 0; i < cnt; i++) {
+ bp--;
+ sp--;
+ *sp = *bp << 8;
+ }
+ break;
+
+ case AFMT_U16_LE:
+ for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+ }
+ break;
+
+ case AFMT_U16_BE:
+ for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+ }
+ break;
+
+ case AFMT_S16_LE:
+ for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = bp[0] | (bp[1] << 8);
+ }
+ break;
+
+ case AFMT_S16_BE:
+ for (bp = buffer+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = bp[1] | (bp[0] << 8);
+ }
+ break;
+ }
+ if (!AFMT_ISSTEREO(u->format) && AFMT_ISSTEREO(u->dma.format)) {
+ /* expand from mono to stereo */
+ for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
+ sp--;
+ sp2 -= 2;
+ sp2[0] = sp2[1] = sp[0];
+ }
+ }
+ if (AFMT_ISSTEREO(u->format) && !AFMT_ISSTEREO(u->dma.format)) {
+ /* contract from stereo to mono */
+ for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
+ sp[0] = (sp2[0] + sp2[1]) >> 1;
+ }
+ cnt = scnt;
+ if (AFMT_ISSTEREO(u->dma.format))
+ cnt <<= 1;
+ sp = tmp.s;
+ bp = tmp.b;
+ switch (u->dma.format & ~AFMT_STEREO) {
+ case AFMT_U8:
+ for (i = 0; i < cnt; i++, sp++, bp++)
+ *bp = (*sp >> 8) ^ 0x80;
+ break;
+
+ case AFMT_S8:
+ for (i = 0; i < cnt; i++, sp++, bp++)
+ *bp = *sp >> 8;
+ break;
+
+ case AFMT_U16_LE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[0] = s;
+ bp[1] = (s >> 8) ^ 0x80;
+ }
+ break;
+
+ case AFMT_U16_BE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[1] = s;
+ bp[0] = (s >> 8) ^ 0x80;
+ }
+ break;
+
+ case AFMT_S16_LE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[0] = s;
+ bp[1] = s >> 8;
+ }
+ break;
+
+ case AFMT_S16_BE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[1] = s;
+ bp[0] = s >> 8;
+ }
+ break;
+ }
+ dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
+ buffer += scnt << ufmtsh;
+ samples -= scnt;
+ }
+}
+
+static int usbin_prepare_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+ unsigned int i, maxsize;
+
+ maxsize = (u->freqn + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+ printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
+ for (i = 0; i < DESCFRAMES; i++)
+ id->frames[i].frame_length = maxsize;
+ return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ * convert sample format on the fly if necessary
+ */
+static int usbin_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+ unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree, maxsize;
+ unsigned char *cp = id->data;
+
+ ufmtsh = AFMT_BYTESSHIFT(u->format);
+ maxsize = (u->freqn + 0x3fff) >> (14 - ufmtsh);
+ dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+ for (i = 0; i < DESCFRAMES; i++, cp += maxsize) {
+ if (id->frames[i].frame_status) {
+ printk(KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+ continue;
+ }
+ scnt = id->frames[i].frame_length >> ufmtsh;
+ if (!scnt)
+ continue;
+ cnt = scnt << dfmtsh;
+ if (!u->dma.mapped) {
+ dmafree = u->dma.dmasize - u->dma.count;
+ if (cnt > dmafree) {
+ scnt = dmafree >> dfmtsh;
+ cnt = scnt << dfmtsh;
+ err++;
+ }
+ }
+ u->dma.count += cnt;
+ if (u->format == u->dma.format) {
+ /* we do not need format conversion */
+ dmabuf_copyin(&u->dma, cp, cnt);
+ } else {
+ /* we need sampling format conversion */
+ usbin_convert(u, cp, scnt);
+ }
+ }
+ if (err)
+ u->dma.error++;
+ if (u->dma.count >= (signed)u->dma.fragsize)
+ wake_up(&u->dma.wait);
+ return err ? -1 : 0;
+}
+
+static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+ struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+ struct usb_isoc_desc *id;
+#endif
+ struct usbin *u = &as->usbin;
+ unsigned long flags;
+ unsigned int next, idmask;
+
+#if 0
+ printk(KERN_DEBUG "usbin_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+#endif
+ spin_lock_irqsave(&as->lock, flags);
+ next = !(u->flags & FLG_NEXTID);
+ idmask = FLG_ID1RUNNING >> next;
+ u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
+ id = u->dataiso[!next];
+ if (!usbin_retire_desc(u, id) &&
+ u->flags & FLG_RUNNING &&
+ !usbin_prepare_desc(u, id) &&
+ !usb_run_isoc(id, u->dataiso[next])) {
+ u->flags |= idmask;
+ } else {
+ u->flags &= ~FLG_RUNNING;
+ printk(KERN_DEBUG "usbin_completed: descriptor not restarted\n");
+ }
+ if (!(u->flags & idmask)) {
+ printk(KERN_DEBUG "usbin_completed: killing id\n");
+ usb_kill_isoc(id);
+ printk(KERN_DEBUG "usbin_completed: id killed\n");
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+ return 0;
+}
+
+/*
+ * we output sync data
+ */
+static int usbin_sync_prepare_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+ unsigned char *cp = id->data;
+ unsigned int i;
+
+ for (i = 0; i < DESCFRAMES; i++, cp += 3) {
+ id->frames[i].frame_length = 3;
+ cp[0] = u->freqn;
+ cp[1] = u->freqn >> 8;
+ cp[2] = u->freqn >> 16;
+ }
+ return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbin_sync_retire_desc(struct usbin *u, struct usb_isoc_desc *id)
+{
+ unsigned int i;
+
+ for (i = 0; i < DESCFRAMES; i++) {
+ if (id->frames[i].frame_status) {
+ printk(KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+ continue;
+ }
+ }
+ return 0;
+}
+
+static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+ struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+ struct usb_isoc_desc *id;
+#endif
+ struct usbin *u = &as->usbin;
+ unsigned long flags;
+ unsigned int next, idmask;
+
+#if 0
+ printk(KERN_DEBUG "usbin_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+#endif
+ spin_lock_irqsave(&as->lock, flags);
+ next = !(u->flags & FLG_SYNCNEXTID);
+ idmask = FLG_SYNC1RUNNING >> next;
+ u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
+ id = u->synciso[!next];
+ if (!usbin_sync_retire_desc(u, id) &&
+ u->flags & FLG_RUNNING &&
+ !usbin_sync_prepare_desc(u, id) &&
+ !usb_run_isoc(id, u->synciso[next])) {
+ u->flags |= idmask;
+ } else {
+ u->flags &= ~FLG_RUNNING;
+ printk(KERN_DEBUG "usbin_sync_completed: descriptor not restarted\n");
+ }
+ if (!(u->flags & idmask)) {
+ printk(KERN_DEBUG "usbin_sync_completed: killing id\n");
+ usb_kill_isoc(id);
+ printk(KERN_DEBUG "usbin_sync_completed: id killed\n");
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+ return 0;
+}
+
+static void usbin_start(struct usb_audiodev *as)
+{
+ struct usb_device *dev = as->state->usbdev;
+ struct usbin *u = &as->usbin;
+ struct usb_isoc_desc *id;
+ unsigned long flags;
+ unsigned int which, i;
+
+#if 0
+ printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
+ dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
+ /* allocate USB storage if not already done */
+ /* UHCI wants the data to be page aligned - this is silly */
+ if (!u->data[0])
+ u->data[0] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->data[1])
+ u->data[1] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->dataiso[0] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+0)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->datapipe);
+ u->dataiso[0] = NULL;
+ }
+ if (!u->dataiso[1] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+1)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->datapipe);
+ u->dataiso[1] = NULL;
+ }
+ if (u->syncpipe) {
+ if (!u->syncdata[0])
+ u->syncdata[0] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->syncdata[1])
+ u->syncdata[1] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->synciso[0] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+0)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->syncpipe);
+ u->synciso[0] = NULL;
+ }
+ if (!u->synciso[1] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+1)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->syncpipe);
+ u->synciso[1] = NULL;
+ }
+ }
+ if (!u->data[0] || !u->data[1] || !u->dataiso[0] || !u->dataiso[1] ||
+ (u->syncpipe && (!u->syncdata[0] || !u->syncdata[1] || !u->synciso[0] || !u->synciso[1]))) {
+ printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+ return;
+ }
+ spin_lock_irqsave(&as->lock, flags);
+ if (!(u->flags & FLG_RUNNING)) {
+ u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+ u->phase = 0;
+ }
+ u->flags |= FLG_RUNNING;
+ if (!(u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) {
+ id = u->dataiso[0];
+ id->start_type = START_ASAP;
+ id->start_frame = 0;
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbin_completed;
+ id->data = u->data[0];
+ id->buf_size = PAGE_SIZE;
+ u->flags &= ~FLG_NEXTID;
+ if (!usbin_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+ u->flags |= FLG_ID0RUNNING;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ i = u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING);
+ if (u->flags & FLG_RUNNING && (i == FLG_ID0RUNNING || i == FLG_ID1RUNNING)) {
+ which = !(u->flags & FLG_ID1RUNNING);
+ id = u->dataiso[which];
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbin_completed;
+ id->data = u->data[which];
+ id->buf_size = PAGE_SIZE;
+ if (!usbin_prepare_desc(u, id) && !usb_run_isoc(id, u->dataiso[!which]))
+ u->flags |= FLG_ID0RUNNING << which;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ if (u->syncpipe) {
+ if (!(u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING))) {
+ id = u->synciso[0];
+ id->start_type = START_ASAP;
+ id->start_frame = 0;
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbin_sync_completed;
+ id->data = u->syncdata[0];
+ id->buf_size = PAGE_SIZE;
+ u->flags &= ~FLG_SYNCNEXTID;
+ if (!usbin_sync_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+ u->flags |= FLG_SYNC0RUNNING;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ i = u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING);
+ if (u->flags & FLG_RUNNING && (i == FLG_SYNC0RUNNING || i == FLG_SYNC1RUNNING)) {
+ which = !(u->flags & FLG_SYNC1RUNNING);
+ id = u->synciso[which];
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbin_sync_completed;
+ id->data = u->syncdata[which];
+ id->buf_size = PAGE_SIZE;
+ if (!usbin_sync_prepare_desc(u, id) && !usb_run_isoc(id, u->synciso[!which]))
+ u->flags |= FLG_SYNC0RUNNING << which;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+}
+
+static void usbout_stop(struct usb_audiodev *as)
+{
+ struct usbout *u = &as->usbout;
+ unsigned long flags;
+ unsigned int i;
+
+printk(KERN_DEBUG "usb_audio: usbout_stop (1) flags 0x%04x\n", u->flags);
+ spin_lock_irqsave(&as->lock, flags);
+ u->flags &= ~FLG_RUNNING;
+ i = u->flags;
+ spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i);
+ while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+ schedule_timeout(1);
+ spin_lock_irqsave(&as->lock, flags);
+ i = u->flags;
+ spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i);
+ }
+ if (u->dataiso[0])
+ usb_free_isoc(u->dataiso[0]);
+ if (u->dataiso[1])
+ usb_free_isoc(u->dataiso[1]);
+ if (u->synciso[0])
+ usb_free_isoc(u->synciso[0]);
+ if (u->synciso[1])
+ usb_free_isoc(u->synciso[1]);
+ u->dataiso[0] = u->dataiso[1] = u->synciso[0] = u->synciso[1] = NULL;
+}
+
+static void usbout_release(struct usb_audiodev *as)
+{
+ struct usbout *u = &as->usbout;
+
+ usbout_stop(as);
+ if (u->data[0])
+ free_page((unsigned long)u->data[0]);
+ if (u->data[1])
+ free_page((unsigned long)u->data[1]);
+ if (u->syncdata[0])
+ free_page((unsigned long)u->syncdata[0]);
+ if (u->syncdata[1])
+ free_page((unsigned long)u->syncdata[1]);
+ u->data[0] = u->data[1] = u->syncdata[0] = u->syncdata[1] = NULL;
+}
+
+static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
+{
+ union {
+ __s16 s[64];
+ unsigned char b[0];
+ } tmp;
+ unsigned int scnt, maxs, ufmtsh, dfmtsh, cnt, i;
+ __s16 *sp, *sp2, s;
+ unsigned char *bp;
+
+ ufmtsh = AFMT_BYTESSHIFT(u->format);
+ dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+ maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+ while (samples > 0) {
+ scnt = samples;
+ if (scnt > maxs)
+ scnt = maxs;
+ cnt = scnt;
+ if (AFMT_ISSTEREO(u->dma.format))
+ cnt <<= 1;
+ dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
+ sp = tmp.s + cnt;
+ switch (u->dma.format & ~AFMT_STEREO) {
+ case AFMT_U8:
+ for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
+ bp--;
+ sp--;
+ *sp = (*bp ^ 0x80) << 8;
+ }
+ break;
+
+ case AFMT_S8:
+ for (bp = tmp.b+cnt, i = 0; i < cnt; i++) {
+ bp--;
+ sp--;
+ *sp = *bp << 8;
+ }
+ break;
+
+ case AFMT_U16_LE:
+ for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+ }
+ break;
+
+ case AFMT_U16_BE:
+ for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+ }
+ break;
+
+ case AFMT_S16_LE:
+ for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = bp[0] | (bp[1] << 8);
+ }
+ break;
+
+ case AFMT_S16_BE:
+ for (bp = tmp.b+2*cnt, i = 0; i < cnt; i++) {
+ bp -= 2;
+ sp--;
+ *sp = bp[1] | (bp[0] << 8);
+ }
+ break;
+ }
+ if (!AFMT_ISSTEREO(u->dma.format) && AFMT_ISSTEREO(u->format)) {
+ /* expand from mono to stereo */
+ for (sp = tmp.s+scnt, sp2 = tmp.s+2*scnt, i = 0; i < scnt; i++) {
+ sp--;
+ sp2 -= 2;
+ sp2[0] = sp2[1] = sp[0];
+ }
+ }
+ if (AFMT_ISSTEREO(u->dma.format) && !AFMT_ISSTEREO(u->format)) {
+ /* contract from stereo to mono */
+ for (sp = sp2 = tmp.s, i = 0; i < scnt; i++, sp++, sp2 += 2)
+ sp[0] = (sp2[0] + sp2[1]) >> 1;
+ }
+ cnt = scnt;
+ if (AFMT_ISSTEREO(u->format))
+ cnt <<= 1;
+ sp = tmp.s;
+ bp = buffer;
+ switch (u->format & ~AFMT_STEREO) {
+ case AFMT_U8:
+ for (i = 0; i < cnt; i++, sp++, bp++)
+ *bp = (*sp >> 8) ^ 0x80;
+ break;
+
+ case AFMT_S8:
+ for (i = 0; i < cnt; i++, sp++, bp++)
+ *bp = *sp >> 8;
+ break;
+
+ case AFMT_U16_LE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[0] = s;
+ bp[1] = (s >> 8) ^ 0x80;
+ }
+ break;
+
+ case AFMT_U16_BE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[1] = s;
+ bp[0] = (s >> 8) ^ 0x80;
+ }
+ break;
+
+ case AFMT_S16_LE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[0] = s;
+ bp[1] = s >> 8;
+ }
+ break;
+
+ case AFMT_S16_BE:
+ for (i = 0; i < cnt; i++, sp++, bp += 2) {
+ s = *sp;
+ bp[1] = s;
+ bp[0] = s >> 8;
+ }
+ break;
+ }
+ buffer += scnt << ufmtsh;
+ samples -= scnt;
+ }
+}
+
+static int usbout_prepare_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+ unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt;
+ unsigned char *cp = id->data;
+
+ ufmtsh = AFMT_BYTESSHIFT(u->format);
+ dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+ for (i = 0; i < DESCFRAMES; i++) {
+ u->phase = (u->phase & 0x3fff) + u->freqm;
+ scnt = u->phase >> 14;
+ if (!scnt) {
+ id->frames[i].frame_length = 0;
+ continue;
+ }
+ cnt = scnt << dfmtsh;
+ if (!u->dma.mapped) {
+ if (cnt > u->dma.count) {
+ scnt = u->dma.count >> dfmtsh;
+ cnt = scnt << dfmtsh;
+ err++;
+ }
+ u->dma.count -= cnt;
+ } else
+ u->dma.count += cnt;
+ if (u->format == u->dma.format) {
+ /* we do not need format conversion */
+ dmabuf_copyout(&u->dma, cp, cnt);
+ } else {
+ /* we need sampling format conversion */
+ usbout_convert(u, cp, scnt);
+ }
+ cnt = scnt << ufmtsh;
+ id->frames[i].frame_length = cnt;
+ cp += cnt;
+ }
+ if (err)
+ u->dma.error++;
+ if (u->dma.mapped) {
+ if (u->dma.count >= (signed)u->dma.fragsize)
+ wake_up(&u->dma.wait);
+ } else {
+ if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
+ wake_up(&u->dma.wait);
+ }
+ return err ? -1 : 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+ unsigned int i;
+
+ for (i = 0; i < DESCFRAMES; i++) {
+ if (id->frames[i].frame_status) {
+ printk(KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+ continue;
+ }
+ }
+ return 0;
+}
+
+static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+ struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+ struct usb_isoc_desc *id;
+#endif
+ struct usbout *u = &as->usbout;
+ unsigned long flags;
+ unsigned int next, idmask;
+
+#if 0
+ printk(KERN_DEBUG "usbout_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+#endif
+ spin_lock_irqsave(&as->lock, flags);
+ next = !(u->flags & FLG_NEXTID);
+ idmask = FLG_ID1RUNNING >> next;
+ u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
+ id = u->dataiso[!next];
+ if (!usbout_retire_desc(u, id) &&
+ u->flags & FLG_RUNNING &&
+ !usbout_prepare_desc(u, id) &&
+ !usb_run_isoc(id, u->dataiso[next])) {
+ u->flags |= idmask;
+ } else {
+ u->flags &= ~FLG_RUNNING;
+ printk(KERN_DEBUG "usbout_completed: descriptor not restarted\n");
+ }
+ if (!(u->flags & idmask)) {
+ printk(KERN_DEBUG "usbout_completed: killing id\n");
+ usb_kill_isoc(id);
+ printk(KERN_DEBUG "usbout_completed: id killed\n");
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+ return 0;
+}
+
+static int usbout_sync_prepare_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+ unsigned int i;
+
+ for (i = 0; i < DESCFRAMES; i++)
+ id->frames[i].frame_length = 3;
+ return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_sync_retire_desc(struct usbout *u, struct usb_isoc_desc *id)
+{
+ unsigned char *cp = id->data;
+ unsigned int i, f;
+
+ for (i = 0; i < DESCFRAMES; i++, cp += 3) {
+ if (id->frames[i].frame_status) {
+ printk(KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, id->frames[i].frame_status);
+ continue;
+ }
+ if (id->frames[i].frame_length < 3) {
+ printk(KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, id->frames[i].frame_length);
+ continue;
+ }
+ f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
+ if (abs(f - u->freqn) > (u->freqn >> 3)) {
+ printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
+ continue;
+ }
+ u->freqm = f;
+ }
+ return 0;
+}
+
+static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct usb_audiodev *as = (struct usb_audiodev *)id->context;
+#else
+ struct usb_audiodev *as = (struct usb_audiodev *)dev_id;
+ struct usb_isoc_desc *id;
+#endif
+ struct usbout *u = &as->usbout;
+ unsigned long flags;
+ unsigned int next, idmask;
+
+#if 0
+ printk(KERN_DEBUG "usbout_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
+#endif
+ spin_lock_irqsave(&as->lock, flags);
+ next = !(u->flags & FLG_SYNCNEXTID);
+ idmask = FLG_SYNC1RUNNING >> next;
+ u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
+ id = u->synciso[!next];
+ if (!usbout_sync_retire_desc(u, id) &&
+ u->flags & FLG_RUNNING &&
+ !usbout_sync_prepare_desc(u, id) &&
+ !usb_run_isoc(id, u->synciso[next])) {
+ u->flags |= idmask;
+ } else {
+ u->flags &= ~FLG_RUNNING;
+ printk(KERN_DEBUG "usbout_sync_completed: descriptor not restarted\n");
+ }
+ if (!(u->flags & idmask)) {
+ printk(KERN_DEBUG "usbout_sync_completed: killing id\n");
+ usb_kill_isoc(id);
+ printk(KERN_DEBUG "usbout_sync_completed: id killed\n");
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+ return 0;
+}
+
+static void usbout_start(struct usb_audiodev *as)
+{
+ struct usb_device *dev = as->state->usbdev;
+ struct usbout *u = &as->usbout;
+ struct usb_isoc_desc *id;
+ unsigned long flags;
+ unsigned int which, i;
+
+#if 0
+ printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
+ dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
+ /* allocate USB storage if not already done */
+ /* UHCI wants the data to be page aligned - this is silly */
+ if (!u->data[0])
+ u->data[0] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->data[1])
+ u->data[1] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->dataiso[0] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+0)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->datapipe);
+ u->dataiso[0] = NULL;
+ }
+ if (!u->dataiso[1] && usb_init_isoc(dev, u->datapipe, DESCFRAMES, as, u->dataiso+1)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->datapipe);
+ u->dataiso[1] = NULL;
+ }
+ if (u->syncpipe) {
+ if (!u->syncdata[0])
+ u->syncdata[0] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->syncdata[1])
+ u->syncdata[1] = (void *)get_free_page(GFP_KERNEL);
+ if (!u->synciso[0] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+0)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->syncpipe);
+ u->synciso[0] = NULL;
+ }
+ if (!u->synciso[1] && usb_init_isoc(dev, u->syncpipe, DESCFRAMES, as, u->synciso+1)) {
+ printk(KERN_ERR "usbaudio: cannot init isoc descriptor device %d pipe 0x%08x\n",
+ dev->devnum, u->syncpipe);
+ u->synciso[1] = NULL;
+ }
+ }
+ if (!u->data[0] || !u->data[1] || !u->dataiso[0] || !u->dataiso[1] ||
+ (u->syncpipe && (!u->syncdata[0] || !u->syncdata[1] || !u->synciso[0] || !u->synciso[1]))) {
+ printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+ return;
+ }
+ spin_lock_irqsave(&as->lock, flags);
+ if (!(u->flags & FLG_RUNNING)) {
+ u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+ u->phase = 0;
+ }
+ u->flags |= FLG_RUNNING;
+ if (!(u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING))) {
+ id = u->dataiso[0];
+ id->start_type = START_ASAP;
+ id->start_frame = 0;
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbout_completed;
+ id->data = u->data[0];
+ id->buf_size = PAGE_SIZE;
+ u->flags &= ~FLG_NEXTID;
+ if (!usbout_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+ u->flags |= FLG_ID0RUNNING;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ i = u->flags & (FLG_ID0RUNNING|FLG_ID1RUNNING);
+ if (u->flags & FLG_RUNNING && (i == FLG_ID0RUNNING || i == FLG_ID1RUNNING)) {
+ which = !(u->flags & FLG_ID1RUNNING);
+ id = u->dataiso[which];
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbout_completed;
+ id->data = u->data[which];
+ id->buf_size = PAGE_SIZE;
+ if (!usbout_prepare_desc(u, id) && !usb_run_isoc(id, u->dataiso[!which]))
+ u->flags |= FLG_ID0RUNNING << which;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ if (u->syncpipe) {
+ if (!(u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING))) {
+ id = u->synciso[0];
+ id->start_type = START_ASAP;
+ id->start_frame = 0;
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbout_sync_completed;
+ id->data = u->syncdata[0];
+ id->buf_size = PAGE_SIZE;
+ u->flags &= ~FLG_NEXTID;
+ if (!usbout_sync_prepare_desc(u, id) && !usb_run_isoc(id, NULL))
+ u->flags |= FLG_SYNC0RUNNING;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ i = u->flags & (FLG_SYNC0RUNNING|FLG_SYNC1RUNNING);
+ if (u->flags & FLG_RUNNING && (i == FLG_SYNC0RUNNING || i == FLG_SYNC1RUNNING)) {
+ which = !(u->flags & FLG_SYNC1RUNNING);
+ id = u->synciso[which];
+ id->callback_frames = /*0*/DESCFRAMES;
+ id->callback_fn = usbout_sync_completed;
+ id->data = u->syncdata[which];
+ id->buf_size = PAGE_SIZE;
+ if (!usbout_sync_prepare_desc(u, id) && !usb_run_isoc(id, u->synciso[!which]))
+ u->flags |= FLG_SYNC0RUNNING << which;
+ else
+ u->flags &= ~FLG_RUNNING;
+ }
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+}
+
+/* --------------------------------------------------------------------- */
+
+static unsigned int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt)
+{
+ unsigned int i;
+
+ /* first find an exact match */
+ for (i = 0; i < nr; i++)
+ if (afp[i].format == fmt)
+ return i;
+ /* second find a match with the same stereo/mono and 8bit/16bit property */
+ for (i = 0; i < nr; i++)
+ if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt) &&
+ !AFMT_IS16BIT(afp[i].format) == !AFMT_IS16BIT(fmt))
+ return i;
+ /* third find a match with the same number of channels */
+ for (i = 0; i < nr; i++)
+ if (!AFMT_ISSTEREO(afp[i].format) == !AFMT_ISSTEREO(fmt))
+ return i;
+ /* return anything */
+ return 0;
+}
+
+static int set_format_in(struct usb_audiodev *as)
+{
+ struct usb_device *dev = as->state->usbdev;
+ struct usb_config_descriptor *config = dev->actconfig;
+ struct usb_interface_descriptor *alts;
+ struct usb_interface *iface;
+ struct usbin *u = &as->usbin;
+ struct dmabuf *d = &u->dma;
+ struct audioformat *fmt;
+ unsigned int fmtnr, ep;
+ unsigned char data[3];
+
+ if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+ return 0;
+ iface = &config->interface[u->interface];
+ fmtnr = find_format(as->fmtin, as->numfmtin, d->format);
+ fmt = as->fmtin + fmtnr;
+ alts = &iface->altsetting[fmt->altsetting];
+ u->format = fmt->format;
+ u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+ u->syncpipe = u->syncinterval = 0;
+ if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) {
+ if (alts->bNumEndpoints < 2 ||
+ alts->endpoint[1].bmAttributes != 0x01 ||
+ alts->endpoint[1].bSynchAddress != 0 ||
+ alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) {
+ printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
+ dev->devnum, u->interface, fmt->altsetting);
+ return -1;
+ }
+ u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+ u->syncinterval = alts->endpoint[1].bRefresh;
+ }
+ if (d->srate < fmt->sratelo)
+ d->srate = fmt->sratelo;
+ if (d->srate > fmt->sratehi)
+ d->srate = fmt->sratehi;
+ if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
+ printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+ dev->devnum, u->interface, fmt->altsetting);
+ return -1;
+ }
+ if (fmt->sratelo == fmt->sratehi)
+ return 0;
+ data[0] = d->srate;
+ data[1] = d->srate >> 8;
+ data[2] = d->srate >> 16;
+ ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+ printk(KERN_ERR "usbaudio: failure to set input sampling frequency device %d endpoint 0x%x to %u\n",
+ dev->devnum, ep, d->srate);
+ return -1;
+ }
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+ printk(KERN_ERR "usbaudio: failure to get input sampling frequency device %d endpoint 0x%x\n",
+ dev->devnum, ep);
+ return -1;
+ }
+ printk(KERN_DEBUG "usb_audio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
+ dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
+ d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+ return 0;
+}
+
+static int set_format_out(struct usb_audiodev *as)
+{
+ struct usb_device *dev = as->state->usbdev;
+ struct usb_config_descriptor *config = dev->actconfig;
+ struct usb_interface_descriptor *alts;
+ struct usb_interface *iface;
+ struct usbout *u = &as->usbout;
+ struct dmabuf *d = &u->dma;
+ struct audioformat *fmt;
+ unsigned int fmtnr, ep;
+ unsigned char data[3];
+
+ if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+ return 0;
+ iface = &config->interface[u->interface];
+ fmtnr = find_format(as->fmtout, as->numfmtout, d->format);
+ fmt = as->fmtout + fmtnr;
+ u->format = fmt->format;
+ alts = &iface->altsetting[fmt->altsetting];
+ u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+ u->syncpipe = u->syncinterval = 0;
+ if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) {
+ if (alts->bNumEndpoints < 2 ||
+ alts->endpoint[1].bmAttributes != 0x01 ||
+ alts->endpoint[1].bSynchAddress != 0 ||
+ alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) {
+ printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
+ dev->devnum, u->interface, fmt->altsetting);
+ return -1;
+ }
+ u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+ u->syncinterval = alts->endpoint[1].bRefresh;
+ }
+ if (d->srate < fmt->sratelo)
+ d->srate = fmt->sratelo;
+ if (d->srate > fmt->sratehi)
+ d->srate = fmt->sratehi;
+ if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
+ printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+ dev->devnum, u->interface, fmt->altsetting);
+ return -1;
+ }
+ if (fmt->sratelo == fmt->sratehi)
+ return 0;
+ data[0] = d->srate;
+ data[1] = d->srate >> 8;
+ data[2] = d->srate >> 16;
+ ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+ printk(KERN_ERR "usbaudio: failure to set output sampling frequency device %d endpoint 0x%x to %u\n",
+ dev->devnum, ep, d->srate);
+ return -1;
+ }
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+ SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+ printk(KERN_ERR "usbaudio: failure to get output sampling frequency device %d endpoint 0x%x\n",
+ dev->devnum, ep);
+ return -1;
+ }
+ printk(KERN_DEBUG "usb_audio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
+ dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
+ d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+ return 0;
+}
+
+static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
+{
+ int ret1 = 0, ret2 = 0;
+
+ if (!(fmode & (FMODE_READ|FMODE_WRITE)))
+ return -EINVAL;
+ if (fmode & FMODE_READ) {
+ usbin_stop(s);
+ s->usbin.dma.ready = 0;
+ if (fmt == AFMT_QUERY)
+ fmt = s->usbin.dma.format;
+ else
+ s->usbin.dma.format = fmt;
+ if (!srate)
+ srate = s->usbin.dma.srate;
+ else
+ s->usbin.dma.srate = srate;
+ }
+ if (fmode & FMODE_WRITE) {
+ usbout_stop(s);
+ s->usbout.dma.ready = 0;
+ if (fmt == AFMT_QUERY)
+ fmt = s->usbout.dma.format;
+ else
+ s->usbout.dma.format = fmt;
+ if (!srate)
+ srate = s->usbout.dma.srate;
+ else
+ s->usbout.dma.srate = srate;
+ }
+ if (fmode & FMODE_READ)
+ ret1 = set_format_in(s);
+ if (fmode & FMODE_WRITE)
+ ret2 = set_format_out(s);
+ return ret1 ? ret1 : ret2;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
+{
+ struct usb_device *dev = ms->state->usbdev;
+ unsigned char data[2];
+ struct mixerchannel *ch;
+ int v1, v2, v3;
+
+ if (mixch >= ms->numch)
+ return -1;
+ ch = &ms->ch[mixch];
+ v3 = ch->maxval - ch->minval;
+ v1 = value & 0xff;
+ v2 = (value >> 8) & 0xff;
+ if (v1 > 100)
+ v1 = 100;
+ if (v2 > 100)
+ v2 = 100;
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+ v2 = v1;
+ ch->value = v1 | (v2 << 8);
+ v1 = (v1 * v3) / 100 + ch->minval;
+ v2 = (v2 * v3) / 100 + ch->minval;
+ switch (ch->selector) {
+ case 0: /* mixer unit request */
+ data[0] = v1;
+ data[1] = v1 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ goto err;
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+ return 0;
+ data[0] = v2;
+ data[1] = v2 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+ ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ goto err;
+ return 0;
+
+ /* various feature unit controls */
+ case VOLUME_CONTROL:
+ data[0] = v1;
+ data[1] = v1 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ goto err;
+ if (ch->chnum == 0)
+ return 0;
+ data[0] = v2;
+ data[1] = v2 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+ goto err;
+ return 0;
+
+ case BASS_CONTROL:
+ case MID_CONTROL:
+ case TREBLE_CONTROL:
+ data[0] = v1 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+ goto err;
+ if (ch->chnum == 0)
+ return 0;
+ data[0] = v2 >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+ goto err;
+ return 0;
+
+ default:
+ return -1;
+ }
+ return 0;
+
+ err:
+ printk(KERN_ERR "usb_audio: mixer request device %u if %u unit %u ch %u selector %u failed\n",
+ dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
+ return -1;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * should be called with open_sem hold, so that no new processes
+ * look at the audio device to be destroyed
+ */
+
+static void release(struct usb_audio_state *s)
+{
+ struct usb_audiodev *as;
+ struct usb_mixerdev *ms;
+
+ s->count--;
+ if (s->count) {
+ up(&open_sem);
+ return;
+ }
+ up(&open_sem);
+ wake_up(&open_wait);
+ while (!list_empty(&s->audiolist)) {
+ as = list_entry(s->audiolist.next, struct usb_audiodev, list);
+ list_del(&as->list);
+ usbin_release(as);
+ usbout_release(as);
+ dmabuf_release(&as->usbin.dma);
+ dmabuf_release(&as->usbout.dma);
+ kfree(as);
+ }
+ while (!list_empty(&s->mixerlist)) {
+ ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
+ list_del(&ms->list);
+ kfree(ms);
+ }
+ kfree(s);
+ MOD_DEC_USE_COUNT;
+}
+
+extern inline int prog_dmabuf_in(struct usb_audiodev *as)
+{
+ usbin_stop(as);
+ return dmabuf_init(&as->usbin.dma);
+}
+
+extern inline int prog_dmabuf_out(struct usb_audiodev *as)
+{
+ usbout_stop(as);
+ return dmabuf_init(&as->usbout.dma);
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ struct list_head *devs, *mdevs;
+ struct usb_mixerdev *ms;
+ struct usb_audio_state *s;
+
+ down(&open_sem);
+ for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+ s = list_entry(devs, struct usb_audio_state, audiodev);
+ for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) {
+ ms = list_entry(mdevs, struct usb_mixerdev, list);
+ if (ms->dev_mixer == minor)
+ goto mixer_found;
+ }
+ }
+ up(&open_sem);
+ return -ENODEV;
+
+ mixer_found:
+ if (!s->usbdev) {
+ up(&open_sem);
+ return -EIO;
+ }
+ file->private_data = ms;
+ s->count++;
+ up(&open_sem);
+ return 0;
+}
+
+static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
+{
+ struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+ struct usb_audio_state *s = ms->state;
+
+ down(&open_sem);
+ release(s);
+ return 0;
+}
+
+static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+ int i, j, val;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+ strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+ info.modify_counter = ms->modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+ strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ /* don't know how to handle this yet */
+ return put_user(0, (int *)arg);
+
+ case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+ for (val = i = 0; i < ms->numch; i++)
+ val |= 1 << ms->ch[i].osschannel;
+ return put_user(val, (int *)arg);
+
+ case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+ /* don't know how to handle this yet */
+ return put_user(0, (int *)arg);
+
+ case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+ for (val = i = 0; i < ms->numch; i++)
+ if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
+ val |= 1 << ms->ch[i].osschannel;
+ return put_user(val, (int *)arg);
+
+ case SOUND_MIXER_CAPS:
+ return put_user(0, (int *)arg);
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES)
+ return -EINVAL;
+ for (j = 0; j < ms->numch; j++) {
+ if (ms->ch[j].osschannel == i) {
+ return put_user(ms->ch[j].value, (int *)arg);
+ }
+ }
+ return -EINVAL;
+ }
+ }
+ if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE))
+ return -EINVAL;
+ ms->modcnt++;
+ switch (_IOC_NR(cmd)) {
+ case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+ get_user_ret(val, (int *)arg, -EFAULT);
+ /* set recording source: val */
+ return 0;
+
+ default:
+ i = _IOC_NR(cmd);
+ if (i >= SOUND_MIXER_NRDEVICES)
+ return -EINVAL;
+ for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
+ if (j >= ms->numch)
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (wrmixer(ms, j, val))
+ return -EIO;
+ return put_user(ms->ch[j].value, (int *)arg);
+ }
+}
+
+static /*const*/ struct file_operations usb_mixer_fops = {
+ &usb_audio_llseek,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ &usb_audio_ioctl_mixdev,
+ NULL, /* mmap */
+ &usb_audio_open_mixdev,
+ NULL, /* flush */
+ &usb_audio_release_mixdev,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_out(struct usb_audiodev *as, int nonblock)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int count, tmo;
+
+ if (as->usbout.dma.mapped || !as->usbout.dma.ready)
+ return 0;
+ __set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&as->usbout.dma.wait, &wait);
+ for (;;) {
+ spin_lock_irqsave(&as->lock, flags);
+ count = as->usbout.dma.count;
+ spin_unlock_irqrestore(&as->lock, flags);
+ if (count <= 0)
+ break;
+ if (signal_pending(current))
+ break;
+ if (nonblock) {
+ remove_wait_queue(&as->usbout.dma.wait, &wait);
+ set_current_state(TASK_RUNNING);
+ return -EBUSY;
+ }
+ tmo = 3 * HZ * count / as->usbout.dma.srate;
+ tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
+ if (!schedule_timeout(tmo + 1))
+ printk(KERN_DEBUG "usbaudio: dma timed out??\n");
+ }
+ remove_wait_queue(&as->usbout.dma.wait, &wait);
+ set_current_state(TASK_RUNNING);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t ret = 0;
+ unsigned long flags;
+ unsigned int ptr;
+ int cnt, err;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (as->usbin.dma.mapped)
+ return -ENXIO;
+ if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+ return ret;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
+ __set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&as->usbin.dma.wait, &wait);
+ while (count > 0) {
+ spin_lock_irqsave(&as->lock, flags);
+ ptr = as->usbin.dma.rdptr;
+ cnt = as->usbin.dma.count;
+ spin_unlock_irqrestore(&as->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ usbin_start(as);
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ continue;
+ }
+ if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
+ if (!ret)
+ ret = err;
+ break;
+ }
+ ptr += cnt;
+ if (ptr >= as->usbin.dma.dmasize)
+ ptr -= as->usbin.dma.dmasize;
+ spin_lock_irqsave(&as->lock, flags);
+ as->usbin.dma.rdptr = ptr;
+ as->usbin.dma.count -= cnt;
+ spin_unlock_irqrestore(&as->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&as->usbin.dma.wait, &wait);
+ return ret;
+}
+
+static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t ret = 0;
+ unsigned long flags;
+ unsigned int ptr;
+ int cnt, err;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ if (as->usbout.dma.mapped)
+ return -ENXIO;
+ if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+ return ret;
+ if (!access_ok(VERIFY_READ, buffer, count))
+ return -EFAULT;
+ __set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&as->usbout.dma.wait, &wait);
+ while (count > 0) {
+ spin_lock_irqsave(&as->lock, flags);
+ if (as->usbout.dma.count < 0) {
+ as->usbout.dma.count = 0;
+ as->usbout.dma.rdptr = as->usbout.dma.wrptr;
+ }
+ ptr = as->usbout.dma.wrptr;
+ cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
+ spin_unlock_irqrestore(&as->lock, flags);
+ if (cnt > count)
+ cnt = count;
+ if (cnt <= 0) {
+ usbout_start(as);
+ if (file->f_flags & O_NONBLOCK) {
+ if (!ret)
+ ret = -EAGAIN;
+ break;
+ }
+ schedule();
+ if (signal_pending(current)) {
+ if (!ret)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ continue;
+ }
+ if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
+ if (!ret)
+ ret = err;
+ break;
+ }
+ ptr += cnt;
+ if (ptr >= as->usbout.dma.dmasize)
+ ptr -= as->usbout.dma.dmasize;
+ spin_lock_irqsave(&as->lock, flags);
+ as->usbout.dma.wrptr = ptr;
+ as->usbout.dma.count += cnt;
+ spin_unlock_irqrestore(&as->lock, flags);
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+ usbout_start(as);
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&as->usbout.dma.wait, &wait);
+ return ret;
+}
+
+static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (!as->usbout.dma.ready)
+ prog_dmabuf_out(as);
+ poll_wait(file, &as->usbout.dma.wait, wait);
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (!as->usbin.dma.ready)
+ prog_dmabuf_in(as);
+ poll_wait(file, &as->usbin.dma.wait, wait);
+ }
+ spin_lock_irqsave(&as->lock, flags);
+ if (file->f_mode & FMODE_READ) {
+ if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
+ mask |= POLLIN | POLLRDNORM;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (as->usbout.dma.mapped) {
+ if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ } else {
+ if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+ return mask;
+}
+
+static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ struct dmabuf *db;
+ int ret;
+
+ if (vma->vm_flags & VM_WRITE) {
+ if ((ret = prog_dmabuf_out(as)) != 0)
+ return ret;
+ db = &as->usbout.dma;
+ } else if (vma->vm_flags & VM_READ) {
+ if ((ret = prog_dmabuf_in(as)) != 0)
+ return ret;
+ db = &as->usbin.dma;
+ } else
+ return -EINVAL;
+ if (vma->vm_offset != 0)
+ return -EINVAL;
+ return dmabuf_mmap(db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ struct usb_audio_state *s = as->state;
+ unsigned long flags;
+ audio_buf_info abinfo;
+ count_info cinfo;
+ int val, val2, mapped, ret;
+
+ if (!s->usbdev)
+ return -EIO;
+ mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
+ ((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+ DSP_CAP_MMAP | DSP_CAP_BATCH, (int *)arg);
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_WRITE) {
+ usbout_stop(as);
+ as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
+ }
+ if (file->f_mode & FMODE_READ) {
+ usbin_stop(as);
+ as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
+ }
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val >= 0) {
+ if (val < 4000)
+ val = 4000;
+ if (val > 100000)
+ val = 100000;
+ if (set_format(as, file->f_mode, AFMT_QUERY, val))
+ return -EIO;
+ }
+ return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ if (set_format(as, file->f_mode, val2 | AFMT_STEREO, 0))
+ return -EIO;
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 0) {
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ if (val == 1)
+ val2 &= ~AFMT_STEREO;
+ else
+ val2 |= AFMT_STEREO;
+ if (set_format(as, file->f_mode, val2, 0))
+ return -EIO;
+ }
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+ AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != AFMT_QUERY) {
+ if (hweight32(val) != 1)
+ return -EINVAL;
+ if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+ AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
+ return -EINVAL;
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ val |= val2 & AFMT_STEREO;
+ if (set_format(as, file->f_mode, val, 0))
+ return -EIO;
+ }
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ return put_user(val2 & ~AFMT_STEREO, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETTRIGGER:
+ val = 0;
+ if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING)
+ val |= PCM_ENABLE_INPUT;
+ if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING)
+ val |= PCM_ENABLE_OUTPUT;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_SETTRIGGER:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ if (val & PCM_ENABLE_INPUT) {
+ if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+ return ret;
+ usbin_start(as);
+ } else
+ usbin_stop(as);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ if (val & PCM_ENABLE_OUTPUT) {
+ if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+ return ret;
+ usbout_start(as);
+ } else
+ usbout_stop(as);
+ }
+ return 0;
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
+ return val;
+ spin_lock_irqsave(&as->lock, flags);
+ abinfo.fragsize = as->usbout.dma.fragsize;
+ abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
+ abinfo.fragstotal = as->usbout.dma.numfrag;
+ abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;
+ spin_unlock_irqrestore(&as->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
+ return val;
+ spin_lock_irqsave(&as->lock, flags);
+ abinfo.fragsize = as->usbin.dma.fragsize;
+ abinfo.bytes = as->usbin.dma.count;
+ abinfo.fragstotal = as->usbin.dma.numfrag;
+ abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;
+ spin_unlock_irqrestore(&as->lock, flags);
+ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_GETODELAY:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&as->lock, flags);
+ val = as->usbout.dma.count;
+ spin_unlock_irqrestore(&as->lock, flags);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETIPTR:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ spin_lock_irqsave(&as->lock, flags);
+ cinfo.bytes = as->usbin.dma.total_bytes;
+ cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
+ cinfo.ptr = as->usbin.dma.wrptr;
+ if (as->usbin.dma.mapped)
+ as->usbin.dma.count &= as->usbin.dma.fragsize-1;
+ spin_unlock_irqrestore(&as->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETOPTR:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ spin_lock_irqsave(&as->lock, flags);
+ cinfo.bytes = as->usbout.dma.total_bytes;
+ cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
+ cinfo.ptr = as->usbout.dma.rdptr;
+ if (as->usbout.dma.mapped)
+ as->usbout.dma.count &= as->usbout.dma.fragsize-1;
+ spin_unlock_irqrestore(&as->lock, flags);
+ return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (file->f_mode & FMODE_WRITE) {
+ if ((val = prog_dmabuf_out(as)))
+ return val;
+ return put_user(as->usbout.dma.fragsize, (int *)arg);
+ }
+ if ((val = prog_dmabuf_in(as)))
+ return val;
+ return put_user(as->usbin.dma.fragsize, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (file->f_mode & FMODE_READ) {
+ as->usbin.dma.ossfragshift = val & 0xffff;
+ as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
+ if (as->usbin.dma.ossfragshift < 4)
+ as->usbin.dma.ossfragshift = 4;
+ if (as->usbin.dma.ossfragshift > 15)
+ as->usbin.dma.ossfragshift = 15;
+ if (as->usbin.dma.ossmaxfrags < 4)
+ as->usbin.dma.ossmaxfrags = 4;
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ as->usbout.dma.ossfragshift = val & 0xffff;
+ as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
+ if (as->usbout.dma.ossfragshift < 4)
+ as->usbout.dma.ossfragshift = 4;
+ if (as->usbout.dma.ossfragshift > 15)
+ as->usbout.dma.ossfragshift = 15;
+ if (as->usbout.dma.ossmaxfrags < 4)
+ as->usbout.dma.ossmaxfrags = 4;
+ }
+ return 0;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
+ (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
+ return -EINVAL;
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val != 1 && val != 2 && val != 4)
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ as->usbin.dma.subdivision = val;
+ if (file->f_mode & FMODE_WRITE)
+ as->usbout.dma.subdivision = val;
+ return 0;
+
+ case SOUND_PCM_READ_RATE:
+ return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ return put_user(AFMT_IS16BIT(val2) ? 16 : 8, (int *)arg);
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int usb_audio_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
+ struct list_head *devs, *adevs;
+ struct usb_audiodev *as;
+ struct usb_audio_state *s;
+
+ for (;;) {
+ down(&open_sem);
+ for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+ s = list_entry(devs, struct usb_audio_state, audiodev);
+ for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) {
+ as = list_entry(adevs, struct usb_audiodev, list);
+ if (!((as->dev_audio ^ minor) & ~0xf))
+ goto device_found;
+ }
+ }
+ up(&open_sem);
+ return -ENODEV;
+
+ device_found:
+ if (!s->usbdev) {
+ up(&open_sem);
+ return -EIO;
+ }
+ /* wait for device to become free */
+ if (!(as->open_mode & file->f_mode))
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ up(&open_sem);
+ return -EBUSY;
+ }
+ __set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&open_wait, &wait);
+ up(&open_sem);
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&open_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+ if (file->f_mode & FMODE_READ)
+ as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
+ if (file->f_mode & FMODE_WRITE)
+ as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
+ if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
+ up(&open_sem);
+ return -EIO;
+ }
+ file->private_data = as;
+ as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+ s->count++;
+ up(&open_sem);
+ return 0;
+}
+
+static int usb_audio_release(struct inode *inode, struct file *file)
+{
+ struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+ struct usb_audio_state *s = as->state;
+
+ if (file->f_mode & FMODE_WRITE)
+ drain_out(as, file->f_flags & O_NONBLOCK);
+ down(&open_sem);
+ if (file->f_mode & FMODE_WRITE) {
+ usbout_stop(as);
+ if (s->usbdev)
+ usb_set_interface(s->usbdev, as->usbout.interface, 0);
+ dmabuf_release(&as->usbout.dma);
+ usbout_release(as);
+ }
+ if (file->f_mode & FMODE_READ) {
+ usbin_stop(as);
+ if (s->usbdev)
+ usb_set_interface(s->usbdev, as->usbin.interface, 0);
+ dmabuf_release(&as->usbin.dma);
+ usbin_release(as);
+ }
+ as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+ release(s);
+ wake_up(&open_wait);
+ return 0;
+}
+
+static /*const*/ struct file_operations usb_audio_fops = {
+ &usb_audio_llseek,
+ &usb_audio_read,
+ &usb_audio_write,
+ NULL, /* readdir */
+ &usb_audio_poll,
+ &usb_audio_ioctl,
+ &usb_audio_mmap,
+ &usb_audio_open,
+ NULL, /* flush */
+ &usb_audio_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * TO DO in order to get to the point of building an OSS interface
+ * structure, let alone playing music..
+ *
+ * Use kmalloc/kfree for the descriptors we build
+ * Write the descriptor->OSS convertor code
+ * Figure how we deal with mixers
+ * Check alternate configurations. For now assume we will find one
+ * zero bandwidth (idle) config and one or more live one pers interface.
+ */
+
+static int usb_audio_probe(struct usb_device *dev);
+static void usb_audio_disconnect(struct usb_device *dev);
+
static struct usb_driver usb_audio_driver = {
"audio",
usb_audio_probe,
@@ -32,7 +2547,7 @@ static struct usb_driver usb_audio_driver = {
static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
{
#if 0
- struct usb_audio *aud = (struct usb_audio *)dev_id;
+ struct usb_audio_device *aud = (struct usb_audio_device *)dev_id;
printk("irq on %p\n", aud);
#endif
@@ -41,107 +2556,953 @@ static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
}
#endif
-static int usb_audio_probe(struct usb_device *dev)
+static void *find_descriptor(void *descstart, unsigned int desclen, void *after,
+ u8 dtype, int iface, int altsetting)
{
- struct usb_interface_descriptor *interface;
- struct usb_audio *aud;
- int i;
- int na=0;
-
- for (i=0; i<dev->config[0].bNumInterfaces; i++) {
- interface = &dev->config->interface[i].altsetting[0];
-
- if (interface->bInterfaceClass != 1)
- continue;
-
- printk(KERN_INFO "USB audio device detected.\n");
-
- switch(interface->bInterfaceSubClass) {
- case 0x01:
- printk(KERN_INFO "audio: control device\n");
- break;
- case 0x02:
- printk(KERN_INFO "audio: streaming\n");
- break;
- case 0x03:
- printk(KERN_INFO "audio: nonstreaming\n");
- break;
+ u8 *p, *end, *next;
+ int ifc = -1, as = -1;
+
+ p = descstart;
+ end = p + desclen;
+ for (; p < end;) {
+ if (p[0] < 2)
+ return NULL;
+ next = p + p[0];
+ if (next > end)
+ return NULL;
+ if (p[1] == USB_DT_INTERFACE) {
+ /* minimum length of interface descriptor */
+ if (p[0] < 9)
+ return NULL;
+ ifc = p[2];
+ as = p[3];
+ }
+ if (p[1] == dtype && (!after || (void *)p > after) &&
+ (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
+ return p;
}
- na++;
+ p = next;
}
-
- if (!na)
- return -1;
+ return NULL;
+}
- aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL);
- if (!aud)
- return -1;
+static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
+{
+ unsigned char *p;
- memset(aud, 0, sizeof(*aud));
- aud->dev = dev;
- dev->private = aud;
+ p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
+ while (p) {
+ if (p[0] >= 3 && p[2] == dsubtype)
+ return p;
+ p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
+ }
+ return NULL;
+}
-/*
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO "Failed usb_set_configuration: Audio\n");
- break;
+static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
+{
+ unsigned char *p;
+
+ p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
+ while (p) {
+ if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
+ return p;
+ p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
}
- usb_set_protocol(dev, 0);
- usb_set_idle(dev, 0, 0);
-*/
-
-/*
- aud->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
- na = usb_request_irq(dev, aud->irqpipe,
- usb_audio_irq, endpoint->bInterval,
- aud, &aud->irq_handle);
- if (na) {
- printk (KERN_WARNING "usb-audio: usb_request_irq failed (0x%x)\n", na);
+ return NULL;
+}
+
+static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
+{
+ struct usb_device *dev = s->usbdev;
+ struct usb_audiodev *as;
+ struct usb_config_descriptor *config = dev->actconfig;
+ struct usb_interface_descriptor *alts;
+ struct usb_interface *iface;
+ struct audioformat *fp;
+ unsigned char *fmt;
+ unsigned int i, j, k, format;
+
+ if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
+ return;
+ memset(as, 0, sizeof(struct usb_audiodev));
+ init_waitqueue_head(&as->usbin.dma.wait);
+ init_waitqueue_head(&as->usbout.dma.wait);
+ spin_lock_init(&as->lock);
+ as->state = s;
+ as->usbin.interface = asifin;
+ as->usbout.interface = asifout;
+ /* search for input formats */
+ if (asifin >= 0) {
+ iface = &config->interface[asifin];
+ for (i = 0; i < iface->num_altsetting; i++) {
+ alts = &iface->altsetting[i];
+ if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+ continue;
+ if (alts->bNumEndpoints < 1) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u does not have an endpoint\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+ !(alts->endpoint[0].bEndpointAddress & 0x80)) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u first endpoint not isochronous in\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
+ if (!fmt) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u format not supported\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+ fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
+ if (!fmt) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n",
+ dev->devnum, asifin, i);
+ continue;
+ }
+ if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n",
+ dev->devnum, asifin, i, fmt[4], fmt[5]);
+ continue;
+ }
+ if (as->numfmtin >= MAXFORMATS)
+ continue;
+ fp = &as->fmtin[as->numfmtin++];
+ if (fmt[5] == 2)
+ format &= (AFMT_U16_LE | AFMT_S16_LE);
+ else
+ format &= (AFMT_U8 | AFMT_S8);
+ if (fmt[4] == 2)
+ format |= AFMT_STEREO;
+ fp->format = format;
+ fp->altsetting = i;
+ fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+ for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+ k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+ if (k > fp->sratehi)
+ fp->sratehi = k;
+ if (k < fp->sratelo)
+ fp->sratelo = k;
+ }
+ printk(KERN_INFO "usb_audio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u\n",
+ dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi);
+ }
}
-*/
+ /* search for output formats */
+ if (asifout >= 0) {
+ iface = &config->interface[asifout];
+ for (i = 0; i < iface->num_altsetting; i++) {
+ alts = &iface->altsetting[i];
+ if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+ continue;
+ if (alts->bNumEndpoints < 1) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u does not have an endpoint\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+ (alts->endpoint[0].bEndpointAddress & 0x80)) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u first endpoint not isochronous out\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
+ if (!fmt) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u format not supported\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+ fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
+ if (!fmt) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n",
+ dev->devnum, asifout, i);
+ continue;
+ }
+ if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+ printk(KERN_ERR "usb_audio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n",
+ dev->devnum, asifout, i, fmt[4], fmt[5]);
+ continue;
+ }
+ if (as->numfmtout >= MAXFORMATS)
+ continue;
+ fp = &as->fmtout[as->numfmtout++];
+ if (fmt[5] == 2)
+ format &= (AFMT_U16_LE | AFMT_S16_LE);
+ else
+ format &= (AFMT_U8 | AFMT_S8);
+ if (fmt[4] == 2)
+ format |= AFMT_STEREO;
+ fp->format = format;
+ fp->altsetting = i;
+ fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+ for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+ k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+ if (k > fp->sratehi)
+ fp->sratehi = k;
+ if (k < fp->sratelo)
+ fp->sratelo = k;
+ }
+ printk(KERN_INFO "usb_audio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u\n",
+ dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi);
+ }
+ }
+ if (as->numfmtin == 0 && as->numfmtout == 0) {
+ kfree(as);
+ return;
+ }
+ if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
+ printk(KERN_ERR "usb_audio: cannot register dsp\n");
+ kfree(as);
+ return;
+ }
+ /* everything successful */
+ list_add_tail(&as->list, &s->audiolist);
+}
+
+struct consmixstate {
+ struct usb_audio_state *s;
+ unsigned char *buffer;
+ unsigned int buflen;
+ unsigned int ctrlif;
+ struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
+ unsigned int nrmixch;
+ unsigned int mixchmask;
+ unsigned long unitbitmap[32/sizeof(unsigned long)];
+ /* return values */
+ unsigned int nrchannels;
+ unsigned int termtype;
+ unsigned int chconfig;
+};
+
+static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
+{
+ struct mixerchannel *c;
+
+ if (nr >= SOUND_MIXER_NRDEVICES) {
+ printk(KERN_ERR "usb_audio: invalid OSS mixer channel %u\n", nr);
+ return NULL;
+ }
+ if (!(state->mixchmask & (1 << nr))) {
+ printk(KERN_WARNING "usb_audio: OSS mixer channel %u already in use\n", nr);
+ return NULL;
+ }
+ c = &state->mixch[state->nrmixch++];
+ c->osschannel = nr;
+ state->mixchmask &= ~(1 << nr);
+ return c;
+}
+
+static unsigned int getvolchannel(struct consmixstate *state)
+{
+ unsigned int u;
+
+ if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
+ return SOUND_MIXER_VOLUME;
+ if ((state->termtype & 0xff00) == 0x0100) {
+ if (state->mixchmask & SOUND_MASK_PCM)
+ return SOUND_MIXER_PCM;
+ if (state->mixchmask & SOUND_MASK_ALTPCM)
+ return SOUND_MIXER_ALTPCM;
+ }
+ if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
+ return SOUND_MIXER_MIC;
+ if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
+ return SOUND_MIXER_SPEAKER;
+ if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
+ return SOUND_MIXER_SPEAKER;
+ if ((state->termtype & 0xff00) == 0x0500) {
+ if (state->mixchmask & SOUND_MASK_PHONEIN)
+ return SOUND_MIXER_PHONEIN;
+ if (state->mixchmask & SOUND_MASK_PHONEOUT)
+ return SOUND_MIXER_PHONEOUT;
+ }
+ if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
+ return SOUND_MIXER_RADIO;
+ if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
+ return SOUND_MIXER_VIDEO;
+ u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
+ SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
+ return u-1;
+}
- list_add(&aud->list, &usb_audio_list);
+static void prepmixch(struct consmixstate *state)
+{
+ struct usb_device *dev = state->s->usbdev;
+ struct mixerchannel *ch;
+ unsigned char buf[2];
+ __s16 v1;
+ unsigned int v2, v3;
+
+ if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
+ return;
+ ch = &state->mixch[state->nrmixch-1];
+ switch (ch->selector) {
+ case 0: /* mixer unit request */
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ ch->minval = buf[0] | (buf[1] << 8);
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ ch->maxval = buf[0] | (buf[1] << 8);
+ v2 = ch->maxval - ch->minval;
+ if (!v2)
+ v2 = 1;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ v1 = buf[0] | (buf[1] << 8);
+ v3 = v1 - ch->minval;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ ch->value = v3;
+ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+ state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ v1 = buf[0] | (buf[1] << 8);
+ v3 = v1 - ch->minval;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ }
+ ch->value |= v3 << 8;
+ break;
+
+ /* various feature unit controls */
+ case VOLUME_CONTROL:
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ ch->minval = buf[0] | (buf[1] << 8);
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ ch->maxval = buf[0] | (buf[1] << 8);
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ v1 = buf[0] | (buf[1] << 8);
+ v2 = ch->maxval - ch->minval;
+ v3 = v1 - ch->minval;
+ if (!v2)
+ v2 = 1;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ ch->value = v3;
+ if (ch->chnum != 0) {
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+ goto err;
+ v1 = buf[0] | (buf[1] << 8);
+ v3 = v1 - ch->minval;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ }
+ ch->value |= v3 << 8;
+ break;
- return 0;
+ case BASS_CONTROL:
+ case MID_CONTROL:
+ case TREBLE_CONTROL:
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ goto err;
+ ch->minval = buf[0] << 8;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ goto err;
+ ch->maxval = buf[0] << 8;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ goto err;
+ v1 = buf[0] << 8;
+ v2 = ch->maxval - ch->minval;
+ v3 = v1 - ch->minval;
+ if (!v2)
+ v2 = 1;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ ch->value = v3;
+ if (ch->chnum != 0) {
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+ goto err;
+ v1 = buf[0] << 8;
+ v3 = v1 - ch->minval;
+ v3 = 100 * v3 / v2;
+ if (v3 > 100)
+ v3 = 100;
+ }
+ ch->value |= v3 << 8;
+ break;
+
+ default:
+ goto err;
+ }
+ return;
+
+ err:
+ printk(KERN_ERR "usb_audio: mixer request device %u if %u unit %u ch %u selector %u failed\n",
+ dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
+ if (state->nrmixch)
+ state->nrmixch--;
}
-static void usb_audio_disconnect(struct usb_device *dev)
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
+
+extern inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
+{
+ unsigned int idx;
+
+ idx = inidx*numoch;
+ if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
+ return 0;
+ if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+ return 1;
+ idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
+ if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
+ return 0;
+ return 1;
+}
+
+static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
{
- struct usb_audio *aud = (struct usb_audio*) dev->private;
+ unsigned int nroutch = mixer[5+mixer[4]];
+ unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
+ unsigned int termt[SOUND_MIXER_NRDEVICES];
+ unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
+ unsigned char *bmap = &mixer[9+mixer[4]];
+ unsigned int bmapsize;
+ struct mixerchannel *ch;
+ unsigned int i;
- if (!aud)
+ if (!mixer[4]) {
+ printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
+ return;
+ }
+ if (mixer[4] > SOUND_MIXER_NRDEVICES) {
+ printk(KERN_ERR "usb_audio: mixer unit %u: too many input pins\n", mixer[3]);
return;
+ }
+ chidx[0] = 0;
+ for (i = 0; i < mixer[4]; i++) {
+ usb_audio_recurseunit(state, mixer[5+i]);
+ chidx[i+1] = chidx[i] + state->nrchannels;
+ termt[i] = state->termtype;
+ }
+ state->termtype = 0;
+ state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
+ bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
+ bmap += bmapsize - 1;
+ if (mixer[0] < 10+mixer[4]+bmapsize) {
+ printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
+ return;
+ }
+ for (i = 0; i < mixer[4]; i++) {
+ state->termtype = termt[i];
+ if (chidx[i+1]-chidx[i] >= 2) {
+ flg |= MIXFLG_STEREOIN;
+ if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = mixer[3];
+ ch->selector = 0;
+ ch->chnum = chidx[i]+1;
+ ch->flags = flg;
+ prepmixch(state);
+ }
+ continue;
+ }
+ }
+ flg &= ~MIXFLG_STEREOIN;
+ if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = mixer[3];
+ ch->selector = 0;
+ ch->chnum = chidx[i]+1;
+ ch->flags = flg;
+ prepmixch(state);
+ }
+ }
+ }
+ state->termtype = 0;
+}
- list_del(&aud->list);
+static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
+{
+ unsigned int chnum, i;
+
+ if (!selector[4]) {
+ printk(KERN_ERR "usb_audio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
+ return;
+ }
+ usb_audio_recurseunit(state, selector[5]);
+ chnum = state->nrchannels;
+ for (i = 1; i < selector[4]; i++) {
+ usb_audio_recurseunit(state, selector[5+i]);
+ if (chnum != state->nrchannels) {
+ printk(KERN_ERR "usb_audio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
+ state->termtype = 0;
+ state->chconfig = 0;
+ state->nrchannels = 0;
+ return;
+ }
+ }
+ state->termtype = 0;
+ state->chconfig = 0;
+}
- usb_release_irq(aud->dev, aud->irq_handle, aud->irqpipe);
+/* in the future we might try to handle 3D etc. effect units */
- kfree(aud);
- dev->private = NULL;
+static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
+{
+ unsigned int i;
+
+ for (i = 0; i < proc[6]; i++)
+ usb_audio_recurseunit(state, proc[7+i]);
+ state->nrchannels = proc[7+proc[6]];
+ state->termtype = 0;
+ state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
}
-int usb_audio_init(void)
+static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
{
- usb_register(&usb_audio_driver);
+ struct mixerchannel *ch;
+ unsigned short chftr, mchftr;
+
+ usb_audio_recurseunit(state, ftr[4]);
+ if (state->nrchannels == 0) {
+ printk(KERN_ERR "usb_audio: feature unit %u source has no channels\n", ftr[3]);
+ return;
+ }
+ if (state->nrchannels > 2)
+ printk(KERN_WARNING "usb_audio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
+ if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]);
+ return;
+ }
+ mchftr = ftr[6];
+ chftr = ftr[6+ftr[5]];
+ if (state->nrchannels > 1)
+ chftr &= ftr[6+2*ftr[5]];
+ /* volume control */
+ if (chftr & 2) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = VOLUME_CONTROL;
+ ch->chnum = 1;
+ ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ prepmixch(state);
+ }
+ } else if (mchftr & 2) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = VOLUME_CONTROL;
+ ch->chnum = 0;
+ ch->flags = 0;
+ prepmixch(state);
+ }
+ }
+ /* bass control */
+ if (chftr & 4) {
+ ch = getmixchannel(state, SOUND_MIXER_BASS);
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = BASS_CONTROL;
+ ch->chnum = 1;
+ ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ prepmixch(state);
+ }
+ } else if (mchftr & 4) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = BASS_CONTROL;
+ ch->chnum = 0;
+ ch->flags = 0;
+ prepmixch(state);
+ }
+ }
+ /* treble control */
+ if (chftr & 16) {
+ ch = getmixchannel(state, SOUND_MIXER_TREBLE);
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = TREBLE_CONTROL;
+ ch->chnum = 1;
+ ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ prepmixch(state);
+ }
+ } else if (mchftr & 16) {
+ ch = getmixchannel(state, getvolchannel(state));
+ if (ch) {
+ ch->unitid = ftr[3];
+ ch->selector = TREBLE_CONTROL;
+ ch->chnum = 0;
+ ch->flags = 0;
+ prepmixch(state);
+ }
+ }
+}
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
+{
+ unsigned char *p1;
+ unsigned int i, j;
+
+ if (test_and_set_bit(unitid, &state->unitbitmap)) {
+ printk(KERN_ERR "usb_audio: mixer path recursion detected, unit %d!\n", unitid);
+ return;
+ }
+ p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
+ if (!p1) {
+ printk(KERN_ERR "usb_audio: unit %d not found!\n", unitid);
+ return;
+ }
+ state->nrchannels = 0;
+ state->termtype = 0;
+ state->chconfig = 0;
+ switch (p1[2]) {
+ case INPUT_TERMINAL:
+ if (p1[0] < 12) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
+ return;
+ }
+ state->nrchannels = p1[7];
+ state->termtype = p1[4] | (p1[5] << 8);
+ state->chconfig = p1[8] | (p1[9] << 8);
+ return;
+
+ case MIXER_UNIT:
+ if (p1[0] < 10 || p1[0] < 10+p1[4]) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
+ return;
+ }
+ usb_audio_mixerunit(state, p1);
+ return;
+
+ case SELECTOR_UNIT:
+ if (p1[0] < 6 || p1[0] < 6+p1[4]) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
+ return;
+ }
+ usb_audio_selectorunit(state, p1);
+ return;
+
+ case FEATURE_UNIT:
+ if (p1[0] < 7 || p1[0] < 7+p1[5]) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
+ return;
+ }
+ usb_audio_featureunit(state, p1);
+ return;
+
+ case PROCESSING_UNIT:
+ if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]] || p1[0] < 13+p1[6]+p1[11+p1[6]]+p1[13+p1[6]+p1[11+p1[6]]]) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
+ return;
+ }
+ usb_audio_processingunit(state, p1);
+ return;
+
+ case EXTENSION_UNIT:
+ if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
+ printk(KERN_ERR "usb_audio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
+ return;
+ }
+ for (j = i = 0; i < p1[6]; i++) {
+ usb_audio_recurseunit(state, p1[7+i]);
+ if (!i)
+ j = state->termtype;
+ else if (j != state->termtype)
+ j = 0;
+ }
+ state->nrchannels = p1[7+p1[6]];
+ state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
+ state->termtype = j;
+ return;
+
+ default:
+ printk(KERN_ERR "usb_audio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+ return;
+ }
+}
+
+static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
+{
+ struct usb_mixerdev *ms;
+ struct consmixstate state;
+
+ memset(&state, 0, sizeof(state));
+ state.s = s;
+ state.nrmixch = 0;
+ state.mixchmask = ~0;
+ state.buffer = buffer;
+ state.buflen = buflen;
+ state.ctrlif = ctrlif;
+ set_bit(oterm[3], &state.unitbitmap); /* mark terminal ID as visited */
+ printk(KERN_INFO "usb_audio: constructing mixer for Terminal %u type 0x%04x\n",
+ oterm[3], oterm[4] | (oterm[5] << 8));
+ usb_audio_recurseunit(&state, oterm[7]);
+ if (!state.nrmixch) {
+ printk(KERN_INFO "usb_audio: no mixer controls found for Terminal %u\n", oterm[3]);
+ return;
+ }
+ if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
+ return;
+ memset(ms, 0, sizeof(struct usb_mixerdev));
+ memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
+ ms->state = s;
+ ms->iface = ctrlif;
+ ms->numch = state.nrmixch;
+ if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
+ printk(KERN_ERR "usb_audio: cannot register mixer\n");
+ kfree(ms);
+ return;
+ }
+ list_add_tail(&ms->list, &s->mixerlist);
+}
+
+static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
+{
+ struct usb_audio_state *s;
+ struct usb_config_descriptor *config = dev->actconfig;
+ struct usb_interface *iface;
+ unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
+ unsigned char *p1;
+ unsigned int i, j, numifin = 0, numifout = 0;
+
+ if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
+ return -1;
+ memset(s, 0, sizeof(struct usb_audio_state));
+ INIT_LIST_HEAD(&s->audiolist);
+ INIT_LIST_HEAD(&s->mixerlist);
+ s->usbdev = dev;
+ s->count = 1;
+ /* find audiocontrol interface */
+ if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u no HEADER found\n",
+ dev->devnum, ctrlif);
+ goto ret;
+ }
+ if (p1[0] < 8 + p1[7]) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u HEADER error\n",
+ dev->devnum, ctrlif);
+ goto ret;
+ }
+ if (!p1[7])
+ printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
+ dev->devnum, ctrlif);
+ for (i = 0; i < p1[7]; i++) {
+ j = p1[8+i];
+ if (j >= config->bNumInterfaces) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u does not exist\n",
+ dev->devnum, ctrlif, j);
+ continue;
+ }
+ iface = &config->interface[j];
+ if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
+ dev->devnum, ctrlif, j);
+ continue;
+ }
+ if (iface->altsetting[0].bInterfaceSubClass == 3) {
+ printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
+ dev->devnum, ctrlif, j);
+ continue;
+ }
+ if (iface->altsetting[0].bInterfaceSubClass != 2) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
+ dev->devnum, ctrlif, j);
+ continue;
+ }
+ if (iface->num_altsetting < 2 ||
+ iface->altsetting[0].bNumEndpoints > 0) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u altsetting 0 not zero bandwidth\n",
+ dev->devnum, ctrlif);
+ continue;
+ }
+ if (iface->altsetting[1].bNumEndpoints < 1) {
+ printk(KERN_ERR "usb_audio: device %d audiocontrol interface %u interface %u has no endpoint\n",
+ dev->devnum, ctrlif, j);
+ continue;
+ }
+ /* note: this requires the data endpoint to be ep0 and the optional sync
+ ep to be ep1, which seems to be the case */
+ if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
+ if (numifin < USB_MAXINTERFACES)
+ ifin[numifin++] = j;
+ } else {
+ if (numifout < USB_MAXINTERFACES)
+ ifout[numifout++] = j;
+ }
+ }
+ printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
+ dev->devnum, ctrlif, numifin, numifout);
+ for (i = 0; i < numifin && i < numifout; i++)
+ usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
+ for (j = i; j < numifin; j++)
+ usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
+ for (j = i; j < numifout; j++)
+ usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
+ /* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
+ p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
+ while (p1) {
+ if (p1[0] >= 9)
+ usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
+ p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
+ }
+
+ ret:
+ if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
+ kfree(s);
+ return -1;
+ }
+ /* everything successful */
+ dev->private = s;
+ down(&open_sem);
+ list_add_tail(&s->audiodev, &audiodevs);
+ up(&open_sem);
+ MOD_INC_USE_COUNT;
return 0;
}
-/*
- * Support functions for parsing
- */
-
-void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data)
+/* we only care for the currently active configuration */
+
+static int usb_audio_probe(struct usb_device *dev)
{
-#ifdef AUDIO_DEBUG
- printk(KERN_DEBUG "usb_audio_interface.\n");
-#endif
+ struct usb_config_descriptor *config = dev->actconfig;
+ unsigned char *buffer;
+ unsigned char buf[8];
+ unsigned int i, buflen;
+ int ret;
+
+ for (i = 0; i < config->bNumInterfaces; i++)
+ if (config->interface[i].altsetting[0].bInterfaceClass == USB_CLASS_AUDIO &&
+ config->interface[i].altsetting[0].bInterfaceSubClass == 1) /* audiocontrol interface found */
+ goto audioctrlfound;
+ printk(KERN_DEBUG "usb_audio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return -1;
+
+ audioctrlfound:
+ /* find which configuration number is active */
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+ if (dev->config+i == config)
+ goto configfound;
+ printk(KERN_ERR "usb_audio: cannot find active configuration number of device %d\n", dev->devnum);
+ return -1;
+
+ configfound:
+ if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
+ printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
+ return -1;
+ }
+ ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
+ if (ret) {
+ printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
+ return -1;
+ }
+ if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
+ printk(KERN_ERR "usb_audio: invalid config descriptor %d of device %d\n", i, dev->devnum);
+ return -1;
+ }
+ buflen = buf[2] | (buf[3] << 8);
+ if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
+ return -1;
+ ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
+ if (ret) {
+ kfree(buffer);
+ printk(KERN_ERR "usb_audio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
+ return -1;
+ }
+ /* find first audio control interface; we currently cannot handle more than one */
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ if (config->interface[i].altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
+ config->interface[i].altsetting[0].bInterfaceSubClass != 1)
+ continue;
+ /* audiocontrol interface found */
+ if (!usb_audio_parsecontrol(dev, buffer, buflen, i))
+ return 0;
+ }
+ return -1;
}
-void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data)
+
+/* a revoke facility would make things simpler */
+
+static void usb_audio_disconnect(struct usb_device *dev)
{
-#ifdef AUDIO_DEBUG
- printk(KERN_DEBUG "usb_audio_interface.\n");
+ struct usb_audio_state *s = (struct usb_audio_state *)dev->private;
+ struct list_head *list;
+ struct usb_audiodev *as;
+ struct usb_mixerdev *ms;
+
+ down(&open_sem);
+ list_del(&s->audiodev);
+ INIT_LIST_HEAD(&s->audiodev);
+ s->usbdev = NULL;
+ /* deregister all audio and mixer devices, so no new processes can open this device */
+ for(list = s->audiolist.next; list != &s->audiolist; list = list->next) {
+ as = list_entry(list, struct usb_audiodev, list);
+ if (as->dev_audio >= 0)
+ unregister_sound_dsp(as->dev_audio);
+ as->dev_audio = -1;
+ }
+ for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) {
+ ms = list_entry(list, struct usb_mixerdev, list);
+ if (ms->dev_mixer >= 0)
+ unregister_sound_mixer(ms->dev_mixer);
+ }
+#if 0
+ if(aud->irq_handle)
+ usb_release_irq(dev, aud->irq_handle, aud->irqpipe);
+ aud->irq_handle = NULL;
#endif
+ release(s);
+ wake_up(&open_wait);
+ dev->private = NULL;
+}
+
+int usb_audio_init(void)
+{
+ usb_register(&usb_audio_driver);
+ return 0;
}
#ifdef MODULE
@@ -156,4 +3517,3 @@ void cleanup_module(void)
}
#endif
-
diff --git a/drivers/usb/audio.h b/drivers/usb/audio.h
new file mode 100644
index 000000000..a0ecb51ee
--- /dev/null
+++ b/drivers/usb/audio.h
@@ -0,0 +1,116 @@
+#define USB_DT_CS_DEVICE 0x21
+#define USB_DT_CS_CONFIG 0x22
+#define USB_DT_CS_STRING 0x23
+#define USB_DT_CS_INTERFACE 0x24
+#define USB_DT_CS_ENDPOINT 0x25
+
+#define CS_AUDIO_UNDEFINED 0x20
+#define CS_AUDIO_DEVICE 0x21
+#define CS_AUDIO_CONFIGURATION 0x22
+#define CS_AUDIO_STRING 0x23
+#define CS_AUDIO_INTERFACE 0x24
+#define CS_AUDIO_ENDPOINT 0x25
+
+#define HEADER 0x01
+#define INPUT_TERMINAL 0x02
+#define OUTPUT_TERMINAL 0x03
+#define MIXER_UNIT 0x04
+#define SELECTOR_UNIT 0x05
+#define FEATURE_UNIT 0x06
+#define PROCESSING_UNIT 0x07
+#define EXTENSION_UNIT 0x08
+
+#define AS_GENERAL 0x01
+#define FORMAT_TYPE 0x02
+#define FORMAT_SPECIFIC 0x03
+
+#define EP_GENERAL 0x01
+
+#define MAX_CHAN 9
+#define MAX_FREQ 16
+#define MAX_IFACE 8
+#define MAX_FORMAT 8
+#define MAX_ALT 8
+
+struct usb_audio_terminal
+{
+ u8 flags;
+ u8 assoc;
+ u16 type; /* Mic etc */
+ u8 channels;
+ u8 source;
+ u16 chancfg;
+};
+
+struct usb_audio_format
+{
+ u8 type;
+ u8 channels;
+ u8 num_freq;
+ u8 sfz;
+ u8 bits;
+ u16 freq[MAX_FREQ];
+};
+
+struct usb_audio_interface
+{
+ u8 terminal;
+ u8 delay;
+ u16 num_formats;
+ u16 format_type;
+ u8 flags;
+ u8 idleconf; /* Idle config */
+#define AU_IFACE_FOUND 1
+ struct usb_audio_format format[MAX_FORMAT];
+};
+
+struct usb_audio_device
+{
+ struct list_head list;
+ u8 mixer;
+ u8 selector;
+ void *irq_handle;
+ u8 num_channels;
+ u8 num_dsp_iface;
+ u8 channel_map[MAX_CHAN];
+ struct usb_audio_terminal terminal[MAX_CHAN];
+ struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
+};
+
+
+
+/* Audio Class specific Request Codes */
+
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define SET_MIN 0x02
+#define GET_MIN 0x82
+#define SET_MAX 0x03
+#define GET_MAX 0x83
+#define SET_RES 0x04
+#define GET_RES 0x84
+#define SET_MEM 0x05
+#define GET_MEM 0x85
+#define GET_STAT 0xff
+
+/* Terminal Control Selectors */
+
+#define COPY_PROTECT_CONTROL 0x01
+
+/* Feature Unit Control Selectors */
+
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define BASS_CONTROL 0x03
+#define MID_CONTROL 0x04
+#define TREBLE_CONTROL 0x05
+#define GRAPHIC_EQUALIZER_CONTROL 0x06
+#define AUTOMATIC_GAIN_CONTROL 0x07
+#define DELAY_CONTROL 0x08
+#define BASS_BOOST_CONTROL 0x09
+#define LOUDNESS_CONTROL 0x0a
+
+/* Endpoint Control Selectors */
+
+#define SAMPLING_FREQ_CONTROL 0x01
+#define PITCH_CONTROL 0x02
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
index 6a466c5a7..02df61455 100644
--- a/drivers/usb/cpia.c
+++ b/drivers/usb/cpia.c
@@ -28,452 +28,509 @@
#define CPIA_DEBUG /* Gobs of debugging info */
+/* Video Size 384 x 288 x 3 bytes for RGB */
#define MAX_FRAME_SIZE (384 * 288 * 3)
/*******************************/
/* Memory management functions */
/*******************************/
-/* convert virtual user memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+#define MDEBUG(x) do { } while(0) /* Debug memory management */
-static inline unsigned long uvirt_to_phys(unsigned long adr)
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- pgd = pgd_offset(current->mm, adr);
- if (pgd_none(*pgd))
- return 0;
- pmd = pmd_offset(pgd, adr);
- if (pmd_none(*pmd))
- return 0;
- ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
- pte = *ptep;
- if(pte_present(pte))
- return
- virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
- return 0;
+ unsigned long ret = 0UL;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, adr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset(pmd, adr);
+ pte = *ptep;
+ if (pte_present(pte))
+ ret = (pte_page(pte) | (adr & (PAGE_SIZE-1)));
+ }
+ }
+ MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+ return ret;
}
-static inline unsigned long uvirt_to_bus(unsigned long adr)
+static inline unsigned long uvirt_to_bus(unsigned long adr)
{
- return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
-}
+ unsigned long kva, ret;
-/* convert virtual kernel memory address to physical address */
-/* (virt_to_phys only works for kmalloced kernel memory) */
+ kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+ ret = virt_to_bus((void *)kva);
+ MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+ return ret;
+}
-static inline unsigned long kvirt_to_phys(unsigned long adr)
+static inline unsigned long kvirt_to_bus(unsigned long adr)
{
- return uvirt_to_phys(VMALLOC_VMADDR(adr));
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = virt_to_bus((void *)kva);
+ MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+ return ret;
}
-static inline unsigned long kvirt_to_bus(unsigned long adr)
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
{
- return uvirt_to_bus(VMALLOC_VMADDR(adr));
-}
+ unsigned long va, kva, ret;
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = __pa(kva);
+ MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+ return ret;
+}
-static void * rvmalloc(unsigned long size)
+static void *rvmalloc(unsigned long size)
{
- void * mem;
+ void *mem;
unsigned long adr, page;
-
+
+ /* Round it off to PAGE_SIZE */
size += (PAGE_SIZE - 1);
size &= ~(PAGE_SIZE - 1);
- mem=vmalloc(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_phys(adr);
- mem_map_reserve(MAP_NR(phys_to_virt(page)));
- adr+=PAGE_SIZE;
- if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
- else
- size=0;
- }
+ mem = vmalloc(size);
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr = (unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_reserve(MAP_NR(__va(page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
}
+
return mem;
}
-static void rvfree(void * mem, unsigned long size)
+static void rvfree(void *mem, unsigned long size)
{
unsigned long adr, page;
-
+
+ if (!mem)
+ return;
+
size += (PAGE_SIZE - 1);
size &= ~(PAGE_SIZE - 1);
- if (mem)
- {
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_phys(adr);
- mem_map_unreserve(MAP_NR(phys_to_virt(page)));
- adr+=PAGE_SIZE;
- if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
- else
- size=0;
- }
- vfree(mem);
+ adr=(unsigned long) mem;
+ while (size > 0) {
+ page = kvirt_to_pa(adr);
+ mem_map_unreserve(MAP_NR(__va(page)));
+ adr += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
}
+ vfree(mem);
}
-int usb_cpia_get_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_version(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_VERSION;
- dr.value = 0;
- dr.index = 0;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 4);
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_CPIA_GET_VERSION,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 4, HZ);
}
-int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_PNP_ID;
- dr.value = 0;
- dr.index = 0;
- dr.length = 6;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 6);
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_CPIA_GET_PNP_ID,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 6, HZ);
}
+#endif
-int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
+#ifdef NOTUSED
+static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE) | 0x80;
- dr.request = USB_REQ_CPIA_GET_CAMERA_STATUS;
- dr.value = 0;
- dr.index = 0;
- dr.length = 8;
-
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, 8);
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_CPIA_GET_CAMERA_STATUS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 8, HZ);
}
+#endif
-int usb_cpia_goto_hi_power(struct usb_device *dev)
+static int usb_cpia_goto_hi_power(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GOTO_HI_POWER;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, HZ);
}
-int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
+static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GET_VP_VERSION;
- dr.value = 0;
- dr.index = 0;
- dr.length = 4;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, buf, 4);
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_CPIA_GET_VP_VERSION,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 4, HZ);
}
-int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
+static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_SENSOR_FPS;
- dr.value = (sensorclkdivisor << 8) + sensorbaserate;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_SET_SENSOR_FPS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
}
-int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
+static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_GRAB_FRAME;
- dr.value = streamstartline << 8;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ streamstartline << 8, 0, NULL, 0, HZ);
}
-int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
+static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_UPLOAD_FRAME;
- dr.value = forceupload;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_UPLOAD_FRAME,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, forceupload, 0, NULL, 0, HZ);
}
-int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
+static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_GRAB_MODE;
- dr.value = continuousgrab;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_SET_GRAB_MODE,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
+ 0, NULL, 0, HZ);
}
-int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
+static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_FORMAT;
- dr.value = (subsample << 8) + size;
- dr.index = order;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_SET_FORMAT,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (subsample << 8) + size, order, NULL, 0, HZ);
}
-int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
+static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_SET_COMPRESSION;
- dr.value = (decimation << 8) + compmode;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_SET_ROI,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (colend << 8) + colstart, (rowend << 8) + rowstart,
+ NULL, 0, HZ);
}
-int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
+static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_INIT_STREAM_CAP;
- dr.value = (streamstartline << 8) + skipframes;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_SET_COMPRESSION,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (decimation << 8) + compmode, 0, NULL, 0, HZ);
}
-int usb_cpia_finistreamcap(struct usb_device *dev)
+#ifdef NOTUSED
+static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_FINI_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_INIT_STREAM_CAP,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
}
-int usb_cpia_startstreamcap(struct usb_device *dev)
+static int usb_cpia_finistreamcap(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_START_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
-
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_FINI_STREAM_CAP,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
}
-int usb_cpia_endstreamcap(struct usb_device *dev)
+static int usb_cpia_startstreamcap(struct usb_device *dev)
{
- devrequest dr;
-
- dr.requesttype = (USB_TYPE_VENDOR | USB_RECIP_DEVICE);
- dr.request = USB_REQ_CPIA_END_STREAM_CAP;
- dr.value = 0;
- dr.index = 0;
- dr.length = 0;
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_START_STREAM_CAP,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
+}
- return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+static int usb_cpia_endstreamcap(struct usb_device *dev)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CPIA_END_STREAM_CAP,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
}
+#endif
/* How much data is left in the scratch buf? */
#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))
static void cpia_parse_data(struct usb_cpia *cpia)
{
+ struct cpia_frame *frame, *pframe;
unsigned char *data = cpia->scratch;
unsigned long l;
- int done;
- done = 0;
- while (!done && scratch_left(data)) {
- switch (cpia->state) {
+ frame = &cpia->frame[cpia->curframe];
+ pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
+
+ while (1) {
+ if (!scratch_left(data))
+ goto out;
+
+ switch (frame->scanstate) {
case STATE_SCANNING:
{
- unsigned char *begin = data;
+ struct cpia_frame_header *header;
/* We need atleast 2 bytes for the magic value */
- if (scratch_left(data) < 2) {
- done = 1;
- break;
- }
+ if (scratch_left(data) < 2)
+ goto out;
+
+ header = (struct cpia_frame_header *)data;
- /* 0x1968 is magic */
- printk("header: %X\n", (*data << 8) + *(data + 1));
- if ((*data == 0x19) && (*(data + 1) == 0x68)) {
- cpia->state = STATE_HEADER;
- printk("moving to header\n");
+ if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
+ frame->scanstate = STATE_HEADER;
break;
}
/* Woops, lost the header, find the end of the frame */
- if (scratch_left(data) < 4) {
- done = 1;
- break;
- }
+ if (scratch_left(data) < 4)
+ goto out;
- printk("Scanning for end of frame\n");
+ /* See if we found the end of the frame */
while (scratch_left(data) >= 4) {
- if ((*data == 0xFF) &&
- (*(data + 1) == 0xFF) &&
- (*(data + 2) == 0xFF) &&
- (*(data + 3) == 0xFF)) {
+ if (*((__u32 *)data) == 0xFFFFFFFF) {
+printk("found end of frame\n");
data += 4;
- break;
+goto error;
}
data++;
}
-#ifdef CPIA_DEBUG
- printk("scan: scanned %d bytes\n", data-begin);
-#endif
break;
}
case STATE_HEADER:
/* We need atleast 64 bytes for the header */
- if (scratch_left(data) < 64) {
- done = 1;
- break;
- }
+ if (scratch_left(data) <
+ sizeof(struct cpia_frame_header))
+ goto out;
+
+ memcpy(&frame->header, data,
+ sizeof(struct cpia_frame_header));
+
+ /* Skip over the header */
+ data += sizeof(struct cpia_frame_header);
+ frame->hdrwidth = (frame->header.col_end -
+ frame->header.col_start) * 8;
+ frame->hdrheight = (frame->header.row_end -
+ frame->header.row_start) * 4;
#ifdef CPIA_DEBUG
- printk("header: framerate %d\n", data[41]);
+ printk("cpia: frame size %dx%d\n",
+ frame->hdrwidth, frame->hdrheight);
+ printk("cpia: frame %scompressed\n",
+ frame->header.comp_enable ? "" : "not ");
#endif
- data += 64;
+ frame->scanstate = STATE_LINES;
+ frame->curline = 0;
- cpia->state = STATE_LINES;
-
break;
case STATE_LINES:
{
- unsigned char *begin = data;
- int found = 0;
-
- while (scratch_left(data)) {
- if (*data == 0xFD) {
- data++;
- found = 1;
- break;
- } else if ((*data == 0xFF) &&
- (scratch_left(data) >= 3) &&
- (*(data + 1) == 0xFF) &&
- (*(data + 2) == 0xFF) &&
- (*(data + 3) == 0xFF)) {
- data += 4;
- cpia->curline = 144;
- found = 1;
- break;
- }
-
- data++;
+ unsigned char *f, *end;
+ unsigned int len;
+ int i;
+ int y, u, y1, v, r, g, b;
+
+ /* We want atleast 2 bytes for the length */
+ if (scratch_left(data) < 2)
+ goto out;
+
+ /* Grab the length */
+ len = data[0] + (data[1] << 8);
+
+printk("line %d, %d bytes long\n", frame->curline, len);
+ /* Check to make sure it's nothing outrageous */
+ if (len > (frame->hdrwidth * 2) + 1) {
+ printk(KERN_INFO "cpia: bad length, resynching\n");
+ goto error;
}
- if (data-begin == 355 && cpia->frame[cpia->curframe].width != 64) {
- int i;
- char *f = cpia->frame[cpia->curframe].data, *b = begin;
-
- b += 2;
- f += (cpia->frame[cpia->curframe].width * 3) * cpia->curline;
-
- for (i = 0; i < 176; i++)
- f[(i * 3) + 0] =
- f[(i * 3) + 1] =
- f[(i * 3) + 2] =
- b[(i * 2)];
+ /* Make sure there's enough data for the entire line */
+ if (scratch_left(data + 2) < len)
+ goto out;
+
+ /* Skip over the length */
+ data += 2;
+
+ /* Is the end of the line there */
+ if (data[len - 1] != 0xFD) {
+ printk(KERN_INFO "cpia: lost synch\n");
+end = data + len - 1 - 4;
+printk("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+end[0], end[1],
+end[2], end[3],
+end[4], end[5],
+end[6], end[7]);
+ goto error;
}
- if (found) {
- cpia->curline++;
- if (cpia->curline >= 144) {
- wake_up(&cpia->wq);
- cpia->state = STATE_SCANNING;
- cpia->curline = 0;
- cpia->curframe = -1;
- done = 1;
+ /* Start at the beginning */
+ end = data + len - 1;
+
+ f = frame->data + (frame->width * 3 * frame->curline);
+
+ if (frame->header.comp_enable) {
+ unsigned char *fp;
+
+ /* We use the previous frame as a reference */
+ fp = pframe->data +
+ (frame->width * 3 * frame->curline);
+
+ while (data < end) {
+ if (*data & 1) {
+ /* Compress RLE data */
+ i = *data >> 1;
+ memcpy(f, fp, i * 3);
+ f += (i * 3);
+ fp += (i * 3);
+ data++;
+ } else {
+ /* Raw data */
+
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+y = *data++ - 16;
+u = *data++ - 128;
+y1 = *data++ - 16;
+v = *data++ - 128;
+r = 104635 * v;
+g = -25690 * u + -53294 * v;
+b = 132278 * u;
+y *= 76310;
+y1 *= 76310;
+*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
+*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
+ fp += 6;
+/*
+ f[0] = f[1] = f[2] = *data;
+ f += 3;
+ data += 2;
+ fp += 3;
+*/
+ }
}
} else {
- data = begin;
- done = 1;
+ /* Raw data */
+ while (data < end) {
+y = *data++ - 16;
+u = *data++ - 128;
+y1 = *data++ - 16;
+v = *data++ - 128;
+r = 104635 * v;
+g = -25690 * u + -53294 * v;
+b = 132278 * u;
+y *= 76310;
+y1 *= 76310;
+*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
+*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
+ }
}
-
+
+#ifdef CPIA_DEBUG
+ /* Make sure we found the end correctly */
+ if (*data != 0xFD)
+ printk("cpia: missed end!\n");
+#endif
+
+ /* Skip the last byte */
+ data++;
+
+ if (++frame->curline >= frame->hdrheight)
+ goto nextframe;
+
break;
}
}
}
+nextframe:
+ if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF) {
+ data += 4;
+printk("end of frame found normally\n");
+}
+
+ frame->grabstate = FRAME_DONE;
+ cpia->curframe = -1;
+
+ /* This will cause the process to request another frame */
+ if (waitqueue_active(&frame->wq))
+ wake_up_interruptible(&frame->wq);
+
+ goto out;
+
+error:
+ frame->grabstate = FRAME_ERROR;
+ cpia->curframe = -1;
+ cpia->compress = 0;
+
+ /* This will cause the process to request another frame */
+ if (waitqueue_active(&frame->wq))
+ wake_up_interruptible(&frame->wq);
+
+out:
+printk("scanned %d bytes, %d left\n", data - cpia->scratch, scratch_left(data));
/* Grab the remaining */
l = scratch_left(data);
memmove(cpia->scratch, data, l);
-
cpia->scratchlen = l;
}
/*
- * For the moment there is no actual data compression (making blocks
- * of data contiguous). This just checks the "frames" array for errors.
+ * Make all of the blocks of data contiguous
*/
-static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc)
+static int cpia_compress_isochronous(struct usb_cpia *cpia, struct usb_isoc_desc *isodesc)
{
- char *data = isodesc->data;
+ unsigned char *cdata, *data;
int i, totlen = 0;
+ cdata = isodesc->data;
+ data = cpia->scratch + cpia->scratchlen;
for (i = 0; i < isodesc->frame_count; i++) {
- int n = isodesc->frames [i].frame_length;
- int st = isodesc->frames [i].frame_status;
-
+ int n = isodesc->frames[i].frame_length;
#ifdef CPIA_DEBUG
- /* Debugging */
+ int st = isodesc->frames[i].frame_status;
+
if (st)
printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
i, n, st);
#endif
+ if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
+ printk(KERN_ERR "cpia: scratch buf overflow!\n");
+ return 0;
+ }
+
+ if (n)
+ memmove(data, cdata, n);
+ data += n;
+ totlen += n;
+ cpia->scratchlen += n;
+ cdata += isodesc->frame_size;
}
return totlen;
@@ -481,157 +538,114 @@ static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc)
static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id)
{
- struct usb_cpia *cpia = dev_id;
- struct usb_device *dev = cpia->dev;
+ struct usb_cpia *cpia = (struct usb_cpia *)dev_id;
struct cpia_sbuf *sbuf;
int i;
- char *p;
if (!cpia->streaming) {
printk("oops, not streaming, but interrupt\n");
return 0;
}
- if (cpia->curframe < 0) {
- if (cpia->frame[0].state == FRAME_READY) {
- cpia->curframe = 0;
- cpia->frame[0].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
- printk("capturing to frame 0\n");
-#endif
- } else if (cpia->frame[1].state == FRAME_READY) {
- cpia->curframe = 1;
- cpia->frame[1].state = FRAME_GRABBING;
-#ifdef CPIA_DEBUG
- printk("capturing to frame 1\n");
-#endif
-#ifdef CPIA_DEBUG
- } else
- printk("no frame available\n");
-#else
- }
-#endif
- }
-
- sbuf = &cpia->sbuf[cpia->receivesbuf];
-
+ sbuf = &cpia->sbuf[cpia->cursbuf];
usb_kill_isoc(sbuf->isodesc);
- /* Do something to it now */
- sbuf->len = cpia_compress_isochronous(sbuf->isodesc);
+ /* Copy the data received into our scratch buffer */
+ len = cpia_compress_isochronous(cpia, sbuf->isodesc);
-#ifdef CPIA_DEBUG
- if (sbuf->len)
- printk("%d bytes received\n", sbuf->len);
-#endif
+printk("%d bytes received\n", len);
+ /* If we don't have a frame we're current working on, complain */
+ if (len) {
+ if (cpia->curframe < 0)
+ printk("cpia: received data, but no frame available\n");
+ else
+ cpia_parse_data(cpia);
+ }
- if (sbuf->len && cpia->curframe >= 0) {
- if (sbuf->len > (SCRATCH_BUF_SIZE - cpia->scratchlen)) {
- printk("overflow!\n");
- return 0;
- }
- memcpy(cpia->scratch + cpia->scratchlen, sbuf->data, sbuf->len);
- cpia->scratchlen += sbuf->len;
+ for (i = 0; i < FRAMES_PER_DESC; i++)
+ sbuf->isodesc->frames[i].frame_length = FRAME_SIZE_PER_DESC;
- cpia_parse_data(cpia);
- }
+ /* Move to the next sbuf */
+ cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
/* Reschedule this block of Isochronous desc */
- /*
- usb_run_isoc(sbuf->isodesc, NULL);
- */
-/*
- usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
-*/
-
- /* Move to the next one */
- cpia->receivesbuf = (cpia->receivesbuf + 1) % 3;
+ usb_run_isoc(sbuf->isodesc, cpia->sbuf[cpia->cursbuf].isodesc);
- return 1;
+ return -1;
}
-int cpia_init_isoc(struct usb_cpia *cpia)
+static int cpia_init_isoc(struct usb_cpia *cpia)
{
struct usb_device *dev = cpia->dev;
struct usb_isoc_desc *id;
int fx, err;
- cpia->receivesbuf = 0;
-
+ cpia->curframe = -1;
+ cpia->cursbuf = 0;
cpia->scratchlen = 0;
- cpia->curline = 0;
- cpia->state = STATE_SCANNING;
- /* ALT_ISOC is only doing double-buffering, not triple. */
- err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
- &cpia->sbuf[0].isodesc);
- if (err)
- printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
- err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia,
- &cpia->sbuf[1].isodesc);
- if (err)
- printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err);
+ /* We double buffer the Iso lists */
+ err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+ cpia, &cpia->sbuf[0].isodesc);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+ err);
+ return -ENOMEM;
+ }
- if (!cpia->sbuf[0].isodesc || !cpia->sbuf[1].isodesc) {
- if (cpia->sbuf[0].isodesc)
- usb_free_isoc (cpia->sbuf[0].isodesc);
- if (cpia->sbuf[1].isodesc)
- usb_free_isoc (cpia->sbuf[1].isodesc);
+ err = usb_init_isoc(dev, usb_rcvisocpipe(dev, 1), FRAMES_PER_DESC,
+ cpia, &cpia->sbuf[1].isodesc);
+ if (err) {
+ printk(KERN_ERR "cpia_init_isoc: usb_init_isoc() ret %d\n",
+ err);
+ usb_free_isoc (cpia->sbuf[0].isodesc);
return -ENOMEM;
}
-#if 0
- cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
- cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
- cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-#endif
#ifdef CPIA_DEBUG
printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
-#if 0
- printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
-#endif
#endif
/* Set the Isoc. desc. parameters. */
/* First for desc. [0] */
- id = cpia->sbuf [0].isodesc;
+ id = cpia->sbuf[0].isodesc;
id->start_type = START_ASAP;
id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
id->data = cpia->sbuf[0].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
- id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+ id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
/* and the desc. [1] */
- id = cpia->sbuf [1].isodesc;
+ id = cpia->sbuf[1].isodesc;
id->start_type = 0; /* will follow the first desc. */
id->callback_frames = 10; /* on every 10th frame */
id->callback_fn = cpia_isoc_irq;
id->data = cpia->sbuf[1].data;
id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
for (fx = 0; fx < FRAMES_PER_DESC; fx++)
- id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
+ id->frames[fx].frame_length = FRAME_SIZE_PER_DESC;
- usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
- usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
-
-#if 0
- usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
- usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
- usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
-#endif
+ usb_run_isoc(cpia->sbuf[0].isodesc, NULL);
+ usb_run_isoc(cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
#ifdef CPIA_DEBUG
printk("done scheduling\n");
#endif
- if (usb_set_interface(cpia->dev, 1, 3)) {
- printk("cpia_set_interface error\n");
- return -EINVAL;
+ /* Alternate interface 3 is is the biggest frame size */
+ if (usb_set_interface(cpia->dev, 1, 3) < 0) {
+ printk("usb_set_interface error\n");
+ return -EBUSY;
}
- usb_cpia_startstreamcap(cpia->dev);
+#if 0
+ if (usb_cpia_grab_frame(dev, 120) < 0) {
+ printk(KERN_INFO "cpia_grab_frame error\n");
+ return -EBUSY;
+ }
+#endif
cpia->streaming = 1;
#ifdef CPIA_DEBUG
@@ -641,41 +655,102 @@ int cpia_init_isoc(struct usb_cpia *cpia)
return 0;
}
-void cpia_stop_isoc(struct usb_cpia *cpia)
+static void cpia_stop_isoc(struct usb_cpia *cpia)
{
- struct usb_device *dev = cpia->dev;
-
if (!cpia->streaming)
return;
cpia->streaming = 0;
- /* Stop the streaming */
- usb_cpia_endstreamcap(cpia->dev);
+ /* Turn off continuous grab */
+ if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
+ printk(KERN_INFO "cpia_set_grab_mode error\n");
+ return /* -EBUSY */;
+ }
+
+#if 0
+ if (usb_cpia_grab_frame(cpia->dev, 0) < 0) {
+ printk(KERN_INFO "cpia_grab_frame error\n");
+ return /* -EBUSY */;
+ }
+#endif
/* Set packet size to 0 */
- if (usb_set_interface(cpia->dev, 1, 0)) {
- printk("cpia_set_interface error\n");
+ if (usb_set_interface(cpia->dev, 1, 0) < 0) {
+ printk(KERN_INFO "usb_set_interface error\n");
return /* -EINVAL */;
}
/* Unschedule all of the iso td's */
- usb_kill_isoc (cpia->sbuf[1].isodesc);
- usb_kill_isoc (cpia->sbuf[0].isodesc);
-#if 0
- usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc);
- usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc);
- usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+ usb_kill_isoc(cpia->sbuf[1].isodesc);
+ usb_kill_isoc(cpia->sbuf[0].isodesc);
/* Delete them all */
- usb_free_isoc (cpia->sbuf[1].isodesc);
- usb_free_isoc (cpia->sbuf[0].isodesc);
-#if 0
- usb_delete_isochronous(dev, cpia->sbuf[2].isodesc);
- usb_delete_isochronous(dev, cpia->sbuf[1].isodesc);
- usb_delete_isochronous(dev, cpia->sbuf[0].isodesc);
-#endif
+ usb_free_isoc(cpia->sbuf[1].isodesc);
+ usb_free_isoc(cpia->sbuf[0].isodesc);
+}
+
+static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
+{
+ struct cpia_frame *frame;
+ int width, height;
+
+printk("new frame %d\n", framenum);
+ if (framenum == -1) {
+ int i;
+ for (i = 0; i < CPIA_NUMFRAMES; i++)
+ if (cpia->frame[i].grabstate == FRAME_READY)
+ break;
+
+ if (i >= CPIA_NUMFRAMES) {
+ printk("no frame ready\n");
+ return 0;
+ }
+
+ framenum = i;
+printk("using frame %d\n", framenum);
+ }
+
+ if (cpia->curframe != -1 && cpia->curframe != framenum)
+ return 0;
+
+ frame = &cpia->frame[framenum];
+ width = frame->width;
+ height = frame->height;
+
+ /* Make sure it's not too big */
+ if (width > 352)
+ width = 352;
+ width = (width / 8) * 8; /* Multiple of 8 */
+
+ if (height > 288)
+ height = 288;
+ height = (height / 4) * 4; /* Multiple of 4 */
+
+ /* Set the ROI they want */
+ if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
+ return -EBUSY;
+
+ if (usb_cpia_set_compression(cpia->dev, cpia->compress ? 1 : 0, 0) < 0) {
+ printk(KERN_INFO "cpia_set_compression error\n");
+ return -EBUSY;
+ }
+
+ /* We want a fresh frame every 30 we get */
+ cpia->compress = (cpia->compress + 1) % 30;
+
+ /* Grab the frame */
+ if (usb_cpia_upload_frame(cpia->dev, 1) < 0) {
+ printk(KERN_INFO "cpia_upload_frame error\n");
+ return -EBUSY;
+ }
+
+ frame->grabstate = FRAME_GRABBING;
+ frame->scanstate = STATE_SCANNING;
+
+ cpia->curframe = framenum;
+
+ return 0;
}
/* Video 4 Linux API */
@@ -688,13 +763,14 @@ static int cpia_open(struct video_device *dev, int flags)
printk("cpia_open\n");
#endif
+ cpia->frame[0].grabstate = FRAME_UNUSED;
+ cpia->frame[1].grabstate = FRAME_UNUSED;
+
+ /* Allocate memory for the frame buffers */
cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
if (!cpia->fbuf)
goto open_err_ret;
- cpia->frame[0].state = FRAME_DONE;
- cpia->frame[1].state = FRAME_DONE;
-
cpia->frame[0].data = cpia->fbuf;
cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
#ifdef CPIA_DEBUG
@@ -710,37 +786,17 @@ static int cpia_open(struct video_device *dev, int flags)
if (!cpia->sbuf[1].data)
goto open_err_on1;
-#if 0
- cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[0].data)
- goto open_err_on0;
-
- cpia->sbuf[1].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[1].data)
- goto open_err_on1;
-
- cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL);
- if (!cpia->sbuf[2].data)
- goto open_err_on2;
-#endif
-
#ifdef CPIA_DEBUG
printk("sbuf[0] @ %p\n", cpia->sbuf[0].data);
printk("sbuf[1] @ %p\n", cpia->sbuf[1].data);
-#if 0
- printk("sbuf[2] @ %p\n", cpia->sbuf[2].data);
-#endif
#endif
- cpia->curframe = -1;
- cpia->receivesbuf = 0;
-
- usb_cpia_initstreamcap(cpia->dev, 0, 60);
-
err = cpia_init_isoc(cpia);
if (err)
goto open_err_on2;
+ MOD_INC_USE_COUNT;
+
return 0;
open_err_on2:
@@ -761,13 +817,12 @@ static void cpia_close(struct video_device *dev)
printk("cpia_close\n");
#endif
- cpia_stop_isoc(cpia);
+ MOD_DEC_USE_COUNT;
- usb_cpia_finistreamcap(cpia->dev);
+ cpia_stop_isoc(cpia);
rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
- kfree(cpia->sbuf[2].data);
kfree(cpia->sbuf[1].data);
kfree(cpia->sbuf[0].data);
}
@@ -791,23 +846,32 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_capability b;
+#ifdef CPIA_DEBUG
+ printk("GCAP\n");
+#endif
+
strcpy(b.name, "CPiA USB Camera");
- b.type = VID_TYPE_CAPTURE /* | VID_TYPE_SUBCAPTURE */;
+ b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
b.channels = 1;
b.audios = 0;
- b.maxwidth = 176 /* 352 */;
- b.maxheight = 144 /* 240 */;
- b.minwidth = 176 /* (Something small?) */;
- b.minheight = 144 /* " " */;
+ b.maxwidth = 352; /* CIF */
+ b.maxheight = 288; /* " */
+ b.minwidth = 176; /* QCIF */
+ b.minheight = 144; /* " */
if (copy_to_user(arg, &b, sizeof(b)))
return -EFAULT;
+
return 0;
}
case VIDIOCGCHAN:
{
struct video_channel v;
+#ifdef CPIA_DEBUG
+ printk("GCHAN\n");
+#endif
+
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
if (v.channel != 0)
@@ -826,47 +890,14 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
int v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v != 0)
- return -EINVAL;
-
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner v;
-
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
-
- if (v.tuner)
- return -EINVAL;
-
- strcpy(v.name, "Format");
-
- v.rangelow = 0;
- v.rangehigh = 0;
- v.flags = 0;
- v.mode = VIDEO_MODE_AUTO;
-
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
-
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner v;
+#ifdef CPIA_DEBUG
+ printk("SCHAN\n");
+#endif
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- if (v.tuner)
- return -EINVAL;
-
- if (v.mode != VIDEO_MODE_AUTO)
+ if (v != 0)
return -EINVAL;
return 0;
@@ -875,6 +906,10 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_picture p;
+#ifdef CPIA_DEBUG
+ printk("GPICT\n");
+#endif
+
p.colour = 0x8000; /* Damn British people :) */
p.hue = 0x8000;
p.brightness = 180 << 8; /* XXX */
@@ -895,6 +930,10 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_picture p;
+#ifdef CPIA_DEBUG
+ printk("SPICT\n");
+#endif
+
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
@@ -910,7 +949,7 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_window vw;
#ifdef CPIA_DEBUG
- printk("VIDIOCSWIN\n");
+ printk("SWIN\n");
#endif
if (copy_from_user(&vw, arg, sizeof(vw)))
@@ -924,6 +963,8 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (vw.width != 144)
return -EINVAL;
+ cpia->compress = 0;
+
return 0;
}
case VIDIOCGWIN:
@@ -931,7 +972,7 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_window vw;
#ifdef CPIA_DEBUG
- printk("VIDIOCGWIN\n");
+ printk("GWIN\n");
#endif
vw.x = 0;
@@ -949,6 +990,9 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGMBUF:
{
struct video_mbuf vm;
+#ifdef CPIA_DEBUG
+ printk("MBUF\n");
+#endif
memset(&vm, 0, sizeof(vm));
vm.size = MAX_FRAME_SIZE * 2;
@@ -965,6 +1009,7 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_mmap vm;
+
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
@@ -980,53 +1025,85 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if ((vm.frame != 0) && (vm.frame != 1))
return -EINVAL;
+ if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
+ return -EBUSY;
+
+ /* Don't compress if the size changed */
+ if ((cpia->frame[vm.frame].width != vm.width) ||
+ (cpia->frame[vm.frame].height != vm.height))
+ cpia->compress = 0;
+
cpia->frame[vm.frame].width = vm.width;
cpia->frame[vm.frame].height = vm.height;
- /* Mark it as free */
- cpia->frame[vm.frame].state = FRAME_READY;
+ /* Mark it as ready */
+ cpia->frame[vm.frame].grabstate = FRAME_READY;
- return 0;
+ return cpia_new_frame(cpia, vm.frame);
}
case VIDIOCSYNC:
{
int frame;
+#ifdef CPIA_DEBUG
+ printk("SYNC\n");
+#endif
+
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
#ifdef CPIA_DEBUG
- printk("syncing to frame %d\n", frame);
+ printk("cpia: syncing to frame %d\n", frame);
#endif
- switch (cpia->frame[frame].state) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- interruptible_sleep_on(&cpia->wq);
- case FRAME_DONE:
- cpia->frame[frame].state = FRAME_UNUSED;
- break;
+
+ switch (cpia->frame[frame].grabstate) {
+ case FRAME_UNUSED:
+ return -EINVAL;
+ case FRAME_READY:
+ case FRAME_GRABBING:
+redo:
+ do {
+printk("enter sleeping\n");
+ interruptible_sleep_on(&cpia->frame[frame].wq);
+printk("back from sleeping\n");
+ if (signal_pending(current))
+ return -EINTR;
+ } while (cpia->frame[frame].grabstate ==
+ FRAME_GRABBING);
+
+ if (cpia->frame[frame].grabstate ==
+ FRAME_ERROR) {
+ int ret;
+
+ if ((ret = cpia_new_frame(cpia, frame)) < 0)
+ return ret;
+ goto redo;
+ }
+ case FRAME_DONE:
+ cpia->frame[frame].grabstate = FRAME_UNUSED;
+ break;
}
+
#ifdef CPIA_DEBUG
- printk("synced to frame %d\n", frame);
+ printk("cpia: finished, synced to frame %d\n", frame);
#endif
- return 0;
+
+ return cpia_new_frame(cpia, -1);
}
+ case VIDIOCKEY:
+ return 0;
case VIDIOCCAPTURE:
return -EINVAL;
case VIDIOCGFBUF:
- return -EINVAL;
case VIDIOCSFBUF:
return -EINVAL;
- case VIDIOCKEY:
- return 0;
- case VIDIOCGFREQ:
+ case VIDIOCGTUNER:
+ case VIDIOCSTUNER:
return -EINVAL;
+ case VIDIOCGFREQ:
case VIDIOCSFREQ:
return -EINVAL;
case VIDIOCGAUDIO:
- return -EINVAL;
case VIDIOCSAUDIO:
return -EINVAL;
default:
@@ -1037,17 +1114,14 @@ static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
{
+#if 0
struct usb_cpia *cpia = (struct usb_cpia *)dev;
int len;
+#endif
#ifdef CPIA_DEBUG
printk("cpia_read: %ld bytes\n", count);
#endif
-#if 0
- len = cpia_capture(cpia, buf, count);
-
- return len;
-#endif
return 0;
}
@@ -1064,17 +1138,17 @@ static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long si
return -EINVAL;
pos = (unsigned long)cpia->fbuf;
- while (size > 0)
- {
- page = kvirt_to_phys(pos);
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
- start+=PAGE_SIZE;
- pos+=PAGE_SIZE;
+
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
if (size > PAGE_SIZE)
- size-=PAGE_SIZE;
+ size -= PAGE_SIZE;
else
- size=0;
+ size = 0;
}
return 0;
@@ -1097,87 +1171,92 @@ static struct video_device cpia_template = {
0
};
-static void usb_cpia_configure(struct usb_cpia *cpia)
+static int usb_cpia_configure(struct usb_cpia *cpia)
{
struct usb_device *dev = cpia->dev;
unsigned char version[4];
- unsigned char pnpid[6];
- unsigned char camerastat[8];
- unsigned char *buf;
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- printk (KERN_INFO " Failed usb_set_configuration: CPIA\n");
- return;
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) {
+ printk(KERN_INFO "cpia: usb_set_configuration failed\n");
+ return -EBUSY;
}
- if (usb_cpia_get_version(dev, version)) {
- printk("cpia_get_version error\n");
- return;
+ /* Set packet size to 0 */
+ if (usb_set_interface(dev, 1, 0) < 0) {
+ printk(KERN_INFO "usb_set_interface error\n");
+ return -EBUSY;
}
- printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
- version[0], version[1], version[2], version[3]);
-
- if (usb_cpia_get_pnp_id(dev, pnpid)) {
- printk("cpia_get_pnp_id error\n");
- return;
+ if (usb_cpia_get_version(dev, version) < 0) {
+ printk(KERN_INFO "cpia_get_version error\n");
+ return -EBUSY;
}
- printk("cpia: PnP Id: Vendor: %X, Product: %X, Revision: %X\n",
- (pnpid[1] << 8) + pnpid[0], (pnpid[3] << 8) + pnpid[2],
- (pnpid[5] << 8) + pnpid[4]);
+ printk("cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
+ version[0], version[1], version[2], version[3]);
memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
- init_waitqueue_head(&cpia->wq);
+ init_waitqueue_head(&cpia->frame[0].wq);
+ init_waitqueue_head(&cpia->frame[1].wq);
if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
- printk("video_register_device failed\n");
- return;
+ printk(KERN_INFO "video_register_device failed\n");
+ return -EBUSY;
}
- if (usb_cpia_goto_hi_power(dev)) {
- printk("cpia_goto_hi_power error\n");
- return;
+ if (usb_cpia_goto_hi_power(dev) < 0) {
+ printk(KERN_INFO "cpia_goto_hi_power error\n");
+ goto error;
}
- if (usb_cpia_get_vp_version(dev, version)) {
- printk("cpia_get_vp_version error\n");
- return;
+ if (usb_cpia_get_vp_version(dev, version) < 0) {
+ printk(KERN_INFO "cpia_get_vp_version error\n");
+ goto error;
}
printk("cpia: VP v%d rev %d\n", version[0], version[1]);
printk("cpia: Camera Head ID %04X\n", (version[3] << 8) + version[2]);
- /* Turn off continuous grab */
- if (usb_cpia_set_grab_mode(dev, 1)) {
- printk("cpia_set_grab_mode error\n");
- return;
+ /* Turn on continuous grab */
+ if (usb_cpia_set_grab_mode(dev, 1) < 0) {
+ printk(KERN_INFO "cpia_set_grab_mode error\n");
+ goto error;
}
/* Set up the sensor to be 30fps */
- if (usb_cpia_set_sensor_fps(dev, 1, 0)) {
- printk("cpia_set_sensor_fps error\n");
- return;
+ if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
+ printk(KERN_INFO "cpia_set_sensor_fps error\n");
+ goto error;
}
- /* Set video into QCIF mode, and order into YUYV mode */
- if (usb_cpia_set_format(dev, CPIA_QCIF, 1, CPIA_YUYV)) {
- printk("cpia_set_format error\n");
- return;
+ /* Set video into CIF mode, and order into YUYV mode */
+ if (usb_cpia_set_format(dev, CPIA_CIF, 1, CPIA_YUYV) < 0) {
+ printk(KERN_INFO "cpia_set_format error\n");
+ goto error;
}
/* Turn off compression */
- if (usb_cpia_set_compression(dev, 0, 0)) {
- printk("cpia_set_compression error\n");
- return;
+ if (usb_cpia_set_compression(dev, 0, 0) < 0) {
+ printk(KERN_INFO "cpia_set_compression error\n");
+ goto error;
}
+
+ cpia->compress = 0;
+
+ return 0;
+
+error:
+ video_unregister_device(&cpia->vdev);
+
+ kfree(cpia);
+
+ return -EBUSY;
}
static int cpia_probe(struct usb_device *dev)
{
struct usb_interface_descriptor *interface;
- struct usb_endpoint_descriptor *endpoint;
struct usb_cpia *cpia;
/* We don't handle multi-config cameras */
@@ -1191,6 +1270,8 @@ static int cpia_probe(struct usb_device *dev)
return -1;
if (dev->descriptor.idProduct != 0x0002)
return -1;
+
+ /* Checking vendor/product should be enough, but what the hell */
if (interface->bInterfaceClass != 0xFF)
return -1;
if (interface->bInterfaceSubClass != 0x00)
@@ -1209,9 +1290,7 @@ static int cpia_probe(struct usb_device *dev)
dev->private = cpia;
cpia->dev = dev;
- usb_cpia_configure(cpia);
-
- return 0;
+ return usb_cpia_configure(cpia);
}
static void cpia_disconnect(struct usb_device *dev)
@@ -1231,9 +1310,6 @@ static struct usb_driver cpia_driver = {
{ NULL, NULL }
};
-/*
- * This should be a separate module.
- */
int usb_cpia_init(void)
{
usb_register(&cpia_driver);
@@ -1241,6 +1317,11 @@ int usb_cpia_init(void)
return 0;
}
+void usb_cpia_cleanup(void)
+{
+ usb_deregister(&cpia_driver);
+}
+
#ifdef MODULE
int init_module(void)
{
@@ -1249,6 +1330,7 @@ int init_module(void)
void cleanup_module(void)
{
+ usb_cpia_cleanup();
}
#endif
diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h
index 4596ec159..f1d9ed7cd 100644
--- a/drivers/usb/cpia.h
+++ b/drivers/usb/cpia.h
@@ -78,9 +78,10 @@
#define CPIA_YUYV 0
#define CPIA_UYVY 1
-#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
+#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
+/* #define STREAM_BUF_SIZE (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC) */
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
#define FRAMES_PER_DESC 10
#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
@@ -91,54 +92,97 @@ enum {
STATE_LINES, /* Parsing lines */
};
+#define CPIA_MAGIC 0x1968
+struct cpia_frame_header {
+ __u16 magic; /* 0 - 1 */
+ __u16 timestamp; /* 2 - 3 */
+ __u16 unused; /* 4 - 5 */
+ __u16 timestamp1; /* 6 - 7 */
+ __u8 unused1[8]; /* 8 - 15 */
+ __u8 video_size; /* 16 0 = QCIF, 1 = CIF */
+ __u8 sub_sample; /* 17 0 = 4:2:0, 1 = 4:2:2 */
+ __u8 yuv_order; /* 18 0 = YUYV, 1 = UYVY */
+ __u8 unused2[5]; /* 19 - 23 */
+ __u8 col_start; /* 24 */
+ __u8 col_end; /* 25 */
+ __u8 row_start; /* 26 */
+ __u8 row_end; /* 27 */
+ __u8 comp_enable; /* 28 0 = non compressed, 1 = compressed */
+ __u8 decimation; /* 29 0 = no decimation, 1 = decimation */
+ __u8 y_thresh; /* 30 */
+ __u8 uv_thresh; /* 31 */
+ __u8 system_state; /* 32 */
+ __u8 grab_state; /* 33 */
+ __u8 stream_state; /* 34 */
+ __u8 fatal_error; /* 35 */
+ __u8 cmd_error; /* 36 */
+ __u8 debug_flags; /* 37 */
+ __u8 camera_state_7; /* 38 */
+ __u8 camera_state_8; /* 39 */
+ __u8 cr_achieved; /* 40 */
+ __u8 fr_achieved; /* 41 */
+ __u8 unused3[22]; /* 42 - 63 */
+};
+
struct usb_device;
struct cpia_sbuf {
char *data;
- int len;
struct usb_isoc_desc *isodesc;
-#if 0
- void *isodesc;
-#endif
};
enum {
- FRAME_READY, /* Ready to grab into */
+ FRAME_UNUSED, /* Unused (no MCAPTURE) */
+ FRAME_READY, /* Ready to start grabbing */
FRAME_GRABBING, /* In the process of being grabbed into */
FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
+ FRAME_ERROR, /* Something bad happened while processing */
};
struct cpia_frame {
- char *data;
- int width;
- int height;
- int state;
+ char *data; /* Frame buffer */
+
+ struct cpia_frame_header header; /* Header from stream */
+
+ int width; /* Width application is expecting */
+ int height; /* Height */
+
+ int hdrwidth; /* Width the frame actually is */
+ int hdrheight; /* Height */
+
+ int grabstate; /* State of grabbing */
+ int scanstate; /* State of scanning */
+
+ int curline; /* Line of frame we're working on */
+
+ wait_queue_head_t wq; /* Processes waiting */
};
+#define CPIA_NUMFRAMES 2
+#define CPIA_NUMSBUF 2
+
struct usb_cpia {
struct video_device vdev;
/* Device structure */
struct usb_device *dev;
- int streaming;
+ int streaming; /* Are we streaming Isochronous? */
+ int grabbing; /* Are we grabbing? */
- char *fbuf; /* Videodev buffer area */
+ int compress; /* Should the next frame be compressed? */
- int curframe;
- struct cpia_frame frame[2]; /* Double buffering */
+ char *fbuf; /* Videodev buffer area */
- int receivesbuf; /* Current receiving sbuf */
- struct cpia_sbuf sbuf[3]; /* Triple buffering */
+ int curframe;
+ struct cpia_frame frame[CPIA_NUMFRAMES]; /* Double buffering */
- int state; /* Current scanning state */
- int curline;
+ int cursbuf; /* Current receiving sbuf */
+ struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
- char scratch[SCRATCH_BUF_SIZE];
+ /* Scratch space from the Isochronous pipe */
+ unsigned char scratch[SCRATCH_BUF_SIZE];
int scratchlen;
-
- wait_queue_head_t wq;
};
#endif
diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c
index 4c00ef143..59e7b4a67 100644
--- a/drivers/usb/ezusb.c
+++ b/drivers/usb/ezusb.c
@@ -27,7 +27,8 @@
* Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
* Preliminary ISO support
* 0.3 01.09.99 Async Bulk and ISO support
- * 0.4 01.09.99
+ * 0.4 01.09.99 Set callback_frames to the total number of frames to make
+ * it work with OHCI-HCD
*
*/
@@ -40,9 +41,10 @@
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <asm/uaccess.h>
+#include <linux/spinlock.h>
+
#include "usb.h"
#include "ezusb.h"
@@ -76,9 +78,9 @@ struct async {
/* --------------------------------------------------------------------- */
-extern inline unsigned ld2(unsigned int x)
+extern inline unsigned int ld2(unsigned int x)
{
- unsigned r = 0;
+ unsigned int r = 0;
if (x >= 0x10000) {
x >>= 16;
@@ -101,6 +103,17 @@ extern inline unsigned ld2(unsigned int x)
return r;
}
+#if 0
+/* why doesn't this work properly on i386? */
+extern inline unsigned int ld2(unsigned int x)
+{
+ unsigned int r;
+
+ __asm__("bsrl %1,%0" : "=r" (r) : "g" (x));
+ return r;
+}
+#endif
+
/* --------------------------------------------------------------------- */
extern __inline__ void async_removelist(struct async *as)
@@ -173,22 +186,41 @@ extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context
/* --------------------------------------------------------------------- */
-static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+static int bulk_completed(int status, void *__buffer, int rval, void *dev_id)
{
struct async *as = (struct async *)dev_id;
struct ezusb *ez = as->ez;
unsigned cnt;
-printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+printk(KERN_DEBUG "ezusb: bulk_completed: status %d rval %d\n", status, rval);
as->completed.length = rval;
- if (as->numframes > 0) {
- as->completed.status = USB_ST_NOERROR;
- for (cnt = 0; cnt < as->numframes; cnt++) {
- as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
- as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
- }
- } else
- as->completed.status = status;
+ as->completed.status = status;
+ spin_lock(&ez->lock);
+ list_del(&as->asynclist);
+ list_add_tail(&as->asynclist, &ez->async_completed);
+ spin_unlock(&ez->lock);
+ wake_up(&ez->wait);
+ return 0;
+}
+
+static int iso_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+#if 1
+ struct async *as = (struct async *)dev_id;
+#else
+ struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
+ struct async *as = (struct async *)id->context;
+#endif
+ struct ezusb *ez = as->ez;
+ unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: iso_completed: status %d rval %d\n", status, rval);
+ as->completed.length = rval;
+ as->completed.status = USB_ST_NOERROR;
+ for (cnt = 0; cnt < as->numframes; cnt++) {
+ as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+ as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+ }
spin_lock(&ez->lock);
list_del(&as->asynclist);
list_add_tail(&as->asynclist, &ez->async_completed);
@@ -264,7 +296,6 @@ static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
unsigned ret = 0;
unsigned len;
unsigned char b[64];
- devrequest dr;
int i;
if (*ppos < 0 || *ppos >= 0x10000)
@@ -280,15 +311,10 @@ static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
len = sizeof(b);
if (pos + len > 0x10000)
len = 0x10000 - pos;
- dr.requesttype = 0xc0;
- dr.request = 0xa0;
- dr.value = pos;
- dr.index = 0;
- dr.length = len;
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), &dr, b, len);
+ i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ);
if (i) {
up(&ez->mutex);
- printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+ printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i);
*ppos = pos;
if (ret)
return ret;
@@ -318,7 +344,6 @@ static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t
unsigned ret = 0;
unsigned len;
unsigned char b[64];
- devrequest dr;
int i;
if (*ppos < 0 || *ppos >= 0x10000)
@@ -341,15 +366,10 @@ static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t
return ret;
return -EFAULT;
}
- dr.requesttype = 0x40;
- dr.request = 0xa0;
- dr.value = pos;
- dr.index = 0;
- dr.length = len;
- i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), &dr, b, len);
+ i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ);
if (i) {
up(&ez->mutex);
- printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+ printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i);
*ppos = pos;
if (ret)
return ret;
@@ -401,7 +421,7 @@ static int ezusb_release(struct inode *inode, struct file *file)
static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
unsigned char request, unsigned short value,
unsigned short index, unsigned short length,
- void *data)
+ unsigned int timeout, void *data)
{
unsigned char *tbuf = NULL;
unsigned int pipe;
@@ -429,7 +449,7 @@ static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
}
}
}
- i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+ i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length, timeout);
if (i < 0) {
if (length > 0)
free_page((unsigned long)tbuf);
@@ -444,7 +464,7 @@ static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
return i;
}
-static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data)
{
unsigned char *tbuf = NULL;
unsigned int pipe;
@@ -473,7 +493,7 @@ static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int l
}
}
}
- ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+ ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout);
if (ret < 0) {
if (length > 0)
free_page((unsigned long)tbuf);
@@ -553,7 +573,7 @@ static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
}
}
async_newpending(as);
- if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+ if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, bulk_completed, as->data, ab->len, as))) {
async_removelist(as);
goto err_inval;
}
@@ -592,6 +612,7 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
return -EINVAL;
dsize = maxpkt * ai->framecnt;
+printk(KERN_DEBUG "ezusb: iso: dsize %d\n", dsize);
if (dsize > 65536)
return -EINVAL;
order = ld2(dsize >> PAGE_SHIFT);
@@ -603,6 +624,7 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
if (!(as = kmalloc(assize, GFP_KERNEL)))
return -ENOMEM;
+printk(KERN_DEBUG "ezusb: iso: assize %d\n", assize);
memset(as, 0, assize);
INIT_LIST_HEAD(&as->asynclist);
as->ez = ez;
@@ -630,8 +652,8 @@ static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigne
}
as->desc.iso->start_type = START_ABSOLUTE;
as->desc.iso->start_frame = ai->startframe;
- as->desc.iso->callback_frames = 0;
- as->desc.iso->callback_fn = async_completed;
+ as->desc.iso->callback_frames = /*0*/ai->framecnt;
+ as->desc.iso->callback_fn = iso_completed;
as->desc.iso->data = as->data;
as->desc.iso->buf_size = dsize;
for (j = 0; j < ai->framecnt; j++) {
@@ -709,9 +731,13 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
DECLARE_WAITQUEUE(wait, current);
struct usb_proc_ctrltransfer pctrl;
struct usb_proc_bulktransfer pbulk;
+ struct usb_proc_old_ctrltransfer opctrl;
+ struct usb_proc_old_bulktransfer opbulk;
struct usb_proc_setinterface psetintf;
struct ezusb_ctrltransfer ctrl;
struct ezusb_bulktransfer bulk;
+ struct ezusb_old_ctrltransfer octrl;
+ struct ezusb_old_bulktransfer obulk;
struct ezusb_setinterface setintf;
struct ezusb_asyncbulk abulk;
struct ezusb_asynciso aiso;
@@ -732,7 +758,8 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
}
ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request,
- pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+ pctrl.value, pctrl.index, pctrl.length,
+ (pctrl.timeout * HZ + 500) / 1000, pctrl.data);
break;
case USB_PROC_BULK:
@@ -740,7 +767,25 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+ ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len,
+ (pbulk.timeout * HZ + 500) / 1000, pbulk.data);
+ break;
+
+ case USB_PROC_OLD_CONTROL:
+ if (copy_from_user(&opctrl, (void *)arg, sizeof(opctrl))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_control(ez->usbdev, opctrl.requesttype, opctrl.request,
+ opctrl.value, opctrl.index, opctrl.length, HZ, opctrl.data);
+ break;
+
+ case USB_PROC_OLD_BULK:
+ if (copy_from_user(&opbulk, (void *)arg, sizeof(opbulk))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_bulk(ez->usbdev, opbulk.ep, opbulk.len, 5*HZ, opbulk.data);
break;
case USB_PROC_RESETEP:
@@ -772,12 +817,9 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- if (ctrl.dlen != ctrl.length) {
- ret = -EINVAL;
- break;
- }
ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request,
- ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+ ctrl.value, ctrl.index, ctrl.length,
+ (ctrl.timeout * HZ + 500) / 1000, ctrl.data);
break;
case EZUSB_BULK:
@@ -785,7 +827,29 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
ret = -EFAULT;
break;
}
- ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+ ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len,
+ (bulk.timeout * HZ + 500) / 1000, bulk.data);
+ break;
+
+ case EZUSB_OLD_CONTROL:
+ if (copy_from_user(&octrl, (void *)arg, sizeof(octrl))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (octrl.dlen != octrl.length) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = ezusb_control(ez->usbdev, octrl.requesttype, octrl.request,
+ octrl.value, octrl.index, octrl.length, HZ, octrl.data);
+ break;
+
+ case EZUSB_OLD_BULK:
+ if (copy_from_user(&obulk, (void *)arg, sizeof(obulk))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = ezusb_bulk(ez->usbdev, obulk.ep, obulk.len, 5*HZ, obulk.data);
break;
case EZUSB_RESETEP:
@@ -813,6 +877,7 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case EZUSB_ASYNCCOMPLETED:
+ as = NULL;
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&ez->wait, &wait);
for (;;) {
@@ -928,9 +993,11 @@ static int ezusb_probe(struct usb_device *usbdev)
if (usbdev->descriptor.bNumConfigurations != 1)
return -1;
+#if 0
/* We don't handle multiple interfaces */
if (usbdev->config[0].bNumInterfaces != 1)
return -1;
+#endif
down(&ez->mutex);
if (ez->usbdev) {
diff --git a/drivers/usb/ezusb.h b/drivers/usb/ezusb.h
index 630169d11..1d2597129 100644
--- a/drivers/usb/ezusb.h
+++ b/drivers/usb/ezusb.h
@@ -31,6 +31,23 @@
/* --------------------------------------------------------------------- */
+struct ezusb_old_ctrltransfer {
+ /* keep in sync with usb.h:devrequest */
+ unsigned char requesttype;
+ unsigned char request;
+ unsigned short value;
+ unsigned short index;
+ unsigned short length;
+ unsigned int dlen;
+ void *data;
+};
+
+struct ezusb_old_bulktransfer {
+ unsigned int ep;
+ unsigned int len;
+ void *data;
+};
+
struct ezusb_ctrltransfer {
/* keep in sync with usb.h:devrequest */
unsigned char requesttype;
@@ -38,14 +55,14 @@ struct ezusb_ctrltransfer {
unsigned short value;
unsigned short index;
unsigned short length;
- /* pointer to data */
- unsigned dlen;
+ unsigned int timeout; /* in milliseconds */
void *data;
};
struct ezusb_bulktransfer {
unsigned int ep;
unsigned int len;
+ unsigned int timeout; /* in milliseconds */
void *data;
};
@@ -84,8 +101,10 @@ struct ezusb_asynciso {
struct ezusb_isoframestat isostat[0];
};
-#define EZUSB_CONTROL _IOWR('E', 0, struct ezusb_ctrltransfer)
+#define EZUSB_CONTROL _IOWR('E', 1, struct ezusb_ctrltransfer)
#define EZUSB_BULK _IOWR('E', 2, struct ezusb_bulktransfer)
+#define EZUSB_OLD_CONTROL _IOWR('E', 0, struct ezusb_old_ctrltransfer)
+#define EZUSB_OLD_BULK _IOWR('E', 2, struct ezusb_old_bulktransfer)
#define EZUSB_RESETEP _IOR('E', 3, unsigned int)
#define EZUSB_SETINTERFACE _IOR('E', 4, struct ezusb_setinterface)
#define EZUSB_SETCONFIGURATION _IOR('E', 5, unsigned int)
diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c
index c7a5af555..bdf3c4181 100644
--- a/drivers/usb/hp_scanner.c
+++ b/drivers/usb/hp_scanner.c
@@ -130,7 +130,7 @@ write_scanner(struct file * file, const char * buffer,
return bytes_written ? bytes_written : -EINTR;
}
- result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial);
+ result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial, HZ*10);
//printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
@@ -188,7 +188,7 @@ read_scanner(struct file * file, char * buffer,
return -ENODEV;
this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
- result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial);
+ result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial, HZ*10);
printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 691cb9a58..59a539867 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -34,33 +34,33 @@ static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
- USB_DT_HUB << 8, 0, data, size);
+ USB_DT_HUB << 8, 0, data, size, HZ);
}
static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0);
+ USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}
static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0);
+ USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
}
static int usb_get_hub_status(struct usb_device *dev, void *data)
{
/* FIXME: Don't hardcode 4 */
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4);
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4, HZ);
}
static int usb_get_port_status(struct usb_device *dev, int port, void *data)
{
/* FIXME: Don't hardcode 4 */
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4);
+ USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4, HZ);
}
/*
diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h
index cc49fbbd5..1d9acb1a4 100644
--- a/drivers/usb/inits.h
+++ b/drivers/usb/inits.h
@@ -6,5 +6,8 @@ int usb_printer_init(void);
void usb_hub_cleanup(void);
void usb_mouse_cleanup(void);
int usb_scsi_init(void);
+int usb_hp_scanner_init(void);
+void usb_hp_scanner_cleanup(void);
int proc_usb_init (void);
void proc_usb_cleanup (void);
+int usb_serial_init (void);
diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c
index 13f5eccaa..f35f1b091 100644
--- a/drivers/usb/keyboard.c
+++ b/drivers/usb/keyboard.c
@@ -21,7 +21,7 @@
#define PCKBD_RELEASED 0x80
#define PCKBD_NEEDS_E0 0x80
-#define USBKBD_MODIFIER_BASE 120
+#define USBKBD_MODIFIER_BASE 224
#define USBKBD_KEYCODE_OFFSET 2
#define USBKBD_KEYCODE_COUNT 6
diff --git a/drivers/usb/keymap.c b/drivers/usb/keymap.c
index 478de504b..82e2f1454 100644
--- a/drivers/usb/keymap.c
+++ b/drivers/usb/keymap.c
@@ -22,7 +22,7 @@ unsigned char usb_kbd_map[256] =
0xbd, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -42,7 +42,7 @@ unsigned char usb_kbd_map[256] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/drivers/usb/maps/usb.map b/drivers/usb/maps/usb.map
index e05c71cd8..f4f40ffbf 100644
--- a/drivers/usb/maps/usb.map
+++ b/drivers/usb/maps/usb.map
@@ -223,11 +223,11 @@ keycode 104 = F13
keycode 105 = F14
# modifiers
-keycode 120 = Control
-keycode 121 = Shift
-keycode 122 = Alt
-keycode 123 = Window
-keycode 124 = Control_R
-keycode 125 = Shift_R
-keycode 126 = Alt_R
-keycode 127 = Window_R
+keycode 224 = Control
+keycode 225 = Shift
+keycode 226 = Alt
+keycode 227 = Window
+keycode 228 = Control_R
+keycode 229 = Shift_R
+keycode 230 = Alt_R
+keycode 231 = Window_R
diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c
index 4384f07d3..da5ee515e 100644
--- a/drivers/usb/mouse.c
+++ b/drivers/usb/mouse.c
@@ -120,7 +120,7 @@ static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
wake_up_interruptible(&mouse->wait);
if (mouse->fasync)
- kill_fasync(mouse->fasync, SIGIO);
+ kill_fasync(mouse->fasync, SIGIO, POLL_IN);
return 1;
}
diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c
index 339652d21..628b93428 100644
--- a/drivers/usb/ohci-debug.c
+++ b/drivers/usb/ohci-debug.c
@@ -80,7 +80,7 @@ void show_ohci_ed(struct ohci_ed *ed)
printk(KERN_DEBUG " ohci ED:\n");
printk(KERN_DEBUG " status = 0x%x\n", stat);
- printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d%s\n",
+ printk(KERN_DEBUG " %sMPS %d%s%s%s%s tc%d e%d fa%d [HCD_%d%s]\n",
skip ? "Skip " : "",
mps,
isoc ? " Isoc." : "",
@@ -91,7 +91,8 @@ void show_ohci_ed(struct ohci_ed *ed)
toggle,
endnum,
funcaddr,
- (stat & ED_ALLOCATED) ? " Allocated" : "");
+ ohci_ed_hcdtype(ed) >> 27,
+ (stat & ED_ALLOCATED) ? ", Allocated" : "");
printk(KERN_DEBUG " tail_td = 0x%x\n", ed_tail_td(ed));
printk(KERN_DEBUG " head_td = 0x%x\n", ed_head_td(ed));
printk(KERN_DEBUG " next_ed = 0x%x\n", le32_to_cpup(&ed->next_ed));
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
index 34f2613e6..eeace6d61 100644
--- a/drivers/usb/ohci-hcd.c
+++ b/drivers/usb/ohci-hcd.c
@@ -14,7 +14,7 @@
* [ Open Host Controller Interface driver for USB. ]
* [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
* [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
+ * [ _Log: ohci-hcd.c,v _
* [ Revision 1.1 1999/04/05 08:32:30 greg ]
*
* v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
@@ -224,7 +224,7 @@ static int sohci_release_irq(struct usb_device *usb_dev, void * ed)
return 0;
}
-static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
+static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct ohci_state state = {0, TD_NOTACCESSED};
@@ -254,7 +254,7 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devr
OHCI_DEBUG(printk("USB HC trans req ed %x: %x :", ed->hwINFO, (unsigned int ) ed); )
OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed);
- schedule_timeout(HZ*5);
+ schedule_timeout(timeout);
if(state.status == TD_NOTACCESSED) {
current->state = TASK_UNINTERRUPTIBLE;
@@ -266,7 +266,7 @@ static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devr
return state.status;
}
-static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
+static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct ohci_state state = {0, TD_NOTACCESSED};
@@ -286,7 +286,7 @@ static int sohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *d
ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) &state, (__OHCI_BAG) &wait,(usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_blocking_handler);
if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed);
- schedule_timeout(HZ*5);
+ schedule_timeout(timeout);
if(state.status == TD_NOTACCESSED) {
current->state = TASK_UNINTERRUPTIBLE;
diff --git a/drivers/usb/ohci-hcd.h b/drivers/usb/ohci-hcd.h
index 35cb4148c..3ff3ae91d 100644
--- a/drivers/usb/ohci-hcd.h
+++ b/drivers/usb/ohci-hcd.h
@@ -12,7 +12,7 @@
* [ Open Host Controller Interface driver for USB. ]
* [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
* [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
+ * [ _Log: ohci-hcd.h,v _
* [ Revision 1.1 1999/04/05 08:32:30 greg ]
*
* v4.0 1999/08/18
diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c
index a7da1361b..763b8199e 100644
--- a/drivers/usb/ohci.c
+++ b/drivers/usb/ohci.c
@@ -15,7 +15,7 @@
* Architecture" book by Mindshare, Inc. It was a reasonable introduction
* and overview of USB and the two dominant host controller interfaces
* however you're better off just reading the real specs available
- * from www.usb.org as you'll need them to get enough detailt to
+ * from www.usb.org as you'll need them to get enough details to
* actually implement a HCD. The book has many typos and omissions
* Beware, the specs are the victim of a committee.
*
@@ -24,7 +24,7 @@
*
* No filesystems were harmed in the development of this code.
*
- * $Id: ohci.c,v 1.43 1999/05/16 22:35:24 greg Exp $
+ * $Id: ohci.c,v 1.77 1999/09/16 04:30:19 greg Exp $
*/
#include <linux/config.h>
@@ -201,7 +201,6 @@ static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
} /* ohci_add_ed_to_hw() */
-
/*
* Put a control ED on the controller's list
*/
@@ -275,24 +274,19 @@ struct ohci_ed *ohci_get_periodic_ed(struct ohci_device *dev, int period,
for (;;) {
int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed));
/* stop if we get to the end or to another dummy ED. */
- if (int_ed == 0)
- break;
+ if (!int_ed)
+ break; /* return NULL */
status = le32_to_cpup(&int_ed->status);
- if ((status & OHCI_ED_FA) == 0)
- break;
+ if ((status & OHCI_ED_FA) == 0) {
+ int_ed = NULL;
+ break; /* return NULL */
+ }
/* check whether all the appropriate fields match */
if ((status & 0x7ffa7ff) == req_status)
- return int_ed;
+ break; /* return int_ed */
}
- return 0;
-}
-
-/*
- * Put an isochronous ED on the controller's list
- */
-inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
- ohci_add_periodic_ed(ohci, ed, 1);
+ spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+ return int_ed;
}
@@ -326,14 +320,14 @@ static void ohci_wait_sof(struct ohci_regs *regs)
* adds it to a list of EDs to destroy during the SOF interrupt
* processing would be useful (and be callable from an interrupt).
*/
-void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_type)
+void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed)
{
__u32 *hw_listcurrent;
/* tell the controller to skip this ED */
ed->status |= cpu_to_le32(OHCI_ED_SKIP);
- switch (ed_type) {
+ switch (ohci_ed_hcdtype(ed)) {
case HCD_ED_CONTROL:
hw_listcurrent = &regs->ed_controlcurrent;
break;
@@ -370,7 +364,7 @@ void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_ty
*
* Note that the SKIP bit is left on in the removed ED.
*/
-void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_type)
+void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed)
{
unsigned long flags;
struct ohci_regs *regs = ohci->regs;
@@ -378,6 +372,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
__u32 bus_ed = virt_to_bus(ed);
__u32 bus_cur;
__u32 *hw_listhead_p;
+ __u32 ed_type = ohci_ed_hcdtype(ed);
if (ed == NULL || !bus_ed)
return;
@@ -391,7 +386,9 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
hw_listhead_p = &regs->ed_bulkhead;
break;
default:
- printk(KERN_ERR "Unknown HCD ED type %d.\n", ed_type);
+#ifdef OHCI_DEBUG
+ printk(KERN_ERR "Wrong HCD ED type: %d.\n", ed_type);
+#endif
return;
}
@@ -426,7 +423,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
/*
* Make sure this ED is not being accessed by the HC as we speak.
*/
- ohci_wait_for_ed_safe(regs, ed, ed_type);
+ ohci_wait_for_ed_safe(regs, ed);
/* clear any links from the ED for safety */
ed->next_ed = 0;
@@ -434,24 +431,6 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
} /* ohci_remove_norm_ed_from_hw() */
-/*
- * Remove an ED from the controller's control list. Note that the SKIP bit
- * is left on in the removed ED.
- */
-inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
- ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_CONTROL);
-}
-
-/*
- * Remove an ED from the controller's bulk list. Note that the SKIP bit
- * is left on in the removed ED.
- */
-inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
- ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK);
-}
-
/*
* Remove a periodic ED from the host controller
@@ -476,7 +455,7 @@ void ohci_remove_periodic_ed(struct ohci *ohci, struct ohci_ed *ed)
while (cur_ed) {
if (ed == cur_ed) { /* remove the ED */
/* set its SKIP bit and be sure its not in use */
- ohci_wait_for_ed_safe(ohci->regs, ed, HCD_ED_INT);
+ ohci_wait_for_ed_safe(ohci->regs, ed);
/* unlink it */
spin_lock_irqsave(&ohci_edtd_lock, flags);
@@ -506,6 +485,20 @@ void ohci_remove_periodic_ed(struct ohci *ohci, struct ohci_ed *ed)
/*
+ * Remove an ED from the host controller, choosing
+ */
+void ohci_remove_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+ /* Remove the ED from the HC */
+ if (ohci_ed_hcdtype(ed) & HCD_ED_NORMAL) {
+ ohci_remove_norm_ed_from_hw(ohci, ed);
+ } else {
+ ohci_remove_periodic_ed(ohci, ed);
+ }
+} /* ohci_remove_ed() */
+
+
+/*
* Remove all the EDs which have a given device address from a list.
* Used when the device is unplugged.
* Returns 1 if anything was changed.
@@ -573,7 +566,7 @@ void ohci_remove_device(struct ohci *ohci, int devnum)
* Remove a TD from the given EDs TD list. The TD is freed as well.
* (so far this function hasn't been needed)
*/
-static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
{
unsigned long flags;
struct ohci_td *head_td;
@@ -670,10 +663,9 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
* pool. Return NULL if none are left.
*
* NOTE: This function does not allocate and attach the dummy_td.
- * That is done in ohci_fill_ed(). FIXME: it should probably be moved
- * into here.
+ * That is done in ohci_fill_ed(). [should we really do that here?]
*/
-static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
+static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev, __u32 ed_type)
{
int idx;
@@ -687,6 +679,7 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
/* mark it as allocated */
allocate_ed(new_ed);
+ ohci_ed_set_hcdtype(new_ed, ed_type);
new_ed->ohci_dev = dev;
return new_ed;
}
@@ -764,8 +757,7 @@ struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32
* force the Allocated bit on.
*/
struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
- int maxpacketsize, int lowspeed, int endp_id,
- int isoc_tds)
+ int maxpacketsize, int lowspeed, int endp_id)
{
struct ohci_td *dummy_td;
@@ -789,11 +781,12 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
/* set the head TD to the dummy and clear the Carry & Halted bits */
ed->_head_td = ed->tail_td;
- ed->status = cpu_to_le32(
+ ed->status &= cpu_to_le32(OHCI_ED_HCD_MASK);
+ ed->status |= cpu_to_le32(
ed_set_maxpacket(maxpacketsize) |
ed_set_speed(lowspeed) |
(endp_id & 0x7ff) |
- ((isoc_tds == 0) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC));
+ ((ohci_ed_hcdtype(ed) != HCD_ED_ISOC) ? OHCI_ED_F_NORM : OHCI_ED_F_ISOC));
allocate_ed(ed);
ed->next_ed = 0;
@@ -959,7 +952,7 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
/* Get an ED and TD */
interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0);
if (interrupt_ed == 0) {
- interrupt_ed = ohci_get_free_ed(dev);
+ interrupt_ed = ohci_get_free_ed(dev, HCD_ED_INT);
if (!interrupt_ed) {
printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
return (-ENOMEM);
@@ -970,7 +963,7 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
* device number (function address), and type of TD.
*/
ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
- usb_pipe_endpdev(pipe), 0 /* normal TDs */);
+ usb_pipe_endpdev(pipe) );
interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
/* Assimilate the new ED into the collective */
@@ -1077,7 +1070,7 @@ int ohci_release_irq(struct usb_device *usb, void* handle)
static void * ohci_generic_trans(struct usb_device *usb_dev, int pipe,
int data_td_toggle, int round, int autofree,
void *dev_id, usb_device_irq handler, void *data, int len,
- int ed_type, struct ohci_td *setup_td, struct ohci_td *status_td)
+ __u32 ed_type, struct ohci_td *setup_td, struct ohci_td *status_td)
{
struct ohci_device *dev = usb_to_ohci(usb_dev);
struct ohci_ed *trans_ed;
@@ -1089,7 +1082,7 @@ static void * ohci_generic_trans(struct usb_device *usb_dev, int pipe,
printk(KERN_DEBUG "ohci_request_trans()\n");
#endif
- trans_ed = ohci_get_free_ed(dev);
+ trans_ed = ohci_get_free_ed(dev, ed_type);
if (!trans_ed) {
printk("usb-ohci: couldn't get ED for dev %p\n", dev);
return NULL;
@@ -1142,8 +1135,7 @@ static void * ohci_generic_trans(struct usb_device *usb_dev, int pipe,
ohci_fill_ed(dev, trans_ed,
usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)),
usb_pipeslow(pipe),
- usb_pipe_endpdev(pipe),
- (ed_type == HCD_ED_ISOC) );
+ usb_pipe_endpdev(pipe) );
/* initialize the toggle carry flag in the ED */
if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
@@ -1202,7 +1194,7 @@ gt_free_and_exit:
*
* This function is NOT safe to call from an interrupt.
*/
-static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle, int ed_type)
+static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle)
{
struct ohci_ed *req_ed = (struct ohci_ed *) handle;
struct ohci_device *dev = usb_to_ohci(usb_dev);
@@ -1213,20 +1205,10 @@ static int ohci_terminate_trans(struct usb_device *usb_dev, void *handle, int ed
/* stop the transfer & collect the number of bytes */
/* (this is the non-interrupt safe function call) */
- ohci_wait_for_ed_safe(regs, req_ed, ed_type);
+ ohci_wait_for_ed_safe(regs, req_ed);
- /* Remove the ED from the appropriate HC list */
- switch (ed_type) {
- case HCD_ED_ISOC:
- ohci_remove_periodic_ed(dev->ohci, req_ed);
- break;
- case HCD_ED_CONTROL:
- ohci_remove_control_ed(dev->ohci, req_ed);
- break;
- case HCD_ED_BULK:
- ohci_remove_bulk_ed(dev->ohci, req_ed);
- break;
- }
+ /* Remove the ED from the HC */
+ ohci_remove_ed(dev->ohci, req_ed);
ohci_free_ed(req_ed); /* return it to the pool */
@@ -1252,7 +1234,15 @@ static int ohci_control_completed(int stats, void *buffer, int len, void *dev_id
/* pass the TDs completion status back to control_msg */
if (dev_id) {
int *completion_status = (int *)dev_id;
- *completion_status = stats;
+
+ switch (stats) {
+ case USB_ST_NOERROR:
+ case USB_ST_DATAOVERRUN:
+ *completion_status = len;
+ break;
+ default:
+ *completion_status = -stats;
+ }
}
wake_up(&control_wakeup);
@@ -1274,13 +1264,13 @@ static int ohci_control_completed(int stats, void *buffer, int len, void *dev_id
* This function can NOT be called from an interrupt.
*/
static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
- devrequest *cmd, void *data, int len)
+ devrequest *cmd, void *data, int len, int timeout)
{
struct ohci_device *dev = usb_to_ohci(usb_dev);
void *trans_handle;
struct ohci_td *setup_td, *status_td;
DECLARE_WAITQUEUE(wait, current);
- int completion_status = -1;
+ int completion_status = USB_ST_TIMEOUT;
devrequest our_cmd;
/* byte-swap fields of cmd if necessary */
@@ -1356,8 +1346,8 @@ static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
return USB_ST_INTERNALERROR;
}
- /* wait a "reasonable" amount of time for it to complete */
- schedule_timeout(HZ);
+ /* wait a user defined amount of time for it to complete */
+ schedule_timeout(timeout);
remove_wait_queue(&control_wakeup, &wait);
@@ -1369,9 +1359,12 @@ static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
* Also, since the TDs were autofreed, there is no guarantee that
* they haven't been reclaimed by another transfer by now...
*/
- if (completion_status != 0) {
- const char *what = (completion_status < 0)? "timed out":
- cc_names[completion_status & 0xf];
+ if (completion_status < 0) {
+ const char *what;
+ if (completion_status == USB_ST_TIMEOUT)
+ what = "timed out";
+ else
+ what = cc_names[(-completion_status) & 0xf];
printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x",
what, pipe, cmd->requesttype, cmd->request,
cmd->value, cmd->index, cmd->length);
@@ -1422,10 +1415,8 @@ static int ohci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
/* no TD cleanup, the TDs were auto-freed as they finished */
/* remove the generic_trans ED from the HC and free it */
- ohci_terminate_trans(usb_dev, trans_handle, HCD_ED_CONTROL);
+ ohci_terminate_trans(usb_dev, trans_handle);
- if (completion_status < 0)
- completion_status = USB_ST_TIMEOUT;
return completion_status;
} /* ohci_control_msg() */
@@ -1471,7 +1462,7 @@ static void * ohci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u
*/
static int ohci_terminate_bulk(struct usb_device *usb_dev, void * handle)
{
- return ohci_terminate_trans(usb_dev, handle, HCD_ED_CONTROL);
+ return ohci_terminate_trans(usb_dev, handle);
} /* ohci_terminate_bulk() */
@@ -1536,24 +1527,6 @@ static int ohci_bulk_msg_td_handler(int stats, void *buffer, int len, void *dev_
} /* ohci_bulk_msg_td_handler() */
-/*
- * Request to send or receive bulk data for a blocking bulk_msg call.
- *
- * bulk_request->bytes_transferred_p is a pointer to an integer that
- * will be set to the number of bytes that have been successfully
- * transferred upon completion. The interrupt handler will update it
- * after each internal TD completes successfully.
- */
-static struct ohci_ed* ohci_request_bulk_msg(struct ohci_bulk_msg_request_state *bulk_request)
-{
- /* initialize the internal counter */
- bulk_request->_bytes_done = 0;
-
- return ohci_request_bulk(bulk_request->usb_dev, bulk_request->pipe,
- ohci_bulk_msg_td_handler,
- bulk_request->data, bulk_request->length,
- bulk_request);
-} /* ohci_request_bulk_msg() */
static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
@@ -1574,7 +1547,7 @@ static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_i
} /* ohci_bulk_msg_completed() */
-static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p)
+static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int completion_status = USB_ST_INTERNALERROR;
@@ -1598,6 +1571,7 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
req.bytes_transferred_p = bytes_transferred_p;
req.dev_id = &completion_status;
req.completion = ohci_bulk_msg_completed;
+ req._bytes_done = 0;
if (bytes_transferred_p)
*bytes_transferred_p = 0;
@@ -1611,10 +1585,20 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
current->state = TASK_UNINTERRUPTIBLE;
add_wait_queue(&bulk_wakeup, &wait);
- req_ed = ohci_request_bulk_msg(&req);
+ /*
+ * Request to send or receive bulk data for a blocking bulk_msg call.
+ *
+ * req.bytes_transferred_p is a pointer to an integer that
+ * will be set to the number of bytes that have been successfully
+ * transferred upon completion. The interrupt handler will update it
+ * after each internal TD completes successfully.
+ */
+ req_ed = ohci_request_bulk(usb_dev, pipe,
+ ohci_bulk_msg_td_handler,
+ data, len, &req);
- /* FIXME this should to wait for a caller specified time... */
- schedule_timeout(HZ*5);
+ /* wait for a caller specified time... */
+ schedule_timeout(timeout);
/* completion_status will only stay in this state of the
* request never finished */
@@ -1629,7 +1613,7 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
* a previously requested bulk transfer. -greg */
/* stop the transfer & collect the number of bytes */
- ohci_wait_for_ed_safe(regs, req_ed, HCD_ED_BULK);
+ ohci_wait_for_ed_safe(regs, req_ed);
/* Get the number of bytes transferred out of the head TD
* on the ED if it didn't finish while we were waiting. */
@@ -1659,7 +1643,7 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
remove_wait_queue(&bulk_wakeup, &wait);
/* remove the ED from the HC */
- ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+ ohci_remove_norm_ed_from_hw(usb_to_ohci(usb_dev)->ohci, req_ed);
/* save the toggle value back into the usb_dev */
usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe),
@@ -1681,31 +1665,19 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
/*
- * Allocate a new USB device to be attached to an OHCI controller
+ * Allocate a new USB device attached to this OHCI controller
*/
-static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
+static int ohci_dev_allocate(struct usb_device *usb_dev)
{
- struct usb_device *usb_dev;
struct ohci_device *dev;
int idx;
/*
- * Allocate the generic USB device
- */
- usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
- if (!usb_dev)
- return NULL;
-
- memset(usb_dev, 0, sizeof(*usb_dev));
-
- /*
* Allocate an OHCI device (EDs and TDs for this device)
*/
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- kfree(usb_dev);
- return NULL;
- }
+ if (!dev)
+ return -1;
memset(dev, 0, sizeof(*dev));
@@ -1721,80 +1693,71 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
usb_dev->hcpriv = dev;
dev->usb = usb_dev;
- /*
- * Link the device to its parent (hub, etc..) if any.
- */
- usb_dev->parent = parent;
+ if (usb_dev->parent)
+ dev->ohci = usb_to_ohci(usb_dev->parent)->ohci;
- if (parent) {
- usb_dev->bus = parent->bus;
- dev->ohci = usb_to_ohci(parent)->ohci;
- }
-
- return usb_dev;
-} /* ohci_usb_allocate() */
+ return 0;
+} /* ohci_dev_allocate() */
/*
- * Free a usb device.
- *
- * TODO This function needs to take better care of the EDs and TDs, etc.
+ * Free a usb device on this ohci controller.
*/
-static int ohci_usb_deallocate(struct usb_device *usb_dev)
+static int ohci_dev_deallocate(struct usb_device *usb_dev)
{
struct ohci_device *dev = usb_to_ohci(usb_dev);
ohci_remove_device(dev->ohci, usb_dev->devnum);
- /* kfree(usb_to_ohci(usb_dev)); */
- /* kfree(usb_dev); */
+ kfree(usb_to_ohci(usb_dev));
return 0;
}
-
-static void *ohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+static int ohci_get_current_frame_number(struct usb_device *usb_dev)
{
- return NULL;
+ return USB_ST_NOTSUPPORTED;
}
-static void ohci_delete_isochronous (struct usb_device *dev, void *_isodesc)
+static int ohci_alloc_isochronous (struct usb_device *usb_dev,
+unsigned int pipe, int frame_count, void *context,
+struct usb_isoc_desc **isocdesc)
{
- return;
+ return USB_ST_NOTSUPPORTED;
}
-static int ohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+static void ohci_delete_isochronous (struct usb_isoc_desc *isocdesc)
{
- return USB_ST_NOTSUPPORTED;
+ return;
}
-static int ohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc)
+static int ohci_sched_isochronous (struct usb_isoc_desc *isocdesc,
+struct usb_isoc_desc *pr_isocdesc)
{
return USB_ST_NOTSUPPORTED;
}
-static int ohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+static int ohci_unsched_isochronous (struct usb_isoc_desc *isocdesc)
{
return USB_ST_NOTSUPPORTED;
}
-
/*
* functions for the generic USB driver
*/
struct usb_operations ohci_device_operations = {
- ohci_usb_allocate,
- ohci_usb_deallocate,
+ ohci_dev_allocate,
+ ohci_dev_deallocate,
ohci_control_msg,
ohci_bulk_msg,
ohci_request_irq,
ohci_release_irq,
ohci_request_bulk,
ohci_terminate_bulk,
+ ohci_get_current_frame_number,
ohci_alloc_isochronous,
ohci_delete_isochronous,
ohci_sched_isochronous,
- ohci_unsched_isochronous,
- ohci_compress_isochronous
+ ohci_unsched_isochronous
};
@@ -1887,8 +1850,10 @@ static int start_hc(struct ohci *ohci)
/* Enter the USB Operational state & start the frames a flowing.. */
writel_set(OHCI_USB_OPER, &ohci->regs->control);
- /* Enable control lists */
- writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
+ /* Enable control lists, claim the host controller */
+ writel_set(
+ OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE,
+ &ohci->regs->control);
/* Force global power enable -gal@cs.uni-magdeburg.de */
/*
@@ -1988,10 +1953,11 @@ static void ohci_connect_change(struct ohci * ohci, int port)
/*
* Allocate a device for the new thingy that's been attached
*/
- usb_dev = ohci_usb_allocate(root_hub->usb);
- dev = usb_dev->hcpriv;
+ usb_dev = usb_alloc_dev(root_hub->usb, root_hub->usb->bus);
+ if (!usb_dev)
+ return;
- dev->ohci = ohci;
+ dev = usb_dev->hcpriv;
usb_connect(dev->usb);
@@ -2360,6 +2326,8 @@ static struct ohci *alloc_ohci(void* mem_base)
struct usb_bus *bus;
struct ohci_device *dev;
struct usb_device *usb;
+ struct ohci_hcca *hcca;
+ u32 ctrl;
#if 0
printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
@@ -2368,22 +2336,28 @@ static struct ohci *alloc_ohci(void* mem_base)
ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
if (!ohci)
return NULL;
-
memset(ohci, 0, sizeof(*ohci));
ohci->irq = -1;
ohci->regs = mem_base;
INIT_LIST_HEAD(&ohci->interrupt_list);
- bus = kmalloc(sizeof(*bus), GFP_KERNEL);
- if (!bus)
- return NULL;
+ /*
+ * Allocate the Host Controller Communications Area on a 256
+ * byte boundary. XXX take the easy way out and just grab a
+ * page as that's guaranteed to have a nice boundary.
+ */
+ hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
+ if (hcca == NULL)
+ goto au_free_ohci;
+ memset(hcca, 0, sizeof(struct ohci_hcca));
- memset(bus, 0, sizeof(*bus));
+ bus = usb_alloc_bus(&ohci_device_operations);
+ if (!bus)
+ goto au_free_hcca;
ohci->bus = bus;
bus->hcpriv = ohci;
- bus->op = &ohci_device_operations;
/*
* Allocate the USB device structure and root hub.
@@ -2393,25 +2367,21 @@ static struct ohci *alloc_ohci(void* mem_base)
* a nice pool of memory with pointers to endpoint descriptors
* for the different interrupts.
*/
- usb = ohci_usb_allocate(NULL);
+ usb = usb_alloc_dev(NULL, bus);
if (!usb)
- return NULL;
+ goto au_free_bus;
- dev = usb_to_ohci(usb);
- ohci->bus->root_hub= ohci_to_usb(dev);
usb->bus = bus;
+
+ dev = usb_to_ohci(usb);
+ dev->ohci = ohci;
+ dev->hcca = hcca;
+
+ ohci->bus->root_hub = ohci_to_usb(dev);
/* Initialize the root hub */
dev->ohci = ohci; /* link back to the controller */
- /*
- * Allocate the Host Controller Communications Area on a 256
- * byte boundary. XXX take the easy way out and just grab a
- * page as that's guaranteed to have a nice boundary.
- */
- dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
- memset(dev->hcca, 0, sizeof(struct ohci_hcca));
-
/* Tell the controller where the HCCA is */
writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
@@ -2431,6 +2401,25 @@ static struct ohci *alloc_ohci(void* mem_base)
}
printk(KERN_DEBUG "usb-ohci: %d root hub ports found\n", usb->maxchild);
+
+ /*
+ * Fix up legacy mode
+ */
+
+ ctrl = readl(&ohci->regs->control);
+ if(ctrl&OHCI_USB_IR)
+ {
+ int ct = 0;
+ /* Ask SMM for the controls */
+ writel(8, &ohci->regs->cmdstatus);
+ printk(KERN_INFO "usb-ohci: switching interface from legacy mode.\n");
+ while((readl(&ohci->regs->control)&OHCI_USB_IR) && ct < 250)
+ {
+ udelay(100);
+ ct++;
+ }
+ }
+
/*
* Initialize the ED polling "tree" (for simplicity's sake in
* this driver many nodes in the tree will be identical)
@@ -2485,6 +2474,15 @@ static struct ohci *alloc_ohci(void* mem_base)
#endif
return ohci;
+
+au_free_bus:
+ usb_free_bus(bus);
+au_free_hcca:
+ free_page((unsigned long)hcca);
+au_free_ohci:
+ kfree(ohci);
+ return NULL;
+
} /* alloc_ohci() */
@@ -2753,6 +2751,8 @@ static int init_ohci(struct pci_dev *dev)
if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
return -ENODEV;
+ pci_set_master(dev);
+
/* Get the memory address and map it for IO */
mem_base = dev->resource[0].start;
diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h
index 4bb71c55c..b06e5ca65 100644
--- a/drivers/usb/ohci.h
+++ b/drivers/usb/ohci.h
@@ -6,7 +6,7 @@
*
* (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
*
- * $Id: ohci.h,v 1.24 1999/05/16 10:18:26 greg Exp $
+ * $Id: ohci.h,v 1.40 1999/09/05 07:26:46 greg Exp $
*/
#include <linux/list.h>
@@ -148,19 +148,45 @@ struct ohci_ed {
#define OHCI_ED_EN (0xf << 7)
#define OHCI_ED_FA (0x7f)
+
#define ed_get_en(ed) ((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7)
#define ed_get_fa(ed) (le32_to_cpup(&(ed)->status) & OHCI_ED_FA)
/* NOTE: bits 27-31 of the status dword are reserved for the HCD */
+#define OHCI_ED_HCD_MASK (0x1f << 27)
/*
* We'll use this status flag for to mark if an ED is in use by the
- * driver or not. If the bit is set, it is being used.
+ * driver or not. If the bit is set, it is being used. (bit 31)
*/
#define ED_ALLOCATED (1 << 31)
#define ed_allocated(ed) (le32_to_cpup(&(ed).status) & ED_ALLOCATED)
#define allocate_ed(ed) ((ed)->status |= cpu_to_le32(ED_ALLOCATED))
/*
+ * These store the endpoint transfer type for this ED in the status
+ * field. (bits 27 and 28)
+ * Bit 28:
+ * 0 = Periodic ED
+ * Bit 27:
+ * 0 = Isochronous
+ * 1 = Interrupt
+ * 1 = Normal ED
+ * Bit 27:
+ * 0 = Control
+ * 1 = Bulk
+ */
+#define HCD_ED_NORMAL (1 << 28) /* (2 << 27) */
+#define HCD_ED_ISOC (0)
+#define HCD_ED_INT (1 << 27)
+#define HCD_ED_CONTROL (2 << 27)
+#define HCD_ED_BULK (3 << 27)
+#define HCD_ED_MASK (3 << 27)
+
+#define ohci_ed_hcdtype(ed) (le32_to_cpup(&(ed)->status) & HCD_ED_MASK)
+#define ohci_ed_set_hcdtype(ed, t) ( (ed)->status = ((ed)->status & ~cpu_to_le32(HCD_ED_MASK)) | cpu_to_le32((t) & HCD_ED_MASK) )
+
+
+/*
* The HCCA (Host Controller Communications Area) is a 256 byte
* structure defined in the OHCI spec. that the host controller is
* told the base address of. It must be 256-byte aligned.
@@ -299,15 +325,6 @@ struct ohci_regs {
} roothub;
} __attribute((aligned(32)));
-/*
- * These are used by internal ED managing functions as a
- * parameter to state the type of ED to deal with (when it matters).
- */
-#define HCD_ED_ISOC (0)
-#define HCD_ED_INT (1)
-#define HCD_ED_CONTROL (2)
-#define HCD_ED_BULK (3)
-
/*
* Read a MMIO register and re-write it after ANDing with (m)
*/
@@ -368,12 +385,16 @@ struct ohci_regs {
/*
* Control register masks
*/
+#define OHCI_USB_RESUME (1 << 6)
#define OHCI_USB_OPER (2 << 6)
#define OHCI_USB_SUSPEND (3 << 6)
#define OHCI_USB_PLE (1 << 2) /* Periodic (interrupt) list enable */
#define OHCI_USB_IE (1 << 3) /* Isochronous list enable */
#define OHCI_USB_CLE (1 << 4) /* Control list enable */
#define OHCI_USB_BLE (1 << 5) /* Bulk list enable */
+#define OHCI_USB_IR (1 << 8) /* Int. Routing, HCD ownership */
+#define OHCI_USB_RWC (1 << 9) /* Remote Wakeup Connected */
+#define OHCI_USB_RWE (1 << 10) /* Remote Wakeup Enable */
/*
* Command status register masks
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 826df63a8..17dac365a 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -58,7 +58,7 @@ unsigned char printer_read_status(struct pp_usb_data *p)
dr.value = 0;
dr.index = 0;
dr.length = 1;
- if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1)) {
+ if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 1, HZ)) {
return 0;
}
return status;
@@ -104,7 +104,7 @@ void printer_reset(struct pp_usb_data *p)
dr.value = 0;
dr.index = 0;
dr.length = 0;
- dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ);
}
static int open_printer(struct inode * inode, struct file * file)
@@ -129,10 +129,11 @@ static int open_printer(struct inode * inode, struct file * file)
printer_check_status(p);
-
file->private_data = p;
// printer_reset(p);
init_waitqueue_head(&p->wait_q);
+
+ MOD_INC_USE_COUNT;
return 0;
}
@@ -143,13 +144,12 @@ static int close_printer(struct inode * inode, struct file * file)
free_page((unsigned long)p->obuf);
p->isopen = 0;
file->private_data = NULL;
+ /* free the resources if the printer is no longer around */
if(!p->pusb_dev) {
minor_data[p->minor] = NULL;
kfree(p);
-
- MOD_DEC_USE_COUNT;
-
}
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -184,7 +184,7 @@ static ssize_t write_printer(struct file * file,
}
result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
usb_sndbulkpipe(p->pusb_dev, endpoint_num),
- obuf, thistime, &partial);
+ obuf, thistime, &partial, HZ*20);
if (partial) {
obuf += partial;
thistime -= partial;
@@ -243,7 +243,7 @@ static ssize_t read_printer(struct file * file,
result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
usb_rcvbulkpipe(p->pusb_dev, endpoint_num),
- buf, this_read, &partial);
+ buf, this_read, &partial, HZ*20);
/* unlike writes, we don't retry a NAK, just stop now */
if (!result & partial)
@@ -344,7 +344,7 @@ static int printer_probe(struct usb_device *dev)
dr.value = 0;
dr.index = 0;
dr.length = sizeof(ieee_id) - 1;
- if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1) == 0) {
+ if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, ieee_id, sizeof(ieee_id)-1, HZ) == 0) {
if (ieee_id[1] < sizeof(ieee_id) - 1)
ieee_id[ieee_id[1]+2] = '\0';
else
@@ -373,7 +373,6 @@ static void printer_disconnect(struct usb_device *dev)
minor_data[pp->minor] = NULL;
kfree(pp);
dev->private = NULL; /* just in case */
- MOD_DEC_USE_COUNT;
}
static struct usb_driver printer_driver = {
@@ -402,8 +401,6 @@ int usb_printer_init(void)
{
int result;
- MOD_INC_USE_COUNT;
-
if ((result = register_chrdev(USB_PRINTER_MAJOR, "usblp", &usb_printer_fops)) < 0) {
printk(KERN_WARNING "usbprinter: Cannot register device\n");
return result;
diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c
index ae97e749c..53c5e87e0 100644
--- a/drivers/usb/proc_usb.c
+++ b/drivers/usb/proc_usb.c
@@ -286,9 +286,12 @@ static int usb_dump_desc (const struct usb_device *dev, char *buf, int *len)
static int usb_hcd_bandwidth (const struct usb_device *dev, char *buf, int *len)
{
*len += sprintf (buf + *len, format_bandwidth,
- dev->bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
- 100 * dev->bus->bandwidth_allocated / FRAME_TIME_MAX_USECS_ALLOC,
- dev->bus->bandwidth_int_reqs, dev->bus->bandwidth_isoc_reqs
+ dev->bus->bandwidth_allocated,
+ FRAME_TIME_MAX_USECS_ALLOC,
+ (100 * dev->bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) /
+ FRAME_TIME_MAX_USECS_ALLOC,
+ dev->bus->bandwidth_int_reqs,
+ dev->bus->bandwidth_isoc_reqs
);
return (*len >= DUMP_LIMIT) ? -1 : 0;
@@ -360,12 +363,12 @@ static int usb_device_dump (char *buf, int *len,
if (*len >= DUMP_LIMIT)
return -1;
- if (usbdev->devnum > 0) { /* for any except root hub */
- if (usb_dump_desc (usbdev, buf, len) < 0)
+ if ((level == 0) && (usbdev->devnum < 0)) { /* for root hub */
+ if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
return -1;
}
- else { /* for a host controller */
- if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
+ else { /* for anything but a root hub */
+ if (usb_dump_desc (usbdev, buf, len) < 0)
return -1;
}
@@ -509,8 +512,10 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
struct usb_device *dev = (struct usb_device *)dp->data;
struct ezusb_ctrltransfer ctrl;
struct ezusb_bulktransfer bulk;
+ struct ezusb_old_ctrltransfer octrl;
+ struct ezusb_old_bulktransfer obulk;
struct ezusb_setinterface setintf;
- unsigned int len1, ep, pipe;
+ unsigned int len1, ep, pipe, cfg;
unsigned long len2;
unsigned char *tbuf;
int i;
@@ -525,24 +530,28 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
- if (ctrl.dlen > PAGE_SIZE)
+ if (ctrl.length > PAGE_SIZE)
return -EINVAL;
if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
return -ENOMEM;
if (ctrl.requesttype & 0x80) {
- if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) {
+ if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen);
- if (!i && ctrl.dlen) {
- copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
+ i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ ctrl.value, ctrl.index, tbuf, ctrl.length,
+ (ctrl.timeout * HZ + 500) / 1000);
+ if (!i && ctrl.length) {
+ copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
}
} else {
- if (ctrl.dlen) {
- copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
+ if (ctrl.length) {
+ copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
}
- i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen);
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+ ctrl.value, ctrl.index, tbuf, ctrl.length,
+ (ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
if (i) {
@@ -577,7 +586,7 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
if (!i && len2) {
copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
}
@@ -585,7 +594,7 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
if (len1) {
copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
}
- i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
if (i) {
@@ -595,6 +604,85 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
}
return len2;
+ case EZUSB_OLD_CONTROL:
+ if (obsolete_warn < 20) {
+ printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_OLD_CONTROL ioctl\n",
+ current->pid, current->comm);
+ obsolete_warn++;
+ }
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
+ if (octrl.dlen > PAGE_SIZE)
+ return -EINVAL;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (octrl.requesttype & 0x80) {
+ if (octrl.dlen && !access_ok(VERIFY_WRITE, octrl.data, octrl.dlen)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+ if (!i && octrl.dlen) {
+ copy_to_user_ret(octrl.data, tbuf, octrl.dlen, -EFAULT);
+ }
+ } else {
+ if (octrl.dlen) {
+ copy_from_user_ret(tbuf, octrl.data, octrl.dlen, -EFAULT);
+ }
+ i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&octrl, tbuf, octrl.dlen, HZ);
+ }
+ free_page((unsigned long)tbuf);
+ if (i) {
+ printk(KERN_WARNING "procusb: EZUSB_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n",
+ octrl.requesttype, octrl.request, octrl.length, i);
+ return -ENXIO;
+ }
+ return 0;
+
+ case EZUSB_OLD_BULK:
+ if (obsolete_warn < 20) {
+ printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_OLD_BULK ioctl\n",
+ current->pid, current->comm);
+ obsolete_warn++;
+ }
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
+ if (obulk.ep & 0x80)
+ pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
+ if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
+ return -EINVAL;
+ len1 = obulk.len;
+ if (len1 > PAGE_SIZE)
+ len1 = PAGE_SIZE;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (obulk.ep & 0x80) {
+ if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+ if (!i && len2) {
+ copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
+ }
+ } else {
+ if (len1) {
+ copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
+ }
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+ }
+ free_page((unsigned long)tbuf);
+ if (i) {
+ printk(KERN_WARNING "procusb: EZUSB_OLD_BULK failed ep 0x%x len %u ret %d\n",
+ obulk.ep, obulk.len, i);
+ return -ENXIO;
+ }
+ return len2;
+
case EZUSB_RESETEP:
if (obsolete_warn < 20) {
printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_RESETEP ioctl\n",
@@ -621,6 +709,20 @@ static int usbdev_ioctl_ezusbcompat(struct inode *inode, struct file *file, unsi
if (usb_set_interface(dev, setintf.interface, setintf.altsetting))
return -EINVAL;
return 0;
+
+ case EZUSB_SETCONFIGURATION:
+ if (obsolete_warn < 20) {
+ printk(KERN_WARNING "/proc/bus/usb: process %d (%s) used obsolete EZUSB_SETCONFIGURATION ioctl\n",
+ current->pid, current->comm);
+ obsolete_warn++;
+ }
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
+ if (usb_set_configuration(dev, cfg) < 0)
+ return -EINVAL;
+ return 0;
+
}
return -ENOIOCTLCMD;
}
@@ -633,8 +735,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct usb_device *dev = (struct usb_device *)dp->data;
struct usb_proc_ctrltransfer ctrl;
struct usb_proc_bulktransfer bulk;
+ struct usb_proc_old_ctrltransfer octrl;
+ struct usb_proc_old_bulktransfer obulk;
struct usb_proc_setinterface setintf;
- unsigned int len1, ep, pipe;
+ unsigned int len1, ep, pipe, cfg;
unsigned long len2;
unsigned char *tbuf;
int i;
@@ -655,7 +759,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request,
ctrl.requesttype, ctrl.value, ctrl.index, tbuf,
- ctrl.length);
+ ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
if (!i && ctrl.length) {
copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
}
@@ -665,7 +769,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request,
ctrl.requesttype, ctrl.value, ctrl.index, tbuf,
- ctrl.length);
+ ctrl.length, (ctrl.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
if (i) {
@@ -695,7 +799,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
free_page((unsigned long)tbuf);
return -EINVAL;
}
- i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
if (!i && len2) {
copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
}
@@ -703,7 +807,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (len1) {
copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
}
- i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2);
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, (bulk.timeout * HZ + 500) / 1000);
}
free_page((unsigned long)tbuf);
if (i) {
@@ -713,6 +817,79 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
return len2;
+ case USB_PROC_OLD_CONTROL:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ copy_from_user_ret(&octrl, (void *)arg, sizeof(octrl), -EFAULT);
+ if (octrl.length > PAGE_SIZE)
+ return -EINVAL;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (octrl.requesttype & 0x80) {
+ if (octrl.length && !access_ok(VERIFY_WRITE, octrl.data, octrl.length)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), octrl.request,
+ octrl.requesttype, octrl.value, octrl.index, tbuf,
+ octrl.length, HZ);
+ if (!i && octrl.length) {
+ copy_to_user_ret(octrl.data, tbuf, octrl.length, -EFAULT);
+ }
+ } else {
+ if (octrl.length) {
+ copy_from_user_ret(tbuf, octrl.data, octrl.length, -EFAULT);
+ }
+ i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), octrl.request,
+ octrl.requesttype, octrl.value, octrl.index, tbuf,
+ octrl.length, HZ);
+ }
+ free_page((unsigned long)tbuf);
+ if (i) {
+ printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_CONTROL failed rqt %u rq %u len %u ret %d\n",
+ octrl.requesttype, octrl.request, octrl.length, i);
+ return -ENXIO;
+ }
+ return 0;
+
+ case USB_PROC_OLD_BULK:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ copy_from_user_ret(&obulk, (void *)arg, sizeof(obulk), -EFAULT);
+ if (obulk.ep & 0x80)
+ pipe = usb_rcvbulkpipe(dev, obulk.ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(dev, obulk.ep & 0x7f);
+ if (!usb_maxpacket(dev, pipe, !(obulk.ep & 0x80)))
+ return -EINVAL;
+ len1 = obulk.len;
+ if (len1 > PAGE_SIZE)
+ len1 = PAGE_SIZE;
+ if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if (obulk.ep & 0x80) {
+ if (len1 && !access_ok(VERIFY_WRITE, obulk.data, len1)) {
+ free_page((unsigned long)tbuf);
+ return -EINVAL;
+ }
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+ if (!i && len2) {
+ copy_to_user_ret(obulk.data, tbuf, len2, -EFAULT);
+ }
+ } else {
+ if (len1) {
+ copy_from_user_ret(tbuf, obulk.data, len1, -EFAULT);
+ }
+ i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2, HZ*5);
+ }
+ free_page((unsigned long)tbuf);
+ if (i) {
+ printk(KERN_WARNING "/proc/bus/usb: USB_PROC_OLD_BULK failed ep 0x%x len %u ret %d\n",
+ obulk.ep, obulk.len, i);
+ return -ENXIO;
+ }
+ return len2;
+
case USB_PROC_RESETEP:
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
@@ -730,10 +907,21 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
return 0;
+ case USB_PROC_SETCONFIGURATION:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ get_user_ret(cfg, (unsigned int *)arg, -EFAULT);
+ if (usb_set_configuration(dev, cfg) < 0)
+ return -EINVAL;
+ return 0;
+
case EZUSB_CONTROL:
case EZUSB_BULK:
+ case EZUSB_OLD_CONTROL:
+ case EZUSB_OLD_BULK:
case EZUSB_RESETEP:
case EZUSB_SETINTERFACE:
+ case EZUSB_SETCONFIGURATION:
return usbdev_ioctl_ezusbcompat(inode, file, cmd, arg);
}
return -ENOIOCTLCMD;
diff --git a/drivers/usb/serial.c b/drivers/usb/serial.c
new file mode 100644
index 000000000..b85f2b5c6
--- /dev/null
+++ b/drivers/usb/serial.c
@@ -0,0 +1,691 @@
+/*
+ * USB Serial Converter driver
+ *
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This was based on the ACM driver by Armin Fuerst (which was based
+ * on a driver by Brad Keryan)
+ *
+ * Currently only works for the Belkin and Peracom Serial converters.
+ * Should also work on the Etek serial converter, if anyone knows the
+ * vendor and device ids for that device.
+ *
+ *
+ * version 0.1.1 (10/05/99) gkh
+ * Changed the major number to not conflict with anything else.
+ *
+ * version 0.1 (09/28/99) gkh
+ * Can recognize the two different devices and start up a read from
+ * device when asked to. Writes also work. No control signals yet, this
+ * all is vendor specific data (i.e. no spec), also no control for
+ * different baud rates or other bit settings.
+ * Currently we are using the same devid as the acm driver. This needs
+ * to change.
+ *
+ * (C) Copyright 1999 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+#include "usb.h"
+/*#define SERIAL_DEBUG 1*/
+
+#ifdef SERIAL_DEBUG
+ #define debug_info(message); printk(message);
+#else
+ #define debug_info(message);
+#endif
+
+
+/* USB Serial devices vendor ids and device ids that this driver supports */
+#define BELKIN_VENDOR_ID 0x056c
+#define BELKIN_SERIAL_CONVERTER 0x8007
+#define PERACOM_VENDOR_ID 0x0565
+#define PERACOM_SERIAL_CONVERTER 0x0001
+
+
+#define SERIAL_MAJOR 240
+
+#define NUM_PORTS 4 /* Have to pick a number for now. Need to look */
+ /* into dynamically creating them at insertion time. */
+
+
+static int usb_serial_probe(struct usb_device *dev);
+static void usb_serial_disconnect(struct usb_device *dev);
+
+typedef enum {
+ unknown = 0,
+ Belkin = 1,
+ Peracom = 2
+ } SERIAL_TYPE;
+
+struct usb_serial_state {
+ struct usb_device * dev;
+ SERIAL_TYPE type; /* what manufacturer's type of converter */
+ void * irq_handle;
+ unsigned int irqpipe;
+ struct tty_struct *tty; /* the coresponding tty for this device */
+ char present;
+ char active;
+
+ char interrupt_in_inuse;
+ __u8 interrupt_in_endpoint;
+ __u8 interrupt_in_interval;
+ __u16 interrupt_in_size;
+ unsigned int interrupt_in_pipe;
+ unsigned char * interrupt_in_buffer;
+ void * interrupt_in_transfer;
+
+ char bulk_in_inuse;
+ __u8 bulk_in_endpoint;
+ __u8 bulk_in_interval;
+ __u16 bulk_in_size;
+ unsigned int bulk_in_pipe;
+ unsigned char * bulk_in_buffer;
+ void * bulk_in_transfer;
+
+ char bulk_out_inuse;
+ __u8 bulk_out_endpoint;
+ __u8 bulk_out_interval;
+ __u16 bulk_out_size;
+ unsigned int bulk_out_pipe;
+ unsigned char * bulk_out_buffer;
+ void * bulk_out_transfer;
+};
+
+static struct usb_driver usb_serial_driver = {
+ "serial",
+ usb_serial_probe,
+ usb_serial_disconnect,
+ { NULL, NULL }
+};
+
+static int serial_refcount;
+static struct tty_driver serial_tty_driver;
+static struct tty_struct * serial_tty[NUM_PORTS];
+static struct termios * serial_termios[NUM_PORTS];
+static struct termios * serial_termios_locked[NUM_PORTS];
+static struct usb_serial_state serial_state_table[NUM_PORTS];
+
+
+
+static int serial_read_irq (int state, void *buffer, int count, void *dev_id)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *)dev_id;
+ struct tty_struct *tty = serial->tty;
+ unsigned char* data = buffer;
+ int i;
+
+ debug_info("USB: serial_read_irq\n");
+
+#ifdef SERIAL_DEBUG
+ if (count) {
+ printk("%d %s\n", count, data);
+ }
+#endif
+
+ if (count) {
+ for (i=0;i<count;i++) {
+ tty_insert_flip_char(tty,data[i],0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Continue transfer */
+ /* return (1); */
+
+ /* No more transfer, let the irq schedule us again */
+ serial->bulk_in_inuse = 0;
+ return (0);
+}
+
+
+static int serial_write_irq (int state, void *buffer, int count, void *dev_id)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *) dev_id;
+ struct tty_struct *tty = serial->tty;
+
+ debug_info("USB Serial: serial_write_irq\n");
+
+ if (!serial->bulk_out_inuse) {
+ debug_info("USB Serial: write irq for a finished pipe?\n");
+ return (0);
+ }
+
+ usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+ serial->bulk_out_inuse = 0;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ return 0;
+}
+
+
+static int usb_serial_irq (int state, void *buffer, int len, void *dev_id)
+{
+// struct usb_serial_state *serial = (struct usb_serial_state *) dev_id;
+
+ debug_info("USB Serial: usb_serial_irq\n");
+
+ /* ask for a bulk read */
+// serial->bulk_in_inuse = 1;
+// serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+ return (1);
+}
+
+
+
+
+
+/* tty interface functions */
+static int serial_open (struct tty_struct *tty, struct file * filp)
+{
+ struct usb_serial_state *serial;
+
+ debug_info("USB: serial_open\n");
+
+ serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start];
+ tty->driver_data = serial;
+ serial->tty = tty;
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return -EINVAL;
+ }
+
+ if (serial->active) {
+ debug_info ("USB Serial: device already open\n");
+ return -EINVAL;
+ }
+ serial->active = 1;
+
+ /*Start reading from the device*/
+ serial->bulk_in_inuse = 1;
+ serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+ /* Need to do device specific setup here (control lines, baud rate, etc.) */
+ /* FIXME!!! */
+
+ return (0);
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ debug_info("USB: serial_close\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return;
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device already open\n");
+ return;
+ }
+
+ /* Need to change the control lines here */
+ /* FIXME */
+
+ if (serial->bulk_out_inuse){
+ usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+ serial->bulk_out_inuse = 0;
+ }
+ if (serial->bulk_in_inuse){
+ usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+ serial->bulk_in_inuse = 0;
+ }
+
+ /* release the irq? */
+
+ serial->active = 0;
+}
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+ int written;
+
+ debug_info("USB Serial: serial_write\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: device not registered\n");
+ return (-EINVAL);
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not opened\n");
+ return (-EINVAL);
+ }
+
+ if (serial->bulk_out_inuse) {
+ debug_info ("USB Serial: already writing\n");
+ return (0);
+ }
+
+ written = (count > serial->bulk_out_size) ? serial->bulk_out_size : count;
+
+ if (from_user) {
+ copy_from_user(serial->bulk_out_buffer, buf, written);
+ }
+ else {
+ memcpy (serial->bulk_out_buffer, buf, written);
+ }
+
+ /* send the data out the bulk port */
+ serial->bulk_out_inuse = 1;
+ serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, written, serial);
+
+ return (written);
+}
+
+
+static void serial_put_char (struct tty_struct *tty, unsigned char ch)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+
+ debug_info("USB Serial: serial_put_char\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return;
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not open\n");
+ return;
+ }
+
+ if (serial->bulk_out_inuse) {
+ debug_info ("USB Serial: already writing\n");
+ return;
+ }
+
+ /* send the single character out the bulk port */
+ serial->bulk_out_buffer[0] = ch;
+ serial->bulk_out_inuse = 1;
+ serial->bulk_out_transfer = usb_request_bulk (serial->dev, serial->bulk_out_pipe, serial_write_irq, serial->bulk_out_buffer, 1, serial);
+
+ return;
+}
+
+
+static int serial_write_room (struct tty_struct *tty)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+
+ debug_info("USB Serial: serial_write_room\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return (-EINVAL);
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not open\n");
+ return (-EINVAL);
+ }
+
+ if (serial->bulk_out_inuse) {
+ return (0);
+ }
+
+ return serial->bulk_out_size;
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data;
+
+ debug_info("USB Serial: serial_chars_in_buffer\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return (-EINVAL);
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not open\n");
+ return (-EINVAL);
+ }
+
+ if (serial->bulk_out_inuse) {
+ return (serial->bulk_out_size);
+ }
+
+ return (0);
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+
+ debug_info("USB Serial: serial_throttle\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return;
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not open\n");
+ return;
+ }
+
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data;
+
+ debug_info("USB Serial: serial_unthrottle\n");
+
+ if (!serial->present) {
+ debug_info("USB Serial: no device registered\n");
+ return;
+ }
+
+ if (!serial->active) {
+ debug_info ("USB Serial: device not open\n");
+ return;
+ }
+
+
+ /* Change the control signals */
+ /* FIXME!!! */
+
+ return;
+}
+
+
+static int Get_Free_Serial (void)
+{
+ int i;
+
+ for (i=0; i < NUM_PORTS; ++i) {
+ if (!serial_state_table[i].present)
+ return (i);
+ }
+ return (-1);
+}
+
+
+static int usb_serial_probe(struct usb_device *dev)
+{
+ struct usb_serial_state *serial;
+ struct usb_interface_descriptor *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ SERIAL_TYPE type;
+ int serial_num;
+// int ret;
+ int i;
+
+ /* look at the device descriptor to see if it is a type that we recognize */
+ type = unknown;
+ if ((dev->descriptor.idVendor == BELKIN_VENDOR_ID) &&
+ (dev->descriptor.idProduct == BELKIN_SERIAL_CONVERTER)) {
+ /* This is the Belkin serial convertor */
+ type = Belkin;
+ }
+
+ if ((dev->descriptor.idVendor == PERACOM_VENDOR_ID) &&
+ (dev->descriptor.idProduct == PERACOM_SERIAL_CONVERTER)) {
+ /* This is the Peracom serial convertor */
+ type = Peracom;
+ }
+
+ if (type == unknown)
+ return (-1);
+
+ printk (KERN_INFO "USB serial converter detected.\n");
+
+ if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+ printk (KERN_INFO " Failed usb_set_configuration: serial\n");
+ return (-1);
+ }
+
+ if (0>(serial_num = Get_Free_Serial())) {
+ debug_info("USB Serial: Too many devices connected\n");
+ return (-1);
+ }
+
+ serial = &serial_state_table[serial_num];
+
+ memset(serial, 0, sizeof(serial));
+ serial->dev = dev;
+ serial->type = type;
+ dev->private = serial;
+
+ /* we should have 1 bulk in, 1 bulk out, and 1 interrupt in endpoints */
+ interface = &dev->config[0].interface[0].altsetting[0];
+ for (i = 0; i < interface->bNumEndpoints; ++i) {
+ endpoint = &interface->endpoint[i];
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found the bulk in endpoint */
+ serial->bulk_in_inuse = 0;
+ serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+ serial->bulk_in_size = endpoint->wMaxPacketSize;
+ serial->bulk_in_interval = endpoint->bInterval;
+ serial->bulk_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint);
+ serial->bulk_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+ if (!serial->bulk_in_buffer) {
+ printk("USB Serial: Couldn't allocate bulk_in_buffer\n");
+ goto probe_error;
+ }
+ }
+
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found the bulk out endpoint */
+ serial->bulk_out_inuse = 0;
+ serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+ serial->bulk_out_size = endpoint->wMaxPacketSize;
+ serial->bulk_out_interval = endpoint->bInterval;
+ serial->bulk_out_pipe = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint);
+ serial->bulk_out_buffer = kmalloc (serial->bulk_out_size, GFP_KERNEL);
+ if (!serial->bulk_out_buffer) {
+ printk("USB Serial: Couldn't allocate bulk_out_buffer\n");
+ goto probe_error;
+ }
+ }
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x03)) {
+ /* we found the interrupt in endpoint */
+ serial->interrupt_in_inuse = 0;
+ serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+ serial->interrupt_in_size = endpoint->wMaxPacketSize;
+ serial->interrupt_in_interval = endpoint->bInterval;
+ /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */
+ serial->interrupt_in_buffer = kmalloc (serial->bulk_in_size, GFP_KERNEL);
+ if (!serial->bulk_in_buffer) {
+ printk("USB Serial: Couldn't allocate interrupt_in_buffer\n");
+ goto probe_error;
+ }
+ }
+
+ }
+
+
+ /* verify that we found all of the endpoints that we need */
+ if ((!serial->bulk_in_buffer) ||
+ (!serial->bulk_out_buffer) ||
+ (!serial->interrupt_in_buffer)) {
+ printk("USB Serial: did not find all of the required endpoints\n");
+ goto probe_error;
+ }
+
+
+ /* set up an interrupt for out bulk in pipe */
+ /* ask for a bulk read */
+// serial->bulk_in_inuse = 1;
+// serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial);
+
+ /* set up our interrupt to be the time for the bulk in read */
+// ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle);
+// if (ret) {
+// printk(KERN_INFO "USB Serial failed usb_request_irq (0x%x)\n", ret);
+// goto probe_error;
+// }
+
+ serial->present = 1;
+ MOD_INC_USE_COUNT;
+
+ return (0);
+
+probe_error:
+ if (serial) {
+ if (serial->bulk_in_buffer)
+ kfree (serial->bulk_in_buffer);
+ if (serial->bulk_out_buffer)
+ kfree (serial->bulk_out_buffer);
+ if (serial->interrupt_in_buffer)
+ kfree (serial->interrupt_in_buffer);
+ }
+ return (-1);
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev)
+{
+ struct usb_serial_state *serial = (struct usb_serial_state *)dev->private;
+
+ if (serial) {
+ if (!serial->present) {
+ /* something strange is going on */
+ debug_info("USB Serial: disconnect but not present?\n")
+ return;
+ }
+
+ /* need to stop any transfers...*/
+ if (serial->bulk_in_inuse) {
+ usb_terminate_bulk (serial->dev, serial->bulk_in_transfer);
+ serial->bulk_in_inuse = 0;
+ }
+ if (serial->bulk_out_inuse) {
+ usb_terminate_bulk (serial->dev, serial->bulk_out_transfer);
+ serial->bulk_out_inuse = 0;
+ }
+ // usb_release_irq (serial->dev, serial->irq_handle, serial->bulk_in_pipe);
+ if (serial->bulk_in_buffer)
+ kfree (serial->bulk_in_buffer);
+ if (serial->bulk_out_buffer)
+ kfree (serial->bulk_out_buffer);
+ if (serial->interrupt_in_buffer)
+ kfree (serial->interrupt_in_buffer);
+
+ serial->present = 0;
+ serial->active = 0;
+ }
+ dev->private = NULL;
+
+ MOD_DEC_USE_COUNT;
+
+ printk (KERN_INFO "USB Serial device disconnected.\n");
+}
+
+
+
+int usb_serial_init(void)
+{
+ int i;
+
+ /* Initalize our global data */
+ for (i = 0; i < NUM_PORTS; ++i) {
+ memset(&serial_state_table[i], 0x00, sizeof(struct usb_serial_state));
+ }
+
+ /* register the tty driver */
+ memset (&serial_tty_driver, 0, sizeof(struct tty_driver));
+ serial_tty_driver.magic = TTY_DRIVER_MAGIC;
+ serial_tty_driver.driver_name = "usb";
+ serial_tty_driver.name = "ttyUSB";
+ serial_tty_driver.major = SERIAL_MAJOR;
+ serial_tty_driver.minor_start = 0;
+ serial_tty_driver.num = NUM_PORTS;
+ serial_tty_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_tty_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_tty_driver.init_termios = tty_std_termios;
+ serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_tty_driver.refcount = &serial_refcount;
+ serial_tty_driver.table = serial_tty;
+ serial_tty_driver.termios = serial_termios;
+ serial_tty_driver.termios_locked = serial_termios_locked;
+
+ serial_tty_driver.open = serial_open;
+ serial_tty_driver.close = serial_close;
+ serial_tty_driver.write = serial_write;
+ serial_tty_driver.put_char = serial_put_char;
+ serial_tty_driver.flush_chars = NULL; //serial_flush_chars;
+ serial_tty_driver.write_room = serial_write_room;
+ serial_tty_driver.ioctl = NULL; //serial_ioctl;
+ serial_tty_driver.set_termios = NULL; //serial_set_termios;
+ serial_tty_driver.set_ldisc = NULL;
+ serial_tty_driver.throttle = serial_throttle;
+ serial_tty_driver.unthrottle = serial_unthrottle;
+ serial_tty_driver.stop = NULL; //serial_stop;
+ serial_tty_driver.start = NULL; //serial_start;
+ serial_tty_driver.hangup = NULL; //serial_hangup;
+ serial_tty_driver.break_ctl = NULL; //serial_break;
+ serial_tty_driver.wait_until_sent = NULL; //serial_wait_until_sent;
+ serial_tty_driver.send_xchar = NULL; //serial_send_xchar;
+ serial_tty_driver.read_proc = NULL; //serial_read_proc;
+ serial_tty_driver.chars_in_buffer = serial_chars_in_buffer;
+ serial_tty_driver.flush_buffer = NULL; //serial_flush_buffer;
+ if (tty_register_driver (&serial_tty_driver)) {
+ printk( "USB Serial: failed to register tty driver\n" );
+ return -EPERM;
+ }
+
+ /* register the USB driver */
+ usb_register(&usb_serial_driver);
+ printk(KERN_INFO "USB Serial support registered.\n");
+ return 0;
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+ return usb_serial_init();
+}
+
+void cleanup_module(void)
+{
+ tty_unregister_driver(&serial_tty_driver);
+ usb_deregister(&usb_serial_driver);
+}
+
+#endif
+
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 5bfab7da9..e359d7721 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -126,7 +126,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
{
unsigned int status;
struct uhci_td *tmp;
- int count = 1000;
+ int count = 1000, bytesreceived = 0;
if (rval)
*rval = 0;
@@ -144,8 +144,10 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
do {
status = uhci_status_bits(tmp->status);
- if (status) {
- if (debug) {
+ if (status)
+ break;
+#if 0
+ if (debug) {
/* Must reset the toggle on first error */
if (uhci_debug) {
printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
@@ -161,6 +163,13 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
if (rval && ((tmp->info & 0xFF) == USB_PID_IN))
*rval += uhci_actual_length(tmp->status);
}
+#endif
+ /* The length field is only valid if the TD was completed */
+ if (!(tmp->status & TD_CTRL_ACTIVE) && uhci_packetin(tmp->info)) {
+ bytesreceived += uhci_actual_length(tmp->status);
+ if (rval)
+ *rval += uhci_actual_length(tmp->status);
+ }
if ((tmp->link & UHCI_PTR_TERM) ||
(tmp->link & UHCI_PTR_QH))
@@ -173,8 +182,35 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
printk(KERN_ERR "runaway td's in uhci_td_result!\n");
/* Force debugging on */
debug = 1;
- } else if (!status)
- return USB_ST_NOERROR;
+ } else {
+ /* If we got to the last TD */
+
+ /* No error */
+ if (!status)
+ return USB_ST_NOERROR;
+
+ /* APC BackUPS Pro kludge */
+ /* It tries to send all of the descriptor instead of */
+ /* the amount we requested */
+ if (tmp->status & TD_CTRL_IOC &&
+ tmp->status & TD_CTRL_ACTIVE &&
+ tmp->status & TD_CTRL_NAK)
+ return USB_ST_NOERROR;
+
+#if 0
+ /* We got to an error, but the controller hasn't finished */
+ /* with it, yet */
+ if (tmp->status & TD_CTRL_ACTIVE)
+ return USB_ST_NOCHANGE;
+#endif
+
+ /* If this wasn't the last TD and SPD is set, ACTIVE */
+ /* is not and NAK isn't then we received a short */
+ /* packet */
+ if (tmp->status & TD_CTRL_SPD &&
+ !(tmp->status & TD_CTRL_NAK))
+ return USB_ST_NOERROR;
+ }
/* Some debugging code */
if (debug && uhci_debug) {
@@ -1035,7 +1071,7 @@ static int uhci_generic_completed(int status, void *buffer, int len, void *dev_i
}
/* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct uhci_qh *qh = uhci_qh_alloc(dev);
@@ -1053,7 +1089,8 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
/* Add it into the skeleton */
uhci_insert_qh(&dev->uhci->skel_control_qh, qh);
- schedule_timeout(HZ * 5); /* 5 seconds */
+ /* wait a user specified reasonable amount of time */
+ schedule_timeout(timeout);
remove_wait_queue(&qh->wakeup, &wait);
@@ -1094,7 +1131,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
* there is no restriction on length of transfers
* anymore
*/
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len, int timeout)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
@@ -1184,7 +1221,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
td->link = UHCI_PTR_TERM; /* Terminate */
/* Start it up.. */
- ret = uhci_run_control(dev, first, td);
+ ret = uhci_run_control(dev, first, td, timeout);
count = 1000;
td = first;
@@ -1231,7 +1268,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
*/
/* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval)
+static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last, unsigned long *rval, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct uhci_qh *qh = uhci_qh_alloc(dev);
@@ -1249,7 +1286,8 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
/* Add it into the skeleton */
uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh);
- schedule_timeout(HZ * 5); /* 5 seconds */
+ /* wait a user specified reasonable amount of time */
+ schedule_timeout(timeout);
remove_wait_queue(&qh->wakeup, &wait);
@@ -1272,7 +1310,7 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
* A bulk message is only built up from
* the data phase
*/
-static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval)
+static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
@@ -1334,7 +1372,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
/* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
/* Start it up.. */
- ret = uhci_run_bulk(dev, first, td, rval);
+ ret = uhci_run_bulk(dev, first, td, rval, timeout);
{
int count = 100;
@@ -1570,6 +1608,7 @@ static void uhci_check_configuration(struct uhci *uhci)
} while (nr < maxchild);
}
+#if 0
static int fixup_isoc_desc (struct uhci_td *td)
{
struct usb_isoc_desc *isocdesc = td->dev_id;
@@ -1621,6 +1660,7 @@ static int fixup_isoc_desc (struct uhci_td *td)
return 0;
}
+#endif /* 0 */
static void uhci_interrupt_notify(struct uhci *uhci)
{
@@ -2097,7 +2137,7 @@ static int start_uhci(struct pci_dev *dev)
for (i = 0; i < 6; i++) {
unsigned int io_addr = dev->resource[i].start;
unsigned int io_size =
- dev->resource[i].end - dev->resource[i].start;
+ dev->resource[i].end - dev->resource[i].start + 1;
/* IO address? */
if (!(dev->resource[i].flags & 1))
@@ -2107,6 +2147,9 @@ static int start_uhci(struct pci_dev *dev)
if (check_region(io_addr, io_size))
break;
+ /* disable legacy emulation */
+ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
return found_uhci(dev->irq, io_addr, io_size);
}
return -1;
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
index 83b96b0ef..1885c661c 100644
--- a/drivers/usb/uhci.h
+++ b/drivers/usb/uhci.h
@@ -53,6 +53,10 @@
#define USBPORTSC_PR 0x0200 /* Port Reset */
#define USBPORTSC_SUSP 0x1000 /* Suspend */
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+
#define UHCI_NULL_DATA_SIZE 0x7ff /* for UHCI controller TD */
#define UHCI_PTR_BITS 0x000F
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 6692dd796..2dee323a3 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -2,16 +2,16 @@
* driver/usb/usb-core.c
*
* (C) Copyright David Waite 1999
- * based on code from usb.c, by Linus Torvolds
+ * based on code from usb.c, by Linus Torvalds
*
* The purpose of this file is to pull any and all generic modular code from
* usb.c and put it in a separate file. This way usb.c is kept as a generic
* library, while this file handles starting drivers, etc.
*
*/
+
#include <linux/kernel.h>
#include <linux/config.h>
-#include <linux/module.h>
#include "inits.h"
#include "usb.h"
@@ -28,9 +28,11 @@
# endif
#endif
-
int usb_init(void)
{
+#ifdef CONFIG_USB_PROC
+ proc_usb_init ();
+#endif
#ifndef CONFIG_USB_MODULE
# ifdef CONFIG_USB_UHCI
uhci_init();
@@ -59,6 +61,9 @@ int usb_init(void)
# ifdef CONFIG_USB_PRINTER
usb_printer_init();
# endif
+# ifdef CONFIG_USB_SERIAL
+ usb_serial_init();
+# endif
# ifdef CONFIG_USB_CPIA
usb_cpia_init();
# endif
@@ -69,11 +74,9 @@ int usb_init(void)
usb_scsi_init();
# endif
#endif
-#ifdef CONFIG_USB_PROC
- proc_usb_init ();
-#endif
return 0;
}
+
/*
* Clean up when unloading the module
*/
@@ -100,10 +103,9 @@ int init_module(void)
{
return usb_init();
}
+
void cleanup_module(void)
{
cleanup_drivers();
}
#endif
-
-
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 5895bb6df..f6d901aa3 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -13,15 +13,25 @@
* are evil.
*/
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
#define USB_DEBUG 1
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/malloc.h>
#include "usb.h"
+static int usb_find_driver(struct usb_device *);
+static void usb_check_support(struct usb_device *);
+static void usb_driver_purge(struct usb_driver *, struct usb_device *);
+
+
/*
* We have a per-interface "registered driver" list.
*/
@@ -172,14 +182,15 @@ static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount
* However, this first cut at USB bandwidth allocation does not
* contain any frame allocation tracking.
*/
-int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+static int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
{
unsigned int new_alloc;
new_alloc = old_alloc + bustime;
/* what new total allocated bus time would be */
- PRINTD ("usb-bandwidth-alloc: was: %ld, new: %ld, bustime = %ld us, Pipe allowed: %s",
+ PRINTD ("usb-bandwidth-alloc: was: %u, new: %u, "
+ "bustime = %ld us, Pipe allowed: %s",
old_alloc, new_alloc, bustime,
(new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
"yes" : "no");
@@ -263,6 +274,7 @@ static void usb_check_support(struct usb_device *dev)
if (!dev->driver && dev->devnum > 0)
usb_find_driver(dev);
}
+
/*
* This entrypoint gets called for each new device.
*
@@ -318,7 +330,6 @@ void usb_free_dev(struct usb_device *dev)
{
if (atomic_dec_and_test(&dev->refcnt)) {
usb_destroy_configuration(dev);
-
dev->bus->op->deallocate(dev);
kfree(dev);
}
@@ -681,7 +692,7 @@ int usb_set_address(struct usb_device *dev)
dr.index = 0;
dr.length = 0;
- return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0);
+ return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0, HZ);
}
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
@@ -697,7 +708,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
dr.length = size;
while (i--) {
- if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size))
+ if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ))
|| result == USB_ST_STALL)
break;
}
@@ -714,7 +725,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char
dr.index = langid;
dr.length = size;
- return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+ return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size, HZ);
}
int usb_get_device_descriptor(struct usb_device *dev)
@@ -740,7 +751,7 @@ int usb_get_status (struct usb_device *dev, int type, int target, void *data)
dr.index = target;
dr.length = 2;
- return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2);
+ return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2, HZ);
}
int usb_get_protocol(struct usb_device *dev)
@@ -754,7 +765,7 @@ int usb_get_protocol(struct usb_device *dev)
dr.index = 1;
dr.length = 1;
- if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1))
+ if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1, HZ))
return -1;
return buf[0];
@@ -770,7 +781,7 @@ int usb_set_protocol(struct usb_device *dev, int protocol)
dr.index = 1;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+ if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
return -1;
return 0;
@@ -788,7 +799,7 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id)
dr.index = 1;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+ if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
return -1;
return 0;
@@ -838,7 +849,7 @@ int usb_clear_halt(struct usb_device *dev, int endp)
dr.index = endp;
dr.length = 0;
- result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+ result = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0, HZ);
/* don't clear if failed */
if (result)
@@ -850,7 +861,7 @@ int usb_clear_halt(struct usb_device *dev, int endp)
dr.length = 2;
status = 0xffff;
- result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2);
+ result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, &status, 2, HZ);
if (result)
return result;
@@ -876,7 +887,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
dr.index = interface;
dr.length = 0;
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+ if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
return -1;
dev->ifnum = interface;
@@ -907,7 +918,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
printk(KERN_INFO "usb: selecting invalid configuration %d\n", configuration);
return -1;
}
- if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+ if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0, HZ))
return -1;
dev->actconfig = cp;
@@ -927,7 +938,7 @@ int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id,
dr.index = index;
dr.length = size;
- if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size))
+ if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size, HZ))
return -1;
return 0;
@@ -962,9 +973,9 @@ int usb_get_configuration(struct usb_device *dev)
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
- if (result)
+ if (result < 0)
return -1;
-
+
/* Get the full buffer */
le16_to_cpus(&desc->wTotalLength);
@@ -991,7 +1002,6 @@ int usb_get_configuration(struct usb_device *dev)
return 0;
}
-
char *usb_string(struct usb_device *dev, int index)
{
int len, i;
@@ -1115,7 +1125,7 @@ int usb_new_device(struct usb_device *dev)
return 0;
}
-int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size)
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout)
{
devrequest dr;
@@ -1125,7 +1135,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
dr.index = cpu_to_le16p(&index);
dr.length = cpu_to_le16p(&size);
- return dev->bus->op->control_msg(dev, pipe, &dr, data, size);
+ return dev->bus->op->control_msg(dev, pipe, &dr, data, size, timeout);
}
int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
@@ -1148,9 +1158,10 @@ int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq ha
if (!ret) {
dev->bus->bandwidth_allocated += bustime;
dev->bus->bandwidth_int_reqs++;
- PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+ PRINTD ("bw_alloc bumped to %d for %d requesters",
dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs);
+ dev->bus->bandwidth_int_reqs +
+ dev->bus->bandwidth_isoc_reqs);
}
return ret;
@@ -1180,9 +1191,10 @@ int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe)
bustime = NS_TO_US(bustime);
dev->bus->bandwidth_allocated -= bustime;
dev->bus->bandwidth_int_reqs--;
- PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+ PRINTD ("bw_alloc reduced to %d for %d requesters",
dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs);
+ dev->bus->bandwidth_int_reqs +
+ dev->bus->bandwidth_isoc_reqs);
}
return err;
@@ -1208,11 +1220,14 @@ int usb_init_isoc (struct usb_device *usb_dev,
long bustime;
int err;
+ if (frame_count <= 0)
+ return -EINVAL;
+
/* Check host controller's bandwidth for this Isoc. request. */
/* TBD: some way to factor in frame_spacing ??? */
bustime = calc_bus_time (0, usb_pipein(pipe), 1,
usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)));
- bustime = NS_TO_US(bustime); /* work in microseconds */
+ bustime = NS_TO_US(bustime) / frame_count; /* work in microseconds */
if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime))
return USB_ST_BANDWIDTH_ERROR;
@@ -1222,8 +1237,9 @@ int usb_init_isoc (struct usb_device *usb_dev,
if (!err) {
usb_dev->bus->bandwidth_allocated += bustime;
usb_dev->bus->bandwidth_isoc_reqs++;
- PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+ PRINTD ("bw_alloc bumped to %d for %d requesters",
usb_dev->bus->bandwidth_allocated,
+ usb_dev->bus->bandwidth_int_reqs +
usb_dev->bus->bandwidth_isoc_reqs);
}
@@ -1238,11 +1254,12 @@ void usb_free_isoc (struct usb_isoc_desc *isocdesc)
bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1,
usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe,
usb_pipeout(isocdesc->pipe)));
- bustime = NS_TO_US(bustime);
+ bustime = NS_TO_US(bustime) / isocdesc->frame_count;
isocdesc->usb_dev->bus->bandwidth_allocated -= bustime;
isocdesc->usb_dev->bus->bandwidth_isoc_reqs--;
- PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+ PRINTD ("bw_alloc reduced to %d for %d requesters",
isocdesc->usb_dev->bus->bandwidth_allocated,
+ isocdesc->usb_dev->bus->bandwidth_int_reqs +
isocdesc->usb_dev->bus->bandwidth_isoc_reqs);
isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
@@ -1271,3 +1288,49 @@ struct list_head *usb_bus_get_list(void)
}
#endif
+/*
+ * USB may be built into the kernel or be built as modules.
+ * If the USB core [and maybe a host controller driver] is built
+ * into the kernel, and other device drivers are built as modules,
+ * then these symbols need to be exported for the modules to use.
+ */
+EXPORT_SYMBOL(usb_register);
+EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL(usb_alloc_bus);
+EXPORT_SYMBOL(usb_free_bus);
+EXPORT_SYMBOL(usb_register_bus);
+EXPORT_SYMBOL(usb_deregister_bus);
+EXPORT_SYMBOL(usb_alloc_dev);
+EXPORT_SYMBOL(usb_free_dev);
+EXPORT_SYMBOL(usb_inc_dev_use);
+
+EXPORT_SYMBOL(usb_init_root_hub);
+EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_connect);
+EXPORT_SYMBOL(usb_disconnect);
+
+EXPORT_SYMBOL(usb_set_address);
+EXPORT_SYMBOL(usb_get_descriptor);
+EXPORT_SYMBOL(usb_get_string);
+EXPORT_SYMBOL(usb_string);
+EXPORT_SYMBOL(usb_get_protocol);
+EXPORT_SYMBOL(usb_set_protocol);
+EXPORT_SYMBOL(usb_get_report);
+EXPORT_SYMBOL(usb_set_idle);
+EXPORT_SYMBOL(usb_clear_halt);
+EXPORT_SYMBOL(usb_set_interface);
+EXPORT_SYMBOL(usb_get_configuration);
+EXPORT_SYMBOL(usb_set_configuration);
+
+EXPORT_SYMBOL(usb_control_msg);
+EXPORT_SYMBOL(usb_request_irq);
+EXPORT_SYMBOL(usb_release_irq);
+/* EXPORT_SYMBOL(usb_bulk_msg); */
+EXPORT_SYMBOL(usb_request_bulk);
+EXPORT_SYMBOL(usb_terminate_bulk);
+
+EXPORT_SYMBOL(usb_get_current_frame_number);
+EXPORT_SYMBOL(usb_init_isoc);
+EXPORT_SYMBOL(usb_free_isoc);
+EXPORT_SYMBOL(usb_run_isoc);
+EXPORT_SYMBOL(usb_kill_isoc);
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index 4ead45e93..4057536bb 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -49,6 +49,15 @@
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+
/*
* USB Packet IDs (PIDs)
*/
@@ -117,29 +126,44 @@ struct usb_proc_ctrltransfer {
__u16 value;
__u16 index;
__u16 length;
- /* pointer to data */
+ __u32 timeout; /* in milliseconds */
void *data;
};
-#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer)
-
struct usb_proc_bulktransfer {
unsigned int ep;
unsigned int len;
+ unsigned int timeout; /* in milliseconds */
void *data;
};
-#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer)
+struct usb_proc_old_ctrltransfer {
+ __u8 requesttype;
+ __u8 request;
+ __u16 value;
+ __u16 index;
+ __u16 length;
+ /* pointer to data */
+ void *data;
+};
-#define USB_PROC_RESETEP _IOR('U', 3, unsigned int)
+struct usb_proc_old_bulktransfer {
+ unsigned int ep;
+ unsigned int len;
+ void *data;
+};
struct usb_proc_setinterface {
unsigned int interface;
unsigned int altsetting;
};
+#define USB_PROC_CONTROL _IOWR('U', 0, struct usb_proc_ctrltransfer)
+#define USB_PROC_BULK _IOWR('U', 2, struct usb_proc_bulktransfer)
+#define USB_PROC_OLD_CONTROL _IOWR('U', 0, struct usb_proc_old_ctrltransfer)
+#define USB_PROC_OLD_BULK _IOWR('U', 2, struct usb_proc_old_bulktransfer)
+#define USB_PROC_RESETEP _IOR('U', 3, unsigned int)
#define USB_PROC_SETINTERFACE _IOR('U', 4, struct usb_proc_setinterface)
-
#define USB_PROC_SETCONFIGURATION _IOR('U', 5, unsigned int)
@@ -429,8 +453,8 @@ struct usb_isoc_desc {
struct usb_operations {
int (*allocate)(struct usb_device *);
int (*deallocate)(struct usb_device *);
- int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int);
- int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
+ int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int, int);
+ int (*bulk_msg)(struct usb_device *, unsigned int, void *, int, unsigned long *, int);
int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
int (*release_irq)(struct usb_device *, void *);
void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq,
@@ -496,7 +520,7 @@ struct usb_device {
void *hcpriv; /* Host Controller private data */
void *private; /* Upper layer private data */
-
+ void *audiopriv; /* May be both audio and HID */
/* procfs entry */
struct proc_dir_entry *proc_entry;
@@ -515,10 +539,6 @@ struct usb_device {
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
-int usb_find_driver(struct usb_device *);
-void usb_check_support(struct usb_device *);
-void usb_driver_purge(struct usb_driver *, struct usb_device *);
-
extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
extern void usb_free_bus(struct usb_bus *);
extern void usb_register_bus(struct usb_bus *);
@@ -529,7 +549,7 @@ extern void usb_free_dev(struct usb_device *);
extern void usb_inc_dev_use(struct usb_device *);
#define usb_dec_dev_use usb_free_dev
-extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
+extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
extern int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe);
@@ -695,7 +715,7 @@ void usb_show_string(struct usb_device *dev, char *id, int index);
#ifdef USB_DEBUG
#define PRINTD(format, args...) printk("usb: " format "\n" , ## args);
#else /* NOT DEBUGGING */
-#define PRINTD(fmt, arg...) do {} while (0) /**/
+#define PRINTD(fmt, arg...) do {} while (0)
#endif /* USB_DEBUG */
/* A simple way to change one line from DEBUG to NOT DEBUG: */
#define XPRINTD(fmt, arg...) do {} while (0)
diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c
index 777edd76a..de8a1b356 100644
--- a/drivers/usb/usb_scsi.c
+++ b/drivers/usb/usb_scsi.c
@@ -142,7 +142,7 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
do {
/*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/
result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf,
- this_xfer, &partial);
+ this_xfer, &partial, HZ*5);
if (result != 0 || partial != this_xfer)
US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
@@ -263,7 +263,6 @@ static int pop_CB_reset(struct us_data *us)
{
unsigned char cmd[12];
devrequest dr;
- int result;
US_DEBUGP("pop_CB_reset\n");
dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
@@ -276,7 +275,7 @@ static int pop_CB_reset(struct us_data *us)
cmd[1] = 4;
us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
- &dr, cmd, 12);
+ &dr, cmd, 12, HZ);
/* long wait for reset */
@@ -338,7 +337,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
}
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
- &dr, cmd, us->fixedlength);
+ &dr, cmd, us->fixedlength, HZ);
if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/)
&& cmd[0] == TEST_UNIT_READY && result) {
/* as per spec try a start command, wait and retry */
@@ -349,7 +348,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
cmd[4] = 1; /* start */
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
- &dr, cmd, us->fixedlength);
+ &dr, cmd, us->fixedlength, HZ);
wait_ms(100);
retry++;
continue;
@@ -357,7 +356,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
} else
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
- &dr, srb->cmnd, srb->cmd_len);
+ &dr, srb->cmnd, srb->cmd_len, HZ);
if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
return result;
}
@@ -389,7 +388,7 @@ static int pop_CB_status(Scsi_Cmnd *srb)
dr.length = 2;
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_rcvctrlpipe(us->pusb_dev,0),
- &dr, status, sizeof(status));
+ &dr, status, sizeof(status), HZ);
if (result != USB_ST_TIMEOUT)
break;
}
@@ -452,7 +451,6 @@ static int pop_CB_status(Scsi_Cmnd *srb)
static int pop_CBI(Scsi_Cmnd *srb)
{
- struct us_data *us = (struct us_data *)srb->host_scribble;
int result;
/* run the command */
@@ -500,7 +498,7 @@ static int pop_Bulk_reset(struct us_data *us)
dr.index = 0;
dr.length = 0;
- result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0);
+ result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0, HZ);
if (result)
US_DEBUGP("Bulk hard reset failed %d\n", result);
usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
@@ -546,7 +544,7 @@ static int pop_Bulk(Scsi_Cmnd *srb)
bcb.Tag, bcb.DataTransferLength, bcb.Flags, bcb.Length);
result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
usb_sndbulkpipe(us->pusb_dev, us->ep_out), &bcb,
- US_BULK_CB_WRAP_LEN, &partial);
+ US_BULK_CB_WRAP_LEN, &partial, HZ*5);
if (result) {
US_DEBUGP("Bulk command result %x\n", result);
return DID_ABORT << 16;
@@ -570,7 +568,7 @@ static int pop_Bulk(Scsi_Cmnd *srb)
do {
result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev,
usb_rcvbulkpipe(us->pusb_dev, us->ep_in), &bcs,
- US_BULK_CS_WRAP_LEN, &partial);
+ US_BULK_CS_WRAP_LEN, &partial, HZ*5);
if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)
stall++;
else
@@ -1296,7 +1294,7 @@ static int scsi_probe(struct usb_device *dev)
dr.index = 0;
dr.value = 0;
dr.length = 0;
- ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
+ ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2, HZ);
US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
init_waitqueue_head(&ss->ip_waitq);
ss->irqpipe = usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int);
@@ -1413,8 +1411,6 @@ int init_module(void)
void cleanup_module(void)
{
- unsigned int offset;
-
usb_deregister(&scsi_driver);
}
#endif
diff --git a/drivers/usb/usb_scsi_debug.c b/drivers/usb/usb_scsi_debug.c
index 04ff50174..d29622cad 100644
--- a/drivers/usb/usb_scsi_debug.c
+++ b/drivers/usb/usb_scsi_debug.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c
index 7bf2b0634..9fb30b1a3 100644
--- a/drivers/usb/uss720.c
+++ b/drivers/usb/uss720.c
@@ -31,6 +31,7 @@
* ECP currently untested
* 0.3 10.08.99 fixing merge errors
* 0.4 13.08.99 Added Vendor/Product ID of Brad Hard's cable
+ * 0.5 20.09.99 usb_control_msg wrapper used
*
*/
@@ -61,17 +62,11 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha
static const unsigned char regindex[9] = {
4, 0, 1, 5, 5, 0, 2, 3, 6
};
- devrequest dr;
int ret;
if (!usbdev)
return -1;
- dr.requesttype = 0xc0;
- dr.request = 3;
- dr.value = ((unsigned int)reg) << 8;
- dr.index = 0;
- dr.length = 7;
- ret = usbdev->bus->op->control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), &dr, priv->reg, 7);
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, HZ);
if (ret) {
printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x\n",
(unsigned int)reg, ret);
@@ -95,17 +90,11 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha
{
struct parport_uss720_private *priv = pp->private_data;
struct usb_device *usbdev = priv->usbdev;
- devrequest dr;
int ret;
if (!usbdev)
return -1;
- dr.requesttype = 0x40;
- dr.request = 4;
- dr.value = (((unsigned int)reg) << 8) | val;
- dr.index = 0;
- dr.length = 0;
- ret = usbdev->bus->op->control_msg(usbdev, usb_sndctrlpipe(usbdev,0), &dr, NULL, 0);
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, HZ);
if (ret) {
printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n",
(unsigned int)reg, (unsigned int)val, ret);
@@ -374,7 +363,7 @@ static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf,
return 0;
if (change_mode(pp, ECR_EPP))
return 0;
- i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen);
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buf, length, &rlen, HZ*20);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buf, length, rlen);
change_mode(pp, ECR_PS2);
@@ -435,7 +424,7 @@ static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buff
return 0;
if (change_mode(pp, ECR_ECP))
return 0;
- i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen, HZ*20);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
@@ -453,7 +442,7 @@ static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, siz
return 0;
if (change_mode(pp, ECR_ECP))
return 0;
- i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen);
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20);
if (i)
printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %lu\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
@@ -486,7 +475,7 @@ static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer
return 0;
if (change_mode(pp, ECR_PPF))
return 0;
- i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen);
+ i = usbdev->bus->op->bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), buffer, len, &rlen, HZ*20);
if (i)
printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %lu\n", buffer, len, rlen);
change_mode(pp, ECR_PS2);
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 9fb8d3905..a8e223f6b 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -2,350 +2,362 @@
# Video configuration
#
+mainmenu_option next_comment
+comment 'Frame-buffer support'
+
+bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
+
if [ "$CONFIG_FB" = "y" ]; then
- define_bool CONFIG_DUMMY_CONSOLE y
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
- tristate 'Cirrus Logic suport (experimental)' CONFIG_FB_CLGEN
- tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2
- if [ "$CONFIG_FB_PM2" = "y" ]; then
- if [ "$CONFIG_PCI" = "y" ]; then
- bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
- bool ' generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI
- fi
- if [ "$CONFIG_AMIGA" = "y" ]; then
- bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC
- fi
+ define_bool CONFIG_DUMMY_CONSOLE y
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
+ tristate ' Cirrus Logic suport (EXPERIMENTAL)' CONFIG_FB_CLGEN
+ tristate ' Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2
+ if [ "$CONFIG_FB_PM2" = "y" ]; then
+ if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
+ bool ' generic Permedia2 PCI board support' CONFIG_FB_PM2_PCI
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ bool ' Phase5 CVisionPPC/BVisionPPC support' CONFIG_FB_PM2_CVPPC
+ fi
+ fi
fi
- fi
- fi
- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- bool 'Acorn VIDC support' CONFIG_FB_ACORN
- fi
- if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
- tristate 'Cyber2000 support' CONFIG_FB_CYBER2000
- fi
- if [ "$CONFIG_APOLLO" = "y" ]; then
- define_bool CONFIG_FB_APOLLO y
- fi
- if [ "$CONFIG_Q40" = "y" ]; then
- define_bool CONFIG_FB_Q40 y
- fi
- if [ "$CONFIG_AMIGA" = "y" ]; then
- bool 'Amiga native chipset support' CONFIG_FB_AMIGA
- if [ "$CONFIG_FB_AMIGA" != "n" ]; then
- bool 'Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
- bool 'Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
- bool 'Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
- fi
- fi
- if [ "$CONFIG_ZORRO" = "y" ]; then
- tristate 'Amiga CyberVision support' CONFIG_FB_CYBER
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Amiga CyberVision3D support (experimental)' CONFIG_FB_VIRGE
- tristate 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3
- bool 'Amiga FrameMaster II/Rainbow II support (experimental)' CONFIG_FB_FM2
- fi
- fi
- if [ "$CONFIG_ATARI" = "y" ]; then
- bool 'Atari native chipset support' CONFIG_FB_ATARI
- tristate 'ATI Mach64 display support' CONFIG_FB_ATY
- fi
- if [ "$CONFIG_PPC" = "y" ]; then
- bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
- if [ "$CONFIG_FB_OF" = "y" ]; then
- bool 'Apple "control" display support' CONFIG_FB_CONTROL
- bool 'Apple "platinum" display support' CONFIG_FB_PLATINUM
- bool 'Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
- tristate 'ATI Mach64 display support' CONFIG_FB_ATY
- bool 'IMS Twin Turbo display support' CONFIG_FB_IMSTT
- bool 'Chips 65550 display support' CONFIG_FB_CT65550
- bool 'S3 Trio display support' CONFIG_FB_S3TRIO
- fi
- tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
- fi
- if [ "$CONFIG_MAC" = "y" ]; then
- define_bool CONFIG_FB_MAC y
- fi
- if [ "$CONFIG_HP300" = "y" ]; then
- define_bool CONFIG_FB_HP300 y
- fi
- if [ "$ARCH" = "alpha" ]; then
- tristate 'TGA framebuffer support' CONFIG_FB_TGA
- fi
- if [ "$ARCH" = "i386" ]; then
- bool 'VESA VGA graphics console' CONFIG_FB_VESA
- tristate 'VGA 16-color graphics console' CONFIG_FB_VGA16
- define_bool CONFIG_VIDEO_SELECT y
- fi
- if [ "$CONFIG_VISWS" = "y" ]; then
- tristate 'SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
- fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_PCI" != "n" ]; then
- tristate 'Matrox acceleration' CONFIG_FB_MATROX
- if [ "$CONFIG_FB_MATROX" != "n" ]; 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
- bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+ fi
+ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ bool ' Acorn VIDC support' CONFIG_FB_ACORN
+ fi
+ if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
+ tristate ' Cyber2000 support' CONFIG_FB_CYBER2000
+ fi
+ if [ "$CONFIG_APOLLO" = "y" ]; then
+ define_bool CONFIG_FB_APOLLO y
+ fi
+ if [ "$CONFIG_Q40" = "y" ]; then
+ define_bool CONFIG_FB_Q40 y
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ bool ' Amiga native chipset support' CONFIG_FB_AMIGA
+ if [ "$CONFIG_FB_AMIGA" != "n" ]; then
+ bool ' Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
+ bool ' Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
+ bool ' Amiga AGA chipset support' CONFIG_FB_AMIGA_AGA
fi
- tristate 'ATI Mach64 display support' CONFIG_FB_ATY
- fi
- fi
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool 'SBUS and UPA framebuffers' CONFIG_FB_SBUS
- if [ "$CONFIG_FB_SBUS" != "n" ]; then
- if [ "$ARCH" = "sparc64" ]; then
- bool ' Creator/Creator3D support' CONFIG_FB_CREATOR
+ fi
+ if [ "$CONFIG_ZORRO" = "y" ]; then
+ tristate ' Amiga CyberVision support' CONFIG_FB_CYBER
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' Amiga CyberVision3D support (EXPERIMENTAL)' CONFIG_FB_VIRGE
+ tristate ' Amiga RetinaZ3 support (EXPERIMENTAL)' CONFIG_FB_RETINAZ3
+ bool ' Amiga FrameMaster II/Rainbow II support (EXPERIMENTAL)' CONFIG_FB_FM2
fi
- bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
- bool ' BWtwo support' CONFIG_FB_BWTWO
- bool ' CGthree support' CONFIG_FB_CGTHREE
- if [ "$ARCH" = "sparc" ]; then
- bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX
- bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
- bool ' P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
+ fi
+ if [ "$CONFIG_ATARI" = "y" ]; then
+ bool ' Atari native chipset support' CONFIG_FB_ATARI
+ tristate ' ATI Mach64 display support' CONFIG_FB_ATY
+ fi
+ if [ "$CONFIG_PPC" = "y" ]; then
+ bool ' Open Firmware frame buffer device support' CONFIG_FB_OF
+ if [ "$CONFIG_FB_OF" = "y" ]; then
+ bool ' Apple "control" display support' CONFIG_FB_CONTROL
+ bool ' Apple "platinum" display support' CONFIG_FB_PLATINUM
+ bool ' Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
+ bool ' IMS Twin Turbo display support' CONFIG_FB_IMSTT
+ bool ' Chips 65550 display support' CONFIG_FB_CT65550
+ bool ' S3 Trio display support' CONFIG_FB_S3TRIO
fi
- bool ' Leo (ZX) support' CONFIG_FB_LEO
- fi
- fi
- if [ "$ARCH" = "sparc" ]; then
- if [ "$CONFIG_PCI" != "n" ]; then
- bool 'PCI framebuffers' CONFIG_FB_PCI
- if [ "$CONFIG_FB_PCI" != "n" ]; then
- bool ' IGA 168x display support' CONFIG_FB_IGA
+ tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16
+ fi
+ if [ "$CONFIG_MAC" = "y" ]; then
+ define_bool CONFIG_FB_MAC y
+ fi
+ if [ "$CONFIG_HP300" = "y" ]; then
+ define_bool CONFIG_FB_HP300 y
+ fi
+ if [ "$ARCH" = "alpha" ]; then
+ tristate ' TGA framebuffer support' CONFIG_FB_TGA
+ fi
+ if [ "$ARCH" = "i386" ]; then
+ bool ' VESA VGA graphics console' CONFIG_FB_VESA
+ tristate ' VGA 16-color graphics console' CONFIG_FB_VGA16
+ define_bool CONFIG_VIDEO_SELECT y
+ fi
+ if [ "$CONFIG_VISWS" = "y" ]; then
+ tristate ' SGI Visual Workstation framebuffer support' CONFIG_FB_SGIVW
+ define_bool CONFIG_BUS_I2C y
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
+ if [ "$CONFIG_FB_MATROX" != "n" ]; 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
+ bool ' Multihead support' CONFIG_FB_MATROX_MULTIHEAD
+ fi
+ tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+ bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
fi
- fi
- fi
- if [ "$ARCH" = "sparc64" ]; then
- if [ "$CONFIG_PCI" != "n" ]; then
- bool 'PCI framebuffers' CONFIG_FB_PCI
- if [ "$CONFIG_FB_PCI" != "n" ]; then
- tristate ' ATI Mach64 display support' CONFIG_FB_ATY
+ fi
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ bool ' SBUS and UPA framebuffers' CONFIG_FB_SBUS
+ if [ "$CONFIG_FB_SBUS" != "n" ]; then
+ if [ "$ARCH" = "sparc64" ]; then
+ bool ' Creator/Creator3D support' CONFIG_FB_CREATOR
+ fi
+ bool ' CGsix (GX,TurboGX) support' CONFIG_FB_CGSIX
+ bool ' BWtwo support' CONFIG_FB_BWTWO
+ bool ' CGthree support' CONFIG_FB_CGTHREE
+ if [ "$ARCH" = "sparc" ]; then
+ bool ' TCX (SS4/SS5 only) support' CONFIG_FB_TCX
+ bool ' CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
+ bool ' P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
+ fi
+ bool ' Leo (ZX) support' CONFIG_FB_LEO
fi
- fi
- fi
- tristate 'Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
-
- bool 'Advanced low level driver options' CONFIG_FBCON_ADVANCED
- if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
- tristate 'Monochrome support' CONFIG_FBCON_MFB
- tristate '2 bpp packed pixels support' CONFIG_FBCON_CFB2
- tristate '4 bpp packed pixels support' CONFIG_FBCON_CFB4
- tristate '8 bpp packed pixels support' CONFIG_FBCON_CFB8
- tristate '16 bpp packed pixels support' CONFIG_FBCON_CFB16
- tristate '24 bpp packed pixels support' CONFIG_FBCON_CFB24
- tristate '32 bpp packed pixels support' CONFIG_FBCON_CFB32
- tristate 'Amiga bitplanes support' CONFIG_FBCON_AFB
- tristate 'Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
- tristate 'Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
- tristate 'Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
- tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
-# tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
- tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
- tristate 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
- tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA
- else
- # Guess what we need
- if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
- "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
- "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
- "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
- "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
- define_bool CONFIG_FBCON_MFB y
- else
- if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
- "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
- "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
- "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
- "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
- define_bool CONFIG_FBCON_MFB m
+ fi
+ if [ "$ARCH" = "sparc" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ bool ' PCI framebuffers' CONFIG_FB_PCI
+ if [ "$CONFIG_FB_PCI" != "n" ]; then
+ bool ' IGA 168x display support' CONFIG_FB_IGA
+ fi
+ fi
+ fi
+ if [ "$ARCH" = "sparc64" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ bool ' PCI framebuffers' CONFIG_FB_PCI
+ if [ "$CONFIG_FB_PCI" != "n" ]; then
+ tristate ' ATI Mach64 display support' CONFIG_FB_ATY
+ fi
fi
- fi
- if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
- "$CONFIG_FB_VIRTUAL" = "y" ]; then
- define_bool CONFIG_FBCON_CFB2 y
- define_bool CONFIG_FBCON_CFB4 y
- else
- if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
- "$CONFIG_FB_VIRTUAL" = "m" ]; then
- define_bool CONFIG_FBCON_CFB2 m
- define_bool CONFIG_FBCON_CFB4 m
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate ' Virtual Frame Buffer support (ONLY FOR TESTING!)' CONFIG_FB_VIRTUAL
+ fi
+
+ bool ' Advanced low level driver options' CONFIG_FBCON_ADVANCED
+ if [ "$CONFIG_FBCON_ADVANCED" = "y" ]; then
+ tristate ' Monochrome support' CONFIG_FBCON_MFB
+ tristate ' 2 bpp packed pixels support' CONFIG_FBCON_CFB2
+ tristate ' 4 bpp packed pixels support' CONFIG_FBCON_CFB4
+ tristate ' 8 bpp packed pixels support' CONFIG_FBCON_CFB8
+ tristate ' 16 bpp packed pixels support' CONFIG_FBCON_CFB16
+ tristate ' 24 bpp packed pixels support' CONFIG_FBCON_CFB24
+ tristate ' 32 bpp packed pixels support' CONFIG_FBCON_CFB32
+ tristate ' Amiga bitplanes support' CONFIG_FBCON_AFB
+ tristate ' Amiga interleaved bitplanes support' CONFIG_FBCON_ILBM
+ tristate ' Atari interleaved bitplanes (2 planes) support' CONFIG_FBCON_IPLAN2P2
+ tristate ' Atari interleaved bitplanes (4 planes) support' CONFIG_FBCON_IPLAN2P4
+ tristate ' Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8
+# tristate ' Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16
+ tristate ' Mac variable bpp packed pixels support' CONFIG_FBCON_MAC
+ tristate ' VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES
+ tristate ' VGA characters/attributes support' CONFIG_FBCON_VGA
+ else
+ # Guess what we need
+ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
+ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then
+ define_bool CONFIG_FBCON_MFB y
+ else
+ if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
+ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then
+ define_bool CONFIG_FBCON_MFB m
+ fi
fi
- fi
- if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
- "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
- "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
- "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
- "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
- "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
- "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
- "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
- "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
- "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
- "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
- "$CONFIG_FB_P9100" = "y" -o \
- "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
- define_bool CONFIG_FBCON_CFB8 y
- else
- if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
- "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
- "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
- "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
- "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
- "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
- "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
- "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
- "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
- "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
- "$CONFIG_FB_P9100" = "m" -o \
- "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
- define_bool CONFIG_FBCON_CFB8 m
+ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+ "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ define_bool CONFIG_FBCON_CFB2 y
+ define_bool CONFIG_FBCON_CFB4 y
+ else
+ if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB2 m
+ define_bool CONFIG_FBCON_CFB4 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
- "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
- "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
- "$CONFIG_FB_Q40" = "y" -o \
- "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
- "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
- "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
- "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
- "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
- "$CONFIG_FB_CYBER2000" = "y" ]; then
- define_bool CONFIG_FBCON_CFB16 y
- else
- if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
- "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
- "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
- "$CONFIG_FB_Q40" = "m" -o \
- "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
- "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
- "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
- "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
- "$CONFIG_FB_CYBER2000" = "m" ]; then
- define_bool CONFIG_FBCON_CFB16 m
+ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
+ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+ "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+ "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+ "$CONFIG_FB_P9100" = "y" -o \
+ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+ "$CONFIG_FB_3DFX" = "y" ]; then
+ define_bool CONFIG_FBCON_CFB8 y
+ else
+ if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+ "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
+ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+ "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+ "$CONFIG_FB_P9100" = "m" -o \
+ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB8 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
- "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
- "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
- "$CONFIG_FB_CYBER2000" = "y" ]; then
- define_bool CONFIG_FBCON_CFB24 y
- else
- if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
- "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
- "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
- "$CONFIG_FB_CYBER2000" = "m" ]; then
- define_bool CONFIG_FBCON_CFB24 m
+ if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+ "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
+ "$CONFIG_FB_Q40" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
+ "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
+ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" ]; then
+ define_bool CONFIG_FBCON_CFB16 y
+ else
+ if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+ "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
+ "$CONFIG_FB_Q40" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
+ "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
+ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
+ "$CONFIG_FB_CYBER2000" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB16 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
- "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
- "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
- "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
- "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
- "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then
- define_bool CONFIG_FBCON_CFB32 y
- else
- if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
- "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
- "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
- "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
- "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
- "$CONFIG_FB_SGIVW" = "m" ]; then
- define_bool CONFIG_FBCON_CFB32 m
+ if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
+ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+ "$CONFIG_FB_CYBER2000" = "y" ]; then
+ define_bool CONFIG_FBCON_CFB24 y
+ else
+ if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
+ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+ "$CONFIG_FB_CYBER2000" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB24 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_AMIGA" = "y" ]; then
- define_bool CONFIG_FBCON_AFB y
- define_bool CONFIG_FBCON_ILBM y
- else
- if [ "$CONFIG_FB_AMIGA" = "m" ]; then
- define_bool CONFIG_FBCON_AFB m
- define_bool CONFIG_FBCON_ILBM m
+ if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
+ "$CONFIG_FB_VESA" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+ "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
+ "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+ "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+ "$CONFIG_FB_3DFX" = "y" ]; then
+ define_bool CONFIG_FBCON_CFB32 y
+ else
+ if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+ "$CONFIG_FB_VESA" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+ "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
+ "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+ "$CONFIG_FB_SGIVW" = "m" ]; then
+ define_bool CONFIG_FBCON_CFB32 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_ATARI" = "y" ]; then
- define_bool CONFIG_FBCON_IPLAN2P2 y
- define_bool CONFIG_FBCON_IPLAN2P4 y
- define_bool CONFIG_FBCON_IPLAN2P8 y
-# define_bool CONFIG_FBCON_IPLAN2P16 y
- else
- if [ "$CONFIG_FB_ATARI" = "m" ]; then
- define_bool CONFIG_FBCON_IPLAN2P2 m
- define_bool CONFIG_FBCON_IPLAN2P4 m
- define_bool CONFIG_FBCON_IPLAN2P8 m
-# define_bool CONFIG_FBCON_IPLAN2P16 m
+ if [ "$CONFIG_FB_AMIGA" = "y" ]; then
+ define_bool CONFIG_FBCON_AFB y
+ define_bool CONFIG_FBCON_ILBM y
+ else
+ if [ "$CONFIG_FB_AMIGA" = "m" ]; then
+ define_bool CONFIG_FBCON_AFB m
+ define_bool CONFIG_FBCON_ILBM m
+ fi
fi
- fi
- if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
- define_bool CONFIG_FBCON_MAC y
- else
- if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
- define_bool CONFIG_FBCON_MAC m
+ if [ "$CONFIG_FB_ATARI" = "y" ]; then
+ define_bool CONFIG_FBCON_IPLAN2P2 y
+ define_bool CONFIG_FBCON_IPLAN2P4 y
+ define_bool CONFIG_FBCON_IPLAN2P8 y
+# define_bool CONFIG_FBCON_IPLAN2P16 y
+ else
+ if [ "$CONFIG_FB_ATARI" = "m" ]; then
+ define_bool CONFIG_FBCON_IPLAN2P2 m
+ define_bool CONFIG_FBCON_IPLAN2P4 m
+ define_bool CONFIG_FBCON_IPLAN2P8 m
+# define_bool CONFIG_FBCON_IPLAN2P16 m
+ fi
fi
- fi
- if [ "$CONFIG_FB_VGA16" = "y" ]; then
- define_bool CONFIG_FBCON_VGA_PLANES y
- else
- if [ "$CONFIG_FB_VGA16" = "m" ]; then
- define_bool CONFIG_FBCON_VGA_PLANES m
+ if [ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" ]; then
+ define_bool CONFIG_FBCON_MAC y
+ else
+ if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then
+ define_bool CONFIG_FBCON_MAC m
+ fi
fi
- fi
- if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
- define_bool CONFIG_FBCON_VGA y
- else
- if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then
- define_bool CONFIG_FBCON_VGA m
+ if [ "$CONFIG_FB_VGA16" = "y" ]; then
+ define_bool CONFIG_FBCON_VGA_PLANES y
+ else
+ if [ "$CONFIG_FB_VGA16" = "m" ]; then
+ define_bool CONFIG_FBCON_VGA_PLANES m
+ fi
fi
- fi
- fi
- bool 'Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
- if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
- bool 'Sparc console 8x16 font' CONFIG_FONT_SUN8x16
- if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
- bool 'Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
- fi
- bool 'Select other fonts' CONFIG_FBCON_FONTS
- if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
- bool ' VGA 8x8 font' CONFIG_FONT_8x8
- bool ' VGA 8x16 font' CONFIG_FONT_8x16
- if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
- bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then
+ define_bool CONFIG_FBCON_VGA y
+ else
+ if [ "$CONFIG_FB_MDA" = "m" -o "$CONFIG_FB_VGA" = "m" ]; then
+ define_bool CONFIG_FBCON_VGA m
+ fi
fi
- bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
- bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
- fi
- else
- bool 'Select compiled-in fonts' CONFIG_FBCON_FONTS
- if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
- bool ' VGA 8x8 font' CONFIG_FONT_8x8
- bool ' VGA 8x16 font' CONFIG_FONT_8x16
+ fi
+ bool ' Support only 8 pixels wide fonts' CONFIG_FBCON_FONTWIDTH8_ONLY
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16
if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
- bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
- bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
fi
- bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
- bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
- else
- define_bool CONFIG_FONT_8x8 y
- define_bool CONFIG_FONT_8x16 y
- if [ "$CONFIG_MAC" = "y" ]; then
- if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
- define_bool CONFIG_FONT_6x11 y
- fi
+ bool ' Select other fonts' CONFIG_FBCON_FONTS
+ if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+ bool ' VGA 8x8 font' CONFIG_FONT_8x8
+ bool ' VGA 8x16 font' CONFIG_FONT_8x16
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ fi
+ bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+ bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
fi
- if [ "$CONFIG_AMIGA" = "y" ]; then
- define_bool CONFIG_FONT_PEARL_8x8 y
+ else
+ bool ' Select compiled-in fonts' CONFIG_FBCON_FONTS
+ if [ "$CONFIG_FBCON_FONTS" = "y" ]; then
+ bool ' VGA 8x8 font' CONFIG_FONT_8x8
+ bool ' VGA 8x16 font' CONFIG_FONT_8x16
+ bool ' Sparc console 8x16 font' CONFIG_FONT_SUN8x16
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ bool ' Sparc console 12x22 font (not supported by all drivers)' CONFIG_FONT_SUN12x22
+ bool ' Mac console 6x11 font (not supported by all drivers)' CONFIG_FONT_6x11
+ fi
+ bool ' Pearl (old m68k) console 8x8 font' CONFIG_FONT_PEARL_8x8
+ bool ' Acorn console 8x8 font' CONFIG_FONT_ACORN_8x8
+ else
+ define_bool CONFIG_FONT_8x8 y
+ define_bool CONFIG_FONT_8x16 y
+ if [ "$CONFIG_MAC" = "y" ]; then
+ if [ "$CONFIG_FBCON_FONTWIDTH8_ONLY" = "n" ]; then
+ define_bool CONFIG_FONT_6x11 y
+ fi
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ define_bool CONFIG_FONT_PEARL_8x8 y
+ fi
+ if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
+ define_bool CONFIG_FONT_ACORN_8x8 y
+ fi
fi
- if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
- define_bool CONFIG_FONT_ACORN_8x8 y
- fi
- fi
- fi
+ fi
fi
+
+endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8e328ed1e..e4466cfcb 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -150,13 +150,17 @@ else
endif
ifeq ($(CONFIG_FB_SGIVW),y)
-L_OBJS += sgivwfb.o
+LX_OBJS += sgivwfb.o
else
ifeq ($(CONFIG_FB_SGIVW),m)
- M_OBJS += sgivwfb.o
+ MX_OBJS += sgivwfb.o
endif
endif
+ifeq ($(CONFIG_FB_3DFX),y)
+L_OBJS += tdfxfb.o
+endif
+
ifeq ($(CONFIG_FB_MAC),y)
L_OBJS += macfb.o
endif
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 47531e1bb..fb578ffdb 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1736,6 +1736,7 @@ default_chipset:
fb_info.updatevar = &amifbcon_updatevar;
fb_info.blank = &amifbcon_blank;
fb_info.flags = FBINFO_FLAG_DEFAULT;
+ memset(&var, 0, sizeof(var));
if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4))
diff --git a/drivers/video/aty.h b/drivers/video/aty.h
index e7b6620ad..2e5900f34 100644
--- a/drivers/video/aty.h
+++ b/drivers/video/aty.h
@@ -103,6 +103,8 @@
#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */
+#define POWER_MANAGEMENT 0x00D8 /* Dword offset 0_36 (LG) */
+
#define CONFIG_CNTL 0x00DC /* Dword offset 0_37 (CT, ET, VT) */
#define CONFIG_CHIP_ID 0x00E0 /* Dword offset 0_38 */
#define CONFIG_STAT0 0x00E4 /* Dword offset 0_39 */
@@ -951,4 +953,15 @@
#define MACH64_NUM_CLOCKS 16
#define MACH64_NUM_FREQS 50
+/* Power Management register constants (LTG and LT Pro) */
+#define PWR_MGT_ON 0x00000001
+#define PWR_MGT_MODE_MASK 0x00000006
+#define AUTO_PWR_UP 0x00000008
+#define SELF_REFRESH 0x00000080
+#define PWR_BLON 0x02000000
+#define STANDBY_NOW 0x10000000
+#define SUSPEND_NOW 0x20000000
+#define PWR_MGT_STATUS_MASK 0xC0000000
+#define PWR_MGT_STATUS_SUSPEND 0x80000000
+
#endif /* REGMACH64_H */
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index f12fec6e1..edba704a3 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -1,4 +1,4 @@
-/* $Id: atyfb.c,v 1.122 1999/09/06 20:44:08 geert Exp $
+/* $Id: atyfb.c,v 1.126 1999/09/16 18:46:23 geert Exp $
* linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
* Copyright (C) 1997-1998 Geert Uytterhoeven
@@ -52,7 +52,6 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/nvram.h>
#include <linux/kd.h>
#include <linux/vt_kern.h>
@@ -62,12 +61,15 @@
#include <asm/io.h>
-#if defined(CONFIG_PPC)
+#ifdef __powerpc__
+#include <linux/adb.h>
+#include <linux/pmu.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#endif
+#ifdef CONFIG_NVRAM
+#include <linux/nvram.h>
#endif
#ifdef __sparc__
#include <asm/pbm.h>
@@ -272,8 +274,20 @@ struct fb_info_aty {
int vtconsole;
int consolecnt;
#endif
+#ifdef CONFIG_PMAC_PBOOK
+ unsigned char *save_framebuffer;
+ unsigned long save_pll[64];
+#endif
};
+#ifdef CONFIG_PMAC_PBOOK
+ int aty_sleep_notify(struct pmu_sleep_notifier *self, int when);
+ static struct pmu_sleep_notifier aty_sleep_notifier = {
+ aty_sleep_notify, SLEEP_LEVEL_VIDEO,
+ };
+ static struct fb_info_aty* first_display = NULL;
+#endif
+
/*
* Frame buffer device API
@@ -446,7 +460,7 @@ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *fb);
static void do_install_cmap(int con, struct fb_info *info);
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
static int read_aty_sense(const struct fb_info_aty *info);
#endif
@@ -488,9 +502,14 @@ static int default_mclk __initdata = 0;
static const char *mode_option __initdata = NULL;
#endif
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
+#ifdef CONFIG_NVRAM
static int default_vmode __initdata = VMODE_NVRAM;
static int default_cmode __initdata = CMODE_NVRAM;
+#else
+static int default_vmode __initdata = VMODE_CHOOSE;
+static int default_cmode __initdata = CMODE_CHOOSE;
+#endif
#endif
#ifdef CONFIG_ATARI
@@ -550,58 +569,46 @@ static const char *aty_ct_ram[8] __initdata = {
static inline u32 aty_ld_le32(unsigned int regindex,
const struct fb_info_aty *info)
{
+#if defined(__powerpc__)
unsigned long temp;
u32 val;
-#if defined(__powerpc__)
temp = info->ati_regbase;
asm volatile("lwbrx %0,%1,%2" : "=r"(val) : "b" (regindex), "r" (temp));
-#elif defined(__sparc_v9__)
- temp = info->ati_regbase + regindex;
- val = readl(temp);
+ return val;
+#elif defined(__mc68000__)
+ return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));
#else
- temp = info->ati_regbase+regindex;
- val = le32_to_cpu(*((volatile u32 *)(temp)));
+ return readl (info->ati_regbase + regindex);
#endif
- return val;
}
static inline void aty_st_le32(unsigned int regindex, u32 val,
const struct fb_info_aty *info)
{
+#if defined(__powerpc__)
unsigned long temp;
-#if defined(__powerpc__)
temp = info->ati_regbase;
asm volatile("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r" (temp) :
"memory");
-#elif defined(__sparc_v9__)
- temp = info->ati_regbase + regindex;
- writel(val, temp);
+#elif defined(__mc68000__)
+ *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);
#else
- temp = info->ati_regbase+regindex;
- *((volatile u32 *)(temp)) = cpu_to_le32(val);
+ writel (val, info->ati_regbase + regindex);
#endif
}
static inline u8 aty_ld_8(unsigned int regindex,
const struct fb_info_aty *info)
{
-#ifdef __sparc_v9__
- return readb(info->ati_regbase + regindex);
-#else
- return *(volatile u8 *)(info->ati_regbase+regindex);
-#endif
+ return readb (info->ati_regbase + regindex);
}
static inline void aty_st_8(unsigned int regindex, u8 val,
const struct fb_info_aty *info)
{
-#ifdef __sparc_v9__
- writeb(val, info->ati_regbase + regindex);
-#else
- *(volatile u8 *)(info->ati_regbase+regindex) = val;
-#endif
+ writeb (val, info->ati_regbase + regindex);
}
@@ -791,7 +798,7 @@ static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
return res;
}
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
/*
* Apple monitor sense
@@ -831,7 +838,7 @@ static int read_aty_sense(const struct fb_info_aty *info)
return sense;
}
-#endif /* defined(CONFIG_PPC) */
+#endif /* CONFIG_PMAC */
/* ------------------------------------------------------------------------- */
@@ -903,17 +910,19 @@ aty_set_cursor_shape(struct fb_info_aty *fb)
for (x = 0; x < c->size.x >> 2; x++) {
m = c->mask[x][y];
b = c->bits[x][y];
- *ram++ = cursor_mask_lookup[m >> 4] |
- cursor_bits_lookup[(b & m) >> 4];
- *ram++ = cursor_mask_lookup[m & 0x0f] |
- cursor_bits_lookup[(b & m) & 0x0f];
+ fb_writeb (cursor_mask_lookup[m >> 4] |
+ cursor_bits_lookup[(b & m) >> 4],
+ ram++);
+ fb_writeb (cursor_mask_lookup[m & 0x0f] |
+ cursor_bits_lookup[(b & m) & 0x0f],
+ ram++);
}
for ( ; x < 8; x++) {
- *ram++ = 0xaa;
- *ram++ = 0xaa;
+ fb_writeb (0xaa, ram++);
+ fb_writeb (0xaa, ram++);
}
}
- memset(ram, 0xaa, (64 - c->size.y) * 16);
+ fb_memset (ram, 0xaa, (64 - c->size.y) * 16);
}
static void
@@ -3239,7 +3248,7 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
struct display *disp;
const char *chipname = NULL, *ramname = NULL, *xtal;
int pll, mclk, gtb_memsize;
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
int sense;
#endif
u8 pll_ref_div;
@@ -3501,16 +3510,22 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
var = default_var;
#else /* !MODULE */
memset(&var, 0, sizeof(var));
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
+ /*
+ * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
+ * applies to all Mac video cards
+ */
if (mode_option) {
if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
var = default_var;
} else {
+#ifdef CONFIG_NVRAM
if (default_vmode == VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_CHOOSE;
}
+#endif
if (default_vmode == VMODE_CHOOSE) {
if (Gx == LG_CHIP_ID)
/* G3 PowerBook with 1024x768 LCD */
@@ -3522,14 +3537,16 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
}
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
+#ifdef CONFIG_NVRAM
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
+#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
}
-#else /* !CONFIG_PPC */
+#else /* !CONFIG_PMAC */
#ifdef __sparc__
if (mode_option) {
if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
@@ -3540,7 +3557,7 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
var = default_var;
#endif /* !__sparc__ */
-#endif /* !CONFIG_PPC */
+#endif /* !CONFIG_PMAC */
#endif /* !MODULE */
if (noaccel)
var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -3964,6 +3981,13 @@ void __init atyfb_of_init(struct device_node *dp)
struct fb_info_aty *info;
int i;
+ if (device_is_compatible(dp, "ATY,264LTPro")) {
+ /* XXX kludge for now */
+ if (dp->name == 0 || strcmp(dp->name, "ATY,264LTProA") != 0
+ || dp->parent == 0)
+ return;
+ dp = dp->parent;
+ }
switch (dp->n_addrs) {
case 1:
case 2:
@@ -4032,6 +4056,14 @@ void __init atyfb_of_init(struct device_node *dp)
return;
}
+#ifdef CONFIG_PMAC_PBOOK
+ if (first_display == NULL)
+ pmu_register_sleep_notifier(&aty_sleep_notifier);
+ info->next = first_display;
+ first_display = info;
+#endif
+
+
#ifdef CONFIG_FB_COMPAT_XPMAC
if (!console_fb_info)
console_fb_info = &info->fb_info;
@@ -4070,7 +4102,7 @@ int __init atyfb_setup(char *options)
default_pll = simple_strtoul(this_opt+4, NULL, 0);
else if (!strncmp(this_opt, "mclk:", 5))
default_mclk = simple_strtoul(this_opt+5, NULL, 0);
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
@@ -4207,7 +4239,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
struct fb_info_aty *info = (struct fb_info_aty *)fb;
u8 gen_cntl;
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
if ((_machine == _MACH_Pmac) && blank)
pmu_enable_backlight(0);
#endif
@@ -4232,7 +4264,7 @@ static void atyfbcon_blank(int blank, struct fb_info *fb)
gen_cntl &= ~(0x4c);
aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
-#if defined(CONFIG_PPC)
+#ifdef CONFIG_PMAC
if ((_machine == _MACH_Pmac) && !blank)
pmu_enable_backlight(1);
#endif
@@ -4736,6 +4768,98 @@ static struct display_switch fbcon_aty32 = {
};
#endif
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+int
+aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ struct fb_info_aty *info;
+ unsigned int pm;
+
+ for (info = first_display; info != NULL; info = info->next) {
+ struct fb_fix_screeninfo fix;
+ int nb;
+
+ atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
+ nb = fb_display[fg_console].var.yres * fix.line_length;
+
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ /* Stop accel engine (stop bus mastering) */
+ if (info->current_par.accel_flags & FB_ACCELF_TEXT)
+ reset_engine(info);
+#if 1
+ /* Backup fb content */
+ info->save_framebuffer = vmalloc(nb);
+ if (info->save_framebuffer)
+ memcpy(info->save_framebuffer,
+ (void *)info->frame_buffer, nb);
+#endif
+ /* Blank display and LCD */
+ atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+ /* Set chip to "suspend" mode. Note: There's an HW bug in the
+ chip which prevents proper resync on wakeup with automatic
+ power management, we handle suspend manually using the
+ following (weird) sequence described by ATI. Note2:
+ We could enable this for all Rage LT Pro chip ids */
+ if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm &= ~PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm &= ~(PWR_BLON | AUTO_PWR_UP);
+ pm |= SUSPEND_NOW;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm |= PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ do {
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+ mdelay(500);
+ }
+ break;
+ case PBOOK_WAKE:
+ /* Wakeup chip */
+ if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm &= ~PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm |= (PWR_BLON | AUTO_PWR_UP);
+ pm &= ~SUSPEND_NOW;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ pm |= PWR_MGT_ON;
+ aty_st_le32(POWER_MANAGEMENT, pm, info);
+ do {
+ pm = aty_ld_le32(POWER_MANAGEMENT, info);
+ } while ((pm & PWR_MGT_STATUS_MASK) != 0);
+ mdelay(500);
+ }
+#if 1
+ /* Restore fb content */
+ if (info->save_framebuffer) {
+ memcpy((void *)info->frame_buffer,
+ info->save_framebuffer, nb);
+ vfree(info->save_framebuffer);
+ info->save_framebuffer = 0;
+ }
+#endif
+ /* Restore display */
+ atyfb_set_par(&info->current_par, info);
+ atyfbcon_blank(0, (struct fb_info *)info);
+ break;
+ }
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
#ifdef MODULE
int __init init_module(void)
{
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 79df3aa98..dd20b767e 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -35,8 +35,8 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-#include <asm/adb.h>
-#include <asm/pmu.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
@@ -103,9 +103,9 @@ struct fb_info_chips {
static struct fb_info_chips *all_chips;
#ifdef CONFIG_PMAC_PBOOK
-int chips_sleep_notify(struct notifier_block *, unsigned long, void *);
-static struct notifier_block chips_sleep_notifier = {
- chips_sleep_notify, NULL, 0
+int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier chips_sleep_notifier = {
+ chips_sleep_notify, SLEEP_LEVEL_VIDEO,
};
#endif
@@ -329,8 +329,9 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
out_8(p->io_base + 0x3c9, blue);
#ifdef FBCON_HAS_CFB16
- if (regno < 16) p->fbcon_cfb16_cmap[regno] =
- ((red & 0xf8) << 7) | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);
+ if (regno < 16)
+ p->fbcon_cfb16_cmap[regno] = ((red & 0xf8) << 7)
+ | ((green & 0xf8) << 2) | ((blue & 0xf8) >> 3);
#endif
return 0;
@@ -638,8 +639,7 @@ static void __init init_chips(struct fb_info_chips *p)
#ifdef CONFIG_PMAC_PBOOK
if (all_chips == NULL)
- notifier_chain_register(&sleep_notifier_list,
- &chips_sleep_notifier);
+ pmu_register_sleep_notifier(&chips_sleep_notifier);
#endif /* CONFIG_PMAC_PBOOK */
p->next = all_chips;
all_chips = p;
@@ -705,15 +705,26 @@ void __init chips_of_init(struct device_node *dp)
* and restore it when we wake up again.
*/
int
-chips_sleep_notify(struct notifier_block *this, unsigned long code, void *x)
+chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
{
struct fb_info_chips *p;
for (p = all_chips; p != NULL; p = p->next) {
int nb = p->var.yres * p->fix.line_length;
-
- switch (code) {
- case PBOOK_SLEEP:
+ int i;
+
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ chipsfb_blank(1, (struct fb_info *)p);
+ /* get the palette from the chip, Xpmac seems
+ to set it directly in the chip */
+ for (i = 0; i < 256; ++i) {
+ out_8(p->io_base + 0x3c8, i);
+ udelay(1);
+ p->palette[i].red = in_8(p->io_base + 0x3c9);
+ p->palette[i].green = in_8(p->io_base + 0x3c9);
+ p->palette[i].blue = in_8(p->io_base + 0x3c9);
+ }
p->save_framebuffer = vmalloc(nb);
if (p->save_framebuffer)
memcpy(p->save_framebuffer,
@@ -726,9 +737,10 @@ chips_sleep_notify(struct notifier_block *this, unsigned long code, void *x)
vfree(p->save_framebuffer);
p->save_framebuffer = 0;
}
+ chipsfb_blank(0, (struct fb_info *)p);
break;
}
}
- return NOTIFY_DONE;
+ return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 6893afbef..cd269e864 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -43,11 +43,11 @@
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
#endif
+#include <linux/adb.h>
+#include <linux/cuda.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
@@ -702,26 +702,48 @@ void __init control_of_init(struct device_node *dp)
p->cmap_regs = ioremap(p->cmap_regs_phys, 0x1000);
/* Work out which banks of VRAM we have installed. */
- /* danj: I guess the card just ignores writes to nonexistant VRAM... */
+ /* According to Andrew Fyfe <bandr@best.com>, the VRAM behaves like so: */
+ /* afyfe: observations from an 8500:
+ * - with 2M vram in bank 1, it appears at offsets 0, 2M and 4M
+ * - with 2M vram in bank 2, it appears only at offset 6M
+ * - with 4M vram, it appears only as a 4M block at offset 0.
+ */
+
+ /* We know there is something at 2M if there is something at 0M. */
+ out_8(&p->frame_buffer[0x200000], 0xa5);
+ out_8(&p->frame_buffer[0x200001], 0x38);
+ asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x200000]) : "memory" );
+
out_8(&p->frame_buffer[0], 0x5a);
out_8(&p->frame_buffer[1], 0xc7);
asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0]) : "memory" );
- bank1 = (in_8(&p->frame_buffer[0]) == 0x5a) && (in_8(&p->frame_buffer[1]) == 0xc7);
- out_8(&p->frame_buffer[0x600000], 0xa5);
- out_8(&p->frame_buffer[0x600001], 0x38);
- asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
- bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
- && (in_8(&p->frame_buffer[0x600001]) == 0x38);
-
- p->total_vram = (bank1 + bank2) * 0x200000;
- /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
- p->control_use_bank2 = !bank1;
- if (p->control_use_bank2) {
+ bank1 = (in_8(&p->frame_buffer[0x000000]) == 0x5a)
+ && (in_8(&p->frame_buffer[0x000001]) == 0xc7);
+ bank2 = (in_8(&p->frame_buffer[0x200000]) == 0xa5)
+ && (in_8(&p->frame_buffer[0x200001]) == 0x38);
+
+ if(bank2 && !bank1)
+ printk(KERN_INFO "controlfb: Found memory at 2MB but not at 0! Please contact dan@debian.org\n");
+
+ if(!bank1) {
+ out_8(&p->frame_buffer[0x600000], 0xa5);
+ out_8(&p->frame_buffer[0x600001], 0x38);
+ asm volatile("eieio; dcbi 0,%0" : : "r" (&p->frame_buffer[0x600000]) : "memory" );
+ bank2 = (in_8(&p->frame_buffer[0x600000]) == 0xa5)
+ && (in_8(&p->frame_buffer[0x600001]) == 0x38);
+ /* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+ p->control_use_bank2 = 1;
p->frame_buffer += 0x600000;
p->frame_buffer_phys += 0x600000;
}
+ p->total_vram = (bank1 + bank2) * 0x200000;
+
+ printk(KERN_INFO "controlfb: Memory bank 1 %s, bank 2 %s, total VRAM %dMB\n",
+ bank1 ? "present" : "absent", bank2 ? "present" : "absent",
+ 2 * (bank1 + bank2));
+
init_control(p);
}
diff --git a/drivers/video/fbcon-afb.c b/drivers/video/fbcon-afb.c
index 3b9d4bb93..5bc95651b 100644
--- a/drivers/video/fbcon-afb.c
+++ b/drivers/video/fbcon-afb.c
@@ -178,7 +178,7 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
dest = p->screen_base+dy*fontheight(p)*width;
i = p->var.bits_per_pixel;
do {
- mymemmove(dest, src, height*fontheight(p)*width);
+ fb_memmove(dest, src, height*fontheight(p)*width);
src += p->next_plane;
dest += p->next_plane;
} while (--i);
@@ -191,7 +191,7 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
dest = dest0;
j = height*fontheight(p);
do {
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
src += p->next_line;
dest += p->next_line;
} while (--j);
@@ -209,7 +209,7 @@ void fbcon_afb_bmove(struct display *p, int sy, int sx, int dy, int dx,
do {
src -= p->next_line;
dest -= p->next_line;
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
} while (--j);
src0 += p->next_plane;
dest0 += p->next_plane;
@@ -233,9 +233,9 @@ void fbcon_afb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
j = height*fontheight(p);
do {
if (bg & 1)
- mymemset(dest, width);
+ fb_memset255(dest, width);
else
- mymemclear(dest, width);
+ fb_memclear(dest, width);
dest += p->next_line;
} while (--j);
bg >>= 1;
diff --git a/drivers/video/fbcon-cfb16.c b/drivers/video/fbcon-cfb16.c
index 9fef8171e..0c3c79ab7 100644
--- a/drivers/video/fbcon-cfb16.c
+++ b/drivers/video/fbcon-cfb16.c
@@ -14,6 +14,7 @@
#include <linux/console.h>
#include <linux/string.h>
#include <linux/fb.h>
+#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb16.h>
@@ -46,7 +47,7 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src, *dst;
if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
return;
@@ -64,7 +65,7 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx;
dst = p->screen_base + dy * linesize + dx;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src += bytes;
dst += bytes;
}
@@ -72,7 +73,7 @@ void fbcon_cfb16_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + (sy+height) * linesize + sx - bytes;
dst = p->screen_base + (dy+height) * linesize + dx - bytes;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
@@ -89,13 +90,13 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
while (height-- > 0) {
u32 *p = (u32 *)dest;
for (i = 0; i < width/4; i++) {
- *p++ = data;
- *p++ = data;
+ fb_writel(data, p++);
+ fb_writel(data, p++);
}
if (width & 2)
- *p++ = data;
+ fb_writel(data, p++);
if (width & 1)
- *(u16 *)p = data;
+ fb_writew(data, (u16*)p);
dest += linesize;
}
}
@@ -139,11 +140,11 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
cdat = p->fontdata + (c & p->charmask) * fontheight(p);
for (rows = fontheight(p); rows--; dest += bytes) {
bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
if (fontwidth(p) == 8) {
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
}
}
break;
@@ -152,16 +153,16 @@ void fbcon_cfb16_putc(struct vc_data *conp, struct display *p, int c, int yy,
cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1);
for (rows = fontheight(p); rows--; dest += bytes) {
bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
bits = *cdat++;
- ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
if (fontwidth(p) == 16) {
- ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
}
}
break;
@@ -191,11 +192,11 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + c * fontheight(p);
for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
u8 bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
if (fontwidth(p) == 8) {
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
}
}
dest0 += fontwidth(p)*2;;
@@ -208,16 +209,16 @@ void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + (c * fontheight(p) << 1);
for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
u8 bits = *cdat++;
- ((u32 *)dest)[0] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[1] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[2] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[3] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+4);
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+8);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+12);
bits = *cdat++;
- ((u32 *)dest)[4] = (tab_cfb16[bits >> 6] & eorx) ^ bgx;
- ((u32 *)dest)[5] = (tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest+16);
+ fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest+20);
if (fontwidth(p) == 16) {
- ((u32 *)dest)[6] = (tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx;
- ((u32 *)dest)[7] = (tab_cfb16[bits & 3] & eorx) ^ bgx;
+ fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest+24);
+ fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest+28);
}
}
dest0 += fontwidth(p)*2;
@@ -235,16 +236,20 @@ void fbcon_cfb16_revc(struct display *p, int xx, int yy)
for (rows = fontheight(p); rows--; dest += bytes) {
switch (fontwidth(p)) {
case 16:
- ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24);
+ fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28);
/* FALL THROUGH */
case 12:
- ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16);
+ fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20);
/* FALL THROUGH */
case 8:
- ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8);
+ fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12);
/* FALL THROUGH */
case 4:
- ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
+ fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
}
}
}
diff --git a/drivers/video/fbcon-cfb2.c b/drivers/video/fbcon-cfb2.c
index 5b339a4fa..4326b87f8 100644
--- a/drivers/video/fbcon-cfb2.c
+++ b/drivers/video/fbcon-cfb2.c
@@ -61,7 +61,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src,*dst;
if (sx == 0 && dx == 0 && width * 2 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
}
@@ -70,7 +70,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx * 2;
dst = p->screen_base + dy * linesize + dx * 2;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width * 2);
+ fb_memmove(dst, src, width * 2);
src += bytes;
dst += bytes;
}
@@ -81,7 +81,7 @@ void fbcon_cfb2_bmove(struct display *p, int sy, int sx, int dy, int dx,
dst = p->screen_base + (dy+height) * linesize + dx * 2
- bytes;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width * 2);
+ fb_memmove(dst, src, width * 2);
src -= bytes;
dst -= bytes;
}
@@ -105,7 +105,7 @@ void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx,
if (sx == 0 && width * 2 == bytes) {
for (i = 0 ; i < lines * width ; i++) {
- ((u16 *)dest)[0]=bgx;
+ fb_writew (bgx, dest);
dest+=2;
}
} else {
@@ -114,7 +114,7 @@ void fbcon_cfb2_clear(struct vc_data *conp, struct display *p, int sy, int sx,
dest=dest0;
for (i = 0 ; i < width ; i++) {
/* memset ?? */
- ((u16 *)dest)[0]=bgx;
+ fb_writew (bgx, dest);
dest+=2;
}
}
@@ -140,10 +140,8 @@ void fbcon_cfb2_putc(struct vc_data *conp, struct display *p, int c, int yy,
eorx = fgx ^ bgx;
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u8 *)dest)[0]=
- (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
- ((u8 *)dest)[1]=
- (nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writeb((nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx, dest+0);
+ fb_writeb((nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx, dest+1);
}
}
@@ -168,10 +166,8 @@ void fbcon_cfb2_putcs(struct vc_data *conp, struct display *p, const unsigned sh
cdat = p->fontdata + c * fontheight(p);
for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
- ((u8 *)dest)[0]=
- (nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx;
- ((u8 *)dest)[1]=
- (nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writeb((nibbletab_cfb2[*cdat >> 4] & eorx) ^ bgx, dest+0);
+ fb_writeb((nibbletab_cfb2[*cdat++ & 0xf] & eorx) ^ bgx, dest+1);
}
dest0+=2;
}
@@ -184,7 +180,7 @@ void fbcon_cfb2_revc(struct display *p, int xx, int yy)
dest = p->screen_base + yy * fontheight(p) * bytes + xx * 2;
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u16 *)dest)[0] ^= 0xffff;
+ fb_writew(fb_readw(dest) ^ 0xffff, dest);
}
}
diff --git a/drivers/video/fbcon-cfb24.c b/drivers/video/fbcon-cfb24.c
index 17e8ee08a..74ace660f 100644
--- a/drivers/video/fbcon-cfb24.c
+++ b/drivers/video/fbcon-cfb24.c
@@ -36,7 +36,7 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src, *dst;
if (sx == 0 && dx == 0 && width * fontwidth(p) * 3 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
return;
@@ -55,7 +55,7 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx;
dst = p->screen_base + dy * linesize + dx;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src += bytes;
dst += bytes;
}
@@ -63,7 +63,7 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + (sy+height) * linesize + sx - bytes;
dst = p->screen_base + (dy+height) * linesize + dx - bytes;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
@@ -90,7 +90,11 @@ void fbcon_cfb24_bmove(struct display *p, int sy, int sx, int dy, int dx,
static inline void store4pixels(u32 d1, u32 d2, u32 d3, u32 d4, u32 *dest)
{
- convert4to3(d1, d2, d3, d4, *dest++, *dest++, *dest++);
+ u32 o1, o2, o3;
+ convert4to3(d1, d2, d3, d4, o1, o2, o3);
+ fb_writel (o1, dest++);
+ fb_writel (o2, dest++);
+ fb_writel (o3, dest);
}
static inline void rectfill(u8 *dest, int width, int height, u32 data,
@@ -103,9 +107,9 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
while (height-- > 0) {
u32 *p = (u32 *)dest;
for (i = 0; i < width/4; i++) {
- *p++ = d1;
- *p++ = d2;
- *p++ = d3;
+ fb_writel(d1, p++);
+ fb_writel(d2, p++);
+ fb_writel(d3, p++);
}
dest += linesize;
}
@@ -174,7 +178,7 @@ void fbcon_cfb24_putc(struct vc_data *conp, struct display *p, int c, int yy,
d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
d4 = (-(bits & 1) & eorx) ^ bgx;
- store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+36));
}
}
@@ -225,7 +229,7 @@ void fbcon_cfb24_putcs(struct vc_data *conp, struct display *p,
d2 = (-(bits >> 2 & 1) & eorx) ^ bgx;
d3 = (-(bits >> 1 & 1) & eorx) ^ bgx;
d4 = (-(bits & 1) & eorx) ^ bgx;
- store4pixels(d1, d2, d3, d4, (u32 *)(dest+32));
+ store4pixels(d1, d2, d3, d4, (u32 *)(dest+36));
}
dest0 += fontwidth(p)*3;
}
@@ -240,17 +244,24 @@ void fbcon_cfb24_revc(struct display *p, int xx, int yy)
for (rows = fontheight(p); rows--; dest += bytes) {
switch (fontwidth(p)) {
case 16:
- ((u32 *)dest)[9] ^= 0xffffffff; ((u32 *)dest)[10] ^= 0xffffffff;
- ((u32 *)dest)[11] ^= 0xffffffff; /* FALL THROUGH */
+ fb_writel(fb_readl(dest+36) ^ 0xffffffff, dest+36);
+ fb_writel(fb_readl(dest+40) ^ 0xffffffff, dest+40);
+ fb_writel(fb_readl(dest+44) ^ 0xffffffff, dest+44);
+ /* FALL THROUGH */
case 12:
- ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
- ((u32 *)dest)[8] ^= 0xffffffff; /* FALL THROUGH */
+ fb_writel(fb_readl(dest+24) ^ 0xffffffff, dest+24);
+ fb_writel(fb_readl(dest+28) ^ 0xffffffff, dest+28);
+ fb_writel(fb_readl(dest+32) ^ 0xffffffff, dest+32);
+ /* FALL THROUGH */
case 8:
- ((u32 *)dest)[3] ^= 0xffffffff; ((u32 *)dest)[4] ^= 0xffffffff;
- ((u32 *)dest)[5] ^= 0xffffffff; /* FALL THROUGH */
+ fb_writel(fb_readl(dest+12) ^ 0xffffffff, dest+12);
+ fb_writel(fb_readl(dest+16) ^ 0xffffffff, dest+16);
+ fb_writel(fb_readl(dest+20) ^ 0xffffffff, dest+20);
+ /* FALL THROUGH */
case 4:
- ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
- ((u32 *)dest)[2] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
+ fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4);
+ fb_writel(fb_readl(dest+8) ^ 0xffffffff, dest+8);
}
}
}
diff --git a/drivers/video/fbcon-cfb32.c b/drivers/video/fbcon-cfb32.c
index b66ec2bad..bedd81c96 100644
--- a/drivers/video/fbcon-cfb32.c
+++ b/drivers/video/fbcon-cfb32.c
@@ -36,7 +36,7 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src, *dst;
if (sx == 0 && dx == 0 && width * fontwidth(p) * 4 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
return;
@@ -54,7 +54,7 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx;
dst = p->screen_base + dy * linesize + dx;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src += bytes;
dst += bytes;
}
@@ -62,7 +62,7 @@ void fbcon_cfb32_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + (sy+height) * linesize + sx - bytes;
dst = p->screen_base + (dy+height) * linesize + dx - bytes;
for (rows = height * fontheight(p); rows--;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
@@ -77,17 +77,17 @@ static inline void rectfill(u8 *dest, int width, int height, u32 data,
while (height-- > 0) {
u32 *p = (u32 *)dest;
for (i = 0; i < width/4; i++) {
- *p++ = data;
- *p++ = data;
- *p++ = data;
- *p++ = data;
+ fb_writel(data, p++);
+ fb_writel(data, p++);
+ fb_writel(data, p++);
+ fb_writel(data, p++);
}
if (width & 2) {
- *p++ = data;
- *p++ = data;
+ fb_writel(data, p++);
+ fb_writel(data, p++);
}
if (width & 1)
- *p++ = data;
+ fb_writel(data, p++);
dest += linesize;
}
}
@@ -115,7 +115,7 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
{
u8 *dest, *cdat, bits;
int bytes = p->next_line, rows;
- u32 eorx, fgx, bgx;
+ u32 eorx, fgx, bgx, *pt;
dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
if (fontwidth(p) <= 8)
@@ -128,29 +128,30 @@ void fbcon_cfb32_putc(struct vc_data *conp, struct display *p, int c, int yy,
for (rows = fontheight(p); rows--; dest += bytes) {
bits = *cdat++;
- ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
- ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ pt = (u32 *) dest;
+ fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 8)
continue;
- ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 12)
continue;
bits = *cdat++;
- ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
- ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 16)
continue;
- ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
}
}
@@ -160,7 +161,7 @@ void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
u8 *cdat, *dest, *dest0, bits;
u16 c;
int rows, bytes = p->next_line;
- u32 eorx, fgx, bgx;
+ u32 eorx, fgx, bgx, *pt;
dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 4;
fgx = ((u32 *)p->dispsw_data)[attr_fgcol(p, scr_readw(s))];
@@ -174,29 +175,30 @@ void fbcon_cfb32_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + (c * fontheight(p) << 1);
for (rows = fontheight(p), dest = dest0; rows--; dest += bytes) {
bits = *cdat++;
- ((u32 *)dest)[0] = (-(bits >> 7) & eorx) ^ bgx;
- ((u32 *)dest)[1] = (-(bits >> 6 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[2] = (-(bits >> 5 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[3] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ pt = (u32 *) dest;
+ fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 8)
continue;
- ((u32 *)dest)[4] = (-(bits >> 3 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[5] = (-(bits >> 2 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[6] = (-(bits >> 1 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[7] = (-(bits & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 12)
continue;
bits = *cdat++;
- ((u32 *)dest)[8] = (-(bits >> 7) & eorx) ^ bgx;
- ((u32 *)dest)[9] = (-(bits >> 6 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[10] = (-(bits >> 5 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[11] = (-(bits >> 4 & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 7) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 6 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 5 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 4 & 1) & eorx) ^ bgx, pt++);
if (fontwidth(p) < 16)
continue;
- ((u32 *)dest)[12] = (-(bits >> 3 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[13] = (-(bits >> 2 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[14] = (-(bits >> 1 & 1) & eorx) ^ bgx;
- ((u32 *)dest)[15] = (-(bits & 1) & eorx) ^ bgx;
+ fb_writel((-(bits >> 3 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 2 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits >> 1 & 1) & eorx) ^ bgx, pt++);
+ fb_writel((-(bits & 1) & eorx) ^ bgx, pt++);
}
dest0 += fontwidth(p)*4;
}
@@ -211,20 +213,28 @@ void fbcon_cfb32_revc(struct display *p, int xx, int yy)
for (rows = fontheight(p); rows--; dest += bytes) {
switch (fontwidth(p)) {
case 16:
- ((u32 *)dest)[12] ^= 0xffffffff; ((u32 *)dest)[13] ^= 0xffffffff;
- ((u32 *)dest)[14] ^= 0xffffffff; ((u32 *)dest)[15] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+(4*12)) ^ 0xffffffff, dest+(4*12));
+ fb_writel(fb_readl(dest+(4*13)) ^ 0xffffffff, dest+(4*13));
+ fb_writel(fb_readl(dest+(4*14)) ^ 0xffffffff, dest+(4*14));
+ fb_writel(fb_readl(dest+(4*15)) ^ 0xffffffff, dest+(4*15));
/* FALL THROUGH */
case 12:
- ((u32 *)dest)[8] ^= 0xffffffff; ((u32 *)dest)[9] ^= 0xffffffff;
- ((u32 *)dest)[10] ^= 0xffffffff; ((u32 *)dest)[11] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+(4*8)) ^ 0xffffffff, dest+(4*8));
+ fb_writel(fb_readl(dest+(4*9)) ^ 0xffffffff, dest+(4*9));
+ fb_writel(fb_readl(dest+(4*10)) ^ 0xffffffff, dest+(4*10));
+ fb_writel(fb_readl(dest+(4*11)) ^ 0xffffffff, dest+(4*11));
/* FALL THROUGH */
case 8:
- ((u32 *)dest)[4] ^= 0xffffffff; ((u32 *)dest)[5] ^= 0xffffffff;
- ((u32 *)dest)[6] ^= 0xffffffff; ((u32 *)dest)[7] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+(4*4)) ^ 0xffffffff, dest+(4*4));
+ fb_writel(fb_readl(dest+(4*5)) ^ 0xffffffff, dest+(4*5));
+ fb_writel(fb_readl(dest+(4*6)) ^ 0xffffffff, dest+(4*6));
+ fb_writel(fb_readl(dest+(4*7)) ^ 0xffffffff, dest+(4*7));
/* FALL THROUGH */
case 4:
- ((u32 *)dest)[0] ^= 0xffffffff; ((u32 *)dest)[1] ^= 0xffffffff;
- ((u32 *)dest)[2] ^= 0xffffffff; ((u32 *)dest)[3] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+(4*0)) ^ 0xffffffff, dest+(4*0));
+ fb_writel(fb_readl(dest+(4*1)) ^ 0xffffffff, dest+(4*1));
+ fb_writel(fb_readl(dest+(4*2)) ^ 0xffffffff, dest+(4*2));
+ fb_writel(fb_readl(dest+(4*3)) ^ 0xffffffff, dest+(4*3));
/* FALL THROUGH */
}
}
diff --git a/drivers/video/fbcon-cfb4.c b/drivers/video/fbcon-cfb4.c
index 6248c28ee..a885fddfa 100644
--- a/drivers/video/fbcon-cfb4.c
+++ b/drivers/video/fbcon-cfb4.c
@@ -61,7 +61,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src,*dst;
if (sx == 0 && dx == 0 && width * 4 == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
}
@@ -70,7 +70,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx * 4;
dst = p->screen_base + dy * linesize + dx * 4;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width * 4);
+ fb_memmove(dst, src, width * 4);
src += bytes;
dst += bytes;
}
@@ -81,7 +81,7 @@ void fbcon_cfb4_bmove(struct display *p, int sy, int sx, int dy, int dx,
dst = p->screen_base + (dy+height) * linesize + dx * 4
- bytes;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width * 4);
+ fb_memmove(dst, src, width * 4);
src -= bytes;
dst -= bytes;
}
@@ -107,7 +107,7 @@ void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
if (sx == 0 && width * 4 == bytes) {
for (i = 0 ; i < lines * width ; i++) {
- ((u32 *)dest)[0]=bgx;
+ fb_writel (bgx, dest);
dest+=4;
}
} else {
@@ -116,7 +116,7 @@ void fbcon_cfb4_clear(struct vc_data *conp, struct display *p, int sy, int sx,
dest=dest0;
for (i = 0 ; i < width ; i++) {
/* memset ?? */
- ((u32 *)dest)[0]=bgx;
+ fb_writel (bgx, dest);
dest+=4;
}
}
@@ -142,10 +142,8 @@ void fbcon_cfb4_putc(struct vc_data *conp, struct display *p, int c, int yy,
eorx = fgx ^ bgx;
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u16 *)dest)[0]=
- (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
- ((u16 *)dest)[1]=
- (nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
+ fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
}
}
@@ -172,10 +170,8 @@ void fbcon_cfb4_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + c * fontheight(p);
for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
- ((u16 *)dest)[0]=
- (nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx;
- ((u16 *)dest)[1]=
- (nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writew((nibbletab_cfb4[*cdat >> 4] & eorx) ^ bgx, dest+0);
+ fb_writew((nibbletab_cfb4[*cdat++ & 0xf] & eorx) ^ bgx, dest+2);
}
dest0+=4;
}
@@ -188,7 +184,7 @@ void fbcon_cfb4_revc(struct display *p, int xx, int yy)
dest = p->screen_base + yy * fontheight(p) * bytes + xx * 4;
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0] ^= 0xffffffff;
+ fb_writel(fb_readl(dest+0) ^ 0xffffffff, dest+0);
}
}
diff --git a/drivers/video/fbcon-cfb8.c b/drivers/video/fbcon-cfb8.c
index 0acf7c989..78e3d462f 100644
--- a/drivers/video/fbcon-cfb8.c
+++ b/drivers/video/fbcon-cfb8.c
@@ -52,7 +52,7 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
u8 *src,*dst;
if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) {
- mymemmove(p->screen_base + dy * linesize,
+ fb_memmove(p->screen_base + dy * linesize,
p->screen_base + sy * linesize,
height * linesize);
return;
@@ -66,7 +66,7 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + sy * linesize + sx;
dst = p->screen_base + dy * linesize + dx;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src += bytes;
dst += bytes;
}
@@ -74,7 +74,7 @@ void fbcon_cfb8_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base + (sy+height) * linesize + sx - bytes;
dst = p->screen_base + (dy+height) * linesize + dx - bytes;
for (rows = height * fontheight(p) ; rows-- ;) {
- mymemmove(dst, src, width);
+ fb_memmove(dst, src, width);
src -= bytes;
dst -= bytes;
}
@@ -85,7 +85,7 @@ static inline void rectfill(u8 *dest, int width, int height, u8 data,
int linesize)
{
while (height-- > 0) {
- memset(dest, data, width);
+ fb_memset(dest, data, width);
dest += linesize;
}
}
@@ -132,22 +132,22 @@ void fbcon_cfb8_putc(struct vc_data *conp, struct display *p, int c, int yy,
switch (fontwidth(p)) {
case 4:
for (rows = fontheight(p) ; rows-- ; dest += bytes)
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx, dest);
break;
case 8:
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+ fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
}
break;
case 12:
case 16:
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
- ((u32 *)dest)[2]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+ fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
+ fb_writel((nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx, dest+8);
if (fontwidth(p) == 16)
- ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx, dest+12);
cdat++;
}
break;
@@ -177,7 +177,7 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + c * fontheight(p);
for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes)
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat++ >> 4] & eorx) ^ bgx, dest);
dest0+=4;
}
break;
@@ -187,8 +187,8 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + c * fontheight(p);
for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+ fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
}
dest0+=8;
}
@@ -200,11 +200,11 @@ void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p,
cdat = p->fontdata + (c * fontheight(p) << 1);
for (rows = fontheight(p), dest = dest0; rows-- ; dest += bytes) {
- ((u32 *)dest)[0]= (nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx;
- ((u32 *)dest)[1]= (nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx;
- ((u32 *)dest)[2]= (nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat >> 4] & eorx) ^ bgx, dest);
+ fb_writel((nibbletab_cfb8[*cdat++ & 0xf] & eorx) ^ bgx, dest+4);
+ fb_writel((nibbletab_cfb8[(*cdat >> 4) & 0xf] & eorx) ^ bgx, dest+8);
if (fontwidth(p) == 16)
- ((u32 *)dest)[3]= (nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx;
+ fb_writel((nibbletab_cfb8[*cdat & 0xf] & eorx) ^ bgx, dest+12);
cdat++;
}
dest0+=fontwidth(p);
@@ -221,10 +221,10 @@ void fbcon_cfb8_revc(struct display *p, int xx, int yy)
dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p);
for (rows = fontheight(p) ; rows-- ; dest += bytes) {
switch (fontwidth(p)) {
- case 16: ((u32 *)dest)[3] ^= 0x0f0f0f0f; /* FALL THROUGH */
- case 12: ((u32 *)dest)[2] ^= 0x0f0f0f0f; /* FALL THROUGH */
- case 8: ((u32 *)dest)[1] ^= 0x0f0f0f0f; /* FALL THROUGH */
- case 4: ((u32 *)dest)[0] ^= 0x0f0f0f0f; /* FALL THROUGH */
+ case 16: fb_writel(fb_readl(dest+12) ^ 0x0f0f0f0f, dest+12); /* fall thru */
+ case 12: fb_writel(fb_readl(dest+8) ^ 0x0f0f0f0f, dest+8); /* fall thru */
+ case 8: fb_writel(fb_readl(dest+4) ^ 0x0f0f0f0f, dest+4); /* fall thru */
+ case 4: fb_writel(fb_readl(dest) ^ 0x0f0f0f0f, dest); /* fall thru */
default: break;
}
}
diff --git a/drivers/video/fbcon-ilbm.c b/drivers/video/fbcon-ilbm.c
index fbba519d9..d23c7e4b1 100644
--- a/drivers/video/fbcon-ilbm.c
+++ b/drivers/video/fbcon-ilbm.c
@@ -45,7 +45,7 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
if (sx == 0 && dx == 0 && width == p->next_plane)
- mymemmove(p->screen_base+dy*fontheight(p)*p->next_line,
+ fb_memmove(p->screen_base+dy*fontheight(p)*p->next_line,
p->screen_base+sy*fontheight(p)*p->next_line,
height*fontheight(p)*p->next_line);
else {
@@ -56,7 +56,7 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
src += p->next_plane;
dest += p->next_plane;
}
@@ -66,7 +66,7 @@ void fbcon_ilbm_bmove(struct display *p, int sy, int sx, int dy, int dx,
for (i = p->var.bits_per_pixel*height*fontheight(p); i--;) {
src -= p->next_plane;
dest -= p->next_plane;
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
}
}
}
@@ -86,9 +86,9 @@ void fbcon_ilbm_clear(struct vc_data *conp, struct display *p, int sy, int sx,
bg = bg0;
for (i = p->var.bits_per_pixel; i--; dest += p->next_plane) {
if (bg & 1)
- mymemset(dest, width);
+ fb_memset255(dest, width);
else
- mymemclear(dest, width);
+ fb_memclear(dest, width);
bg >>= 1;
}
}
diff --git a/drivers/video/fbcon-iplan2p2.c b/drivers/video/fbcon-iplan2p2.c
index 0dfdc6107..8be581507 100644
--- a/drivers/video/fbcon-iplan2p2.c
+++ b/drivers/video/fbcon-iplan2p2.c
@@ -169,7 +169,7 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
/* Special (but often used) case: Moving whole lines can be
* done with memmove()
*/
- mymemmove(p->screen_base + dy * p->next_line * fontheight(p),
+ fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
p->screen_base + sy * p->next_line * fontheight(p),
p->next_line * height * fontheight(p));
} else {
@@ -201,7 +201,7 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
}
if (width > 1) {
for (rows = colsize; rows > 0; --rows) {
- mymemmove(dst, src, (width>>1)*4);
+ fb_memmove(dst, src, (width>>1)*4);
src += bytes;
dst += bytes;
}
@@ -227,7 +227,7 @@ void fbcon_iplan2p2_bmove(struct display *p, int sy, int sx, int dy, int dx,
for(rows = colsize; rows > 0; --rows) {
src -= bytes;
dst -= bytes;
- mymemmove(dst, src, (width>>1)*4);
+ fb_memmove(dst, src, (width>>1)*4);
}
}
if (width & 1)
@@ -295,7 +295,7 @@ void fbcon_iplan2p2_clear(struct vc_data *conp, struct display *p, int sy,
/* Clears are split if the region starts at an odd column or
* end at an even column. These extra columns are spread
* across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
+ * cleared by normal fb_memclear_small(), because both bytes of
* the single plane words are affected.
*/
diff --git a/drivers/video/fbcon-iplan2p4.c b/drivers/video/fbcon-iplan2p4.c
index 805c9170b..8591783d9 100644
--- a/drivers/video/fbcon-iplan2p4.c
+++ b/drivers/video/fbcon-iplan2p4.c
@@ -177,7 +177,7 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
/* Special (but often used) case: Moving whole lines can be
*done with memmove()
*/
- mymemmove(p->screen_base + dy * p->next_line * fontheight(p),
+ fb_memmove(p->screen_base + dy * p->next_line * fontheight(p),
p->screen_base + sy * p->next_line * fontheight(p),
p->next_line * height * fontheight(p));
} else {
@@ -210,7 +210,7 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
}
if (width > 1) {
for(rows = colsize; rows > 0; --rows) {
- mymemmove(dst, src, (width>>1)*8);
+ fb_memmove(dst, src, (width>>1)*8);
src += bytes;
dst += bytes;
}
@@ -236,7 +236,7 @@ void fbcon_iplan2p4_bmove(struct display *p, int sy, int sx, int dy, int dx,
for(rows = colsize; rows > 0; --rows) {
src -= bytes;
dst -= bytes;
- mymemmove(dst, src, (width>>1)*8);
+ fb_memmove(dst, src, (width>>1)*8);
}
}
if (width & 1) {
@@ -305,7 +305,7 @@ void fbcon_iplan2p4_clear(struct vc_data *conp, struct display *p, int sy,
/* Clears are split if the region starts at an odd column or
* end at an even column. These extra columns are spread
* across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
+ * cleared by normal fb_memclear_small(), because both bytes of
* the single plane words are affected.
*/
diff --git a/drivers/video/fbcon-iplan2p8.c b/drivers/video/fbcon-iplan2p8.c
index 411dc5ae9..4ee366019 100644
--- a/drivers/video/fbcon-iplan2p8.c
+++ b/drivers/video/fbcon-iplan2p8.c
@@ -337,7 +337,7 @@ void fbcon_iplan2p8_clear(struct vc_data *conp, struct display *p, int sy,
/* Clears are split if the region starts at an odd column or
* end at an even column. These extra columns are spread
* across the interleaved planes. All in between can be
- * cleared by normal mymemclear_small(), because both bytes of
+ * cleared by normal fb_memclear_small(), because both bytes of
* the single plane words are affected.
*/
diff --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c
index 2c6486c41..58deaff54 100644
--- a/drivers/video/fbcon-mac.c
+++ b/drivers/video/fbcon-mac.c
@@ -62,7 +62,7 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
if( sx == 0 && width == p->conp->vc_cols) {
s = height * fontheight(p) * p->next_line;
- mymemmove(dest, src, s);
+ fb_memmove(dest, src, s);
return;
}
@@ -158,7 +158,7 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx,
plot_pixel_mac(p, get_pixel_mac(p, j+(dx-sx), i+(dy-sy)), j, i);
if (j < r) {
- mymemmove(dest, src, s);
+ fb_memmove(dest, src, s);
if (move_up) {
dest += p->next_line;
src += p->next_line;
@@ -202,9 +202,9 @@ void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
if( sx == 0 && width == p->conp->vc_cols) {
s = height * fontheight(p) * p->next_line;
if (inverse)
- mymemclear(dest, s);
+ fb_memclear(dest, s);
else
- mymemset(dest, s);
+ fb_memset255(dest, s);
}
l = sx * fontwidth(p);
@@ -251,9 +251,9 @@ void fbcon_mac_clear(struct vc_data *conp, struct display *p, int sy, int sx,
if (j < r) {
if (PIXEL_WHITE_MAC == pixel)
- mymemclear(dest, s);
+ fb_memclear(dest, s);
else
- mymemset(dest, s);
+ fb_memset255(dest, s);
dest += p->next_line;
j += w;
}
diff --git a/drivers/video/fbcon-mfb.c b/drivers/video/fbcon-mfb.c
index 76caf5cc9..9aa3528dd 100644
--- a/drivers/video/fbcon-mfb.c
+++ b/drivers/video/fbcon-mfb.c
@@ -41,12 +41,12 @@ void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
if (sx == 0 && dx == 0 && width == p->next_line) {
src = p->screen_base+sy*fontheight(p)*width;
dest = p->screen_base+dy*fontheight(p)*width;
- mymemmove(dest, src, height*fontheight(p)*width);
+ fb_memmove(dest, src, height*fontheight(p)*width);
} else if (dy <= sy) {
src = p->screen_base+sy*fontheight(p)*p->next_line+sx;
dest = p->screen_base+dy*fontheight(p)*p->next_line+dx;
for (rows = height*fontheight(p); rows--;) {
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
src += p->next_line;
dest += p->next_line;
}
@@ -54,7 +54,7 @@ void fbcon_mfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
src = p->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
dest = p->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
for (rows = height*fontheight(p); rows--;) {
- mymemmove(dest, src, width);
+ fb_memmove(dest, src, width);
src -= p->next_line;
dest -= p->next_line;
}
@@ -72,15 +72,15 @@ void fbcon_mfb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
if (sx == 0 && width == p->next_line) {
if (inverse)
- mymemset(dest, height*fontheight(p)*width);
+ fb_memset255(dest, height*fontheight(p)*width);
else
- mymemclear(dest, height*fontheight(p)*width);
+ fb_memclear(dest, height*fontheight(p)*width);
} else
for (rows = height*fontheight(p); rows--; dest += p->next_line)
if (inverse)
- mymemset(dest, width);
+ fb_memset255(dest, width);
else
- mymemclear_small(dest, width);
+ fb_memclear_small(dest, width);
}
void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
@@ -104,7 +104,7 @@ void fbcon_mfb_putc(struct vc_data *conp, struct display *p, int c, int yy,
d |= d>>1;
if (revs)
d = ~d;
- *dest = d;
+ fb_writeb (d, dest);
}
}
@@ -133,19 +133,21 @@ void fbcon_mfb_putcs(struct vc_data *conp, struct display *p,
d |= d>>1;
if (revs)
d = ~d;
- *dest = d;
+ fb_writeb (d, dest);
}
}
}
void fbcon_mfb_revc(struct display *p, int xx, int yy)
{
- u8 *dest;
+ u8 *dest, d;
u_int rows;
dest = p->screen_base+yy*fontheight(p)*p->next_line+xx;
- for (rows = fontheight(p); rows--; dest += p->next_line)
- *dest = ~*dest;
+ for (rows = fontheight(p); rows--; dest += p->next_line) {
+ d = fb_readb(dest);
+ fb_writeb (~d, dest);
+ }
}
void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
@@ -165,9 +167,9 @@ void fbcon_mfb_clear_margins(struct vc_data *conp, struct display *p,
bottom -= p->vrows;
dest = p->screen_base + bottom * fontheight(p) * p->next_line;
if (inverse)
- mymemset(dest, height * p->next_line);
+ fb_memset255(dest, height * p->next_line);
else
- mymemclear(dest, height * p->next_line);
+ fb_memclear(dest, height * p->next_line);
}
diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c
index b54d0b5a4..77336e223 100644
--- a/drivers/video/fbcon.c
+++ b/drivers/video/fbcon.c
@@ -526,7 +526,7 @@ static void fbcon_setup(int con, int init, int logo)
q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
step = logo_lines * old_cols;
for (r = q - logo_lines * old_cols; r < q; r++)
- if (*r != conp->vc_video_erase_char)
+ if (scr_readw(r) != conp->vc_video_erase_char)
break;
if (r != q && nr_rows >= old_rows + logo_lines) {
save = kmalloc(logo_lines * nr_cols * 2, GFP_KERNEL);
@@ -535,7 +535,7 @@ static void fbcon_setup(int con, int init, int logo)
scr_memsetw(save, conp->vc_video_erase_char, logo_lines * nr_cols * 2);
r = q - step;
for (cnt = 0; cnt < logo_lines; cnt++, r += i)
- scr_memcpyw_to(save + cnt * nr_cols, r, 2 * i);
+ scr_memcpyw_from(save + cnt * nr_cols, r, 2 * i);
r = q;
}
}
@@ -551,7 +551,8 @@ static void fbcon_setup(int con, int init, int logo)
conp->vc_pos += logo_lines * conp->vc_size_row;
}
}
- scr_memsetw((unsigned short *)conp->vc_origin, conp->vc_video_erase_char,
+ scr_memsetw((unsigned short *)conp->vc_origin,
+ conp->vc_video_erase_char,
conp->vc_size_row * logo_lines);
}
@@ -603,7 +604,7 @@ static void fbcon_setup(int con, int init, int logo)
}
if (save) {
q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
- scr_memcpyw_from(q, save, logo_lines * nr_cols * 2);
+ memcpy(q, save, logo_lines * nr_cols * 2);
conp->vc_y += logo_lines;
conp->vc_pos += logo_lines * conp->vc_size_row;
kfree(save);
@@ -1386,19 +1387,11 @@ static int fbcon_blank(struct vc_data *conp, int blank)
if (!p->can_soft_blank) {
if (blank) {
-#ifdef CONFIG_MAC
- if (MACH_IS_MAC) {
- if (p->screen_base)
- mymemset(p->screen_base,
- p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
- } else
-#endif
if (p->visual == FB_VISUAL_MONO01) {
if (p->screen_base)
- mymemset(p->screen_base,
- p->var.xres_virtual*p->var.yres_virtual*
- p->var.bits_per_pixel>>3);
+ fb_memset255(p->screen_base,
+ p->var.xres_virtual*p->var.yres_virtual*
+ p->var.bits_per_pixel>>3);
} else {
unsigned short oldc;
u_int height;
@@ -2048,7 +2041,7 @@ static int __init fbcon_show_logo( void )
(*src << blueshift);
if (bdepth == 4 && !((long)dst & 3)) {
/* Some cards require 32bit access */
- *(u32 *)dst = val;
+ fb_writel (val, dst);
dst += 4;
} else {
#ifdef __LITTLE_ENDIAN
@@ -2056,7 +2049,7 @@ static int __init fbcon_show_logo( void )
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
@@ -2078,7 +2071,7 @@ static int __init fbcon_show_logo( void )
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
pix = (*src & 0x0f) | 0x10; /* lower nibble */
val = (pix << redshift) |
(pix << greenshift) |
@@ -2088,7 +2081,7 @@ static int __init fbcon_show_logo( void )
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
@@ -2122,7 +2115,7 @@ static int __init fbcon_show_logo( void )
safe_shift((linux_logo_blue[*src-32] & bluemask), blueshift);
if (bdepth == 4 && !((long)dst & 3)) {
/* Some cards require 32bit access */
- *(u32 *)dst = val;
+ fb_writel (val, dst);
dst += 4;
} else {
#ifdef __LITTLE_ENDIAN
@@ -2130,7 +2123,7 @@ static int __init fbcon_show_logo( void )
#else
for( i = bdepth-1; i >= 0; --i )
#endif
- *dst++ = val >> (i*8);
+ fb_writeb (val >> (i*8), dst++);
}
}
}
@@ -2145,7 +2138,7 @@ static int __init fbcon_show_logo( void )
for( x1 = 0; x1 < LOGO_W/2; x1++) {
u8 q = *src++;
q = (q << 4) | (q >> 4);
- *dst++ = q;
+ fb_writeb (q, dst++);
}
}
done = 1;
@@ -2159,7 +2152,7 @@ static int __init fbcon_show_logo( void )
for( y1 = 0; y1 < LOGO_H; y1++ ) {
dst = fb + y1*line + x;
for( x1 = 0; x1 < LOGO_W; x1++ )
- *dst++ = *src++;
+ fb_writeb (*src++, dst++);
}
done = 1;
}
@@ -2228,14 +2221,15 @@ static int __init fbcon_show_logo( void )
p->type == FB_TYPE_INTERLEAVED_PLANES)) {
/* monochrome */
- unsigned char inverse = p->inverse ? 0x00 : 0xff;
+ unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01
+ ? 0x00 : 0xff;
/* can't use simply memcpy because need to apply inverse */
for( y1 = 0; y1 < LOGO_H; y1++ ) {
- src = logo + y1*LOGO_LINE + x/8;
- dst = fb + y1*line;
+ src = logo + y1*LOGO_LINE;
+ dst = fb + y1*line + x/8;
for( x1 = 0; x1 < LOGO_LINE; ++x1 )
- *dst++ = *src++ ^ inverse;
+ fb_writeb(fb_readb(src++) ^ inverse, dst++);
}
done = 1;
}
@@ -2255,13 +2249,15 @@ static int __init fbcon_show_logo( void )
outb_p(*src >> 4,0x3cf);
outb_p(8,0x3ce);
outb_p(1 << (7 - x1 % 4 * 2),0x3cf);
- *(volatile char *) dst |= 1;
+ fb_readb (dst);
+ fb_writeb (0, dst);
outb_p(0,0x3ce);
outb_p(*src & 0xf,0x3cf);
outb_p(8,0x3ce);
outb_p(1 << (7 - (1 + x1 % 4 * 2)),0x3cf);
- *(volatile char *) dst |= 1;
+ fb_readb (dst);
+ fb_writeb (0, dst);
src++;
}
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index a02920395..24504b17a 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -100,12 +100,17 @@ extern int fm2fb_setup(char*);
extern int q40fb_init(void);
extern int sgivwfb_init(void);
extern int sgivwfb_setup(char*);
+extern int tdfxfb_init(void);
+extern int tdfxfb_setup(char*);
static struct {
const char *name;
int (*init)(void);
int (*setup)(char*);
} fb_drivers[] __initdata = {
+#ifdef CONFIG_FB_3DFX
+ { "tdfx", tdfxfb_init, tdfxfb_setup },
+#endif
#ifdef CONFIG_FB_SGIVW
{ "sgivw", sgivwfb_init, sgivwfb_setup },
#endif
@@ -454,6 +459,11 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
for (i = 0; i < MAX_NR_CONSOLES; i++)
set_con2fb_map(i, con2fb.framebuffer);
return 0;
+ case FBIOBLANK:
+ if (info->blank == 0)
+ return -EINVAL;
+ (*info->blank)(arg, info);
+ return 0;
default:
return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info),
info);
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 398e8e500..d020ed752 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -354,9 +354,12 @@ struct fb_info_imstt {
} palette[256];
struct imstt_regvals init;
struct imstt_cursor cursor;
- __u8 *frame_buffer_phys, *frame_buffer;
- __u32 *dc_regs_phys, *dc_regs;
- __u8 *cmap_regs_phys, *cmap_regs;
+ unsigned long frame_buffer_phys;
+ __u8 *frame_buffer;
+ unsigned long dc_regs_phys;
+ __u32 *dc_regs;
+ unsigned long cmap_regs_phys;
+ __u8 *cmap_regs;
__u32 total_vram;
__u32 ramdac;
};
@@ -1077,7 +1080,7 @@ imsttfbcon_clear (struct vc_data *conp, struct display *disp,
out_le32(&p->dc_regs[BI], 0xffffffff);
out_le32(&p->dc_regs[MBC], 0xffffffff);
out_le32(&p->dc_regs[CLR], bgc);
- out_le32(&p->dc_regs[BLTCTL], 0x200000);
+ out_le32(&p->dc_regs[BLTCTL], 0x840); /* 0x200000 */
while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
while(in_le32(&p->dc_regs[SSTATUS]) & 0x40);
}
@@ -1854,10 +1857,10 @@ init_imstt(struct fb_info_imstt *p)
fb_info_imstt_p[i] = p;
#ifdef CONFIG_FB_COMPAT_XPMAC
strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
- display_info.fb_address = (__u32)p->frame_buffer_phys;
- display_info.cmap_adr_address = (__u32)&p->cmap_regs_phys[PADDRW];
- display_info.cmap_data_address = (__u32)&p->cmap_regs_phys[PDATA];
- display_info.disp_reg_address = (__u32)p->dc_regs_phys;
+ display_info.fb_address = p->frame_buffer_phys;
+ display_info.cmap_adr_address = p->cmap_regs_phys + PADDRW;
+ display_info.cmap_data_address = p->cmap_regs_phys + PDATA;
+ display_info.disp_reg_address = p->dc_regs_phys;
if (!console_fb_info)
console_fb_info = &p->info;
#endif /* CONFIG_FB_COMPAT_XPMAC */
@@ -1897,11 +1900,11 @@ imsttfb_of_init(struct device_node *dp)
else
p->ramdac = IBM;
- p->frame_buffer_phys = (__u8 *)addr;
+ p->frame_buffer_phys = addr;
p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
- p->dc_regs_phys = (__u32 *)(addr + 0x800000);
+ p->dc_regs_phys = addr + 0x800000;
p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
- p->cmap_regs_phys = (__u8 *)(addr + 0x840000);
+ p->cmap_regs_phys = addr + 0x840000;
p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
init_imstt(p);
@@ -1953,11 +1956,11 @@ imsttfb_init(void)
break;
}
- p->frame_buffer_phys = (__u8 *)addr;
+ p->frame_buffer_phys = addr;
p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
- p->dc_regs_phys = (__u32 *)(addr + 0x800000);
+ p->dc_regs_phys = addr + 0x800000;
p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
- p->cmap_regs_phys = (__u8 *)(addr + 0x840000);
+ p->cmap_regs_phys = addr + 0x840000;
p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
init_imstt(p);
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index af58b457a..404c646f5 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -14,7 +14,7 @@
#include <linux/sched.h>
-#define DEBUG
+#undef DEBUG
#define name_matches(v, s, l) \
((v).name && !strncmp((s), (v).name, (l)) && strlen((v).name) == (l))
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index cf7fe3418..12d067b79 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -10,7 +10,7 @@
*
* Hardware information from:
* platinum.c: Console support for PowerMac "platinum" display adaptor.
- * Copyright (C) 1996 Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
@@ -39,7 +39,6 @@
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
-#include <asm/adb.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
@@ -66,6 +65,7 @@ struct fb_par_platinum {
struct fb_info_platinum {
struct fb_info fb_info;
struct display disp;
+ struct display_switch dispsw;
struct fb_par_platinum default_par;
struct fb_par_platinum current_par;
@@ -145,6 +145,8 @@ static int platinum_var_to_par(const struct fb_var_screeninfo *var,
static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
const struct fb_par_platinum *par,
const struct fb_info_platinum *info);
+static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info,
+ int cmode, int accel);
static int platinum_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
u_int *transp, struct fb_info *fb);
static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -175,10 +177,6 @@ static struct fb_ops platinumfb_ops = {
platinum_ioctl
};
-
-__openfirmware
-
-
static int platinum_open(struct fb_info *info, int user)
{
MOD_INC_USE_COUNT;
@@ -219,6 +217,36 @@ static int platinum_get_var(struct fb_var_screeninfo *var, int con,
return 0;
}
+static void platinum_set_disp(struct display *disp, struct fb_info_platinum *info,
+ int cmode, int accel)
+{
+ switch(cmode) {
+#ifdef FBCON_HAS_CFB8
+ case CMODE_8:
+ info->dispsw = fbcon_cfb8;
+ disp->dispsw = &info->dispsw;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case CMODE_16:
+ info->dispsw = fbcon_cfb16;
+ disp->dispsw = &info->dispsw;
+ disp->dispsw_data = info->fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case CMODE_32:
+ info->dispsw = fbcon_cfb32;
+ disp->dispsw = &info->dispsw;
+ disp->dispsw_data = info->fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ disp->dispsw = &fbcon_dummy;
+ break;
+ }
+}
+
static int platinum_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *fb)
{
@@ -227,6 +255,7 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
struct display *display;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp, err;
int activate = var->activate;
+ struct platinum_regvals *init;
display = (con >= 0) ? &fb_display[con] : fb->disp;
@@ -242,6 +271,8 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
return 0;
}
+ init = platinum_reg_init[par.vmode-1];
+
oldxres = display->var.xres;
oldyres = display->var.yres;
oldvxres = display->var.xres_virtual;
@@ -255,7 +286,7 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
struct fb_fix_screeninfo fix;
platinum_encode_fix(&fix, &par, info);
- display->screen_base = (char *) info->frame_buffer + 0x1000;
+ display->screen_base = (char *) info->frame_buffer + init->fb_offset + 0x20;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
@@ -264,36 +295,14 @@ static int platinum_set_var(struct fb_var_screeninfo *var, int con,
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = 0;
-
- switch(par.cmode) {
-#ifdef FBCON_HAS_CFB8
- case CMODE_8:
- display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case CMODE_16:
- display->dispsw = &fbcon_cfb16;
- display->dispsw_data = info->fbcon_cmap.cfb16;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case CMODE_32:
- display->dispsw = &fbcon_cfb32;
- display->dispsw_data = info->fbcon_cmap.cfb32;
- break;
-#endif
- default:
- display->dispsw = &fbcon_dummy;
- break;
- }
-
+ platinum_set_disp(display, info, par.cmode, 0);
display->scrollmode = SCROLL_YREDRAW;
if (info->fb_info.changevar)
(*info->fb_info.changevar)(con);
}
- if (con == currcon)
+ if (!info->fb_info.display_fg ||
+ info->fb_info.display_fg->vc_num == con)
platinum_set_par(&par, info);
if (oldbpp != var->bits_per_pixel) {
@@ -322,7 +331,8 @@ static int platinum_pan_display(struct fb_var_screeninfo *var, int con,
static int platinum_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
- if (con == currcon) /* current console? */
+ if (!info->display_fg ||
+ info->display_fg->vc_num == con) /* current console? */
return fb_get_cmap(cmap, kspc, platinum_getcolreg, info);
if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
@@ -337,17 +347,23 @@ static int platinum_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
int err;
+ struct display *disp;
- if (!fb_display[con].cmap.len) {
- int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
- err = fb_alloc_cmap(&fb_display[con].cmap, size, 0);
- if (err)
+ if (con >= 0)
+ disp = &fb_display[con];
+ else
+ disp = info->disp;
+ if (!disp->cmap.len) { /* no colormap allocated? */
+ int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
+ if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
return err;
}
- if (con == currcon)
+ if (!info->display_fg ||
+ info->display_fg->vc_num == con) /* current console? */
return fb_set_cmap(cmap, kspc, platinum_setcolreg, info);
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+ else
+ fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
return 0;
}
@@ -368,8 +384,9 @@ static int platinum_switch(int con, struct fb_info *fb)
fb);
currcon = con;
- platinum_var_to_par(&fb_display[currcon].var, &par, info);
+ platinum_var_to_par(&fb_display[con].var, &par, info);
platinum_set_par(&par, info);
+ platinum_set_disp(&fb_display[con], info, par.cmode, 0);
do_install_cmap(con, fb);
return 1;
@@ -431,7 +448,6 @@ static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
{
struct fb_info_platinum *info = (struct fb_info_platinum *) fb;
volatile struct cmap_regs *cmap_regs = info->cmap_regs;
- int scale;
if (regno > 255)
return 1;
@@ -444,12 +460,10 @@ static int platinum_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
info->palette[regno].green = green;
info->palette[regno].blue = blue;
- scale = (info->current_par.cmode == CMODE_16) ? 3 : 0;
-
out_8(&cmap_regs->addr, regno); /* tell clut what addr to fill */
- out_8(&cmap_regs->lut, red<<scale); /* send one color channel at */
- out_8(&cmap_regs->lut, green<<scale); /* a time... */
- out_8(&cmap_regs->lut, blue<<scale);
+ out_8(&cmap_regs->lut, red); /* send one color channel at */
+ out_8(&cmap_regs->lut, green); /* a time... */
+ out_8(&cmap_regs->lut, blue);
if(regno < 16) {
#ifdef FBCON_HAS_CFB16
@@ -538,7 +552,7 @@ static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_p
out_be32(&platinum_regs->reg[26+32].r, (info->total_vram == 0x100000 ?
init->offset[cmode] + 4 - cmode :
init->offset[cmode]));
- out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys + 0x1000 - 0x10);
+ out_be32(&platinum_regs->reg[16].r, (unsigned) info->frame_buffer_phys+init->fb_offset+0x10);
out_be32(&platinum_regs->reg[18].r, init->pitch[cmode]);
out_be32(&platinum_regs->reg[19].r, (info->total_vram == 0x100000 ?
init->mode[cmode+1] :
@@ -571,7 +585,7 @@ static void platinum_set_par(const struct fb_par_platinum *par, struct fb_info_p
display_info.mode = vmode;
strncpy(display_info.name, "platinum",
sizeof(display_info.name));
- display_info.fb_address = info->frame_buffer_phys + 0x1000;
+ display_info.fb_address = info->frame_buffer_phys + init->fb_offset + 0x20;
display_info.cmap_adr_address = info->cmap_regs_phys;
display_info.cmap_data_address = info->cmap_regs_phys + 0x30;
display_info.disp_reg_address = info->platinum_regs_phys;
@@ -665,7 +679,7 @@ int __init platinum_init(void)
#ifdef __powerpc__
#define invalidate_cache(addr) \
- asm volatile("eieio; dcbi 0,%1" \
+ asm volatile("eieio; dcbf 0,%1" \
: "=m" (*(addr)) : "r" (addr) : "memory");
#else
#define invalidate_cache(addr)
@@ -675,6 +689,7 @@ void __init platinum_of_init(struct device_node *dp)
{
struct fb_info_platinum *info;
unsigned long addr, size;
+ volatile __u8 *fbuffer;
int i, bank0, bank1, bank2, bank3;
if(dp->n_addrs != 2) {
@@ -711,19 +726,20 @@ void __init platinum_of_init(struct device_node *dp)
out_be32(&info->platinum_regs->reg[20].r, 0x1011); /* select max vram */
out_be32(&info->platinum_regs->reg[24].r, 0); /* switch in vram */
- info->base_frame_buffer[0x100000] = 0x34;
- info->base_frame_buffer[0x100008] = 0x0;
- invalidate_cache(&info->base_frame_buffer[0x100000]);
- info->base_frame_buffer[0x200000] = 0x56;
- info->base_frame_buffer[0x200008] = 0x0;
- invalidate_cache(&info->base_frame_buffer[0x200000]);
- info->base_frame_buffer[0x300000] = 0x78;
- info->base_frame_buffer[0x300008] = 0x0;
- invalidate_cache(&info->base_frame_buffer[0x300000]);
+ fbuffer = info->base_frame_buffer;
+ fbuffer[0x100000] = 0x34;
+ fbuffer[0x100008] = 0x0;
+ invalidate_cache(&fbuffer[0x100000]);
+ fbuffer[0x200000] = 0x56;
+ fbuffer[0x200008] = 0x0;
+ invalidate_cache(&fbuffer[0x200000]);
+ fbuffer[0x300000] = 0x78;
+ fbuffer[0x300008] = 0x0;
+ invalidate_cache(&fbuffer[0x300000]);
bank0 = 1; /* builtin 1MB vram, always there */
- bank1 = info->base_frame_buffer[0x100000] == 0x34;
- bank2 = info->base_frame_buffer[0x200000] == 0x56;
- bank3 = info->base_frame_buffer[0x300000] == 0x78;
+ bank1 = fbuffer[0x100000] == 0x34;
+ bank2 = fbuffer[0x200000] == 0x56;
+ bank3 = fbuffer[0x300000] == 0x78;
info->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
printk(KERN_INFO "Total VRAM = %dMB %d%d%d%d\n", (int) (info->total_vram / 1024 / 1024), bank3, bank2, bank1, bank0);
@@ -835,10 +851,14 @@ static int platinum_encode_fix(struct fb_fix_screeninfo *fix,
const struct fb_par_platinum *par,
const struct fb_info_platinum *info)
{
+ struct platinum_regvals *init;
+
+ init = platinum_reg_init[par->vmode-1];
+
memset(fix, 0, sizeof(*fix));
strcpy(fix->id, "platinum");
- fix->smem_start = (info->frame_buffer_phys + 0x1000);
- fix->smem_len = (u32) info->total_vram - 0x1000;
+ fix->smem_start = (info->frame_buffer_phys) + init->fb_offset + 0x20;
+ fix->smem_len = (u32) info->total_vram;
fix->mmio_start = (info->platinum_regs_phys);
fix->mmio_len = 0x1000;
fix->type = FB_TYPE_PACKED_PIXELS;
@@ -884,6 +904,7 @@ int __init platinum_setup(char *options)
} else if (!strncmp(this_opt, "cmode:", 6)) {
int depth = simple_strtoul(this_opt+6, NULL, 0);
switch (depth) {
+ case 0:
case 8:
default_cmode = CMODE_8;
break;
diff --git a/drivers/video/sbusfb.c b/drivers/video/sbusfb.c
index aafa04542..1a3b02e64 100644
--- a/drivers/video/sbusfb.c
+++ b/drivers/video/sbusfb.c
@@ -304,13 +304,13 @@ static void sbusfb_clear_margin(struct display *p, int s)
fb_base -= (skip_bytes + fb->x_margin) / 8;
skip_bytes /= 8;
scr_size /= 8;
- mymemset (fb_base, skip_bytes - fb->x_margin / 8);
- mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
+ fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8);
+ fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
incr = fb->var.xres_virtual / 8;
size = fb->x_margin / 8 * 2;
for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
h <= he; q += incr, h++)
- mymemset (q, size);
+ fb_memset255 (q, size);
} else {
fb_base -= (skip_bytes + fb->x_margin);
memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
new file mode 100644
index 000000000..30f9111ed
--- /dev/null
+++ b/drivers/video/tdfxfb.c
@@ -0,0 +1,1891 @@
+/*
+ *
+ * tdfxfb.c
+ *
+ * Author: Hannu Mallat <hmallat@cc.hut.fi>
+ *
+ * Copyright © 1999 Hannu Mallat
+ * All rights reserved
+ *
+ * Created : Thu Sep 23 18:17:43 1999, hmallat
+ * Last modified: Thu Oct 7 18:39:04 1999, hmallat
+ *
+ * Lots of the information here comes from the Daryll Strauss' Banshee
+ * patches to the XF86 server, and the rest comes from the 3dfx
+ * Banshee specification. I'm very much indebted to Daryll for his
+ * work on the X server.
+ *
+ * Voodoo3 support was contributed Harold Oga. Thanks!
+ *
+ * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
+ * I do wish the next version is a bit more complete. Without the XF86
+ * patches I couldn't have gotten even this far... for instance, the
+ * extensions to the VGA register set go completely unmentioned in the
+ * spec! Also, lots of references are made to the 'SST core', but no
+ * spec is publicly available, AFAIK.
+ *
+ * The structure of this driver comes pretty much from the Permedia
+ * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
+ *
+ * TODO:
+ * - support for 16/32 bpp needs fixing (funky bootup penguin)
+ * - multihead support (it's all hosed now with pokes to VGA standard
+ * register locations, but shouldn't be that hard to change, some
+ * other code needs to be changed too where the fb_info (which should
+ * be an array of head-specific information) is referred to directly.
+ * are referred to )
+ * - hw cursor
+ * - better acceleration support (e.g., font blitting from fb memory?)
+ * - banshee and voodoo3 now supported -- any others? afaik, the original
+ * voodoo was a 3d-only card, so we won't consider that. what about
+ * voodoo2?
+ * - 24bpp
+ * - panning (doesn't seem to work properly yet)
+ *
+ * Version history:
+ *
+ * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
+ * 0.1.0 (released 1999-10-06) initial version
+ *
+ */
+
+#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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/nvram.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
+#endif
+
+/* membase0 register offsets */
+#define STATUS 0x00
+#define PCIINIT0 0x04
+#define SIPMONITOR 0x08
+#define LFBMEMORYCONFIG 0x0c
+#define MISCINIT0 0x10
+#define MISCINIT1 0x14
+#define DRAMINIT0 0x18
+#define DRAMINIT1 0x1c
+#define AGPINIT 0x20
+#define TMUGBEINIT 0x24
+#define VGAINIT0 0x28
+#define VGAINIT1 0x2c
+#define DRAMCOMMAND 0x30
+#define DRAMDATA 0x34
+/* reserved 0x38 */
+/* reserved 0x3c */
+#define PLLCTRL0 0x40
+#define PLLCTRL1 0x44
+#define PLLCTRL2 0x48
+#define DACMODE 0x4c
+#define DACADDR 0x50
+#define DACDATA 0x54
+#define RGBMAXDELTA 0x58
+#define VIDPROCCFG 0x5c
+#define HWCURPATADDR 0x60
+#define HWCURLOC 0x64
+#define HWCURC0 0x68
+#define HWCURC1 0x6c
+#define VIDINFORMAT 0x70
+#define VIDINSTATUS 0x74
+#define VIDSERPARPORT 0x78
+#define VIDINXDELTA 0x7c
+#define VIDININITERR 0x80
+#define VIDINYDELTA 0x84
+#define VIDPIXBUFTHOLD 0x88
+#define VIDCHRMIN 0x8c
+#define VIDCHRMAX 0x90
+#define VIDCURLIN 0x94
+#define VIDSCREENSIZE 0x98
+#define VIDOVRSTARTCRD 0x9c
+#define VIDOVRENDCRD 0xa0
+#define VIDOVRDUDX 0xa4
+#define VIDOVRDUDXOFF 0xa8
+#define VIDOVRDVDY 0xac
+/* ... */
+#define VIDOVRDVDYOFF 0xe0
+#define VIDDESKSTART 0xe4
+#define VIDDESKSTRIDE 0xe8
+#define VIDINADDR0 0xec
+#define VIDINADDR1 0xf0
+#define VIDINADDR2 0xf4
+#define VIDINSTRIDE 0xf8
+#define VIDCUROVRSTART 0xfc
+
+#define INTCTRL (0x00100000 + 0x04)
+#define CLIP0MIN (0x00100000 + 0x08)
+#define CLIP0MAX (0x00100000 + 0x0c)
+#define DSTBASE (0x00100000 + 0x10)
+#define DSTFORMAT (0x00100000 + 0x14)
+#define SRCBASE (0x00100000 + 0x34)
+#define COMMANDEXTRA_2D (0x00100000 + 0x38)
+#define CLIP1MIN (0x00100000 + 0x4c)
+#define CLIP1MAX (0x00100000 + 0x50)
+#define SRCFORMAT (0x00100000 + 0x54)
+#define SRCSIZE (0x00100000 + 0x58)
+#define SRCXY (0x00100000 + 0x5c)
+#define COLORBACK (0x00100000 + 0x60)
+#define COLORFORE (0x00100000 + 0x64)
+#define DSTSIZE (0x00100000 + 0x68)
+#define DSTXY (0x00100000 + 0x6c)
+#define COMMAND_2D (0x00100000 + 0x70)
+#define LAUNCH_2D (0x00100000 + 0x80)
+
+#define COMMAND_3D (0x00200000 + 0x120)
+
+/* register bitfields (not all, only as needed) */
+
+#define BIT(x) (1UL << (x))
+
+#define ROP_COPY 0xcc
+
+#define COMMAND_2D_FILLRECT 0x05
+#define COMMAND_2D_BITBLT 0x01
+
+#define COMMAND_3D_NOP 0x00
+
+#define STATUS_RETRACE BIT(6)
+#define STATUS_BUSY BIT(9)
+
+#define MISCINIT1_CLUT_INV BIT(0)
+#define MISCINIT1_2DBLOCK_DIS BIT(15)
+
+#define DRAMINIT0_SGRAM_NUM BIT(26)
+#define DRAMINIT0_SGRAM_TYPE BIT(27)
+
+#define DRAMINIT1_MEM_SDRAM BIT(30)
+
+#define VGAINIT0_VGA_DISABLE BIT(0)
+#define VGAINIT0_EXT_TIMING BIT(1)
+#define VGAINIT0_8BIT_DAC BIT(2)
+#define VGAINIT0_EXT_ENABLE BIT(6)
+#define VGAINIT0_WAKEUP_3C3 BIT(8)
+#define VGAINIT0_LEGACY_DISABLE BIT(9)
+#define VGAINIT0_ALT_READBACK BIT(10)
+#define VGAINIT0_FAST_BLINK BIT(11)
+#define VGAINIT0_EXTSHIFTOUT BIT(12)
+#define VGAINIT0_DECODE_3C6 BIT(13)
+#define VGAINIT0_SGRAM_HBLANK_DISABLE BIT(22)
+
+#define VGAINIT1_MASK 0x1fffff
+
+#define VIDCFG_VIDPROC_ENABLE BIT(0)
+#define VIDCFG_CURS_X11 BIT(1)
+#define VIDCFG_HALF_MODE BIT(4)
+#define VIDCFG_DESK_ENABLE BIT(7)
+#define VIDCFG_CLUT_BYPASS BIT(10)
+#define VIDCFG_2X BIT(26)
+#define VIDCFG_PIXFMT_SHIFT 18
+
+#define DACMODE_2X BIT(0)
+
+/* VGA rubbish, need to change this for multihead support */
+#define MISC_W 0x3c2
+#define MISC_R 0x3cc
+#define SEQ_I 0x3c4
+#define SEQ_D 0x3c5
+#define CRT_I 0x3d4
+#define CRT_D 0x3d5
+#define ATT_IW 0x3c0
+#define IS1_R 0x3da
+#define GRA_I 0x3ce
+#define GRA_D 0x3cf
+#define DAC_IR 0x3c7
+#define DAC_IW 0x3c8
+#define DAC_D 0x3c9
+
+#ifndef FB_ACCEL_3DFX_BANSHEE
+#define FB_ACCEL_3DFX_BANSHEE 31
+#endif
+
+#define TDFXF_HSYNC_ACT_HIGH 0x01
+#define TDFXF_HSYNC_ACT_LOW 0x02
+#define TDFXF_VSYNC_ACT_HIGH 0x04
+#define TDFXF_VSYNC_ACT_LOW 0x08
+#define TDFXF_LINE_DOUBLE 0x10
+#define TDFXF_VIDEO_ENABLE 0x20
+
+#define TDFXF_HSYNC_MASK 0x03
+#define TDFXF_VSYNC_MASK 0x0c
+
+/* #define TDFXFB_DEBUG */
+#ifdef TDFXFB_DEBUG
+#define DPRINTK(a,b...) printk("fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif
+
+#define PICOS2KHZ(a) (1000000000UL/(a))
+#define KHZ2PICOS(a) (1000000000UL/(a))
+
+#define BANSHEE_MAX_PIXCLOCK 270000.0
+#define VOODOO3_MAX_PIXCLOCK 300000.0
+
+struct banshee_reg {
+ /* VGA rubbish */
+ unsigned char att[21];
+ unsigned char crt[25];
+ unsigned char gra[ 9];
+ unsigned char misc[1];
+ unsigned char seq[ 5];
+
+ /* Banshee extensions */
+ unsigned char ext[2];
+ unsigned long vidcfg;
+ unsigned long vidpll;
+ unsigned long mempll;
+ unsigned long gfxpll;
+ unsigned long dacmode;
+ unsigned long vgainit0;
+ unsigned long vgainit1;
+ unsigned long screensize;
+ unsigned long stride;
+ unsigned long cursloc;
+ unsigned long startaddr;
+ unsigned long clip0min;
+ unsigned long clip0max;
+ unsigned long clip1min;
+ unsigned long clip1max;
+ unsigned long srcbase;
+ unsigned long dstbase;
+};
+
+struct tdfxfb_par {
+ u32 pixclock;
+
+ u32 baseline;
+
+ u32 width;
+ u32 height;
+ u32 width_virt;
+ u32 height_virt;
+ u32 lpitch; /* line pitch, in bytes */
+ u32 ppitch; /* pixel pitch, in bits */
+ u32 bpp;
+
+ u32 hdispend;
+ u32 hsyncsta;
+ u32 hsyncend;
+ u32 htotal;
+
+ u32 vdispend;
+ u32 vsyncsta;
+ u32 vsyncend;
+ u32 vtotal;
+
+ u32 video;
+ u32 accel_flags;
+};
+
+struct fb_info_tdfx {
+ struct fb_info fb_info;
+
+ u16 dev;
+ u32 max_pixclock;
+
+ unsigned long regbase_phys;
+ unsigned long regbase_virt;
+ unsigned long regbase_size;
+ unsigned long bufbase_phys;
+ unsigned long bufbase_virt;
+ unsigned long bufbase_size;
+
+ struct { u8 red, green, blue, pad; } palette[256];
+ struct tdfxfb_par default_par;
+ struct tdfxfb_par current_par;
+ struct display disp;
+ struct display_switch dispsw;
+
+ union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+ } fbcon_cmap;
+};
+
+/*
+ * Frame buffer device API
+ */
+static int tdfxfb_open(struct fb_info* info,
+ int user);
+static int tdfxfb_release(struct fb_info* info,
+ int user);
+static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix,
+ int con,
+ struct fb_info* fb);
+static int tdfxfb_get_var(struct fb_var_screeninfo* var,
+ int con,
+ struct fb_info* fb);
+static int tdfxfb_set_var(struct fb_var_screeninfo* var,
+ int con,
+ struct fb_info* fb);
+static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
+ int con,
+ struct fb_info* fb);
+static int tdfxfb_get_cmap(struct fb_cmap *cmap,
+ int kspc,
+ int con,
+ struct fb_info* info);
+static int tdfxfb_set_cmap(struct fb_cmap* cmap,
+ int kspc,
+ int con,
+ struct fb_info* info);
+static int tdfxfb_ioctl(struct inode* inode,
+ struct file* file,
+ u_int cmd,
+ u_long arg,
+ int con,
+ struct fb_info* info);
+
+/*
+ * Interface to the low level console driver
+ */
+static int tdfxfb_switch_con(int con,
+ struct fb_info* fb);
+static int tdfxfb_updatevar(int con,
+ struct fb_info* fb);
+static void tdfxfb_blank(int blank,
+ struct fb_info* fb);
+
+/*
+ * Internal routines
+ */
+static void tdfxfb_set_par(const struct tdfxfb_par* par,
+ struct fb_info_tdfx*
+ info);
+static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
+ struct tdfxfb_par *par,
+ const struct fb_info_tdfx *info);
+static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
+ const struct tdfxfb_par* par,
+ const struct fb_info_tdfx* info);
+static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
+ const struct tdfxfb_par* par,
+ const struct fb_info_tdfx* info);
+static void tdfxfb_set_disp(struct display* disp,
+ struct fb_info_tdfx* info,
+ int bpp,
+ int accel);
+static int tdfxfb_getcolreg(u_int regno,
+ u_int* red,
+ u_int* green,
+ u_int* blue,
+ u_int* transp,
+ struct fb_info* fb);
+static int tdfxfb_setcolreg(u_int regno,
+ u_int red,
+ u_int green,
+ u_int blue,
+ u_int transp,
+ struct fb_info* fb);
+static void tdfxfb_install_cmap(int con,
+ struct fb_info *info);
+
+/*
+ * Interface used by the world
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+void tdfxfb_init(void);
+#else
+int tdfxfb_init(void);
+#endif
+void tdfxfb_setup(char *options,
+ int *ints);
+
+static int currcon = 0;
+
+static struct fb_ops tdfxfb_ops = {
+ tdfxfb_open,
+ tdfxfb_release,
+ tdfxfb_get_fix,
+ tdfxfb_get_var,
+ tdfxfb_set_var,
+ tdfxfb_get_cmap,
+ tdfxfb_set_cmap,
+ tdfxfb_pan_display,
+ tdfxfb_ioctl,
+ NULL
+};
+
+struct mode {
+ char* name;
+ struct fb_var_screeninfo var;
+} mode;
+
+/* 2.3.x kernels have a fb mode database, so supply only one backup default */
+struct mode default_mode[] = {
+ { "640x480-8@60", /* @ 60 Hz */
+ {
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 39722, 40, 24, 32, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ ,
+ { "800x600-8@56", /* @ 56 Hz */
+ {
+ 800, 600, 800, 600, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 27778, 128, 24, 22, 1, 72, 2,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ },
+ { "1024x768-8@60", /* @ 60 Hz */
+ {
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 15385, 168, 8, 29, 3, 144, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ },
+ { "1280x1024-8@61", /* @ 61 Hz */
+ {
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 9091, 200, 48, 26, 1, 184, 3,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ },
+ { "1024x768-16@60", /* @ 60 Hz */ /* basically for testing */
+ {
+ 1024, 768, 1024, 768, 0, 0, 16, 0,
+ {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
+ 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
+ 15385, 168, 8, 29, 3, 144, 6,
+ 0, FB_VMODE_NONINTERLACED
+ }
+ }
+#endif
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+static int modes = sizeof(default_mode)/sizeof(struct mode);
+static int default_mode_index = 0;
+#endif
+
+static struct fb_info_tdfx fb_info;
+
+static int __initdata noaccel = 0;
+static int __initdata nopan = 0;
+static int __initdata nowrap = 0;
+static int __initdata inverse = 0;
+static char __initdata fontname[40] = { 0 };
+static const char *mode_option __initdata = NULL;
+
+/* ------------------------------------------------------------------------- */
+
+static inline __u8 vga_inb(__u32 reg) { return inb(reg); }
+static inline __u16 vga_inw(__u32 reg) { return inw(reg); }
+static inline __u16 vga_inl(__u32 reg) { return inl(reg); }
+
+static inline void vga_outb(__u32 reg, __u8 val) { outb(val, reg); }
+static inline void vga_outw(__u32 reg, __u16 val) { outw(val, reg); }
+static inline void vga_outl(__u32 reg, __u32 val) { outl(val, reg); }
+
+static inline void gra_outb(__u32 idx, __u8 val) {
+ vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
+}
+
+static inline __u8 gra_inb(__u32 idx) {
+ vga_outb(GRA_I, idx); return vga_inb(GRA_D);
+}
+
+static inline void seq_outb(__u32 idx, __u8 val) {
+ vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
+}
+
+static inline __u8 seq_inb(__u32 idx) {
+ vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
+}
+
+static inline void crt_outb(__u32 idx, __u8 val) {
+ vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
+}
+
+static inline __u8 crt_inb(__u32 idx) {
+ vga_outb(CRT_I, idx); return vga_inb(CRT_D);
+}
+
+static inline void att_outb(__u32 idx, __u8 val) {
+ unsigned char tmp;
+ tmp = vga_inb(IS1_R);
+ vga_outb(ATT_IW, idx);
+ vga_outb(ATT_IW, val);
+}
+
+static inline __u8 att_inb(__u32 idx) {
+ unsigned char tmp;
+ tmp = vga_inb(IS1_R);
+ vga_outb(ATT_IW, idx);
+ return vga_inb(ATT_IW);
+}
+
+static inline void vga_disable_video(void) {
+ unsigned char s;
+ s = seq_inb(0x01) | 0x20;
+ seq_outb(0x00, 0x01);
+ seq_outb(0x01, s);
+ seq_outb(0x00, 0x03);
+}
+
+static inline void vga_enable_video(void) {
+ unsigned char s;
+ s = seq_inb(0x01) & 0xdf;
+ seq_outb(0x00, 0x01);
+ seq_outb(0x01, s);
+ seq_outb(0x00, 0x03);
+}
+
+static inline void vga_disable_palette(void) {
+ vga_inb(IS1_R);
+ vga_outb(ATT_IW, 0x00);
+}
+
+static inline void vga_enable_palette(void) {
+ vga_inb(IS1_R);
+ vga_outb(ATT_IW, 0x20);
+}
+
+static inline __u32 tdfx_inl(unsigned int reg) {
+ return readl(fb_info.regbase_virt + reg);
+}
+
+static inline void tdfx_outl(unsigned int reg, __u32 val) {
+ writel(val, fb_info.regbase_virt + reg);
+}
+
+static inline void banshee_make_room(int size) {
+ while((tdfx_inl(STATUS) & 0x1f) < size);
+}
+
+static inline void banshee_wait_idle(void) {
+ int i = 0;
+
+ banshee_make_room(1);
+ tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+
+ while(1) {
+ i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
+ if(i == 3) break;
+ }
+}
+
+static void banshee_fillrect(__u32 x,
+ __u32 y,
+ __u32 w,
+ __u32 h,
+ __u32 color,
+ __u32 stride,
+ __u32 bpp) {
+ banshee_make_room(2);
+ tdfx_outl(DSTFORMAT,
+ (stride & 0x3fff) |
+ (bpp == 8 ? 0x10000 :
+ bpp == 16 ? 0x30000 : 0x50000));
+ tdfx_outl(COLORFORE, color);
+
+ banshee_make_room(3);
+ tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (ROP_COPY << 24));
+ tdfx_outl(DSTSIZE, (w & 0x1fff) | ((h & 0x1fff) << 16));
+ tdfx_outl(LAUNCH_2D, (x & 0x1fff) | ((y & 0x1fff) << 16));
+}
+
+static void banshee_bitblt(__u32 curx,
+ __u32 cury,
+ __u32 dstx,
+ __u32 dsty,
+ __u32 width,
+ __u32 height,
+ __u32 stride,
+ __u32 bpp) {
+ int xdir, ydir;
+
+ xdir = dstx < curx ? 1 : -1;
+ ydir = dsty < cury ? 1 : -1;
+
+ banshee_make_room(4);
+ tdfx_outl(SRCFORMAT,
+ (stride & 0x3fff) |
+ (bpp == 8 ? 0x10000 :
+ bpp == 16 ? 0x30000 : 0x50000));
+ tdfx_outl(DSTFORMAT,
+ (stride & 0x3fff) |
+ (bpp == 8 ? 0x10000 :
+ bpp == 16 ? 0x30000 : 0x50000));
+ tdfx_outl(COMMAND_2D,
+ COMMAND_2D_BITBLT |
+ (xdir == -1 ? BIT(14) : 0) |
+ (ydir == -1 ? BIT(15) : 0));
+ tdfx_outl(COMMANDEXTRA_2D, 0); /* no color keying */
+
+ if(xdir == -1) {
+ curx += width - 1;
+ dstx += width - 1;
+ }
+ if(ydir == -1) {
+ cury += height - 1;
+ dsty += height - 1;
+ }
+
+ /* Consecutive overlapping regions can hang the board --
+ since we allow mmap'ing of control registers, we cannot
+ __safely__ assume anything, like XF86 does... */
+ banshee_make_room(1);
+ tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
+
+ banshee_make_room(3);
+ tdfx_outl(DSTSIZE, (width & 0x1fff) | ((height & 0x1fff) << 16));
+ tdfx_outl(DSTXY, (dstx & 0x1fff) | ((dsty & 0x1fff) << 16));
+ tdfx_outl(LAUNCH_2D, (curx & 0x1fff) | ((cury & 0x1fff) << 16));
+}
+
+static __u32 banshee_calc_pll(int freq, int* freq_out) {
+ int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+ int fref = 14318;
+
+ /* this really could be done with more intelligence */
+ best_error = freq;
+ best_n = best_m = best_k = 0;
+ for(n = 1; n < 256; n++) {
+ for(m = 1; m < 64; m++) {
+ for(k = 0; k < 4; k++) {
+ f_cur = fref*(n + 2)/(m + 2)/(1 << k);
+ if(abs(f_cur - freq) < best_error) {
+ best_error = abs(f_cur-freq);
+ best_n = n;
+ best_m = m;
+ best_k = k;
+ }
+ }
+ }
+ }
+ n = best_n;
+ m = best_m;
+ k = best_k;
+ *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+
+ DPRINTK("freq = %d kHz, freq_out = %d kHz\n", freq, *freq_out);
+ DPRINTK("N = %d, M = %d, K = %d\n", n, m, k);
+
+ return (n << 8) | (m << 2) | k;
+}
+
+static void banshee_write_regs(struct banshee_reg* reg) {
+ int i;
+
+ banshee_wait_idle();
+
+ tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
+
+ crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
+
+ banshee_make_room(3);
+ tdfx_outl(VGAINIT1, reg->vgainit1 & 0x001FFFFF);
+ tdfx_outl(VIDPROCCFG, reg->vidcfg & ~0x00000001);
+#if 0
+ tdfx_outl(PLLCTRL1, reg->mempll);
+ tdfx_outl(PLLCTRL2, reg->gfxpll);
+#endif
+ tdfx_outl(PLLCTRL0, reg->vidpll);
+
+ vga_outb(MISC_W, reg->misc[0x00] | 0x01);
+
+ for(i = 0; i < 5; i++)
+ seq_outb(i, reg->seq[i]);
+
+ for(i = 0; i < 25; i++)
+ crt_outb(i, reg->crt[i]);
+
+ for(i = 0; i < 9; i++)
+ gra_outb(i, reg->gra[i]);
+
+ for(i = 0; i < 21; i++)
+ att_outb(i, reg->att[i]);
+
+ crt_outb(0x1a, reg->ext[0]);
+ crt_outb(0x1b, reg->ext[1]);
+
+ vga_enable_palette();
+ vga_enable_video();
+
+ banshee_make_room(9);
+ tdfx_outl(VGAINIT0, reg->vgainit0);
+ tdfx_outl(DACMODE, reg->dacmode);
+ tdfx_outl(VIDDESKSTRIDE, reg->stride);
+ tdfx_outl(HWCURPATADDR, reg->cursloc);
+ tdfx_outl(VIDSCREENSIZE, reg->screensize);
+ tdfx_outl(VIDDESKSTART, reg->startaddr);
+ tdfx_outl(VIDPROCCFG, reg->vidcfg);
+ tdfx_outl(VGAINIT1, reg->vgainit1);
+
+ banshee_make_room(7);
+ tdfx_outl(SRCBASE, reg->srcbase);
+ tdfx_outl(DSTBASE, reg->dstbase);
+ tdfx_outl(COMMANDEXTRA_2D, 0);
+ tdfx_outl(CLIP0MIN, 0);
+ tdfx_outl(CLIP0MAX, 0x0fff0fff);
+ tdfx_outl(CLIP1MIN, 0);
+ tdfx_outl(CLIP1MAX, 0x0fff0fff);
+
+ banshee_wait_idle();
+}
+
+static unsigned long tdfx_lfb_size(void) {
+ __u32 draminit0 = 0;
+ __u32 draminit1 = 0;
+ __u32 miscinit1 = 0;
+ __u32 lfbsize = 0;
+ int sgram_p = 0;
+
+ if(!((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+ (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)))
+ return 0;
+
+ draminit0 = tdfx_inl(DRAMINIT0);
+ draminit1 = tdfx_inl(DRAMINIT1);
+
+ sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
+
+ lfbsize = sgram_p ?
+ (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
+ ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+ 16 * 1024 * 1024;
+
+ /* disable block writes for SDRAM (why?) */
+ miscinit1 = tdfx_inl(MISCINIT1);
+ miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+ miscinit1 |= MISCINIT1_CLUT_INV;
+ tdfx_outl(MISCINIT1, miscinit1);
+
+ return lfbsize;
+}
+
+static void fbcon_banshee_bmove(struct display* p,
+ int sy,
+ int sx,
+ int dy,
+ int dx,
+ int height,
+ int width) {
+ banshee_bitblt(fontwidth(p)*sx,
+ fontheight(p)*sy,
+ fontwidth(p)*dx,
+ fontheight(p)*dy,
+ fontwidth(p)*width,
+ fontheight(p)*height,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp);
+}
+
+static void fbcon_banshee_clear(struct vc_data* conp,
+ struct display* p,
+ int sy,
+ int sx,
+ int height,
+ int width) {
+ unsigned int bg;
+
+ bg = attr_bgcol_ec(p,conp);
+ banshee_fillrect(fontwidth(p)*sx,
+ fontheight(p)*sy,
+ fontwidth(p)*width,
+ fontheight(p)*height,
+ bg,
+ fb_info.current_par.lpitch,
+ fb_info.current_par.bpp);
+}
+
+#ifdef FBCON_HAS_CFB8
+static struct display_switch fbcon_banshee8 = {
+ fbcon_cfb8_setup,
+ fbcon_banshee_bmove,
+ fbcon_banshee_clear,
+ fbcon_cfb8_putc,
+ fbcon_cfb8_putcs,
+ fbcon_cfb8_revc,
+ NULL,
+ NULL,
+ fbcon_cfb8_clear_margins,
+ FONTWIDTH(8)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_banshee16 = {
+ fbcon_cfb16_setup,
+ fbcon_banshee_bmove,
+ fbcon_banshee_clear,
+ fbcon_cfb16_putc,
+ fbcon_cfb16_putcs,
+ fbcon_cfb16_revc,
+ NULL,
+ NULL,
+ fbcon_cfb16_clear_margins,
+ FONTWIDTH(8)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_banshee32 = {
+ fbcon_cfb32_setup,
+ fbcon_banshee_bmove,
+ fbcon_banshee_clear,
+ fbcon_cfb32_putc,
+ fbcon_cfb32_putcs,
+ fbcon_cfb32_revc,
+ NULL,
+ NULL,
+ fbcon_cfb32_clear_margins,
+ FONTWIDTH(8)
+};
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+static void tdfxfb_set_par(const struct tdfxfb_par* par,
+ struct fb_info_tdfx* info) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+ struct banshee_reg reg;
+ __u32 cpp;
+ __u32 hd, hs, he, ht, hbs, hbe;
+ __u32 vd, vs, ve, vt, vbs, vbe;
+ __u32 wd;
+ int fout;
+ int freq;
+
+ memset(&reg, 0, sizeof(reg));
+
+ cpp = (par->bpp + 7)/8;
+
+ wd = (par->hdispend >> 3) - 1;
+
+ hd = (par->hdispend >> 3) - 1;
+ hs = (par->hsyncsta >> 3) - 1;
+ he = (par->hsyncend >> 3) - 1;
+ ht = (par->htotal >> 3) - 1;
+ hbs = hd;
+ hbe = ht;
+
+ vd = par->vdispend - 1;
+ vs = par->vsyncsta - 1;
+ ve = par->vsyncend - 1;
+ vt = par->vtotal - 2;
+ vbs = vd;
+ vbe = vt;
+
+ /* this is all pretty standard VGA register stuffing */
+ reg.misc[0x00] =
+ 0x0f |
+ (par->hdispend < 400 ? 0xa0 :
+ par->hdispend < 480 ? 0x60 :
+ par->hdispend < 768 ? 0xe0 : 0x20);
+
+ reg.gra[0x00] = 0x00;
+ reg.gra[0x01] = 0x00;
+ reg.gra[0x02] = 0x00;
+ reg.gra[0x03] = 0x00;
+ reg.gra[0x04] = 0x00;
+ reg.gra[0x05] = 0x40;
+ reg.gra[0x06] = 0x05;
+ reg.gra[0x07] = 0x0f;
+ reg.gra[0x08] = 0xff;
+
+ reg.att[0x00] = 0x00;
+ reg.att[0x01] = 0x01;
+ reg.att[0x02] = 0x02;
+ reg.att[0x03] = 0x03;
+ reg.att[0x04] = 0x04;
+ reg.att[0x05] = 0x05;
+ reg.att[0x06] = 0x06;
+ reg.att[0x07] = 0x07;
+ reg.att[0x08] = 0x08;
+ reg.att[0x09] = 0x09;
+ reg.att[0x0a] = 0x0a;
+ reg.att[0x0b] = 0x0b;
+ reg.att[0x0c] = 0x0c;
+ reg.att[0x0d] = 0x0d;
+ reg.att[0x0e] = 0x0e;
+ reg.att[0x0f] = 0x0f;
+ reg.att[0x10] = 0x41;
+ reg.att[0x11] = 0x00;
+ reg.att[0x12] = 0x0f;
+ reg.att[0x13] = 0x00;
+ reg.att[0x14] = 0x00;
+
+ reg.seq[0x00] = 0x03;
+ reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
+ reg.seq[0x02] = 0x0f;
+ reg.seq[0x03] = 0x00;
+ reg.seq[0x04] = 0x0e;
+
+ reg.crt[0x00] = ht - 4;
+ reg.crt[0x01] = hd;
+ reg.crt[0x02] = hbs;
+ reg.crt[0x03] = 0x80 | (hbe & 0x1f);
+ reg.crt[0x04] = hs;
+ reg.crt[0x05] =
+ ((hbe & 0x20) << 2) |
+ (he & 0x1f);
+ reg.crt[0x06] = vt;
+ reg.crt[0x07] =
+ ((vs & 0x200) >> 2) |
+ ((vd & 0x200) >> 3) |
+ ((vt & 0x200) >> 4) |
+ 0x10 |
+ ((vbs & 0x100) >> 5) |
+ ((vs & 0x100) >> 6) |
+ ((vd & 0x100) >> 7) |
+ ((vt & 0x100) >> 8);
+ reg.crt[0x08] = 0x00;
+ reg.crt[0x09] =
+ 0x40 |
+ ((vbs & 0x200) >> 4);
+ reg.crt[0x0a] = 0x00;
+ reg.crt[0x0b] = 0x00;
+ reg.crt[0x0c] = 0x00;
+ reg.crt[0x0d] = 0x00;
+ reg.crt[0x0e] = 0x00;
+ reg.crt[0x0f] = 0x00;
+ reg.crt[0x10] = vs;
+ reg.crt[0x11] =
+ (ve & 0x0f) |
+ 0x20;
+ reg.crt[0x12] = vd;
+ reg.crt[0x13] = wd;
+ reg.crt[0x14] = 0x00;
+ reg.crt[0x15] = vbs;
+ reg.crt[0x16] = vbe + 1;
+ reg.crt[0x17] = 0xc3;
+ reg.crt[0x18] = 0xff;
+
+ /* Banshee's nonvga stuff */
+ reg.ext[0x00] = (((ht & 0x100) >> 8) |
+ ((hd & 0x100) >> 6) |
+ ((hbs & 0x100) >> 4) |
+ ((hbe & 0x40) >> 1) |
+ ((hs & 0x100) >> 2) |
+ ((he & 0x20) << 2));
+ reg.ext[0x01] = (((vt & 0x400) >> 10) |
+ ((vd & 0x400) >> 8) |
+ ((vbs & 0x400) >> 6) |
+ ((vbe & 0x400) >> 4));
+
+ reg.vgainit0 =
+ VGAINIT0_8BIT_DAC |
+ VGAINIT0_EXT_ENABLE |
+ VGAINIT0_WAKEUP_3C3 |
+ VGAINIT0_ALT_READBACK |
+ VGAINIT0_EXTSHIFTOUT;
+ reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
+
+ reg.vidcfg =
+ VIDCFG_VIDPROC_ENABLE |
+ VIDCFG_DESK_ENABLE |
+ ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
+ (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+ reg.stride = par->width*cpp;
+ reg.cursloc = 0;
+
+ reg.startaddr = par->baseline*reg.stride;
+ reg.srcbase = reg.startaddr;
+ reg.dstbase = reg.startaddr;
+
+ /* PLL settings */
+ freq = par->pixclock;
+
+ reg.dacmode &= ~DACMODE_2X;
+ reg.vidcfg &= ~VIDCFG_2X;
+ if(freq > i->max_pixclock/2) {
+ freq = freq > i->max_pixclock ? i->max_pixclock : freq;
+ reg.dacmode |= DACMODE_2X;
+ reg.vidcfg |= VIDCFG_2X;
+ }
+ reg.vidpll = banshee_calc_pll(freq, &fout);
+#if 0
+ reg.mempll = banshee_calc_pll(..., &fout);
+ reg.gfxpll = banshee_calc_pll(..., &fout);
+#endif
+
+ reg.screensize = par->width | (par->height << 12);
+ reg.vidcfg &= ~VIDCFG_HALF_MODE;
+
+ banshee_write_regs(&reg);
+
+ i->current_par = *par;
+}
+
+static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
+ struct tdfxfb_par* par,
+ const struct fb_info_tdfx* info) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+
+ if(var->bits_per_pixel != 8 &&
+ var->bits_per_pixel != 16 &&
+ var->bits_per_pixel != 32) {
+ DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ DPRINTK("interlace not supported\n");
+ return -EINVAL;
+ }
+
+ if(var->xoffset) {
+ DPRINTK("xoffset not supported\n");
+ return -EINVAL;
+ }
+
+ if(var->xres != var->xres_virtual) {
+ DPRINTK("virtual x resolution != physical x resolution not supported\n");
+ return -EINVAL;
+ }
+
+ if(nopan && nowrap) {
+ if(var->yres != var->yres_virtual) {
+ DPRINTK("virtual y resolution != physical y resolution not supported\n");
+ return -EINVAL;
+ }
+ } else {
+ if(var->yres > var->yres_virtual) {
+ DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ return -EINVAL;
+ }
+ }
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ DPRINTK("interlace not supported\n");
+ return -EINVAL;
+ }
+
+ memset(par, 0, sizeof(struct tdfxfb_par));
+
+ switch(i->dev) {
+ case PCI_DEVICE_ID_3DFX_BANSHEE:
+ case PCI_DEVICE_ID_3DFX_VOODOO3:
+ par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */
+ par->width_virt = par->width;
+ par->height = var->yres;
+ par->height_virt = var->yres_virtual;
+ par->bpp = var->bits_per_pixel;
+ par->ppitch = var->bits_per_pixel;
+ par->lpitch = par->width*par->ppitch/8;
+
+ par->baseline = 0;
+
+ if(par->width < 320 || par->width > 2048) {
+ DPRINTK("width not supported: %u\n", par->width);
+ return -EINVAL;
+ }
+ if(par->height < 200 || par->height > 2048) {
+ DPRINTK("height not supported: %u\n", par->height);
+ return -EINVAL;
+ }
+ if(par->lpitch*par->height_virt > i->bufbase_size) {
+ DPRINTK("no memory for screen (%ux%ux%u)\n",
+ par->width, par->height_virt, par->bpp);
+ return -EINVAL;
+ }
+ par->pixclock = PICOS2KHZ(var->pixclock);
+ if(par->pixclock > i->max_pixclock) {
+ DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
+ return -EINVAL;
+ }
+
+ par->hdispend = var->xres;
+ par->hsyncsta = par->hdispend + var->right_margin;
+ par->hsyncend = par->hsyncsta + var->hsync_len;
+ par->htotal = par->hsyncend + var->left_margin;
+
+ par->vdispend = var->yres;
+ par->vsyncsta = par->vdispend + var->lower_margin;
+ par->vsyncend = par->vsyncsta + var->vsync_len;
+ par->vtotal = par->vsyncend + var->upper_margin;
+
+ if(var->sync & FB_SYNC_HOR_HIGH_ACT)
+ par->video |= TDFXF_HSYNC_ACT_HIGH;
+ else
+ par->video |= TDFXF_HSYNC_ACT_LOW;
+ if(var->sync & FB_SYNC_VERT_HIGH_ACT)
+ par->video |= TDFXF_VSYNC_ACT_HIGH;
+ else
+ par->video |= TDFXF_VSYNC_ACT_LOW;
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ par->video |= TDFXF_LINE_DOUBLE;
+ if(var->activate == FB_ACTIVATE_NOW)
+ par->video |= TDFXF_VIDEO_ENABLE;
+ }
+
+ if(var->accel_flags & FB_ACCELF_TEXT)
+ par->accel_flags = FB_ACCELF_TEXT;
+ else
+ par->accel_flags = 0;
+
+ return 0;
+}
+
+static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
+ const struct tdfxfb_par* par,
+ const struct fb_info_tdfx* info) {
+ struct fb_var_screeninfo v;
+
+ memset(&v, 0, sizeof(struct fb_var_screeninfo));
+ v.xres_virtual = par->width_virt;
+ v.yres_virtual = par->height_virt;
+ v.xres = par->width;
+ v.yres = par->height;
+ v.right_margin = par->hsyncsta - par->hdispend;
+ v.hsync_len = par->hsyncend - par->hsyncsta;
+ v.left_margin = par->htotal - par->hsyncend;
+ v.lower_margin = par->vsyncsta - par->vdispend;
+ v.vsync_len = par->vsyncend - par->vsyncsta;
+ v.upper_margin = par->vtotal - par->vsyncend;
+ v.bits_per_pixel = par->bpp;
+ switch(par->bpp) {
+ case 8:
+ v.red.length = v.green.length = v.blue.length = 8;
+ break;
+ case 16:
+ v.red.offset = 11;
+ v.red.length = 5;
+ v.green.offset = 5;
+ v.green.length = 6;
+ v.blue.offset = 0;
+ v.blue.length = 5;
+ break;
+ case 32:
+ v.red.offset = 16;
+ v.green.offset = 8;
+ v.blue.offset = 0;
+ v.red.length = v.green.length = v.blue.length = 8;
+ break;
+ }
+ v.height = v.width = -1;
+ v.pixclock = KHZ2PICOS(par->pixclock);
+ if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
+ v.sync |= FB_SYNC_HOR_HIGH_ACT;
+ if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
+ v.sync |= FB_SYNC_VERT_HIGH_ACT;
+ if(par->video & TDFXF_LINE_DOUBLE)
+ v.vmode = FB_VMODE_DOUBLE;
+ *var = v;
+ return 0;
+}
+
+static int tdfxfb_open(struct fb_info* info,
+ int user) {
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int tdfxfb_release(struct fb_info* info,
+ int user) {
+ MOD_DEC_USE_COUNT;
+ return(0);
+}
+
+
+static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
+ const struct tdfxfb_par* par,
+ const struct fb_info_tdfx* info) {
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ switch(info->dev) {
+ case PCI_DEVICE_ID_3DFX_BANSHEE:
+ case PCI_DEVICE_ID_3DFX_VOODOO3:
+ if (info->dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ strcpy(fix->id, "3Dfx Banshee");
+ else
+ strcpy(fix->id, "3Dfx Voodoo3");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ fix->smem_start = (char*)info->bufbase_phys;
+ fix->smem_len = info->bufbase_size;
+ fix->mmio_start = (char*)info->regbase_phys;
+ fix->mmio_len = info->regbase_size;
+#else
+ fix->smem_start = info->bufbase_phys;
+ fix->smem_len = info->bufbase_size;
+ fix->mmio_start = info->regbase_phys;
+ fix->mmio_len = info->regbase_size;
+#endif
+ fix->accel = FB_ACCEL_3DFX_BANSHEE;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = par->lpitch;
+ fix->visual = par->bpp == 8
+ ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+
+ fix->xpanstep = 0;
+ fix->ypanstep = (nowrap && nopan) ? 0 : 1;
+ fix->ywrapstep = nowrap ? 0 : 1;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
+ int con,
+ struct fb_info *fb) {
+ const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+ struct tdfxfb_par par;
+
+ if(con == -1)
+ par = info->default_par;
+ else
+ tdfxfb_decode_var(&fb_display[con].var, &par, info);
+ tdfxfb_encode_fix(fix, &par, info);
+ return 0;
+}
+
+static int tdfxfb_get_var(struct fb_var_screeninfo *var,
+ int con,
+ struct fb_info *fb) {
+ const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+
+ if(con == -1)
+ tdfxfb_encode_var(var, &info->default_par, info);
+ else
+ *var = fb_display[con].var;
+ return 0;
+}
+
+static void tdfxfb_set_disp(struct display *disp,
+ struct fb_info_tdfx *info,
+ int bpp,
+ int accel) {
+ DPRINTK("actually, %s using acceleration!\n",
+ noaccel ? "NOT" : "");
+
+ switch(bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ info->dispsw = noaccel ? fbcon_cfb8 : fbcon_banshee8;
+ disp->dispsw = &info->dispsw;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ info->dispsw = noaccel ? fbcon_cfb16 : fbcon_banshee16;
+ disp->dispsw = &info->dispsw;
+ disp->dispsw_data = info->fbcon_cmap.cfb16;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ info->dispsw = noaccel ? fbcon_cfb32 : fbcon_banshee32;
+ disp->dispsw = &info->dispsw;
+ disp->dispsw_data = info->fbcon_cmap.cfb32;
+ break;
+#endif
+ default:
+ info->dispsw = fbcon_dummy;
+ disp->dispsw = &info->dispsw;
+ }
+}
+
+static int tdfxfb_set_var(struct fb_var_screeninfo *var,
+ int con,
+ struct fb_info *fb) {
+ struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+ struct tdfxfb_par par;
+ struct display *display;
+ int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
+ int activate = var->activate;
+
+ if(con >= 0)
+ display = &fb_display[con];
+ else
+ display = fb->disp; /* used during initialization */
+
+ if((err = tdfxfb_decode_var(var, &par, info)))
+ return err;
+
+ tdfxfb_encode_var(var, &par, info);
+
+ if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+ oldxres = display->var.xres;
+ oldyres = display->var.yres;
+ oldvxres = display->var.xres_virtual;
+ oldvyres = display->var.yres_virtual;
+ oldbpp = display->var.bits_per_pixel;
+ oldaccel = display->var.accel_flags;
+ display->var = *var;
+ if(con < 0 ||
+ oldxres != var->xres ||
+ oldyres != var->yres ||
+ oldvxres != var->xres_virtual ||
+ oldvyres != var->yres_virtual ||
+ oldbpp != var->bits_per_pixel ||
+ oldaccel != var->accel_flags) {
+ struct fb_fix_screeninfo fix;
+
+ tdfxfb_encode_fix(&fix, &par, info);
+ display->screen_base = (char *)info->bufbase_virt;
+ display->visual = fix.visual;
+ display->type = fix.type;
+ display->type_aux = fix.type_aux;
+ display->ypanstep = fix.ypanstep;
+ display->ywrapstep = fix.ywrapstep;
+ display->line_length = fix.line_length;
+ display->next_line = fix.line_length;
+ display->can_soft_blank = 1;
+ display->inverse = inverse;
+ accel = var->accel_flags & FB_ACCELF_TEXT;
+ tdfxfb_set_disp(display, info, par.bpp, accel);
+
+ if(nopan && nowrap) {
+ display->scrollmode = SCROLL_YREDRAW;
+#ifdef FBCON_HAS_CFB8
+ fbcon_banshee8.bmove = fbcon_redraw_bmove;
+#endif
+#ifdef FBCON_HAS_CFB16
+ fbcon_banshee16.bmove = fbcon_redraw_bmove;
+#endif
+#ifdef FBCON_HAS_CFB32
+ fbcon_banshee32.bmove = fbcon_redraw_bmove;
+#endif
+ }
+ if (info->fb_info.changevar)
+ (*info->fb_info.changevar)(con);
+ }
+ if(!info->fb_info.display_fg ||
+ info->fb_info.display_fg->vc_num == con ||
+ con < 0)
+ tdfxfb_set_par(&par, info);
+ if(oldbpp != var->bits_per_pixel || con < 0) {
+ if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+ return err;
+ tdfxfb_install_cmap(con, &info->fb_info);
+ }
+ }
+
+ return 0;
+}
+
+static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
+ int con,
+ struct fb_info* fb) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+ __u32 addr;
+
+ if(nowrap && nopan) {
+ return -EINVAL;
+ } else {
+ if(var->xoffset)
+ return -EINVAL;
+ if(var->yoffset < 0)
+ return -EINVAL;
+ if(nopan && var->yoffset > var->yres_virtual)
+ return -EINVAL;
+ if(nowrap && var->yoffset + var->yres > var->yres_virtual)
+ return -EINVAL;
+
+ i->current_par.baseline = var->yoffset;
+
+ addr = var->yoffset*i->current_par.lpitch;
+ tdfx_outl(VIDDESKSTART, addr);
+ tdfx_outl(SRCBASE, addr);
+ tdfx_outl(DSTBASE, addr);
+ return 0;
+ }
+}
+
+static int tdfxfb_get_cmap(struct fb_cmap *cmap,
+ int kspc,
+ int con,
+ struct fb_info *fb) {
+ if(!fb->display_fg || con == fb->display_fg->vc_num) {
+ /* current console? */
+ return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
+ } else if(fb_display[con].cmap.len) {
+ /* non default colormap? */
+ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+ } else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
+ return 0;
+}
+
+static int tdfxfb_set_cmap(struct fb_cmap *cmap,
+ int kspc,
+ int con,
+ struct fb_info *fb) {
+ int err;
+ struct display *disp;
+
+ if(con >= 0)
+ disp = &fb_display[con];
+ else
+ disp = fb->disp;
+ if(!disp->cmap.len) { /* no colormap allocated? */
+ int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
+ if((err = fb_alloc_cmap(&disp->cmap, size, 0)))
+ return err;
+ }
+ if(!fb->display_fg || con == fb->display_fg->vc_num) {
+ /* current console? */
+ return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
+ } else {
+ fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+ }
+ return 0;
+}
+
+static int tdfxfb_ioctl(struct inode *inode,
+ struct file *file,
+ u_int cmd,
+ u_long arg,
+ int con,
+ struct fb_info *fb) {
+ return -EINVAL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+__initfunc(void tdfxfb_init(void)) {
+#else
+int __init tdfxfb_init(void) {
+#endif
+ struct pci_dev *pdev = NULL;
+ struct fb_var_screeninfo var;
+ int j, k;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ if(!pcibios_present()) return;
+#else
+ if(!pcibios_present()) return -ENXIO;
+#endif
+
+ for(pdev = pci_devices; pdev; pdev = pdev->next) {
+ if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+ (pdev->vendor == PCI_VENDOR_ID_3DFX) &&
+ ((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+ (pdev->device == PCI_DEVICE_ID_3DFX_VOODOO3))) {
+
+ fb_info.dev = pdev->device;
+ fb_info.max_pixclock =
+ pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE
+ ? BANSHEE_MAX_PIXCLOCK
+ : VOODOO3_MAX_PIXCLOCK;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+ fb_info.regbase_size = 1 << 25;
+ fb_info.regbase_virt =
+ (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+ if(!fb_info.regbase_virt) {
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't remap Banshee register area.\n");
+ else
+ printk("fb: Can't remap Voodoo3 register area.\n");
+ return;
+ }
+
+ fb_info.bufbase_phys = pdev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
+ if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't count Banshee memory.\n");
+ else
+ printk("fb: Can't count Voodoo3 memory.\n");
+ iounmap((void*)fb_info.regbase_virt);
+ return;
+ }
+ fb_info.bufbase_virt =
+ (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+ if(!fb_info.regbase_virt) {
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't remap Banshee framebuffer.\n");
+ else
+ printk("fb: Can't remap Voodoo3 framebuffer.\n");
+ iounmap((void*)fb_info.regbase_virt);
+ return;
+ }
+#else
+ fb_info.regbase_phys = pdev->resource[0].start;
+ fb_info.regbase_size = 1 << 25;
+ fb_info.regbase_virt =
+ (__u32)ioremap_nocache(fb_info.regbase_phys, 1 << 25);
+ if(!fb_info.regbase_virt) {
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't remap Banshee register area.\n");
+ else
+ printk("fb: Can't remap Voodoo3 register area.\n");
+ return -ENXIO;
+ }
+
+ fb_info.bufbase_phys = pdev->resource[1].start;
+ if(!(fb_info.bufbase_size = tdfx_lfb_size())) {
+ iounmap((void*)fb_info.regbase_virt);
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't count Banshee memory.\n");
+ else
+ printk("fb: Can't count Voodoo3 memory.\n");
+ return -ENXIO;
+ }
+ fb_info.bufbase_virt =
+ (__u32)ioremap_nocache(fb_info.bufbase_phys, 1 << 25);
+ if(!fb_info.regbase_virt) {
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Can't remap Banshee framebuffer.\n");
+ else
+ printk("fb: Can't remap Voodoo3 framebuffer.\n");
+ iounmap((void*)fb_info.regbase_virt);
+ return -ENXIO;
+ }
+#endif
+
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ printk("fb: Banshee memory = %ldK\n", fb_info.bufbase_size >> 10);
+ else
+ printk("fb: Voodoo3 memory = %ldK\n", fb_info.bufbase_size >> 10);
+
+ /* clear framebuffer memory */
+ memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
+
+ if (fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE)
+ strcpy(fb_info.fb_info.modename, "3Dfx Banshee");
+ else
+ strcpy(fb_info.fb_info.modename, "3Dfx Voodoo3");
+ fb_info.fb_info.changevar = NULL;
+ fb_info.fb_info.node = -1;
+ fb_info.fb_info.fbops = &tdfxfb_ops;
+ fb_info.fb_info.disp = &fb_info.disp;
+ strcpy(fb_info.fb_info.fontname, fontname);
+ fb_info.fb_info.switch_con = &tdfxfb_switch_con;
+ fb_info.fb_info.updatevar = &tdfxfb_updatevar;
+ fb_info.fb_info.blank = &tdfxfb_blank;
+ fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ var = default_mode[default_mode_index < modes
+ ? default_mode_index
+ : 0].var;
+#else
+ memset(&var, 0, sizeof(var));
+ if(!mode_option ||
+ !fb_find_mode(&var, &fb_info.fb_info, mode_option, NULL, 0, NULL, 8))
+ var = default_mode[0].var;
+#endif
+
+ if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
+ else var.accel_flags |= FB_ACCELF_TEXT;
+
+ if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+ /* ugh -- can't use the mode from the mode db. (or command line),
+ so try the default */
+
+ printk("tdfxfb: "
+ "can't decode the supplied video mode, using default\n");
+
+ var = default_mode[0].var;
+ if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
+ else var.accel_flags |= FB_ACCELF_TEXT;
+
+ if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
+ printk("tdfxfb: can't decode default video mode\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ return;
+#else
+ return -ENXIO;
+#endif
+ }
+ }
+
+ fb_info.disp.screen_base = (void*)fb_info.bufbase_virt;
+ fb_info.disp.visual =
+ var.bits_per_pixel == 8
+ ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ fb_info.disp.type = FB_TYPE_PACKED_PIXELS;
+ fb_info.disp.type_aux = 0;
+
+ fb_info.disp.ypanstep = (nowrap && nopan) ? 0 : 1;
+ fb_info.disp.ywrapstep = nowrap ? 0 : 1;
+
+ fb_info.disp.line_length =
+ fb_info.disp.next_line =
+ var.xres*(var.bits_per_pixel + 7)/8;
+ fb_info.disp.can_soft_blank = 1;
+ fb_info.disp.inverse = inverse;
+ fb_info.disp.scrollmode = SCROLL_YREDRAW;
+ fb_info.disp.var = var;
+ tdfxfb_set_disp(&fb_info.disp, &fb_info,
+ var.bits_per_pixel,
+ 0);
+
+ for(j = 0; j < 16; j++) {
+ k = color_table[j];
+ fb_info.palette[j].red = default_red[k];
+ fb_info.palette[j].green = default_grn[k];
+ fb_info.palette[j].blue = default_blu[k];
+ }
+
+ if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
+ printk("tdfxfb: can't set default video mode\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ return;
+#else
+ return -ENXIO;
+#endif
+ }
+
+ if(register_framebuffer(&fb_info.fb_info) < 0) {
+ printk("tdfxfb: can't register framebuffer\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ return;
+#else
+ return -ENXIO;
+#endif
+ }
+
+ printk("fb%d: %s frame buffer device\n",
+ GET_FB_IDX(fb_info.fb_info.node),
+ fb_info.fb_info.modename);
+
+ MOD_INC_USE_COUNT;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ return;
+#else
+ return 0;
+#endif
+ }
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ return;
+#else
+ return -ENXIO;
+#endif
+}
+
+void tdfxfb_setup(char *options,
+ int *ints) {
+ char* this_opt;
+
+ if(!options || !*options)
+ return;
+
+ for(this_opt = strtok(options, ",");
+ this_opt;
+ this_opt = strtok(NULL, ",")) {
+ if(!strcmp(this_opt, "inverse")) {
+ inverse = 1;
+ fb_invert_cmaps();
+ } else if(!strcmp(this_opt, "noaccel")) {
+ noaccel = 1;
+ } else if(!strcmp(this_opt, "nopan")) {
+ nopan = 1;
+ } else if(!strcmp(this_opt, "nowrap")) {
+ nowrap = 1;
+ } else if (!strncmp(this_opt, "font:", 5)) {
+ strncpy(fontname, this_opt + 5, 40);
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
+ int i;
+ for(i = 0; i < modes; i++) {
+ if(!strcmp(this_opt, default_mode[i].name)) {
+ default_mode_index = i;
+ }
+ }
+#else
+ mode_option = this_opt;
+#endif
+ }
+ }
+}
+
+static int tdfxfb_switch_con(int con,
+ struct fb_info *fb) {
+ struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
+ struct tdfxfb_par par;
+
+ /* Do we have to save the colormap? */
+ if(fb_display[currcon].cmap.len)
+ fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
+
+ currcon = con;
+
+ tdfxfb_decode_var(&fb_display[con].var, &par, info);
+ tdfxfb_set_par(&par, info);
+ tdfxfb_set_disp(&fb_display[con],
+ info,
+ par.bpp,
+ par.accel_flags & FB_ACCELF_TEXT);
+
+ tdfxfb_install_cmap(con, fb);
+ tdfxfb_updatevar(con, fb);
+
+ return 1;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static void tdfxfb_blank(int blank,
+ struct fb_info *fb) {
+ u32 dacmode, state = 0, vgablank = 0;
+
+ dacmode = tdfx_inl(DACMODE);
+
+ switch(blank) {
+ case 0: /* Screen: On; HSync: On, VSync: On */
+ state = 0;
+ vgablank = 0;
+ break;
+ case 1: /* Screen: Off; HSync: On, VSync: On */
+ state = 0;
+ vgablank = 1;
+ break;
+ case 2: /* Screen: Off; HSync: On, VSync: Off */
+ state = BIT(3);
+ vgablank = 1;
+ break;
+ case 3: /* Screen: Off; HSync: Off, VSync: On */
+ state = BIT(1);
+ vgablank = 1;
+ break;
+ case 4: /* Screen: Off; HSync: Off, VSync: Off */
+ state = BIT(1) | BIT(3);
+ vgablank = 1;
+ break;
+ }
+
+ dacmode &= ~(BIT(1) | BIT(3));
+ dacmode |= state;
+ tdfx_outl(DACMODE, dacmode);
+ if(vgablank)
+ vga_disable_video();
+ else
+ vga_enable_video();
+
+ return;
+}
+
+static int tdfxfb_updatevar(int con,
+ struct fb_info* fb) {
+ if(con != currcon || (nowrap && nopan)) {
+ return 0;
+ } else {
+ struct fb_var_screeninfo* var = &fb_display[currcon].var;
+ return tdfxfb_pan_display(var, con, fb);
+ }
+}
+
+static int tdfxfb_getcolreg(unsigned regno,
+ unsigned* red,
+ unsigned* green,
+ unsigned* blue,
+ unsigned* transp,
+ struct fb_info* fb) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
+
+ if(regno < 256) {
+ *red = i->palette[regno].red << 8 | i->palette[regno].red;
+ *green = i->palette[regno].green << 8 | i->palette[regno].green;
+ *blue = i->palette[regno].blue << 8 | i->palette[regno].blue;
+ *transp = 0;
+ }
+ return regno > 255;
+}
+
+static int tdfxfb_setcolreg(unsigned regno,
+ unsigned red,
+ unsigned green,
+ unsigned blue,
+ unsigned transp,
+ struct fb_info* info) {
+ struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
+
+ if(regno < 16) {
+ switch(i->current_par.bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ i->fbcon_cmap.cfb16[regno] =
+ (((u32)red & 0xf800) >> 0) |
+ (((u32)green & 0xfc00) >> 5) |
+ (((u32)blue & 0xf800) >> 11);
+ break;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ i->fbcon_cmap.cfb32[regno] =
+ (((u32)red & 0xff00) << 8) |
+ (((u32)green & 0xff00) << 0) |
+ (((u32)blue & 0xff00) >> 8);
+ break;
+#endif
+ default:
+ DPRINTK("bad depth %u\n", i->current_par.bpp);
+ break;
+ }
+ }
+ if(regno < 256) {
+ i->palette[regno].red = red >> 8;
+ i->palette[regno].green = green >> 8;
+ i->palette[regno].blue = blue >> 8;
+ if(i->current_par.bpp == 8) {
+ vga_outb(DAC_IW, (unsigned char)regno);
+ vga_outb(DAC_D, (unsigned char)(red >> 8));
+ vga_outb(DAC_D, (unsigned char)(green >> 8));
+ vga_outb(DAC_D, (unsigned char)(blue >> 8));
+ }
+ }
+ return regno > 255;
+}
+
+static void tdfxfb_install_cmap(int con,
+ struct fb_info* info) {
+ if(con != currcon) return;
+ if(fb_display[con].cmap.len) {
+ fb_set_cmap(&fb_display[con].cmap, 1, tdfxfb_setcolreg, info);
+ } else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_set_cmap(fb_default_cmap(size), 1, tdfxfb_setcolreg, info);
+ }
+}
+
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 2541d14a4..a60774a61 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -55,11 +55,11 @@
#ifdef CONFIG_FB_COMPAT_XPMAC
#include <asm/vc_ioctl.h>
#endif
+#include <linux/adb.h>
+#include <linux/cuda.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
-#include <asm/adb.h>
-#include <asm/cuda.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
@@ -168,10 +168,6 @@ static int valkyriefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static void do_install_cmap(int con, struct fb_info *info);
-
-__openfirmware
-
-
static int valkyrie_open(struct fb_info *info, int user)
{
MOD_INC_USE_COUNT;
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index bb98bd8c7..cf4f9baa9 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -532,6 +532,8 @@ int __init vesafb_init(void)
video_base = screen_info.lfb_base;
video_bpp = screen_info.lfb_depth;
+ if (15 == video_bpp)
+ video_bpp = 16;
video_width = screen_info.lfb_width;
video_height = screen_info.lfb_height;
video_linelength = screen_info.lfb_linelength;
diff --git a/drivers/video/vga_font.c b/drivers/video/vga_font.c
index d6683ee4b..bed9a5e95 100644
--- a/drivers/video/vga_font.c
+++ b/drivers/video/vga_font.c
@@ -1,6 +1,5 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/modversions.h>
#define cmapsz 8192
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index 1e9abfe3d..050d34543 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -1163,7 +1163,7 @@ int __init virgefb_setup(char *options)
* Initialization
*/
-void __init virgefb_init(void)
+int __init virgefb_init(void)
{
struct virgefb_par par;
unsigned long board_addr;