summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acorn/block/Config.in15
-rw-r--r--drivers/acorn/block/Makefile26
-rw-r--r--drivers/acorn/block/fd1772.c6
-rw-r--r--drivers/acorn/block/fd1772dma.S60
-rw-r--r--drivers/acorn/block/ide-ics.c295
-rw-r--r--drivers/acorn/block/mfm.S47
-rw-r--r--drivers/acorn/block/mfmhd.c3
-rw-r--r--drivers/acorn/char/Config.in15
-rw-r--r--drivers/acorn/char/Makefile27
-rw-r--r--drivers/acorn/char/keyb_arc.c451
-rw-r--r--drivers/acorn/char/keyb_ps2.c10
-rw-r--r--drivers/acorn/char/mouse_rpc.c3
-rw-r--r--drivers/acorn/char/serial-card.c23
-rw-r--r--drivers/acorn/net/ether1.c111
-rw-r--r--drivers/acorn/net/ether3.c207
-rw-r--r--drivers/acorn/net/ether3.h5
-rw-r--r--drivers/acorn/net/etherh.c54
-rw-r--r--drivers/acorn/scsi/Config.in3
-rw-r--r--drivers/acorn/scsi/Makefile34
-rw-r--r--drivers/acorn/scsi/acornscsi.c1648
-rw-r--r--drivers/acorn/scsi/acornscsi.h27
-rw-r--r--drivers/acorn/scsi/arxescsi.c395
-rw-r--r--drivers/acorn/scsi/arxescsi.h80
-rw-r--r--drivers/acorn/scsi/cumana_2.c11
-rw-r--r--drivers/acorn/scsi/eesox.c6
-rw-r--r--drivers/acorn/scsi/fas216.c1290
-rw-r--r--drivers/acorn/scsi/fas216.h35
-rw-r--r--drivers/acorn/scsi/msgqueue.c42
-rw-r--r--drivers/acorn/scsi/msgqueue.h42
-rw-r--r--drivers/acorn/scsi/powertec.c30
-rw-r--r--drivers/acorn/scsi/queue.c1
-rw-r--r--drivers/block/Config.in31
-rw-r--r--drivers/block/icside.c634
-rw-r--r--drivers/block/ll_rw_blk.c2
-rw-r--r--drivers/block/rapide.c (renamed from drivers/acorn/block/ide-rapide.c)23
-rw-r--r--drivers/char/n_hdlc.c41
-rw-r--r--drivers/char/synclink.c516
-rw-r--r--drivers/char/tty_io.c7
-rw-r--r--drivers/net/Makefile16
-rw-r--r--drivers/net/ibmtr.c5
-rw-r--r--drivers/net/irda/irport.c2
-rw-r--r--drivers/pci/pci.c28
-rw-r--r--drivers/sbus/audio/cs4215.h7
-rw-r--r--drivers/sbus/audio/dbri.c1418
-rw-r--r--drivers/sbus/audio/dbri.h19
-rw-r--r--drivers/sbus/char/su.c12
-rw-r--r--drivers/scsi/in2000.h4
-rw-r--r--drivers/scsi/scsi_error.c15
-rw-r--r--drivers/sound/es1370.c9
-rw-r--r--drivers/sound/es1371.c9
-rw-r--r--drivers/sound/sonicvibes.c9
-rw-r--r--drivers/sound/vidc.c12
-rw-r--r--drivers/sound/vidc_audio.c5
-rw-r--r--drivers/sound/vidc_fill.S1
-rw-r--r--drivers/sound/waveartist.c540
-rw-r--r--drivers/sound/waveartist.h15
-rw-r--r--drivers/usb/acm.c2
-rw-r--r--drivers/usb/audio.c2
-rw-r--r--drivers/usb/cpia.c2
-rw-r--r--drivers/usb/hub.c2
-rw-r--r--drivers/usb/keyboard.c2
-rw-r--r--drivers/usb/mouse.c2
-rw-r--r--drivers/usb/ohci-hcd.c2
-rw-r--r--drivers/usb/ohci.c211
-rw-r--r--drivers/usb/uhci-debug.c2
-rw-r--r--drivers/usb/uhci.c42
-rw-r--r--drivers/usb/usb-core.c2
-rw-r--r--drivers/usb/usb.h4
-rw-r--r--drivers/usb/usb_scsi.c402
-rw-r--r--drivers/usb/usb_scsi_debug.c2
-rw-r--r--drivers/video/Config.in9
-rw-r--r--drivers/video/acornfb.c4
-rw-r--r--drivers/video/cyber2000fb.c289
-rw-r--r--drivers/video/cyber2000fb.h8
-rw-r--r--drivers/video/vgacon.c11
75 files changed, 6374 insertions, 3008 deletions
diff --git a/drivers/acorn/block/Config.in b/drivers/acorn/block/Config.in
index 545581525..6ed6cf6a3 100644
--- a/drivers/acorn/block/Config.in
+++ b/drivers/acorn/block/Config.in
@@ -4,15 +4,12 @@
mainmenu_option next_comment
comment 'Acorn-specific block devices'
-bool ' Support expansion card IDE interfaces' CONFIG_BLK_DEV_IDE_CARDS
-if [ "$CONFIG_BLK_DEV_IDE_CARDS" = "y" ]; then
- dep_tristate ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_BLK_DEV_IDE
- dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE
-fi
-
-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
+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
fi
endmenu
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
index c4016ca0d..4db3192b6 100644
--- a/drivers/acorn/block/Makefile
+++ b/drivers/acorn/block/Makefile
@@ -14,29 +14,11 @@ L_OBJS :=
M_OBJS :=
MOD_LIST_NAME := ACORN_BLOCK_MODULES
-ifeq ($(CONFIG_ARCH_ARC),y)
- ifeq ($(CONFIG_BLK_DEV_FD),y)
- L_OBJS += fd1772.o fd1772dma.o
- else
- ifeq ($(CONFIG_BLK_DEV_FD),m)
- M_OBJS += fd1772_mod.o
- endif
- endif
-endif
-
-ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y)
- L_OBJS += ide-ics.o
-else
- ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),m)
- M_OBJS += ide-ics.o
- endif
-endif
-
-ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y)
- L_OBJS += ide-rapide.o
+ifeq ($(CONFIG_BLK_DEV_FD1772),y)
+ L_OBJS += fd1772.o fd1772dma.o
else
- ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),m)
- M_OBJS += ide-rapide.o
+ ifeq ($(CONFIG_BLK_DEV_FD1772),m)
+ M_OBJS += fd1772_mod.o
endif
endif
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index 02a2307d6..8ee368ac9 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -114,6 +114,8 @@
* I wish I knew why that timer didn't work.....
*
* 16/11/96 - Fiddled and frigged for 2.0.18
+ *
+ * DAG 30/01/99 - Started frobbing for 2.2.1
*/
#include <linux/sched.h>
@@ -136,14 +138,14 @@
#include <asm/dma.h>
#include <asm/hardware.h>
#include <asm/io.h>
+#include <asm/ioc.h>
#include <asm/irq.h>
-#include <asm/irq-no.h>
#include <asm/pgtable.h>
#include <asm/segment.h>
#define MAJOR_NR FLOPPY_MAJOR
#define FLOPPY_DMA 0
-#include "blk.h"
+#include <linux/blk.h>
/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
* little additional rework in this file). But I'm not yet sure if
diff --git a/drivers/acorn/block/fd1772dma.S b/drivers/acorn/block/fd1772dma.S
index f145628e7..796443544 100644
--- a/drivers/acorn/block/fd1772dma.S
+++ b/drivers/acorn/block/fd1772dma.S
@@ -4,45 +4,45 @@
.text
- .global _fdc1772_dataaddr
-_fdc1772_fiqdata:
+ .global fdc1772_dataaddr
+fdc1772_fiqdata:
@ Number of bytes left to DMA
- .global _fdc1772_bytestogo
-_fdc1772_bytestogo:
+ .global fdc1772_bytestogo
+fdc1772_bytestogo:
.word 0
@ Place to put/get data from in DMA
- .global _fdc1772_dataaddr
-_fdc1772_dataaddr:
+ .global fdc1772_dataaddr
+fdc1772_dataaddr:
.word 0
- .global _fdc1772_fdc_int_done
-_fdc1772_fdc_int_done:
+ .global fdc1772_fdc_int_done
+fdc1772_fdc_int_done:
.word 0
- .global _fdc1772_comendstatus
-_fdc1772_comendstatus:
+ .global fdc1772_comendstatus
+fdc1772_comendstatus:
.word 0
@ We hang this off DMA channel 1
- .global _fdc1772_comendhandler
-_fdc1772_comendhandler:
+ .global fdc1772_comendhandler
+fdc1772_comendhandler:
mov r8,#IOC_BASE
ldrb r9,[r8,#0x34] @ IOC FIQ status
tst r9,#2
subeqs pc,r14,#4 @ should I leave a space here
orr r9,r8,#0x10000 @ FDC base
- adr r8,_fdc1772_fdc_int_done
+ adr r8,fdc1772_fdc_int_done
ldrb r10,[r9,#0] @ FDC status
mov r9,#1 @ Got a FIQ flag
stmia r8,{r9,r10}
subs pc,r14,#4
- .global _fdc1772_dma_read
-_fdc1772_dma_read:
+ .global fdc1772_dma_read
+fdc1772_dma_read:
mov r8,#IOC_BASE
ldrb r9,[r8,#0x34] @ IOC FIQ status
tst r9,#1
- beq _fdc1772_dma_read_notours
+ beq fdc1772_dma_read_notours
orr r8,r8,#0x10000 @ FDC base
ldrb r10,[r8,#0xc] @ Read from FDC data reg (also clears interrupt)
ldmia r11,{r8,r9}
@@ -51,19 +51,19 @@ _fdc1772_dma_read:
strplb r10,[r9],#1 @ Store the data and increment the pointer
stmplia r11,{r8,r9} @ Update count/pointers
@ Handle any other interrupts if there are any
-_fdc1772_dma_read_notours:
+fdc1772_dma_read_notours:
@ Cant branch because this code has been copied down to the FIQ vector
ldr pc,[pc,#-4]
- .word _fdc1772_comendhandler
- .global _fdc1772_dma_read_end
-_fdc1772_dma_read_end:
+ .word fdc1772_comendhandler
+ .global fdc1772_dma_read_end
+fdc1772_dma_read_end:
- .global _fdc1772_dma_write
-_fdc1772_dma_write:
+ .global fdc1772_dma_write
+fdc1772_dma_write:
mov r8,#IOC_BASE
ldrb r9,[r8,#0x34] @ IOC FIQ status
tst r9,#1
- beq _fdc1772_dma_write_notours
+ beq fdc1772_dma_write_notours
orr r8,r8,#0x10000 @ FDC base
ldmia r11,{r9,r10}
subs r9,r9,#1 @ One less byte to go
@@ -72,23 +72,23 @@ _fdc1772_dma_write:
strplb r12,[r8,#0xc] @ write it to FDC data reg
stmplia r11,{r9,r10} @ Update count and pointer - should clear interrupt
@ Handle any other interrupts
-_fdc1772_dma_write_notours:
+fdc1772_dma_write_notours:
@ Cant branch because this code has been copied down to the FIQ vector
ldr pc,[pc,#-4]
- .word _fdc1772_comendhandler
+ .word fdc1772_comendhandler
- .global _fdc1772_dma_write_end
-_fdc1772_dma_write_end:
+ .global fdc1772_dma_write_end
+fdc1772_dma_write_end:
@ Setup the FIQ R11 to point to the data and store the count, address
@ for this dma
@ R0=count
@ R1=address
- .global _fdc1772_setupdma
-_fdc1772_setupdma:
+ .global fdc1772_setupdma
+fdc1772_setupdma:
@ The big job is flipping in and out of FIQ mode
- adr r2,_fdc1772_fiqdata @ This is what we really came here for
+ adr r2,fdc1772_fiqdata @ This is what we really came here for
stmia r2,{r0,r1}
mov r3, pc
teqp pc,#0x0c000001 @ Disable FIQs, IRQs and switch to FIQ mode
diff --git a/drivers/acorn/block/ide-ics.c b/drivers/acorn/block/ide-ics.c
deleted file mode 100644
index 24ac28094..000000000
--- a/drivers/acorn/block/ide-ics.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * linux/arch/arm/drivers/block/ide-ics.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- * 08-06-1996 RMK Created
- * 12-09-1997 RMK Added interrupt enable/disable
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-#include "../../block/ide.h"
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS 2
-
-#define ICS_IDENT_OFFSET 0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT 0x000
-#define ICS_ARCIN_V5_INTROFFSET 0x001
-#define ICS_ARCIN_V5_IDEOFFSET 0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET 0xae0
-#define ICS_ARCIN_V5_IDESTEPPING 4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1 0x800
-#define ICS_ARCIN_V6_INTROFFSET_1 0x880
-#define ICS_ARCIN_V6_INTRSTAT_1 0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2 0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2 0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2 0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0
-#define ICS_ARCIN_V6_IDESTEPPING 4
-
-static const card_ids icside_cids[] = {
- { MANU_ICS, PROD_ICS_IDE },
- { 0xffff, 0xffff }
-};
-
-typedef enum {
- ics_if_unknown,
- ics_if_arcin_v5,
- ics_if_arcin_v6
-} iftype_t;
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS][MAX_IFS];
-
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
- unsigned int memc_port = (unsigned int)ec->irq_data;
- outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
- unsigned int memc_port = (unsigned int)ec->irq_data;
- inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
- icside_irqenable_arcin_v5,
- icside_irqdisable_arcin_v5,
- NULL,
- NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
- unsigned int ide_base_port = (unsigned int)ec->irq_data;
- outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
- outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
- unsigned int ide_base_port = (unsigned int)ec->irq_data;
- inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
- inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
- icside_irqenable_arcin_v6,
- icside_irqdisable_arcin_v6,
- NULL,
- NULL
-};
-
-
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose : identify IDE interface type
- * Notes : checks the description string
- */
-static iftype_t icside_identifyif (struct expansion_card *ec)
-{
- unsigned int addr;
- iftype_t iftype;
- int id = 0;
-
- iftype = ics_if_unknown;
-
- addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
- id = inb (addr) & 1;
- id |= (inb (addr + 1) & 1) << 1;
- id |= (inb (addr + 2) & 1) << 2;
- id |= (inb (addr + 3) & 1) << 3;
-
- switch (id) {
- case 0: /* A3IN */
- printk ("icside: A3IN unsupported\n");
- break;
-
- case 1: /* A3USER */
- printk ("icside: A3USER unsupported\n");
- break;
-
- case 3: /* ARCIN V6 */
- printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
- iftype = ics_if_arcin_v6;
- break;
-
- case 15:/* ARCIN V5 (no id) */
- printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
- iftype = ics_if_arcin_v5;
- break;
-
- default:/* we don't know - complain very loudly */
- printk ("icside: ***********************************\n");
- printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
- printk ("icside: ***********************************\n");
- printk ("icside: please report this to: linux@arm.uk.linux.org\n");
- printk ("icside: defaulting to ARCIN V5\n");
- iftype = ics_if_arcin_v5;
- break;
- }
-
- return iftype;
-}
-
-static int icside_register_port(unsigned long dataport, unsigned long ctrlport, int stepping, int irq)
-{
- hw_regs_t hw;
- int i;
-
- memset(&hw, 0, sizeof(hw));
-
- for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hw.io_ports[i] = (ide_ioreg_t)dataport;
- dataport += 1 << stepping;
- }
- hw.io_ports[IDE_CONTROL_OFFSET] = ctrlport;
- hw.irq = irq;
-
- return ide_register_hw(&hw, NULL);
-}
-
-/* Prototype: icside_register (struct expansion_card *ec)
- * Purpose : register an ICS IDE card with the IDE driver
- * Notes : we make sure that interrupts are disabled from the card
- */
-static inline void icside_register (struct expansion_card *ec, int index)
-{
- unsigned long port;
-
- result[index][0] = -1;
- result[index][1] = -1;
-
- switch (icside_identifyif (ec)) {
- case ics_if_unknown:
- default:
- printk ("** Warning: ICS IDE Interface unrecognised! **\n");
- break;
-
- case ics_if_arcin_v5:
- port = ecard_address (ec, ECARD_MEMC, 0);
- ec->irqaddr = ioaddr(port + ICS_ARCIN_V5_INTRSTAT);
- ec->irqmask = 1;
- ec->irq_data = (void *)port;
- ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
- /*
- * Be on the safe side - disable interrupts
- */
- inb (port + ICS_ARCIN_V5_INTROFFSET);
- result[index][0] = icside_register_port(port + ICS_ARCIN_V5_IDEOFFSET,
- port + ICS_ARCIN_V5_IDEALTOFFSET,
- ICS_ARCIN_V5_IDESTEPPING,
- ec->irq);
- result[index][1] = -1;
- break;
-
- case ics_if_arcin_v6:
- port = ecard_address (ec, ECARD_IOC, ECARD_FAST);
- ec->irqaddr = ioaddr(port + ICS_ARCIN_V6_INTRSTAT_1);
- ec->irqmask = 1;
- ec->irq_data = (void *)port;
- ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
- /*
- * Be on the safe side - disable interrupts
- */
- inb (port + ICS_ARCIN_V6_INTROFFSET_1);
- inb (port + ICS_ARCIN_V6_INTROFFSET_2);
-
- result[index][0] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_1,
- port + ICS_ARCIN_V6_IDEALTOFFSET_1,
- ICS_ARCIN_V6_IDESTEPPING,
- ec->irq);
- result[index][1] = icside_register_port(port + ICS_ARCIN_V6_IDEOFFSET_2,
- port + ICS_ARCIN_V6_IDEALTOFFSET_2,
- ICS_ARCIN_V6_IDESTEPPING,
- ec->irq);
- break;
- }
-}
-
-int icside_init (void)
-{
- int i;
-
- for (i = 0; i < MAX_ECARDS; i++)
- ec[i] = NULL;
-
- ecard_startfind ();
-
- for (i = 0; ; i++) {
- if ((ec[i] = ecard_find (0, icside_cids)) == NULL)
- break;
-
- ecard_claim (ec[i]);
- icside_register (ec[i], i);
- }
-
- for (i = 0; i < MAX_ECARDS; i++)
- if (ec[i] && result[i][0] < 0 && result[i][1] < 0) {
- ecard_release (ec[i]);
- ec[i] = NULL;
- }
- return 0;
-}
-
-#ifdef MODULE
-int init_module (void)
-{
- return icside_init();
-}
-
-void cleanup_module (void)
-{
- int i;
-
- for (i = 0; i < MAX_ECARDS; i++)
- if (ec[i]) {
- if (result[i][0] >= 0)
- ide_unregister (result[i][0]);
-
- if (result[i][1] >= 0)
- ide_unregister (result[i][1]);
-
- ecard_release (ec[i]);
- ec[i] = NULL;
- }
-}
-#endif
-
diff --git a/drivers/acorn/block/mfm.S b/drivers/acorn/block/mfm.S
index 1efc5ece7..c90cbd41c 100644
--- a/drivers/acorn/block/mfm.S
+++ b/drivers/acorn/block/mfm.S
@@ -1,44 +1,43 @@
-@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400
-@ motherboard on ST506 podules.
-@ (c) David Alan Gilbert (gilbertd@cs.man.ac.uk) 1996
+@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
+@ motherboard and on ST506 expansion podules.
+@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
#include <asm/assembler.h>
-_hdc63463_irqdata:
+hdc63463_irqdata:
@ Controller base address
- .global _hdc63463_baseaddress
-_hdc63463_baseaddress:
+ .global hdc63463_baseaddress
+hdc63463_baseaddress:
.word 0
- .global _hdc63463_irqpolladdress
-_hdc63463_irqpolladdress:
+ .global hdc63463_irqpolladdress
+hdc63463_irqpolladdress:
.word 0
- .global _hdc63463_irqpollmask
-_hdc63463_irqpollmask:
+ .global hdc63463_irqpollmask
+hdc63463_irqpollmask:
.word 0
@ where to read/write data from the kernel data space
- .global _hdc63463_dataptr
-_hdc63463_dataptr:
+ .global hdc63463_dataptr
+hdc63463_dataptr:
.word 0
@ Number of bytes left to transfer
- .global _hdc63463_dataleft
-_hdc63463_dataleft:
+ .global hdc63463_dataleft
+hdc63463_dataleft:
.word 0
@ -------------------------------------------------------------------------
@ hdc63463_writedma: DMA from host to controller
@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
@ r3=data ptr, r4=data left, r5,r6=temporary
- .global _hdc63463_writedma
-_hdc63463_writedma:
+ .global hdc63463_writedma
+hdc63463_writedma:
stmfd sp!,{r4-r7}
- adr r5,_hdc63463_irqdata
+ adr r5,hdc63463_irqdata
ldmia r5,{r0,r1,r2,r3,r4}
-
writedma_again:
@ test number of remaining bytes to transfer
@@ -89,12 +88,12 @@ writedma_loop:
@ If we were too slow we had better go through again - DAG - took out with new interrupt routine
@ sub r0,r0,#32+8
- @ adr r2,_hdc63463_irqdata
+ @ adr r2,hdc63463_irqdata
@ ldr r2,[r2,#8]
@ b writedma_again
writedma_end:
- adr r5,_hdc63463_irqdata+12
+ adr r5,hdc63463_irqdata+12
stmia r5,{r3,r4}
ldmfd sp!,{r4-r7}
RETINSTR(mov,pc,lr)
@@ -103,10 +102,10 @@ writedma_end:
@ hdc63463_readdma: DMA from controller to host
@ internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
@ r3=data ptr, r4=data left, r5,r6=temporary
- .global _hdc63463_readdma
-_hdc63463_readdma:
+ .global hdc63463_readdma
+hdc63463_readdma:
stmfd sp!,{r4-r7}
- adr r5,_hdc63463_irqdata
+ adr r5,hdc63463_irqdata
ldmia r5,{r0,r1,r2,r3,r4}
readdma_again:
@@ -157,7 +156,7 @@ readdma_loop:
@ b readdma_again
readdma_end:
- adr r5,_hdc63463_irqdata+12
+ adr r5,hdc63463_irqdata+12
stmia r5,{r3,r4}
ldmfd sp!,{r4-r7}
RETINSTR(mov,pc,lr)
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 219f10034..7a8ea6f8e 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -123,6 +123,7 @@
#include <asm/dma.h>
#include <asm/hardware.h>
#include <asm/ecard.h>
+#include <asm/ioc.h>
/*
* This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
@@ -261,7 +262,9 @@ static struct cont {
void (*done) (int st); /* done handler */
} *cont = NULL;
+#if 0
static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
+#endif
int number_mfm_drives = 1;
diff --git a/drivers/acorn/char/Config.in b/drivers/acorn/char/Config.in
deleted file mode 100644
index ede0a8266..000000000
--- a/drivers/acorn/char/Config.in
+++ /dev/null
@@ -1,15 +0,0 @@
-if [ "$CONFIG_SERIAL" != "n" ]; then
- tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
- tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
-fi
-
-if [ "$CONFIG_MOUSE" = "y" ]; then
- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
- if [ "$CONFIG_ARCH_RPC" != "y" ]; then
- define_bool CONFIG_KBDMOUSE y
- else
- define_bool CONFIG_RPCMOUSE y
- fi
- fi
-fi
-
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
index ecbbfe90c..c3c6f67ba 100644
--- a/drivers/acorn/char/Makefile
+++ b/drivers/acorn/char/Makefile
@@ -9,20 +9,21 @@
# parent makes..
#
-L_TARGET := acorn-char.a
-M_OBJS :=
-L_OBJS :=
+L_TARGET := acorn-char.a
+M_OBJS :=
+L_OBJS :=
-ifeq ($(MACHINE),rpc)
- MOUSE_OBJS += mouse_rpc.o
- L_OBJS += keyb_ps2.o
-endif
+L_OBJS_arc := keyb_arc.o
+L_OBJS_a5k := keyb_arc.o
+L_OBJS_rpc := keyb_ps2.o
-ifeq ($(CONFIG_MOUSE),y)
- LX_OBJS += $(MOUSE_OBJS)
-else
- ifeq ($(CONFIG_MOUSE),m)
- MX_OBJS += $(MOUSE_OBJS)
+ifeq ($(MACHINE),rpc)
+ ifeq ($(CONFIG_MOUSE),y)
+ LX_OBJS += mouse_rpc.o
+ else
+ ifeq ($(CONFIG_MOUSE),m)
+ MX_OBJS += mouse_rpc.o
+ endif
endif
endif
@@ -42,4 +43,6 @@ else
endif
endif
+L_OBJS += $(L_OBJS_$(MACHINE))
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/acorn/char/keyb_arc.c b/drivers/acorn/char/keyb_arc.c
new file mode 100644
index 000000000..01c496a2b
--- /dev/null
+++ b/drivers/acorn/char/keyb_arc.c
@@ -0,0 +1,451 @@
+/*
+ * linux/arch/arm/drivers/char1/keyb_arc.c
+ *
+ * Acorn keyboard driver for ARM Linux.
+ *
+ * The Acorn keyboard appears to have a ***very*** buggy reset protocol -
+ * every reset behaves differently. We try to get round this by attempting
+ * a few things...
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/tty.h>
+#include <linux/kbd_kern.h>
+#include <linux/delay.h>
+
+#include <asm/bitops.h>
+#include <asm/keyboard.h>
+#include <asm/irq.h>
+#include <asm/ioc.h>
+#include <asm/hardware.h>
+
+#include "../../char/mouse.h"
+
+extern void kbd_reset_kdown(void);
+
+#define VERSION 108
+
+#define KBD_REPORT_ERR
+#define KBD_REPORT_UNKN
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+static char kbd_txval[4];
+static unsigned char kbd_txhead, kbd_txtail;
+#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3)
+static int kbd_id = -1;
+static struct wait_queue *kbd_waitq;
+#ifdef CONFIG_KBDMOUSE
+static int mousedev;
+#endif
+
+/*
+ * Protocol codes to send the keyboard.
+ */
+#define HRST 0xff /* reset keyboard */
+#define RAK1 0xfe /* reset response */
+#define RAK2 0xfd /* reset response */
+#define BACK 0x3f /* Ack for first keyboard pair */
+#define SMAK 0x33 /* Last data byte ack (key scanning + mouse movement scanning) */
+#define MACK 0x32 /* Last data byte ack (mouse movement scanning) */
+#define SACK 0x31 /* Last data byte ack (key scanning) */
+#define NACK 0x30 /* Last data byte ack (no scanning, mouse data) */
+#define RQMP 0x22 /* Request mouse data */
+#define PRST 0x21 /* nothing */
+#define RQID 0x20 /* Request ID */
+
+#define UP_FLAG 1
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char a5kkbd_sysrq_xlate[] =
+{
+ 27, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ '`', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', '0', '-', '=', '£', 127, 0,
+ 0, 0, 0, '/', '*', '#', 9, 'q',
+ 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o',
+ 'p', '[', ']', '\\', 22, 23, 25, '7',
+ '8', '9', '-', 0, 'a', 's', 'd', 'f',
+ 'g', 'h', 'j', 'k', 'l', ';', '\'', 13,
+ '4', '5', '6', '+', 0, 0, 'z', 'x',
+ 'c', 'v', 'b', 'n', 'm', ',', '.', '/',
+ 0, 0, '1', '2', '3', 0, 0, ' ',
+ 0, 0, 0, 0, 0, '0', '.', 10,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#endif
+
+/*
+ * This array converts the scancode that we get from the keyboard to the
+ * real rows/columns on the A5000 keyboard. This might be keyboard specific...
+ *
+ * It is these values that we use to maintain the key down array. That way, we
+ * should pick up on the ghost key presses (which is what happens when you press
+ * three keys, and the keyboard thinks you have pressed four!)
+ *
+ * Row 8 (0x80+c) is actually a column with one key per row. It is isolated from
+ * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
+ *
+ * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
+ * them, and can't process them for ghosts). This does however, cause problems with
+ * autorepeat processing...
+ */
+static unsigned char scancode_2_colrow[256] = {
+ 0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
+ 0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
+ 0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
+ 0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
+ 0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
+ 0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
+ 0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
+};
+
+#define BITS_PER_SHORT (8*sizeof(unsigned short))
+static unsigned short ghost_down[128/BITS_PER_SHORT];
+
+static void a5kkbd_key(unsigned int keycode, unsigned int up_flag)
+{
+ unsigned int real_keycode;
+
+ if (keycode > 0x72) {
+#ifdef KBD_REPORT_UNKN
+ printk ("kbd: unknown scancode 0x%04x\n", keycode);
+#endif
+ return;
+ }
+ if (keycode >= 0x70) {
+#ifdef CONFIG_KBDMOUSE
+ if (mousedev >= 0)
+ switch (keycode) {
+ case 0x70: /* Left mouse button */
+ busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0);
+ break;
+
+ case 0x71: /* Middle mouse button */
+ busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0);
+ break;
+
+ case 0x72:/* Right mouse button */
+ busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0);
+ break;
+ }
+#endif
+ return;
+ }
+
+ /*
+ * We have to work out if we accept this key press as a real key, or
+ * if it is a ghost. IE. If you press three keys, the keyboard will think
+ * that you've pressed a fourth: (@ = key down, # = ghost)
+ *
+ * 0 1 2 3 4 5 6 7
+ * | | | | | | | |
+ * 0-+-+-+-+-+-+-+-+-
+ * | | | | | | | |
+ * 1-+-@-+-+-+-@-+-+-
+ * | | | | | | | |
+ * 2-+-+-+-+-+-+-+-+-
+ * | | | | | | | |
+ * 3-+-@-+-+-+-#-+-+-
+ * | | | | | | | |
+ *
+ * This is what happens when you have a matrix keyboard...
+ */
+
+ real_keycode = scancode_2_colrow[keycode];
+
+ if ((real_keycode & 0x80) == 0) {
+ int rr, kc = (real_keycode >> 4) & 7;
+ int cc;
+ unsigned short res, kdownkc;
+
+ kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
+
+ for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
+ if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
+ /*
+ * we have found a second row with at least one key pressed in the
+ * same column.
+ */
+ for (cc = 0; res; res >>= 1)
+ cc += (res & 1);
+ if (cc > 1)
+ return; /* ignore it */
+ }
+ if (up_flag)
+ clear_bit (real_keycode, ghost_down);
+ else
+ set_bit (real_keycode, ghost_down);
+ }
+
+ handle_scancode(keycode, !up_flag);
+}
+
+static inline void a5kkbd_sendbyte(unsigned char val)
+{
+ kbd_txval[kbd_txhead] = val;
+ KBD_INCTXPTR(kbd_txhead);
+ enable_irq(IRQ_KEYBOARDTX);
+}
+
+static inline void a5kkbd_reset(void)
+{
+ int i;
+
+ for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++)
+ ghost_down[i] = 0;
+
+ kbd_reset_kdown();
+}
+
+void a5kkbd_leds(unsigned char leds)
+{
+ leds = ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
+ ((leds & (1<<VC_CAPSLOCK))?1:0);
+ a5kkbd_sendbyte(leds);
+}
+
+/* Keyboard states:
+ * 0 initial reset condition, receive HRST, send RRAK1
+ * 1 Sent RAK1, wait for RAK1, send RRAK2
+ * 2 Sent RAK2, wait for RAK2, send SMAK or RQID
+ * 3 Sent RQID, expect KBID, send SMAK
+ * 4 Sent SMAK, wait for anything
+ * 5 Wait for second keyboard nibble for key pressed
+ * 6 Wait for second keyboard nibble for key released
+ * 7 Wait for second part of mouse data
+ *
+ * This function returns 1 when we successfully enter the IDLE state
+ * (and hence need to do some keyboard processing).
+ */
+#define KBD_INITRST 0
+#define KBD_RAK1 1
+#define KBD_RAK2 2
+#define KBD_ID 3
+#define KBD_IDLE 4
+#define KBD_KEYDOWN 5
+#define KBD_KEYUP 6
+#define KBD_MOUSE 7
+
+static int handle_rawcode(unsigned int keyval)
+{
+ static signed char kbd_mousedx = 0;
+ signed char kbd_mousedy;
+ static unsigned char kbd_state = KBD_INITRST;
+ static unsigned char kbd_keyhigh = 0;
+
+ if (keyval == HRST && kbd_state != KBD_INITRST && kbd_state != KBD_ID) {
+ a5kkbd_sendbyte (HRST);
+ a5kkbd_reset ();
+ kbd_state = KBD_INITRST;
+ } else switch(kbd_state) {
+ case KBD_INITRST: /* hard reset - sent HRST */
+ if (keyval == HRST) {
+ a5kkbd_sendbyte (RAK1);
+ kbd_state = KBD_RAK1;
+ } else if (keyval == RAK1) {
+ /* Some A5000 keyboards are very fussy and don't follow Acorn's
+ * specs - this appears to fix them, but them it might stop
+ * them from being initialised.
+ * fix by Philip Blundell
+ */
+ printk(KERN_DEBUG "keyboard sent early RAK1 -- ignored\n");
+ } else
+ goto kbd_wontreset;
+ break;
+
+ case KBD_RAK1: /* sent RAK1 - expect RAK1 and send RAK2 */
+ if (keyval == RAK1) {
+ a5kkbd_sendbyte (RAK2);
+ kbd_state = KBD_RAK2;
+ } else
+ goto kbd_wontreset;
+ break;
+
+ case KBD_RAK2: /* Sent RAK2 - expect RAK2 and send either RQID or SMAK */
+ if (keyval == RAK2) {
+ if (kbd_id == -1) {
+ a5kkbd_sendbyte (NACK);
+ a5kkbd_sendbyte (RQID);
+ kbd_state = KBD_ID;
+ } else {
+ a5kkbd_sendbyte (SMAK);
+ kbd_state = KBD_IDLE;
+ }
+ } else
+ goto kbd_wontreset;
+ break;
+
+ case KBD_ID: /* Sent RQID - expect KBID */
+ if (keyval == HRST) {
+ kbd_id = -2;
+ a5kkbd_reset ();
+ a5kkbd_sendbyte (HRST);
+ kbd_state = KBD_INITRST;
+ wake_up (&kbd_waitq);
+ } else if ((keyval & 0xc0) == 0x80) {
+ kbd_id = keyval & 0x3f;
+ a5kkbd_sendbyte (SMAK);
+ kbd_state = KBD_IDLE;
+ wake_up (&kbd_waitq);
+ }
+ break;
+
+ case KBD_IDLE: /* Send SMAK, ready for any reply */
+ switch (keyval & 0xf0) {
+ default: /* 0x00 - 0x7f */
+ kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
+ kbd_state = KBD_MOUSE;
+ a5kkbd_sendbyte (BACK);
+ break;
+
+ case 0x80:
+ case 0x90:
+ case 0xa0:
+ case 0xb0:
+ if (kbd_id == -1)
+ kbd_id = keyval & 0x3f;
+ break;
+
+ case 0xc0:
+ kbd_keyhigh = keyval;
+ kbd_state = KBD_KEYDOWN;
+ a5kkbd_sendbyte (BACK);
+ break;
+
+ case 0xd0:
+ kbd_keyhigh = keyval;
+ kbd_state = KBD_KEYUP;
+ a5kkbd_sendbyte (BACK);
+ break;
+
+ case 0xe0:
+ case 0xf0:
+ goto kbd_error;
+ }
+ break;
+
+ case KBD_KEYDOWN:
+ if ((keyval & 0xf0) != 0xc0)
+ goto kbd_error;
+ else {
+ kbd_state = KBD_IDLE;
+ a5kkbd_sendbyte (SMAK);
+ if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
+ a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), 0);
+ }
+ break;
+
+ case KBD_KEYUP:
+ if ((keyval & 0xf0) != 0xd0)
+ goto kbd_error;
+ else {
+ kbd_state = KBD_IDLE;
+ a5kkbd_sendbyte (SMAK);
+ if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
+ a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), UP_FLAG);
+ }
+ break;
+
+ case KBD_MOUSE:
+ if (keyval & 0x80)
+ goto kbd_error;
+ else {
+ kbd_state = KBD_IDLE;
+ a5kkbd_sendbyte (SMAK);
+ kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
+#ifdef CONFIG_KBDMOUSE
+ if (mousedev >= 0)
+ busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy);
+#endif
+ }
+ }
+ return kbd_state == KBD_IDLE ? 1 : 0;
+
+kbd_wontreset:
+#ifdef KBD_REPORT_ERR
+ printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n",
+ kbd_state, keyval);
+#endif
+ mdelay(1);
+ inb(IOC_KARTRX);
+ a5kkbd_sendbyte (HRST);
+ kbd_state = KBD_INITRST;
+ return 0;
+
+kbd_error:
+#ifdef KBD_REPORT_ERR
+ printk ("kbd: keyboard out of sync - resetting\n");
+#endif
+ a5kkbd_sendbyte (HRST);
+ kbd_state = KBD_INITRST;
+ return 0;
+}
+
+static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+{
+ kbd_pt_regs = regs;
+ if (handle_rawcode(inb(IOC_KARTRX)))
+ mark_bh (KEYBOARD_BH);
+}
+
+static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+{
+ outb (kbd_txval[kbd_txtail], IOC_KARTTX);
+ KBD_INCTXPTR(kbd_txtail);
+ if (kbd_txtail == kbd_txhead)
+ disable_irq(irq);
+}
+
+#ifdef CONFIG_KBDMOUSE
+static struct busmouse a5kkbd_mouse = {
+ 6, "kbdmouse", NULL, NULL, 7
+};
+#endif
+
+__initfunc(void a5kkbd_init_hw (void))
+{
+ unsigned long flags;
+
+ save_flags_cli (flags);
+ if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
+ panic("Could not allocate keyboard transmit IRQ!");
+ disable_irq (IRQ_KEYBOARDTX);
+ if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
+ panic("Could not allocate keyboard receive IRQ!");
+ (void)inb(IOC_KARTRX);
+ restore_flags (flags);
+
+ a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */
+
+ /* wait 1s for keyboard to initialise */
+ interruptible_sleep_on_timeout(&kbd_waitq, HZ);
+
+#ifdef CONFIG_KBDMOUSE
+ mousedev = register_busmouse(&a5kkbd_mouse);
+ if (mousedev < 0)
+ printk(KERN_ERR "Unable to register mouse driver\n");
+#endif
+
+ printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100);
+ if (kbd_id != -1)
+ printk ("id=%d ", kbd_id);
+ printk ("English)\n");
+}
diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c
index 4af051f44..3fa8a03ad 100644
--- a/drivers/acorn/char/keyb_ps2.c
+++ b/drivers/acorn/char/keyb_ps2.c
@@ -25,6 +25,7 @@
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
+#include <asm/iomd.h>
#include <asm/system.h>
extern void kbd_reset_kdown(void);
@@ -221,14 +222,7 @@ unsigned char ps2kbd_sysrq_xlate[] =
};
#endif
-int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p)
-{
- *uf_p = scancode & 0200;
- *keycode_p = scancode & 0x7f;
- return 1;
-}
-
-static void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
+static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
{
handle_scancode(keycode, !up_flag);
}
diff --git a/drivers/acorn/char/mouse_rpc.c b/drivers/acorn/char/mouse_rpc.c
index a5c2b2bff..4eecd0cc1 100644
--- a/drivers/acorn/char/mouse_rpc.c
+++ b/drivers/acorn/char/mouse_rpc.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/char/rpcmouse.c
+ * linux/drivers/char/mouse_rpc.c
*
* Copyright (C) 1996-1998 Russell King
*
@@ -16,6 +16,7 @@
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/iomd.h>
#include "../../char/mouse.h"
diff --git a/drivers/acorn/char/serial-card.c b/drivers/acorn/char/serial-card.c
index 23a625658..a1ea1c61f 100644
--- a/drivers/acorn/char/serial-card.c
+++ b/drivers/acorn/char/serial-card.c
@@ -33,14 +33,20 @@
#ifdef MODULE
static int __serial_ports[NUM_SERIALS];
static int __serial_pcount;
+static int __serial_addr[NUM_SERIALS];
static struct expansion_card *expcard[MAX_ECARDS];
#define ADD_ECARD(ec,card) expcard[(card)] = (ec)
-#define ADD_PORT(port) __serial_ports[__serial_pcount++] = (port)
+#define ADD_PORT(port,addr) \
+ do { \
+ __serial_ports[__serial_pcount] = (port); \
+ __serial_addr[__serial_pcount] = (addr); \
+ __serial_pcount += 1; \
+ } while (0)
#undef MY_INIT
#define MY_INIT init_module
#else
#define ADD_ECARD(ec,card)
-#define ADD_PORT(port)
+#define ADD_PORT(port,addr)
#endif
static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } };
@@ -75,12 +81,15 @@ int MY_INIT (void)
cardaddr = MY_BASE_ADDRESS(ec);
for (port = 0; port < MY_NUMPORTS; port ++) {
+ unsigned long address;
int line;
- line = serial_register_onedev (MY_PORT_ADDRESS(port, cardaddr), ec->irq);
+ address = MY_PORT_ADDRESS(port, cardaddr);
+
+ line = serial_register_onedev (address, ec->irq);
if (line < 0)
break;
- ADD_PORT(line);
+ ADD_PORT(line, address);
}
if (port) {
@@ -97,8 +106,10 @@ void cleanup_module (void)
{
int i;
- for (i = 0; i < __serial_pcount; i++)
- unregister_serial (__serial_ports[i]);
+ for (i = 0; i < __serial_pcount; i++) {
+ unregister_serial(__serial_ports[i]);
+ release_region(__serial_addr[i], 8);
+ }
for (i = 0; i < MAX_ECARDS; i++)
if (expcard[i])
diff --git a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c
index 1d2283f3d..31e7cc087 100644
--- a/drivers/acorn/net/ether1.c
+++ b/drivers/acorn/net/ether1.c
@@ -71,7 +71,7 @@ static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n";
#define BUS_16 16
#define BUS_8 8
-static const card_ids ether1_cids[] = {
+static const card_ids __init ether1_cids[] = {
{ MANU_ACORN, PROD_ACORN_ETHER1 },
{ 0xffff, 0xffff }
};
@@ -128,7 +128,7 @@ ether1_inswb (unsigned int addr, void *data, unsigned int len)
{
int used;
- addr = IO_BASE + (addr << 2);
+ addr = ioaddr(addr);
__asm__ __volatile__(
"subs %3, %3, #2
@@ -171,7 +171,7 @@ ether1_outswb (unsigned int addr, void *data, unsigned int len)
{
int used;
- addr = IO_BASE + (addr << 2);
+ addr = ioaddr(addr);
__asm__ __volatile__(
"subs %3, %3, #2
@@ -659,12 +659,6 @@ ether1_probe1 (struct device *dev))
/* Fill in the fields of the device structure with ethernet values */
ether_setup (dev);
-#ifndef CLAIM_IRQ_AT_OPEN
- if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) {
- kfree (dev->priv);
- return -EAGAIN;
- }
-#endif
return 0;
}
@@ -759,18 +753,16 @@ static int
ether1_open (struct device *dev)
{
struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-#ifdef CLAIM_IRQ_AT_OPEN
+
if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev))
return -EAGAIN;
-#endif
+
MOD_INC_USE_COUNT;
memset (&priv->stats, 0, sizeof (struct enet_statistics));
if (ether1_init_for_open (dev)) {
-#ifdef CLAIM_IRQ_AT_OPEN
free_irq (dev->irq, dev);
-#endif
MOD_DEC_USE_COUNT;
return -EAGAIN;
}
@@ -1080,12 +1072,10 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
static int
ether1_close (struct device *dev)
{
-#ifdef CLAIM_IRQ_AT_OPEN
- free_irq (dev->irq, dev);
-#endif
-
ether1_reset (dev);
+ free_irq(dev->irq, dev);
+
dev->start = 0;
dev->tbusy = 0;
@@ -1117,56 +1107,46 @@ ether1_setmulticastlist (struct device *dev)
#ifdef MODULE
-static char ethernames[MAX_ECARDS][9];
-static struct device *my_ethers[MAX_ECARDS];
-static struct expansion_card *ec[MAX_ECARDS];
+static struct ether_dev {
+ struct expansion_card *ec;
+ char name[9];
+ struct device dev;
+} ether_devs[MAX_ECARDS];
int
init_module (void)
{
- int i;
+ struct expansion_card *ec;
+ int i, ret = -ENODEV;
- for (i = 0; i < MAX_ECARDS; i++) {
- my_ethers[i] = NULL;
- ec[i] = NULL;
- strcpy (ethernames[i], " ");
- }
+ memset(ether_devs, 0, sizeof(ether_devs));
+ ecard_startfind ();
+ ec = ecard_find(0, ether1_cids);
i = 0;
- ecard_startfind ();
+ while (ec && i < MAX_ECARDS) {
+ ecard_claim(ec);
- do {
- if ((ec[i] = ecard_find(0, ether1_cids)) == NULL)
- break;
+ ether_devs[i].ec = ec;
+ ether_devs[i].dev.irq = ec->irq;
+ ether_devs[i].dev.base_addr = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+ ether_devs[i].dev.init = ether1_probe;
+ ether_devs[i].dev.name = ether_devs[i].name;
- my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL);
- memset (my_ethers[i], 0, sizeof (struct device));
-
- my_ethers[i]->irq = ec[i]->irq;
- my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST);
- my_ethers[i]->init = ether1_probe;
- my_ethers[i]->name = ethernames[i];
-
- ecard_claim (ec[i]);
-
- if (register_netdev (my_ethers[i]) != 0) {
- for (i = 0; i < 4; i++) {
- if (my_ethers[i]) {
- kfree (my_ethers[i]);
- my_ethers[i] = NULL;
- }
- if (ec[i]) {
- ecard_release (ec[i]);
- ec[i] = NULL;
- }
- }
- return -EIO;
+ ret = register_netdev(&ether_devs[i].dev);
+
+ if (ret) {
+ ecard_release(ec);
+ ether_devs[i].ec = NULL;
+ break;
}
- i++;
- } while (i < MAX_ECARDS);
- return i != 0 ? 0 : -ENODEV;
+ i += 1;
+ ec = ecard_find(0, ether1_cids);
+ }
+
+ return i != 0 ? 0 : ret;
}
void
@@ -1175,18 +1155,15 @@ cleanup_module (void)
int i;
for (i = 0; i < MAX_ECARDS; i++) {
- if (my_ethers[i]) {
- unregister_netdev (my_ethers[i]);
- release_region (my_ethers[i]->base_addr, 16);
- release_region (my_ethers[i]->base_addr + 0x800, 4096);
-#ifndef CLAIM_IRQ_AT_OPEN
- free_irq (my_ethers[i]->irq, my_ethers[i]);
-#endif
- my_ethers[i] = NULL;
- }
- if (ec[i]) {
- ecard_release (ec[i]);
- ec[i] = NULL;
+ if (ether_devs[i].ec) {
+ unregister_netdev(&ether_devs[i].dev);
+
+ release_region(ether_devs[i].dev.base_addr, 16);
+ release_region(ether_devs[i].dev.base_addr + 0x800, 4096);
+
+ ecard_release(ether_devs[i].ec);
+
+ ether_devs[i].ec = NULL;
}
}
}
diff --git a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c
index ca89b7e59..ea6c13da5 100644
--- a/drivers/acorn/net/ether3.c
+++ b/drivers/acorn/net/ether3.c
@@ -33,11 +33,12 @@
* packet starts two bytes from the end of the
* buffer, it corrupts the receiver chain, and
* never updates the transmit status correctly.
- * TODO:
- * When we detect a fatal error on the interface, we should restart it.
+ * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing.
+ * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy
+ * hardware.
*/
-static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
+static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n";
#include <linux/module.h>
#include <linux/kernel.h>
@@ -66,7 +67,7 @@ static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.13\n";
#include "ether3.h"
static unsigned int net_debug = NET_DEBUG;
-static const card_ids ether3_cids[] = {
+static const card_ids __init ether3_cids[] = {
{ MANU_ANT2, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHERB }, /* trial - will etherb work? */
@@ -77,9 +78,6 @@ static void ether3_setmulticastlist(struct device *dev);
static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt);
static void ether3_tx(struct device *dev, struct dev_priv *priv);
-extern int inswb(int reg, void *buffer, int len);
-extern int outswb(int reg, void *buffer, int len);
-
#define BUS_16 2
#define BUS_8 1
#define BUS_UNKNOWN 0
@@ -88,7 +86,7 @@ extern int outswb(int reg, void *buffer, int len);
* I'm not sure what address we should default to if the internal one
* is corrupted...
*/
-unsigned char def_eth_addr[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
+unsigned char def_eth_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
/* --------------------------------------------------------------------------- */
@@ -99,6 +97,8 @@ typedef enum {
/*
* ether3 read/write. Slow things down a bit...
+ * The SEEQ8005 doesn't like us writing to it's registers
+ * too quickly.
*/
#define ether3_outb(v,r) { outb((v),(r)); udelay(1); }
#define ether3_outw(v,r) { outw((v),(r)); udelay(1); }
@@ -138,7 +138,7 @@ ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
* write data to the buffer memory
*/
#define ether3_writebuffer(dev,data,length) \
- outswb(REG_BUFWIN, (data), (length))
+ outsw(REG_BUFWIN, (data), (length) >> 1)
#define ether3_writeword(dev,data) \
outw((data), REG_BUFWIN)
@@ -153,7 +153,7 @@ ether3_setbuffer(struct device *dev, buffer_rw_t read, int start)
* read data from the buffer memory
*/
#define ether3_readbuffer(dev,data,length) \
- inswb(REG_BUFWIN, (data), (length))
+ insw(REG_BUFWIN, (data), (length) >> 1)
#define ether3_readword(dev) \
inw(REG_BUFWIN)
@@ -249,7 +249,7 @@ ether3_ramtest(struct device *dev, unsigned char byte))
}
} else {
if (bad != -1) {
- if (bad != i - 1)
+ if (bad != i - 1)
printk(" - 0x%04X\n", i - 1);
printk("\n");
bad = -1;
@@ -335,7 +335,6 @@ ether3_init_for_open(struct device *dev)
for (i = 0; i < 6; i++)
ether3_outb(dev->dev_addr[i], REG_BUFWIN);
- priv->tx_used = 0;
priv->tx_head = 0;
priv->tx_tail = 0;
priv->regs.config2 |= CFG2_CTRLO;
@@ -471,6 +470,25 @@ failed:
return error;
}
+__initfunc(static void
+ether3_get_dev(struct device *dev, struct expansion_card *ec))
+{
+ ecard_claim(ec);
+
+ dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+ dev->irq = ec->irq;
+
+ if (ec->cid.manufacturer == MANU_ANT &&
+ ec->cid.product == PROD_ANT_ETHERB) {
+ dev->base_addr += 0x200;
+ }
+
+ ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
+ ec->irqmask = 0xf0;
+
+ ether3_addr(dev->dev_addr, ec);
+}
+
#ifndef MODULE
__initfunc(int
ether3_probe(struct device *dev))
@@ -485,12 +503,8 @@ ether3_probe(struct device *dev))
if ((ec = ecard_find(0, ether3_cids)) == NULL)
return ENODEV;
- dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
- dev->irq = ec->irq;
-
- ecard_claim(ec);
+ ether3_get_dev(dev, ec);
- ether3_addr(dev->dev_addr, ec);
return ether3_probe1(dev);
}
#endif
@@ -581,33 +595,6 @@ static void ether3_setmulticastlist(struct device *dev)
}
/*
- * Allocate memory in transmitter ring buffer.
- */
-static int
-ether3_alloc_tx(struct dev_priv *priv, int length, int alloc)
-{
- int start, head, tail;
-
- tail = priv->tx_tail;
- start = priv->tx_head;
- head = start + length + 4;
-
- if (head >= TX_END) {
- if (tail > priv->tx_head)
- return -1;
- head -= TX_END - TX_START;
- if (tail < head)
- return -1;
- } else if (start < tail && tail < head)
- return -1;
-
- if (alloc)
- priv->tx_head = head;
-
- return start;
-}
-
-/*
* Transmit a packet
*/
static int
@@ -622,7 +609,7 @@ retry:
if (!test_and_set_bit(0, (void *)&dev->tbusy)) {
unsigned long flags;
unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- int ptr;
+ unsigned int ptr, next_ptr;
length = (length + 1) & ~1;
@@ -633,23 +620,31 @@ retry:
return 0;
}
+ next_ptr = (priv->tx_head + 1) & 15;
+
save_flags_cli(flags);
- ptr = ether3_alloc_tx(priv, length, 1);
- if (ptr == -1)
+ if (priv->tx_tail == next_ptr) {
+ restore_flags(flags);
return 1; /* unable to queue */
+ }
+
+ dev->trans_start = jiffies;
+ ptr = 0x600 * priv->tx_head;
+ priv->tx_head = next_ptr;
+ next_ptr *= 0x600;
#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
- ether3_setbuffer(dev, buffer_write, priv->tx_head);
+ ether3_setbuffer(dev, buffer_write, next_ptr);
ether3_writelong(dev, 0);
-
ether3_setbuffer(dev, buffer_write, ptr);
ether3_writelong(dev, 0);
ether3_writebuffer(dev, skb->data, length);
-
+ ether3_writeword(dev, htons(next_ptr));
+ ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
ether3_setbuffer(dev, buffer_write, ptr);
- ether3_writeword(dev, htons(priv->tx_head));
+ ether3_writeword(dev, htons((ptr + length + 4)));
ether3_writeword(dev, TXHDR_FLAGS >> 16);
ether3_ledon(dev, priv);
@@ -658,11 +653,10 @@ retry:
ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
}
- if (ether3_alloc_tx(priv, 2044, 0) != -1)
+ next_ptr = (priv->tx_head + 1) & 15;
+ if (priv->tx_tail != next_ptr)
dev->tbusy = 0;
- dev->trans_start = jiffies;
-
restore_flags(flags);
dev_kfree_skb(skb);
@@ -689,7 +683,7 @@ retry:
ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
- printk(KERN_ERR "%s: tx head=%04X tx tail=%04X\n", dev->name,
+ printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
priv->tx_head, priv->tx_tail);
ether3_setbuffer(dev, buffer_read, priv->tx_tail);
printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
@@ -698,8 +692,9 @@ retry:
dev->tbusy = 0;
priv->regs.config2 |= CFG2_CTRLO;
priv->stats.tx_errors += 1;
- ether3_outw(priv->regs.config2 , REG_CONFIG2);
+ ether3_outw(priv->regs.config2, REG_CONFIG2);
dev->trans_start = jiffies;
+ priv->tx_head = priv->tx_tail = 0;
goto retry;
}
}
@@ -867,6 +862,7 @@ static void
ether3_tx(struct device *dev, struct dev_priv *priv)
{
unsigned int tx_tail = priv->tx_tail;
+ int max_work = 14;
do {
unsigned long status;
@@ -874,7 +870,7 @@ ether3_tx(struct device *dev, struct dev_priv *priv)
/*
* Read the packet header
*/
- ether3_setbuffer(dev, buffer_read, tx_tail);
+ ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
status = ether3_readlong(dev);
/*
@@ -895,95 +891,72 @@ ether3_tx(struct device *dev, struct dev_priv *priv)
if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
}
- tx_tail = htons(status & TX_NEXT);
- if (tx_tail < TX_START || tx_tail >= TX_END) {
- printk("%s: transmit error: next pointer = %04X\n", dev->name, tx_tail);
- tx_tail = TX_START;
- priv->tx_head = TX_START;
- priv->tx_tail = TX_END;
- }
- } while (1);
+ tx_tail = (tx_tail + 1) & 15;
+ } while (--max_work);
if (priv->tx_tail != tx_tail) {
priv->tx_tail = tx_tail;
- if (priv->tx_used <= MAX_TX_BUFFERED) {
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
- }
+ dev->tbusy = 0;
+ mark_bh(NET_BH); /* Inform upper layers. */
}
}
#ifdef MODULE
-char ethernames[MAX_ECARDS][9];
-
-static struct device *my_ethers[MAX_ECARDS];
-static struct expansion_card *ec[MAX_ECARDS];
+static struct ether_dev {
+ struct expansion_card *ec;
+ char name[9];
+ struct device dev;
+} ether_devs[MAX_ECARDS];
int
init_module(void)
{
- int i;
+ struct expansion_card *ec;
+ int i, ret = -ENODEV;
- for(i = 0; i < MAX_ECARDS; i++) {
- my_ethers[i] = NULL;
- ec[i] = NULL;
- strcpy(ethernames[i], " ");
- }
+ memset(ether_devs, 0, sizeof(ether_devs));
+ ecard_startfind ();
+ ec = ecard_find(0, ether3_cids);
i = 0;
- ecard_startfind();
+ while (ec && i < MAX_ECARDS) {
+ ecard_claim(ec);
- do {
- if ((ec[i] = ecard_find(0, ether3_cids)) == NULL)
- break;
+ ether_devs[i].ec = ec;
+ ether_devs[i].dev.init = ether3_probe1;
+ ether_devs[i].dev.name = ether_devs[i].name;
+ ether3_get_dev(&ether_devs[i].dev, ec);
- my_ethers[i] = (struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
- memset(my_ethers[i], 0, sizeof(struct device));
+ ret = register_netdev(&ether_devs[i].dev);
- my_ethers[i]->irq = ec[i]->irq;
- my_ethers[i]->base_addr= ecard_address(ec[i], ECARD_MEMC, 0);
- my_ethers[i]->init = ether3_probe1;
- my_ethers[i]->name = ethernames[i];
-
- ether3_addr(my_ethers[i]->dev_addr, ec[i]);
-
- ecard_claim(ec[i]);
+ if (ret) {
+ ecard_release(ec);
+ ether_devs[i].ec = NULL;
+ } else
+ i += 1;
- if(register_netdev(my_ethers[i]) != 0) {
- for (i = 0; i < 4; i++) {
- if(my_ethers[i]) {
- kfree(my_ethers[i]);
- my_ethers[i] = NULL;
- }
- if(ec[i]) {
- ecard_release(ec[i]);
- ec[i] = NULL;
- }
- }
- return -EIO;
- }
- i++;
+ ec = ecard_find(0, ether3_cids);
}
- while(i < MAX_ECARDS);
- return i != 0 ? 0 : -ENODEV;
+ return i != 0 ? 0 : ret;
}
void
cleanup_module(void)
{
int i;
+
for (i = 0; i < MAX_ECARDS; i++) {
- if (my_ethers[i]) {
- release_region(my_ethers[i]->base_addr, 128);
- unregister_netdev(my_ethers[i]);
- my_ethers[i] = NULL;
- }
- if (ec[i]) {
- ecard_release(ec[i]);
- ec[i] = NULL;
+ if (ether_devs[i].ec) {
+ unregister_netdev(&ether_devs[i].dev);
+
+ release_region(ether_devs[i].dev.base_addr, 128);
+
+ ecard_release(ether_devs[i].ec);
+
+ ether_devs[i].ec = NULL;
}
}
}
diff --git a/drivers/acorn/net/ether3.h b/drivers/acorn/net/ether3.h
index 2a92052a4..ed9f2e6f7 100644
--- a/drivers/acorn/net/ether3.h
+++ b/drivers/acorn/net/ether3.h
@@ -151,9 +151,8 @@ struct dev_priv {
unsigned int config1;
unsigned int config2;
} regs;
- unsigned int tx_head; /* address to insert next packet */
- unsigned int tx_tail; /* address of transmitting packet */
- unsigned int tx_used; /* number of 'slots' used */
+ unsigned char tx_head; /* buffer nr to insert next packet */
+ unsigned char tx_tail; /* buffer nr of transmitting packet */
unsigned int rx_head; /* address to fetch next packet from */
struct enet_statistics stats;
struct timer_list timer;
diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
index 4f88f6bb4..319b66cfc 100644
--- a/drivers/acorn/net/etherh.c
+++ b/drivers/acorn/net/etherh.c
@@ -37,6 +37,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -50,13 +51,16 @@
#define DEBUG_INIT 2
static unsigned int net_debug = NET_DEBUG;
-static const card_ids etherh_cids[] = {
+static const card_ids __init etherh_cids[] = {
{ MANU_I3, PROD_I3_ETHERLAN500 },
{ MANU_I3, PROD_I3_ETHERLAN600 },
{ MANU_I3, PROD_I3_ETHERLAN600A },
{ 0xffff, 0xffff }
};
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("i3 EtherH driver");
+
static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n";
#define ETHERH500_DATAPORT 0x200 /* MEMC */
@@ -80,8 +84,8 @@ static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King
* Read the ethernet address string from the on board rom.
* This is an ascii string...
*/
-static int
-etherh_addr(char *addr, struct expansion_card *ec)
+__initfunc(static int
+etherh_addr(char *addr, struct expansion_card *ec))
{
struct in_chunk_dir cd;
char *s;
@@ -216,10 +220,8 @@ etherh_block_output (struct device *dev, int count, const unsigned char *buf, in
if (ei_status.word16)
outsw (dma_addr, buf, count >> 1);
-#ifdef BIT8
else
outsb (dma_addr, buf, count);
-#endif
dma_start = jiffies;
@@ -268,11 +270,8 @@ etherh_block_input (struct device *dev, int count, struct sk_buff *skb, int ring
insw (dma_addr, buf, count >> 1);
if (count & 1)
buf[count - 1] = inb (dma_addr);
- }
-#ifdef BIT8
- else
+ } else
insb (dma_addr, buf, count);
-#endif
outb (ENISR_RDC, addr + EN0_ISR);
ei_status.dmaing &= ~1;
@@ -307,10 +306,8 @@ etherh_get_header (struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
if (ei_status.word16)
insw (dma_addr, hdr, sizeof (*hdr) >> 1);
-#ifdef BIT8
else
insb (dma_addr, hdr, sizeof (*hdr));
-#endif
outb (ENISR_RDC, addr + EN0_ISR);
ei_status.dmaing &= ~1;
@@ -355,8 +352,8 @@ etherh_close(struct device *dev)
/*
* This is the real probe routine.
*/
-static int
-etherh_probe1(struct device *dev)
+__initfunc(static int
+etherh_probe1(struct device *dev))
{
static int version_printed;
unsigned int addr, i, reg0, tmp;
@@ -461,10 +458,13 @@ static expansioncard_ops_t etherh_ops = {
etherh_irq_enable,
etherh_irq_disable,
NULL,
+ NULL,
+ NULL,
NULL
};
-static void etherh_initdev (ecard_t *ec, struct device *dev)
+__initfunc(static void
+etherh_initdev(ecard_t *ec, struct device *dev))
{
ecard_claim (ec);
@@ -492,27 +492,27 @@ static void etherh_initdev (ecard_t *ec, struct device *dev)
}
ec->ops = &etherh_ops;
- etherh_addr (dev->dev_addr, ec);
+ etherh_addr(dev->dev_addr, ec);
}
#ifndef MODULE
-int
-etherh_probe(struct device *dev)
+__initfunc(int
+etherh_probe(struct device *dev))
{
if (!dev)
return ENODEV;
- ecard_startfind ();
-
- if (!dev->base_addr) {
+ if (!dev->base_addr || dev->base_addr == 0xffe0) {
struct expansion_card *ec;
+ ecard_startfind();
+
if ((ec = ecard_find (0, etherh_cids)) == NULL)
return ENODEV;
- etherh_initdev (ec, dev);
+ etherh_initdev(ec, dev);
}
- return etherh_probe1 (dev);
+ return etherh_probe1(dev);
}
#endif
@@ -529,12 +529,10 @@ static int
init_all_cards(void)
{
struct device *dev = NULL;
- struct expansion_card *boguscards[MAX_ETHERH_CARDS];
int i, found = 0;
for (i = 0; i < MAX_ETHERH_CARDS; i++) {
my_ethers[i] = NULL;
- boguscards[i] = NULL;
ec[i] = NULL;
strcpy (ethernames[i], " ");
}
@@ -571,7 +569,7 @@ init_all_cards(void)
if (register_netdev(dev) != 0) {
printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr);
if (ec[i]) {
- boguscards[i] = ec[i];
+ ecard_release(ec[i]);
ec[i] = NULL;
}
continue;
@@ -583,12 +581,6 @@ init_all_cards(void)
if (dev)
kfree (dev);
- for (i = 0; i < MAX_ETHERH_CARDS; i++)
- if (boguscards[i]) {
- boguscards[i]->ops = NULL;
- ecard_release (boguscards[i]);
- }
-
return found ? 0 : -ENODEV;
}
diff --git a/drivers/acorn/scsi/Config.in b/drivers/acorn/scsi/Config.in
index 5b8d14429..68d4f920b 100644
--- a/drivers/acorn/scsi/Config.in
+++ b/drivers/acorn/scsi/Config.in
@@ -7,11 +7,12 @@ if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then
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
- comment 'The following drives 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
diff --git a/drivers/acorn/scsi/Makefile b/drivers/acorn/scsi/Makefile
index f69638530..6efd22681 100644
--- a/drivers/acorn/scsi/Makefile
+++ b/drivers/acorn/scsi/Makefile
@@ -24,6 +24,16 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_ARXESCSI),y)
+ L_OBJS += arxescsi.o
+ CONFIG_FAS216_BUILTIN=y
+else
+ ifeq ($(CONFIG_SCSI_ARXESCSI),m)
+ M_OBJS += arxescsi.o
+ CONFIG_FAS216_MODULE=y
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_CUMANA_1),y)
L_OBJS += cumana_1.o
else
@@ -34,12 +44,10 @@ endif
ifeq ($(CONFIG_SCSI_CUMANA_2),y)
L_OBJS += cumana_2.o
- CONFIG_QUEUE_BUILTIN=y
CONFIG_FAS216_BUILTIN=y
else
ifeq ($(CONFIG_SCSI_CUMANA_2),m)
M_OBJS += cumana_2.o
- CONFIG_QUEUE_MODULE=y
CONFIG_FAS216_MODULE=y
endif
endif
@@ -62,41 +70,39 @@ endif
ifeq ($(CONFIG_SCSI_POWERTECSCSI),y)
L_OBJS += powertec.o
- CONFIG_QUEUE_BUILTIN=y
CONFIG_FAS216_BUILTIN=y
else
ifeq ($(CONFIG_SCSI_POWERTECSCSI),m)
M_OBJS += powertec.o
- CONFIG_QUEUE_MODULE=y
CONFIG_FAS216_MODULE=y
endif
endif
ifeq ($(CONFIG_SCSI_EESOXSCSI),y)
L_OBJS += eesox.o
- CONFIG_QUEUE_BUILTIN=y
CONFIG_FAS216_BUILTIN=y
else
ifeq ($(CONFIG_SCSI_EESOXSCSI),m)
M_OBJS += eesox.o
- CONFIG_QUEUE_MODULE=y
CONFIG_FAS216_MODULE=y
endif
endif
-ifeq ($(CONFIG_QUEUE_BUILTIN),y)
- LX_OBJS += queue.o msgqueue.o
-else
- ifeq ($(CONFIG_QUEUE_MODULE),y)
- MX_OBJS += queue.o msgqueue.o
- endif
-endif
-
ifeq ($(CONFIG_FAS216_BUILTIN),y)
LX_OBJS += fas216.o
+ CONFIG_QUEUE_BUILTIN=y
else
ifeq ($(CONFIG_FAS216_MODULE),y)
MX_OBJS += fas216.o
+ CONFIG_QUEUE_MODULE=y
+ endif
+endif
+
+ifeq ($(CONFIG_QUEUE_BUILTIN),y)
+ LX_OBJS += queue.o msgqueue.o
+else
+ ifeq ($(CONFIG_QUEUE_MODULE),y)
+ MX_OBJS += queue.o msgqueue.o
endif
endif
diff --git a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c
index 50ec36436..1e83bbead 100644
--- a/drivers/acorn/scsi/acornscsi.c
+++ b/drivers/acorn/scsi/acornscsi.c
@@ -21,6 +21,8 @@
* 12-Oct-1997 RMK Added catch for re-entering interrupt routine.
* 15-Oct-1997 RMK Improved handling of commands.
* 27-Jun-1998 RMK Changed asm/delay.h to linux/delay.h.
+ * 13-Dec-1998 RMK Better abort code and command handling. Extra state
+ * transitions added to allow dodgy devices to work.
*/
#define DEBUG_NO_WRITE 1
#define DEBUG_QUEUES 2
@@ -35,7 +37,7 @@
#define DEBUG_RESET 1024
#define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
- DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE)
+ DEBUG_DMA|DEBUG_QUEUES)
/* DRIVER CONFIGURATION
*
@@ -123,8 +125,8 @@
#ifndef STRINGIFY
#define STRINGIFY(x) #x
#endif
-#define STR(x) STRINGIFY(x)
-#define NO_WRITE_STR STR(NO_WRITE)
+#define STRx(x) STRINGIFY(x)
+#define NO_WRITE_STR STRx(NO_WRITE)
#include <linux/config.h>
#include <linux/module.h>
@@ -142,6 +144,7 @@
#include <asm/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/ecard.h>
#include "../../scsi/scsi.h"
@@ -160,10 +163,6 @@
#error "Yippee! ABORT TAG is now defined! Remove this error!"
#endif
-#ifndef NO_IRQ
-#define NO_IRQ 255
-#endif
-
#ifdef CONFIG_SCSI_ACORNSCSI_LINK
#error SCSI2 LINKed commands not supported (yet)!
#endif
@@ -186,26 +185,7 @@
#define DMAC_BUFFER_SIZE 65536
#endif
-/*
- * This is used to dump the previous states of the SBIC
- */
-static struct status_entry {
- unsigned long when;
- unsigned char ssr;
- unsigned char ph;
- unsigned char irq;
- unsigned char unused;
-} status[9][16];
-static unsigned char status_ptr[9];
-
-#define ADD_STATUS(_q,_ssr,_ph,_irq) \
-({ \
- status[(_q)][status_ptr[(_q)]].when = jiffies; \
- status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \
- status[(_q)][status_ptr[(_q)]].ph = (_ph); \
- status[(_q)][status_ptr[(_q)]].irq = (_irq); \
- status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \
-})
+#define STATUS_BUFFER_TO_PRINT 24
unsigned int sdtr_period = SDTR_PERIOD;
unsigned int sdtr_size = SDTR_SIZE;
@@ -214,31 +194,31 @@ static struct proc_dir_entry proc_scsi_acornscsi = {
PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
};
-static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
-static int acornscsi_reconnect_finish (AS_Host *host);
-static void acornscsi_dma_cleanup (AS_Host *host);
-static void acornscsi_abortcmd (AS_Host *host, unsigned char tag);
+static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static int acornscsi_reconnect_finish(AS_Host *host);
+static void acornscsi_dma_cleanup(AS_Host *host);
+static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
/* ====================================================================================
* Miscellaneous
*/
static inline void
-sbic_arm_write (unsigned int io_port, int reg, int value)
+sbic_arm_write(unsigned int io_port, int reg, int value)
{
- outb_t (reg, io_port);
- outb_t (value, io_port + 4);
+ outb_t(reg, io_port);
+ outb_t(value, io_port + 4);
}
#define sbic_arm_writenext(io,val) \
- outb_t ((val), (io) + 4)
+ outb_t((val), (io) + 4)
static inline
-int sbic_arm_read (unsigned int io_port, int reg)
+int sbic_arm_read(unsigned int io_port, int reg)
{
if(reg == ASR)
return inl_t(io_port) & 255;
- outb_t (reg, io_port);
+ outb_t(reg, io_port);
return inl_t(io_port + 4) & 255;
}
@@ -247,129 +227,165 @@ int sbic_arm_read (unsigned int io_port, int reg)
#ifdef USE_DMAC
#define dmac_read(io_port,reg) \
- inb ((io_port) + (reg))
+ inb((io_port) + (reg))
#define dmac_write(io_port,reg,value) \
- ({ outb ((value), (io_port) + (reg)); })
+ ({ outb((value), (io_port) + (reg)); })
#define dmac_clearintr(io_port) \
- ({ outb (0, (io_port)); })
+ ({ outb(0, (io_port)); })
static inline
-unsigned int dmac_address (unsigned int io_port)
+unsigned int dmac_address(unsigned int io_port)
{
- return dmac_read (io_port, TXADRHI) << 16 |
- dmac_read (io_port, TXADRMD) << 8 |
- dmac_read (io_port, TXADRLO);
+ return dmac_read(io_port, TXADRHI) << 16 |
+ dmac_read(io_port, TXADRMD) << 8 |
+ dmac_read(io_port, TXADRLO);
}
static
-void acornscsi_dumpdma (AS_Host *host, char *where)
+void acornscsi_dumpdma(AS_Host *host, char *where)
{
unsigned int mode, addr, len;
- mode = dmac_read (host->dma.io_port, MODECON);
- addr = dmac_address (host->dma.io_port);
- len = dmac_read (host->dma.io_port, TXCNTHI) << 8 |
- dmac_read (host->dma.io_port, TXCNTLO);
+ mode = dmac_read(host->dma.io_port, MODECON);
+ addr = dmac_address(host->dma.io_port);
+ len = dmac_read(host->dma.io_port, TXCNTHI) << 8 |
+ dmac_read(host->dma.io_port, TXCNTLO);
- printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
+ printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
host->host->host_no, where,
mode, addr, (len + 1) & 0xffff,
- dmac_read (host->dma.io_port, MASKREG));
+ dmac_read(host->dma.io_port, MASKREG));
- printk ("DMA @%06x, ", host->dma.start_addr);
- printk ("BH @%p +%04x, ", host->scsi.SCp.ptr,
+ printk("DMA @%06x, ", host->dma.start_addr);
+ printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
host->scsi.SCp.this_residual);
- printk ("DT @+%04x ST @+%04x", host->dma.transferred,
+ printk("DT @+%04x ST @+%04x", host->dma.transferred,
host->scsi.SCp.scsi_xferred);
- printk ("\n");
+ printk("\n");
}
#endif
static
-unsigned long acornscsi_sbic_xfcount (AS_Host *host)
+unsigned long acornscsi_sbic_xfcount(AS_Host *host)
{
unsigned long length;
- length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16;
- length |= sbic_arm_readnext (host->scsi.io_port) << 8;
- length |= sbic_arm_readnext (host->scsi.io_port);
+ length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16;
+ length |= sbic_arm_readnext(host->scsi.io_port) << 8;
+ length |= sbic_arm_readnext(host->scsi.io_port);
return length;
}
-static
-int acornscsi_sbic_issuecmd (AS_Host *host, int command)
+static int
+acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
{
- int asr;
+ int asr;
- do {
- asr = sbic_arm_read (host->scsi.io_port, ASR);
- } while (asr & ASR_CIP);
+ do {
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+ if ((asr & stat_mask) == stat)
+ return 0;
+
+ udelay(1);
+ } while (--timeout);
+
+ printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
+
+ return -1;
+}
- sbic_arm_write (host->scsi.io_port, CMND, command);
+static
+int acornscsi_sbic_issuecmd(AS_Host *host, int command)
+{
+ if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
+ return -1;
+
+ sbic_arm_write(host->scsi.io_port, CMND, command);
return 0;
}
static void
-acornscsi_csdelay (unsigned int cs)
+acornscsi_csdelay(unsigned int cs)
{
unsigned long target_jiffies, flags;
target_jiffies = jiffies + 1 + cs * HZ / 100;
- save_flags (flags);
- sti ();
+ save_flags(flags);
+ sti();
while (time_before(jiffies, target_jiffies)) barrier();
- restore_flags (flags);
+ restore_flags(flags);
}
static
-void acornscsi_resetcard (AS_Host *host)
+void acornscsi_resetcard(AS_Host *host)
{
- unsigned int i;
+ unsigned int i, timeout;
/* assert reset line */
host->card.page_reg = 0x80;
- outb (host->card.page_reg, host->card.io_page);
+ outb(host->card.page_reg, host->card.io_page);
/* wait 3 cs. SCSI standard says 25ms. */
- acornscsi_csdelay (3);
+ acornscsi_csdelay(3);
host->card.page_reg = 0;
- outb (host->card.page_reg, host->card.io_page);
+ outb(host->card.page_reg, host->card.io_page);
/*
* Should get a reset from the card
*/
- while (!(inb (host->card.io_intr) & 8));
- sbic_arm_read (host->scsi.io_port, ASR);
- sbic_arm_read (host->scsi.io_port, SSR);
+ timeout = 1000;
+ do {
+ if (inb(host->card.io_intr) & 8)
+ break;
+ udelay(1);
+ } while (--timeout);
+
+ if (timeout == 0)
+ printk("scsi%d: timeout while resetting card\n",
+ host->host->host_no);
+
+ sbic_arm_read(host->scsi.io_port, ASR);
+ sbic_arm_read(host->scsi.io_port, SSR);
/* setup sbic - WD33C93A */
- sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
- sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET);
+ sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+ sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
/*
* Command should cause a reset interrupt
*/
- while (!(inb (host->card.io_intr) & 8));
- sbic_arm_read (host->scsi.io_port, ASR);
- if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01)
- printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+ timeout = 1000;
+ do {
+ if (inb(host->card.io_intr) & 8)
+ break;
+ udelay(1);
+ } while (--timeout);
+
+ if (timeout == 0)
+ printk("scsi%d: timeout while resetting card\n",
host->host->host_no);
- sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
- sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
- sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
- sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+ sbic_arm_read(host->scsi.io_port, ASR);
+ if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01)
+ printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+ host->host->host_no);
+
+ sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+ sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+ sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+ sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
host->card.page_reg = 0x40;
- outb (host->card.page_reg, host->card.io_page);
+ outb(host->card.page_reg, host->card.io_page);
/* setup dmac - uPC71071 */
dmac_write(host->dma.io_port, INIT, 0);
@@ -391,7 +407,7 @@ void acornscsi_resetcard (AS_Host *host)
}
/* wait 25 cs. SCSI standard says 250ms. */
- acornscsi_csdelay (25);
+ acornscsi_csdelay(25);
}
/*=============================================================================================
@@ -461,80 +477,101 @@ static char *acornscsi_interruptcode[] = {
};
static
-void print_scsi_status (unsigned int ssr)
+void print_scsi_status(unsigned int ssr)
{
if (acornscsi_map[ssr] != -1)
- printk ("%s:%s",
+ printk("%s:%s",
acornscsi_interrupttype[(ssr >> 4)],
acornscsi_interruptcode[acornscsi_map[ssr]]);
else
- printk ("%X:%X", ssr >> 4, ssr & 0x0f);
+ printk("%X:%X", ssr >> 4, ssr & 0x0f);
}
#endif
static
-void print_sbic_status (int asr, int ssr, int cmdphase)
+void print_sbic_status(int asr, int ssr, int cmdphase)
{
#ifdef CONFIG_ACORNSCSI_CONSTANTS
- printk ("sbic: %c%c%c%c%c%c ",
+ printk("sbic: %c%c%c%c%c%c ",
asr & ASR_INT ? 'I' : 'i',
asr & ASR_LCI ? 'L' : 'l',
asr & ASR_BSY ? 'B' : 'b',
asr & ASR_CIP ? 'C' : 'c',
asr & ASR_PE ? 'P' : 'p',
asr & ASR_DBR ? 'D' : 'd');
- printk ("scsi: ");
- print_scsi_status (ssr);
- printk (" ph %02X\n", cmdphase);
+ printk("scsi: ");
+ print_scsi_status(ssr);
+ printk(" ph %02X\n", cmdphase);
#else
- printk ("sbic: %02X scsi: %X:%X ph: %02X\n",
+ printk("sbic: %02X scsi: %X:%X ph: %02X\n",
asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
#endif
}
-static
-void acornscsi_dumplog (AS_Host *host, int target)
+static void
+acornscsi_dumplogline(AS_Host *host, int target, int line)
{
- unsigned int prev;
- do {
- signed int statptr;
-
- printk ("%c:", target == 8 ? 'H' : ('0' + target));
- statptr = status_ptr[target] - 10;
+ unsigned long prev;
+ signed int ptr;
+
+ ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
+ if (ptr < 0)
+ ptr += STATUS_BUFFER_SIZE;
+
+ printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
+ line == 0 ? "ph" : line == 1 ? "ssr" : "int");
+
+ prev = host->status[target][ptr].when;
+
+ for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+ unsigned long time_diff;
+
+ if (!host->status[target][ptr].when)
+ continue;
+
+ switch (line) {
+ case 0:
+ printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
+ host->status[target][ptr].ph);
+ break;
+
+ case 1:
+ printk(" %02X", host->status[target][ptr].ssr);
+ break;
+
+ case 2:
+ time_diff = host->status[target][ptr].when - prev;
+ prev = host->status[target][ptr].when;
+ if (time_diff == 0)
+ printk("==^");
+ else if (time_diff >= 100)
+ printk(" ");
+ else
+ printk(" %02ld", time_diff);
+ break;
+ }
+ }
- if (statptr < 0)
- statptr += 16;
+ printk("\n");
+}
- prev = status[target][statptr].when;
+static
+void acornscsi_dumplog(AS_Host *host, int target)
+{
+ do {
+ acornscsi_dumplogline(host, target, 0);
+ acornscsi_dumplogline(host, target, 1);
+ acornscsi_dumplogline(host, target, 2);
- for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) {
- if (status[target][statptr].when) {
-#ifdef CONFIG_ACORNSCSI_CONSTANTS
- printk ("%c%02X:S=",
- status[target][statptr].irq ? '-' : ' ',
- status[target][statptr].ph);
- print_scsi_status (status[target][statptr].ssr);
-#else
- printk ("%c%02X:%02X",
- status[target][statptr].irq ? '-' : ' ',
- status[target][statptr].ph,
- status[target][statptr].ssr);
-#endif
- printk ("+%02ld",
- (status[target][statptr].when - prev) < 100 ?
- (status[target][statptr].when - prev) : 99);
- prev = status[target][statptr].when;
- }
- }
- printk ("\n");
if (target == 8)
break;
+
target = 8;
} while (1);
}
static
-char acornscsi_target (AS_Host *host)
+char acornscsi_target(AS_Host *host)
{
if (host->SCpnt)
return '0' + host->SCpnt->target;
@@ -542,7 +579,7 @@ char acornscsi_target (AS_Host *host)
}
/*
- * Prototype: cmdtype_t acornscsi_cmdtype (int command)
+ * Prototype: cmdtype_t acornscsi_cmdtype(int command)
* Purpose : differentiate READ from WRITE from other commands
* Params : command - command to interpret
* Returns : CMD_READ - command reads data,
@@ -550,7 +587,7 @@ char acornscsi_target (AS_Host *host)
* CMD_MISC - everything else
*/
static inline
-cmdtype_t acornscsi_cmdtype (int command)
+cmdtype_t acornscsi_cmdtype(int command)
{
switch (command) {
case WRITE_6: case WRITE_10: case WRITE_12:
@@ -563,7 +600,7 @@ cmdtype_t acornscsi_cmdtype (int command)
}
/*
- * Prototype: int acornscsi_datadirection (int command)
+ * Prototype: int acornscsi_datadirection(int command)
* Purpose : differentiate between commands that have a DATA IN phase
* and a DATA OUT phase
* Params : command - command to interpret
@@ -571,7 +608,7 @@ cmdtype_t acornscsi_cmdtype (int command)
* DATADIR_IN - data in phase expected
*/
static
-datadir_t acornscsi_datadirection (int command)
+datadir_t acornscsi_datadirection(int command)
{
switch (command) {
case CHANGE_DEFINITION: case COMPARE: case COPY:
@@ -605,13 +642,13 @@ static struct sync_xfer_tbl {
};
/*
- * Prototype: int acornscsi_getperiod (unsigned char syncxfer)
+ * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
* Purpose : period for the synchronous transfer setting
* Params : syncxfer SYNCXFER register value
* Returns : period in ns.
*/
static
-int acornscsi_getperiod (unsigned char syncxfer)
+int acornscsi_getperiod(unsigned char syncxfer)
{
int i;
@@ -626,14 +663,14 @@ int acornscsi_getperiod (unsigned char syncxfer)
}
/*
- * Prototype: int round_period (unsigned int period)
+ * Prototype: int round_period(unsigned int period)
* Purpose : return index into above table for a required REQ period
* Params : period - time (ns) for REQ
* Returns : table index
* Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
*/
static inline
-int round_period (unsigned int period)
+int round_period(unsigned int period)
{
int i;
@@ -646,7 +683,7 @@ int round_period (unsigned int period)
}
/*
- * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
+ * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
* Purpose : calculate value for 33c93s SYNC register
* Params : period - time (ns) for REQ
* offset - offset in bytes between REQ/ACK
@@ -654,7 +691,7 @@ int round_period (unsigned int period)
* Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
*/
static
-unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
+unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
{
return sync_xfer_table[round_period(period)].reg_value |
((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
@@ -664,14 +701,14 @@ unsigned char calc_sync_xfer (unsigned int period, unsigned int offset)
* Command functions
*/
/*
- * Function: acornscsi_kick (AS_Host *host)
+ * Function: acornscsi_kick(AS_Host *host)
* Purpose : kick next command to interface
* Params : host - host to send command to
* Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
* Notes : interrupts are always disabled!
*/
static
-intr_ret_t acornscsi_kick (AS_Host *host)
+intr_ret_t acornscsi_kick(AS_Host *host)
{
int from_queue = 0;
Scsi_Cmnd *SCpnt;
@@ -682,7 +719,7 @@ intr_ret_t acornscsi_kick (AS_Host *host)
/* retrieve next command */
if (!SCpnt) {
- SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns);
+ SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
if (!SCpnt)
return INTR_IDLE;
@@ -690,11 +727,11 @@ intr_ret_t acornscsi_kick (AS_Host *host)
}
if (host->scsi.disconnectable && host->SCpnt) {
- queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt);
+ queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
host->scsi.disconnectable = 0;
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n",
- host->host->host_no, acornscsi_target (host)));
+ DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
+ host->host->host_no, acornscsi_target(host)));
#endif
host->SCpnt = NULL;
}
@@ -703,9 +740,9 @@ intr_ret_t acornscsi_kick (AS_Host *host)
* If we have an interrupt pending, then we may have been reselected.
* In this case, we don't want to write to the registers
*/
- if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
- sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target);
- sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN);
+ if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
+ sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target);
+ sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN);
}
/*
@@ -717,9 +754,10 @@ intr_ret_t acornscsi_kick (AS_Host *host)
host->scsi.SCp = SCpnt->SCp;
host->dma.xfer_setup = 0;
host->dma.xfer_required = 0;
+ host->dma.xfer_done = 0;
#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
- DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n",
+ DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
host->host->host_no, '0' + SCpnt->target,
SCpnt->cmnd[0]));
#endif
@@ -736,11 +774,11 @@ intr_ret_t acornscsi_kick (AS_Host *host)
SCpnt->tag = SCpnt->device->current_tag;
} else
#endif
- set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+ set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
host->stats.removes += 1;
- switch (acornscsi_cmdtype (SCpnt->cmnd[0])) {
+ switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
case CMD_WRITE:
host->stats.writes += 1;
break;
@@ -757,25 +795,25 @@ intr_ret_t acornscsi_kick (AS_Host *host)
}
/*
- * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
* Purpose : complete processing for command
* Params : host - interface that completed
* result - driver byte of result
*/
static
-void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
{
Scsi_Cmnd *SCpnt = *SCpntp;
/* clean up */
- sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+ sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
host->stats.fins += 1;
if (SCpnt) {
*SCpntp = NULL;
- acornscsi_dma_cleanup (host);
+ acornscsi_dma_cleanup(host);
SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
@@ -787,35 +825,63 @@ void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
* It doesn't appear to be set to something meaningful by the higher
* levels all the time.
*/
- if (host->scsi.SCp.ptr && result == DID_OK &&
- acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) {
- switch (status_byte (SCpnt->result)) {
- case CHECK_CONDITION:
- case COMMAND_TERMINATED:
- case BUSY:
- case QUEUE_FULL:
- case RESERVATION_CONFLICT:
- break;
-
- default:
- printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
- host->host->host_no, SCpnt->result);
- print_command (SCpnt->cmnd);
- acornscsi_dumpdma (host, "done");
- acornscsi_dumplog (host, SCpnt->target);
- SCpnt->result &= 0xffff;
- SCpnt->result |= DID_ERROR << 16;
- }
+ if (result == DID_OK) {
+ int xfer_warn = 0;
+
+ if (SCpnt->underflow == 0) {
+ if (host->scsi.SCp.ptr &&
+ acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
+ xfer_warn = 1;
+ } else {
+ if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
+ host->scsi.SCp.scsi_xferred != host->dma.transferred)
+ xfer_warn = 1;
+ }
+
+ /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
+ * Targets which break data transfers into multiple
+ * connections shall end each successful connection
+ * (except possibly the last) with a SAVE DATA
+ * POINTER - DISCONNECT message sequence.
+ *
+ * This makes it difficult to ensure that a transfer has
+ * completed. If we reach the end of a transfer during
+ * the command, then we can only have finished the transfer.
+ * therefore, if we seem to have some data remaining, this
+ * is not a problem.
+ */
+ if (host->dma.xfer_done)
+ xfer_warn = 0;
+
+ if (xfer_warn) {
+ switch (status_byte(SCpnt->result)) {
+ case CHECK_CONDITION:
+ case COMMAND_TERMINATED:
+ case BUSY:
+ case QUEUE_FULL:
+ case RESERVATION_CONFLICT:
+ break;
+
+ default:
+ printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
+ host->host->host_no, SCpnt->result);
+ print_command(SCpnt->cmnd);
+ acornscsi_dumpdma(host, "done");
+ acornscsi_dumplog(host, SCpnt->target);
+ SCpnt->result &= 0xffff;
+ SCpnt->result |= DID_ERROR << 16;
+ }
+ }
}
if (!SCpnt->scsi_done)
- panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
+ panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
- clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+ clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
- SCpnt->scsi_done (SCpnt);
+ SCpnt->scsi_done(SCpnt);
} else
- printk ("scsi%d: null command in acornscsi_done", host->host->host_no);
+ printk("scsi%d: null command in acornscsi_done", host->host->host_no);
host->scsi.phase = PHASE_IDLE;
}
@@ -828,7 +894,7 @@ void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
* Notes : this will only be one SG entry or less
*/
static
-void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
+void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
{
SCp->ptr += length;
SCp->this_residual -= length;
@@ -839,13 +905,15 @@ void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int le
SCp->buffers_residual--;
SCp->ptr = (char *)SCp->buffer->address;
SCp->this_residual = SCp->buffer->length;
- } else
+ } else {
SCp->ptr = NULL;
+ host->dma.xfer_done = 1;
+ }
}
}
/*
- * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr,
+ * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
* unsigned int start_addr, unsigned int length)
* Purpose : read data from DMA RAM
* Params : host - host to transfer from
@@ -855,16 +923,16 @@ void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int le
* Notes : this will only be one SG entry or less
*/
static
-void acornscsi_data_read (AS_Host *host, char *ptr,
+void acornscsi_data_read(AS_Host *host, char *ptr,
unsigned int start_addr, unsigned int length)
{
- extern void __acornscsi_in (int port, char *buf, int len);
+ extern void __acornscsi_in(int port, char *buf, int len);
unsigned int page, offset, len = length;
page = (start_addr >> 12);
offset = start_addr & ((1 << 12) - 1);
- outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+ outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
while (len > 0) {
unsigned int this_len;
@@ -874,7 +942,7 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
else
this_len = len;
- __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len);
+ __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
offset += this_len;
ptr += this_len;
@@ -883,14 +951,14 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
if (offset == (1 << 12)) {
offset = 0;
page ++;
- outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+ outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
}
}
- outb (host->card.page_reg, host->card.io_page);
+ outb(host->card.page_reg, host->card.io_page);
}
/*
- * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr,
+ * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
* unsigned int start_addr, unsigned int length)
* Purpose : write data to DMA RAM
* Params : host - host to transfer from
@@ -900,16 +968,16 @@ void acornscsi_data_read (AS_Host *host, char *ptr,
* Notes : this will only be one SG entry or less
*/
static
-void acornscsi_data_write (AS_Host *host, char *ptr,
+void acornscsi_data_write(AS_Host *host, char *ptr,
unsigned int start_addr, unsigned int length)
{
- extern void __acornscsi_out (int port, char *buf, int len);
+ extern void __acornscsi_out(int port, char *buf, int len);
unsigned int page, offset, len = length;
page = (start_addr >> 12);
offset = start_addr & ((1 << 12) - 1);
- outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+ outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
while (len > 0) {
unsigned int this_len;
@@ -919,7 +987,7 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
else
this_len = len;
- __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len);
+ __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
offset += this_len;
ptr += this_len;
@@ -928,10 +996,10 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
if (offset == (1 << 12)) {
offset = 0;
page ++;
- outb ((page & 0x3f) | host->card.page_reg, host->card.io_page);
+ outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
}
}
- outb (host->card.page_reg, host->card.io_page);
+ outb(host->card.page_reg, host->card.io_page);
}
/* =========================================================================================
@@ -939,25 +1007,25 @@ void acornscsi_data_write (AS_Host *host, char *ptr,
*/
#ifdef USE_DMAC
/*
- * Prototype: void acornscsi_dmastop (AS_Host *host)
+ * Prototype: void acornscsi_dmastop(AS_Host *host)
* Purpose : stop all DMA
* Params : host - host on which to stop DMA
* Notes : This is called when leaving DATA IN/OUT phase,
* or when interface is RESET
*/
static inline
-void acornscsi_dma_stop (AS_Host *host)
+void acornscsi_dma_stop(AS_Host *host)
{
- dmac_write (host->dma.io_port, MASKREG, MASK_ON);
- dmac_clearintr (host->dma.io_intr_clear);
+ dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+ dmac_clearintr(host->dma.io_intr_clear);
#if (DEBUG & DEBUG_DMA)
- DBG(host->SCpnt, acornscsi_dumpdma (host, "stop"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
#endif
}
/*
- * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
+ * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
* Purpose : setup DMA controller for data transfer
* Params : host - host to setup
* direction - data transfer direction
@@ -965,19 +1033,19 @@ void acornscsi_dma_stop (AS_Host *host)
* while we're in a DATA I/O phase
*/
static
-void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
+void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
{
unsigned int address, length, mode;
host->dma.direction = direction;
- dmac_write (host->dma.io_port, MASKREG, MASK_ON);
+ dmac_write(host->dma.io_port, MASKREG, MASK_ON);
if (direction == DMA_OUT) {
#if (DEBUG & DEBUG_NO_WRITE)
if (NO_WRITE & (1 << host->SCpnt->target)) {
- printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
- host->host->host_no, acornscsi_target (host));
+ printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
+ host->host->host_no, acornscsi_target(host));
return;
}
#endif
@@ -988,7 +1056,7 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
/*
* Allocate some buffer space, limited to half the buffer size
*/
- length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+ length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
if (length) {
host->dma.start_addr = address = host->dma.free_addr;
host->dma.free_addr = (host->dma.free_addr + length) &
@@ -998,27 +1066,27 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
* Transfer data to DMA memory
*/
if (direction == DMA_OUT)
- acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr,
+ acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
length);
length -= 1;
- dmac_write (host->dma.io_port, TXCNTLO, length);
- dmac_write (host->dma.io_port, TXCNTHI, length >> 8);
- dmac_write (host->dma.io_port, TXADRLO, address);
- dmac_write (host->dma.io_port, TXADRMD, address >> 8);
- dmac_write (host->dma.io_port, TXADRHI, 0);
- dmac_write (host->dma.io_port, MODECON, mode);
- dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+ dmac_write(host->dma.io_port, TXCNTLO, length);
+ dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+ dmac_write(host->dma.io_port, TXADRLO, address);
+ dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+ dmac_write(host->dma.io_port, TXADRHI, 0);
+ dmac_write(host->dma.io_port, MODECON, mode);
+ dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
#if (DEBUG & DEBUG_DMA)
- DBG(host->SCpnt, acornscsi_dumpdma (host, "strt"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
#endif
host->dma.xfer_setup = 1;
}
}
/*
- * Function: void acornscsi_dma_cleanup (AS_Host *host)
+ * Function: void acornscsi_dma_cleanup(AS_Host *host)
* Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
* Params : host - host to finish
* Notes : This is called when a command is:
@@ -1026,10 +1094,10 @@ void acornscsi_dma_setup (AS_Host *host, dmadir_t direction)
* : This must not return until all transfers are completed.
*/
static
-void acornscsi_dma_cleanup (AS_Host *host)
+void acornscsi_dma_cleanup(AS_Host *host)
{
- dmac_write (host->dma.io_port, MASKREG, MASK_ON);
- dmac_clearintr (host->dma.io_intr_clear);
+ dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+ dmac_clearintr(host->dma.io_intr_clear);
/*
* Check for a pending transfer
@@ -1037,7 +1105,7 @@ void acornscsi_dma_cleanup (AS_Host *host)
if (host->dma.xfer_required) {
host->dma.xfer_required = 0;
if (host->dma.direction == DMA_IN)
- acornscsi_data_read (host, host->dma.xfer_ptr,
+ acornscsi_data_read(host, host->dma.xfer_ptr,
host->dma.xfer_start, host->dma.xfer_length);
}
@@ -1056,17 +1124,17 @@ void acornscsi_dma_cleanup (AS_Host *host)
/*
* Calculate number of bytes transferred from DMA.
*/
- transferred = dmac_address (host->dma.io_port) - host->dma.start_addr;
+ transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
host->dma.transferred += transferred;
if (host->dma.direction == DMA_IN)
- acornscsi_data_read (host, host->scsi.SCp.ptr,
+ acornscsi_data_read(host, host->scsi.SCp.ptr,
host->dma.start_addr, transferred);
/*
* Update SCSI pointers
*/
- acornscsi_data_updateptr (host, &host->scsi.SCp, transferred);
+ acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
#if (DEBUG & DEBUG_DMA)
DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
#endif
@@ -1074,7 +1142,7 @@ void acornscsi_dma_cleanup (AS_Host *host)
}
/*
- * Function: void acornscsi_dmacintr (AS_Host *host)
+ * Function: void acornscsi_dmacintr(AS_Host *host)
* Purpose : handle interrupts from DMAC device
* Params : host - host to process
* Notes : If reading, we schedule the read to main memory &
@@ -1084,21 +1152,21 @@ void acornscsi_dma_cleanup (AS_Host *host)
* : Called whenever DMAC finished it's current transfer.
*/
static
-void acornscsi_dma_intr (AS_Host *host)
+void acornscsi_dma_intr(AS_Host *host)
{
unsigned int address, length, transferred;
#if (DEBUG & DEBUG_DMA)
- DBG(host->SCpnt, acornscsi_dumpdma (host, "inti"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
#endif
- dmac_write (host->dma.io_port, MASKREG, MASK_ON);
- dmac_clearintr (host->dma.io_intr_clear);
+ dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+ dmac_clearintr(host->dma.io_intr_clear);
/*
* Calculate amount transferred via DMA
*/
- transferred = dmac_address (host->dma.io_port) - host->dma.start_addr;
+ transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
host->dma.transferred += transferred;
/*
@@ -1111,12 +1179,12 @@ void acornscsi_dma_intr (AS_Host *host)
host->dma.xfer_required = 1;
}
- acornscsi_data_updateptr (host, &host->scsi.SCp, transferred);
+ acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
/*
* Allocate some buffer space, limited to half the on-board RAM size
*/
- length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+ length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
if (length) {
host->dma.start_addr = address = host->dma.free_addr;
host->dma.free_addr = (host->dma.free_addr + length) &
@@ -1126,19 +1194,19 @@ void acornscsi_dma_intr (AS_Host *host)
* Transfer data to DMA memory
*/
if (host->dma.direction == DMA_OUT)
- acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr,
+ acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
length);
length -= 1;
- dmac_write (host->dma.io_port, TXCNTLO, length);
- dmac_write (host->dma.io_port, TXCNTHI, length >> 8);
- dmac_write (host->dma.io_port, TXADRLO, address);
- dmac_write (host->dma.io_port, TXADRMD, address >> 8);
- dmac_write (host->dma.io_port, TXADRHI, 0);
- dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+ dmac_write(host->dma.io_port, TXCNTLO, length);
+ dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+ dmac_write(host->dma.io_port, TXADRLO, address);
+ dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+ dmac_write(host->dma.io_port, TXADRHI, 0);
+ dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
#if (DEBUG & DEBUG_DMA)
- DBG(host->SCpnt, acornscsi_dumpdma (host, "into"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
#endif
} else {
host->dma.xfer_setup = 0;
@@ -1149,48 +1217,48 @@ void acornscsi_dma_intr (AS_Host *host)
* attention condition. We continue giving one byte until
* the device recognises the attention.
*/
- if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) {
- acornscsi_abortcmd (host, host->SCpnt->tag);
-
- dmac_write (host->dma.io_port, TXCNTLO, 0);
- dmac_write (host->dma.io_port, TXCNTHI, 0);
- dmac_write (host->dma.io_port, TXADRLO, 0);
- dmac_write (host->dma.io_port, TXADRMD, 0);
- dmac_write (host->dma.io_port, TXADRHI, 0);
- dmac_write (host->dma.io_port, MASKREG, MASK_OFF);
+ if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) {
+ acornscsi_abortcmd(host, host->SCpnt->tag);
+
+ dmac_write(host->dma.io_port, TXCNTLO, 0);
+ dmac_write(host->dma.io_port, TXCNTHI, 0);
+ dmac_write(host->dma.io_port, TXADRLO, 0);
+ dmac_write(host->dma.io_port, TXADRMD, 0);
+ dmac_write(host->dma.io_port, TXADRHI, 0);
+ dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
}
#endif
}
}
/*
- * Function: void acornscsi_dma_xfer (AS_Host *host)
+ * Function: void acornscsi_dma_xfer(AS_Host *host)
* Purpose : transfer data between AcornSCSI and memory
* Params : host - host to process
*/
static
-void acornscsi_dma_xfer (AS_Host *host)
+void acornscsi_dma_xfer(AS_Host *host)
{
host->dma.xfer_required = 0;
if (host->dma.direction == DMA_IN)
- acornscsi_data_read (host, host->dma.xfer_ptr,
+ acornscsi_data_read(host, host->dma.xfer_ptr,
host->dma.xfer_start, host->dma.xfer_length);
}
/*
- * Function: void acornscsi_dma_adjust (AS_Host *host)
+ * Function: void acornscsi_dma_adjust(AS_Host *host)
* Purpose : adjust DMA pointers & count for bytes transfered to
* SBIC but not SCSI bus.
* Params : host - host to adjust DMA count for
*/
static
-void acornscsi_dma_adjust (AS_Host *host)
+void acornscsi_dma_adjust(AS_Host *host)
{
if (host->dma.xfer_setup) {
signed long transferred;
#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
- DBG(host->SCpnt, acornscsi_dumpdma (host, "adji"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
#endif
/*
* Calculate correct DMA address - DMA is ahead of SCSI bus while
@@ -1205,17 +1273,17 @@ void acornscsi_dma_adjust (AS_Host *host)
*/
transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
if (transferred < 0)
- printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
- host->host->host_no, acornscsi_target (host), transferred);
+ printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
+ host->host->host_no, acornscsi_target(host), transferred);
else if (transferred == 0)
host->dma.xfer_setup = 0;
else {
transferred += host->dma.start_addr;
- dmac_write (host->dma.io_port, TXADRLO, transferred);
- dmac_write (host->dma.io_port, TXADRMD, transferred >> 8);
- dmac_write (host->dma.io_port, TXADRHI, transferred >> 16);
+ dmac_write(host->dma.io_port, TXADRLO, transferred);
+ dmac_write(host->dma.io_port, TXADRMD, transferred >> 8);
+ dmac_write(host->dma.io_port, TXADRHI, transferred >> 16);
#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
- DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo"));
+ DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
#endif
}
}
@@ -1225,66 +1293,88 @@ void acornscsi_dma_adjust (AS_Host *host)
/* =========================================================================================
* Data I/O
*/
+static int
+acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
+{
+ unsigned int asr, timeout = max_timeout;
+ int my_ptr = *ptr;
+
+ while (my_ptr < len) {
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+ if (asr & ASR_DBR) {
+ timeout = max_timeout;
+
+ sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]);
+ } else if (asr & ASR_INT)
+ break;
+ else if (--timeout == 0)
+ break;
+ udelay(1);
+ }
+
+ *ptr = my_ptr;
+
+ return (timeout == 0) ? -1 : 0;
+}
+
/*
- * Function: void acornscsi_sendcommand (AS_Host *host)
+ * Function: void acornscsi_sendcommand(AS_Host *host)
* Purpose : send a command to a target
* Params : host - host which is connected to target
*/
-static
-void acornscsi_sendcommand (AS_Host *host)
+static void
+acornscsi_sendcommand(AS_Host *host)
{
Scsi_Cmnd *SCpnt = host->SCpnt;
- unsigned int asr;
- unsigned char *cmdptr, *cmdend;
-
- sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0);
- sbic_arm_writenext (host->scsi.io_port, 0);
- sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
-
- cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command;
- cmdend = SCpnt->cmnd + SCpnt->cmd_len;
-
- while (cmdptr < cmdend) {
- asr = sbic_arm_read (host->scsi.io_port, ASR);
- if (asr & ASR_DBR)
- sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++);
- else if (asr & ASR_INT)
- break;
- }
- if (cmdptr >= cmdend)
- host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd;
+
+ sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+ sbic_arm_writenext(host->scsi.io_port, 0);
+ sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
+
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+ if (acornscsi_write_pio(host, SCpnt->cmnd,
+ (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
+ printk("scsi%d: timeout while sending command\n", host->host->host_no);
+
host->scsi.phase = PHASE_COMMAND;
}
static
-void acornscsi_sendmessage (AS_Host *host)
+void acornscsi_sendmessage(AS_Host *host)
{
- unsigned int message_length = msgqueue_msglength (&host->scsi.msgs);
- int msgnr;
+ unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
+ unsigned int msgnr;
struct message *msg;
#if (DEBUG & DEBUG_MESSAGES)
- printk ("scsi%d.%c: sending message ",
- host->host->host_no, acornscsi_target (host));
+ printk("scsi%d.%c: sending message ",
+ host->host->host_no, acornscsi_target(host));
#endif
switch (message_length) {
case 0:
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
- sbic_arm_write (host->scsi.io_port, DATA, NOP);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+ acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
+
+ sbic_arm_write(host->scsi.io_port, DATA, NOP);
+
host->scsi.last_message = NOP;
#if (DEBUG & DEBUG_MESSAGES)
- printk ("NOP");
+ printk("NOP");
#endif
break;
case 1:
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
msg = msgqueue_getmsg(&host->scsi.msgs, 0);
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
- sbic_arm_write (host->scsi.io_port, DATA, msg->msg[0]);
+
+ acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
+
+ sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]);
+
host->scsi.last_message = msg->msg[0];
#if (DEBUG & DEBUG_MESSAGES)
print_msg(msg->msg);
@@ -1300,86 +1390,85 @@ void acornscsi_sendmessage (AS_Host *host)
* initiator. This provides an interlock so that the
* initiator can determine which message byte is rejected.
*/
- sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0);
- sbic_arm_writenext (host->scsi.io_port, 0);
- sbic_arm_writenext (host->scsi.io_port, message_length);
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
+ sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+ sbic_arm_writenext(host->scsi.io_port, 0);
+ sbic_arm_writenext(host->scsi.io_port, message_length);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
msgnr = 0;
while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
- unsigned int asr, i;
+ unsigned int i;
#if (DEBUG & DEBUG_MESSAGES)
- print_msg (msg);
+ print_msg(msg);
#endif
- for (i = 0; i < msg->length;) {
- asr = sbic_arm_read (host->scsi.io_port, ASR);
- if (asr & ASR_DBR)
- sbic_arm_write (host->scsi.io_port, DATA, msg->msg[i++]);
- if (asr & ASR_INT)
- break;
- }
+ i = 0;
+ if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
+ printk("scsi%d: timeout while sending message\n", host->host->host_no);
+
host->scsi.last_message = msg->msg[0];
if (msg->msg[0] == EXTENDED_MESSAGE)
host->scsi.last_message |= msg->msg[2] << 8;
- if (asr & ASR_INT)
+
+ if (i != msg->length)
break;
}
break;
}
#if (DEBUG & DEBUG_MESSAGES)
- printk ("\n");
+ printk("\n");
#endif
}
/*
- * Function: void acornscsi_readstatusbyte (AS_Host *host)
+ * Function: void acornscsi_readstatusbyte(AS_Host *host)
* Purpose : Read status byte from connected target
* Params : host - host connected to target
*/
static
-void acornscsi_readstatusbyte (AS_Host *host)
+void acornscsi_readstatusbyte(AS_Host *host)
{
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT);
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
-
- host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
+ acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
+ host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA);
}
/*
- * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host)
+ * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
* Purpose : Read one message byte from connected target
* Params : host - host connected to target
*/
static
-unsigned char acornscsi_readmessagebyte (AS_Host *host)
+unsigned char acornscsi_readmessagebyte(AS_Host *host)
{
unsigned char message;
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT);
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+ acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
- message = sbic_arm_read (host->scsi.io_port, DATA);
+ message = sbic_arm_read(host->scsi.io_port, DATA);
/* wait for MSGIN-XFER-PAUSED */
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0);
- sbic_arm_read (host->scsi.io_port, SSR);
+ acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
+
+ sbic_arm_read(host->scsi.io_port, SSR);
return message;
}
/*
- * Function: void acornscsi_message (AS_Host *host)
+ * Function: void acornscsi_message(AS_Host *host)
* Purpose : Read complete message from connected target & action message
* Params : host - host connected to target
*/
static
-void acornscsi_message (AS_Host *host)
+void acornscsi_message(AS_Host *host)
{
unsigned char message[16];
unsigned int msgidx = 0, msglen = 1;
do {
- message[msgidx] = acornscsi_readmessagebyte (host);
+ message[msgidx] = acornscsi_readmessagebyte(host);
switch (msgidx) {
case 0:
@@ -1395,17 +1484,17 @@ void acornscsi_message (AS_Host *host)
}
msgidx += 1;
if (msgidx < msglen) {
- acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+ acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
/* wait for next msg-in */
- while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0);
- sbic_arm_read (host->scsi.io_port, SSR);
+ acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
+ sbic_arm_read(host->scsi.io_port, SSR);
}
} while (msgidx < msglen);
#if (DEBUG & DEBUG_MESSAGES)
printk("scsi%d.%c: message in: ",
- host->host->host_no, acornscsi_target (host));
+ host->host->host_no, acornscsi_target(host));
print_msg(message);
printk("\n");
#endif
@@ -1419,7 +1508,7 @@ void acornscsi_message (AS_Host *host)
*/
if (message[0] == SIMPLE_QUEUE_TAG)
host->scsi.reconnected.tag = message[1];
- if (acornscsi_reconnect_finish (host))
+ if (acornscsi_reconnect_finish(host))
host->scsi.phase = PHASE_MSGIN;
}
@@ -1429,7 +1518,7 @@ void acornscsi_message (AS_Host *host)
case COMMAND_COMPLETE:
if (host->scsi.phase != PHASE_STATUSIN) {
printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
- host->host->host_no, acornscsi_target (host));
+ host->host->host_no, acornscsi_target(host));
acornscsi_dumplog(host, host->SCpnt->target);
}
host->scsi.phase = PHASE_DONE;
@@ -1443,7 +1532,7 @@ void acornscsi_message (AS_Host *host)
* direct the initiator to copy the active data pointer to
* the saved data pointer for the current I/O process.
*/
- acornscsi_dma_cleanup (host);
+ acornscsi_dma_cleanup(host);
host->SCpnt->SCp = host->scsi.SCp;
host->SCpnt->SCp.sent_command = 0;
host->scsi.phase = PHASE_MSGIN;
@@ -1459,7 +1548,7 @@ void acornscsi_message (AS_Host *host)
* status pointers shall be restored to the beginning of
* the present command and status areas.'
*/
- acornscsi_dma_cleanup (host);
+ acornscsi_dma_cleanup(host);
host->scsi.SCp = host->SCpnt->SCp;
host->scsi.phase = PHASE_MSGIN;
break;
@@ -1474,7 +1563,7 @@ void acornscsi_message (AS_Host *host)
* message. When reconnection is completed, the most recent
* saved pointer values are restored.'
*/
- acornscsi_dma_cleanup (host);
+ acornscsi_dma_cleanup(host);
host->scsi.phase = PHASE_DISCONNECT;
break;
@@ -1493,8 +1582,8 @@ void acornscsi_message (AS_Host *host)
/*
* If we have any messages waiting to go out, then assert ATN now
*/
- if (msgqueue_msglength (&host->scsi.msgs))
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
+ if (msgqueue_msglength(&host->scsi.msgs))
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
switch (host->scsi.last_message) {
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
@@ -1507,21 +1596,21 @@ void acornscsi_message (AS_Host *host)
* message is received, it shall respond with a MESSAGE REJECT
* message and accept the I/O process as if it were untagged.
*/
- printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
- host->host->host_no, acornscsi_target (host));
+ printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
+ host->host->host_no, acornscsi_target(host));
host->SCpnt->device->tagged_queue = 0;
- set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
+ set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
break;
#endif
case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
/*
* Target can't handle synchronous transfers
*/
- printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
- host->host->host_no, acornscsi_target (host));
+ printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
+ host->host->host_no, acornscsi_target(host));
host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA;
host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS;
- sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+ sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
break;
default:
@@ -1535,8 +1624,8 @@ void acornscsi_message (AS_Host *host)
case SIMPLE_QUEUE_TAG:
/* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */
- printk ("scsi%d.%c: reconnect queue tag %02X\n",
- host->host->host_no, acornscsi_target (host),
+ printk("scsi%d.%c: reconnect queue tag %02X\n",
+ host->host->host_no, acornscsi_target(host),
message[1]);
break;
@@ -1552,26 +1641,26 @@ void acornscsi_message (AS_Host *host)
* and the target retries fail, then we fallback to asynchronous mode
*/
host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED;
- printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
+ printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
host->host->host_no, acornscsi_target(host),
message[4], message[3] * 4);
host->device[host->SCpnt->target].sync_xfer =
- calc_sync_xfer (message[3] * 4, message[4]);
+ calc_sync_xfer(message[3] * 4, message[4]);
} else {
unsigned char period, length;
/*
* Target requested synchronous transfers. The agreement is only
* to be in operation AFTER the target leaves message out phase.
*/
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
- period = max (message[3], sdtr_period / 4);
- length = min (message[4], sdtr_size);
- msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+ period = max(message[3], sdtr_period / 4);
+ length = min(message[4], sdtr_size);
+ msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
EXTENDED_SDTR, period, length);
host->device[host->SCpnt->target].sync_xfer =
- calc_sync_xfer (period * 4, length);
+ calc_sync_xfer(period * 4, length);
}
- sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+ sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
break;
#else
/* We do not accept synchronous transfers. Respond with a
@@ -1584,9 +1673,9 @@ void acornscsi_message (AS_Host *host)
* to a wide data transfer request.
*/
default:
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
- msgqueue_flush (&host->scsi.msgs);
- msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT);
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+ msgqueue_flush(&host->scsi.msgs);
+ msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
break;
}
break;
@@ -1607,19 +1696,19 @@ void acornscsi_message (AS_Host *host)
* if there are more linked commands available.
*/
if (!host->SCpnt->next_link) {
- printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
- instance->host_no, acornscsi_target (host), host->SCpnt->tag);
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
- msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
+ printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
+ instance->host_no, acornscsi_target(host), host->SCpnt->tag);
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+ msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
} else {
Scsi_Cmnd *SCpnt = host->SCpnt;
- acornscsi_dma_cleanup (host);
+ acornscsi_dma_cleanup(host);
host->SCpnt = host->SCpnt->next_link;
host->SCpnt->tag = SCpnt->tag;
SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
- SCpnt->done (SCpnt);
+ SCpnt->done(SCpnt);
/* initialise host->SCpnt->SCp */
}
@@ -1628,42 +1717,42 @@ void acornscsi_message (AS_Host *host)
#endif
default: /* reject message */
- printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
- host->host->host_no, acornscsi_target (host),
+ printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
+ host->host->host_no, acornscsi_target(host),
message[0]);
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
- msgqueue_flush (&host->scsi.msgs);
- msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT);
+ acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+ msgqueue_flush(&host->scsi.msgs);
+ msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
host->scsi.phase = PHASE_MSGIN;
break;
}
- acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+ acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
}
/*
- * Function: int acornscsi_buildmessages (AS_Host *host)
+ * Function: int acornscsi_buildmessages(AS_Host *host)
* Purpose : build the connection messages for a host
* Params : host - host to add messages to
*/
static
-void acornscsi_buildmessages (AS_Host *host)
+void acornscsi_buildmessages(AS_Host *host)
{
#if 0
/* does the device need resetting? */
if (cmd_reset) {
- msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET);
+ msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
return;
}
#endif
- msgqueue_addmsg (&host->scsi.msgs, 1,
+ msgqueue_addmsg(&host->scsi.msgs, 1,
IDENTIFY(host->device[host->SCpnt->target].disconnect_ok,
host->SCpnt->lun));
#if 0
/* does the device need the current command aborted */
if (cmd_aborted) {
- acornscsi_abortcmd (host->SCpnt->tag);
+ acornscsi_abortcmd(host->SCpnt->tag);
return;
}
#endif
@@ -1678,14 +1767,14 @@ void acornscsi_buildmessages (AS_Host *host)
tag_type = HEAD_OF_QUEUE_TAG;
else
tag_type = SIMPLE_QUEUE_TAG;
- msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
+ msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
}
#endif
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) {
host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST;
- msgqueue_addmsg (&host->scsi.msgs, 5,
+ msgqueue_addmsg(&host->scsi.msgs, 5,
EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
sdtr_period / 4, sdtr_size);
}
@@ -1693,29 +1782,29 @@ void acornscsi_buildmessages (AS_Host *host)
}
/*
- * Function: int acornscsi_starttransfer (AS_Host *host)
+ * Function: int acornscsi_starttransfer(AS_Host *host)
* Purpose : transfer data to/from connected target
* Params : host - host to which target is connected
* Returns : 0 if failure
*/
static
-int acornscsi_starttransfer (AS_Host *host)
+int acornscsi_starttransfer(AS_Host *host)
{
int residual;
if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
- printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
- host->host->host_no, acornscsi_target (host));
+ printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
+ host->host->host_no, acornscsi_target(host));
return 0;
}
residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
- sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
- sbic_arm_writenext (host->scsi.io_port, residual >> 16);
- sbic_arm_writenext (host->scsi.io_port, residual >> 8);
- sbic_arm_writenext (host->scsi.io_port, residual);
- acornscsi_sbic_issuecmd (host, CMND_XFERINFO);
+ sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
+ sbic_arm_writenext(host->scsi.io_port, residual >> 16);
+ sbic_arm_writenext(host->scsi.io_port, residual >> 8);
+ sbic_arm_writenext(host->scsi.io_port, residual);
+ acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
return 1;
}
@@ -1723,7 +1812,7 @@ int acornscsi_starttransfer (AS_Host *host)
* Connection & Disconnection
*/
/*
- * Function : acornscsi_reconnect (AS_Host *host)
+ * Function : acornscsi_reconnect(AS_Host *host)
* Purpose : reconnect a previously disconnected command
* Params : host - host specific data
* Remarks : SCSI spec says:
@@ -1731,27 +1820,27 @@ int acornscsi_starttransfer (AS_Host *host)
* of saved pointers upon reconnection of the I/O process'
*/
static
-int acornscsi_reconnect (AS_Host *host)
+int acornscsi_reconnect(AS_Host *host)
{
unsigned int target, lun, ok = 0;
- target = sbic_arm_read (host->scsi.io_port, SOURCEID);
+ target = sbic_arm_read(host->scsi.io_port, SOURCEID);
if (!(target & 8))
- printk (KERN_ERR "scsi%d: invalid source id after reselection "
+ printk(KERN_ERR "scsi%d: invalid source id after reselection "
"- device fault?\n",
host->host->host_no);
target &= 7;
if (host->SCpnt && !host->scsi.disconnectable) {
- printk (KERN_ERR "scsi%d.%d: reconnected while command in "
+ printk(KERN_ERR "scsi%d.%d: reconnected while command in "
"progress to target %d?\n",
host->host->host_no, target, host->SCpnt->target);
host->SCpnt = NULL;
}
- lun = sbic_arm_read (host->scsi.io_port, DATA) & 7;
+ lun = sbic_arm_read(host->scsi.io_port, DATA) & 7;
host->scsi.reconnected.target = target;
host->scsi.reconnected.lun = lun;
@@ -1761,7 +1850,7 @@ int acornscsi_reconnect (AS_Host *host)
host->SCpnt->target == target && host->SCpnt->lun == lun)
ok = 1;
- if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun))
+ if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
ok = 1;
ADD_STATUS(target, 0x81, host->scsi.phase, 0);
@@ -1770,26 +1859,28 @@ int acornscsi_reconnect (AS_Host *host)
host->scsi.phase = PHASE_RECONNECTED;
} else {
/* this doesn't seem to work */
- printk (KERN_ERR "scsi%d.%c: reselected with no command "
+ printk(KERN_ERR "scsi%d.%c: reselected with no command "
"to reconnect with\n",
host->host->host_no, '0' + target);
- acornscsi_dumplog (host, target);
- acornscsi_sbic_issuecmd (host, CMND_ASSERTATN);
- msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
- host->scsi.phase = PHASE_ABORTED;
+ acornscsi_dumplog(host, target);
+ acornscsi_abortcmd(host, 0);
+ if (host->SCpnt) {
+ queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+ host->SCpnt = NULL;
+ }
}
- acornscsi_sbic_issuecmd (host, CMND_NEGATEACK);
+ acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
return !ok;
}
/*
- * Function: int acornscsi_reconect_finish (AS_Host *host)
+ * Function: int acornscsi_reconect_finish(AS_Host *host)
* Purpose : finish reconnecting a command
* Params : host - host to complete
* Returns : 0 if failed
*/
static
-int acornscsi_reconnect_finish (AS_Host *host)
+int acornscsi_reconnect_finish(AS_Host *host)
{
if (host->scsi.disconnectable && host->SCpnt) {
host->scsi.disconnectable = 0;
@@ -1797,45 +1888,44 @@ int acornscsi_reconnect_finish (AS_Host *host)
host->SCpnt->lun == host->scsi.reconnected.lun &&
host->SCpnt->tag == host->scsi.reconnected.tag) {
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- DBG(host->SCpnt, printk ("scsi%d.%c: reconnected",
- host->host->host_no, acornscsi_target (host)));
+ DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
+ host->host->host_no, acornscsi_target(host)));
#endif
} else {
- queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt);
+ queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- DBG(host->SCpnt, printk ("scsi%d.%c: had to move command "
+ DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
"to disconnected queue\n",
- host->host->host_no, acornscsi_target (host)));
+ host->host->host_no, acornscsi_target(host)));
#endif
host->SCpnt = NULL;
}
}
if (!host->SCpnt) {
- host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected,
+ host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
host->scsi.reconnected.target,
host->scsi.reconnected.lun,
host->scsi.reconnected.tag);
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- DBG(host->SCpnt, printk ("scsi%d.%c: had to get command",
- host->host->host_no, acornscsi_target (host)));
+ DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
+ host->host->host_no, acornscsi_target(host)));
#endif
}
- if (!host->SCpnt) {
- acornscsi_abortcmd (host, host->scsi.reconnected.tag);
- host->scsi.phase = PHASE_ABORTED;
- } else {
+ if (!host->SCpnt)
+ acornscsi_abortcmd(host, host->scsi.reconnected.tag);
+ else {
/*
* Restore data pointer from SAVED pointers.
*/
host->scsi.SCp = host->SCpnt->SCp;
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- printk (", data pointers: [%p, %X]",
+ printk(", data pointers: [%p, %X]",
host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
#endif
}
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
- printk ("\n");
+ printk("\n");
#endif
host->dma.transferred = host->scsi.SCp.scsi_xferred;
@@ -1844,47 +1934,48 @@ int acornscsi_reconnect_finish (AS_Host *host)
}
/*
- * Function: void acornscsi_disconnect_unexpected (AS_Host *host)
+ * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
* Purpose : handle an unexpected disconnect
* Params : host - host on which disconnect occurred
*/
static
-void acornscsi_disconnect_unexpected (AS_Host *host)
+void acornscsi_disconnect_unexpected(AS_Host *host)
{
- printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n",
- host->host->host_no, acornscsi_target (host));
+ printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
+ host->host->host_no, acornscsi_target(host));
#if (DEBUG & DEBUG_ABORT)
- acornscsi_dumplog (host, 8);
+ acornscsi_dumplog(host, 8);
#endif
- acornscsi_done (host, &host->SCpnt, DID_ABORT);
+ acornscsi_done(host, &host->SCpnt, DID_ERROR);
}
/*
- * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag)
+ * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
* Purpose : abort a currently executing command
* Params : host - host with connected command to abort
* tag - tag to abort
*/
static
-void acornscsi_abortcmd (AS_Host *host, unsigned char tag)
+void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
{
- sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN);
+ host->scsi.phase = PHASE_ABORTED;
+ sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN);
- msgqueue_flush (&host->scsi.msgs);
+ msgqueue_flush(&host->scsi.msgs);
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
if (tag)
- msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag);
+ msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
else
#endif
- msgqueue_addmsg (&host->scsi.msgs, 1, ABORT);
+ msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
}
/* ==========================================================================================
* Interrupt routines.
*/
/*
- * Function: int acornscsi_sbicintr (AS_Host *host)
+ * Function: int acornscsi_sbicintr(AS_Host *host)
* Purpose : handle interrupts from SCSI device
* Params : host - host to process
* Returns : INTR_PROCESS if expecting another SBIC interrupt
@@ -1892,15 +1983,15 @@ void acornscsi_abortcmd (AS_Host *host, unsigned char tag)
* INTR_NEXT_COMMAND if we have finished processing the command
*/
static
-intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
+intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
{
unsigned int asr, ssr;
- asr = sbic_arm_read (host->scsi.io_port, ASR);
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
if (!(asr & ASR_INT))
return INTR_IDLE;
- ssr = sbic_arm_read (host->scsi.io_port, SSR);
+ ssr = sbic_arm_read(host->scsi.io_port, SSR);
#if (DEBUG & DEBUG_PHASES)
print_sbic_status(asr, ssr, host->scsi.phase);
@@ -1913,23 +2004,23 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
switch (ssr) {
case 0x00: /* reset state - not advanced */
- printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
+ printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
host->host->host_no);
/* setup sbic - WD33C93A */
- sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
- sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET);
+ sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+ sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
return INTR_IDLE;
case 0x01: /* reset state - advanced */
- sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
- sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
- sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
- sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
- msgqueue_flush (&host->scsi.msgs);
+ sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+ sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+ sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+ sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+ msgqueue_flush(&host->scsi.msgs);
return INTR_IDLE;
case 0x41: /* unexpected disconnect aborted command */
- acornscsi_disconnect_unexpected (host);
+ acornscsi_disconnect_unexpected(host);
return INTR_NEXT_COMMAND;
}
@@ -1939,35 +2030,35 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
case 0x11: /* -> PHASE_CONNECTED */
/* BUS FREE -> SELECTION */
host->scsi.phase = PHASE_CONNECTED;
- msgqueue_flush (&host->scsi.msgs);
+ msgqueue_flush(&host->scsi.msgs);
host->dma.transferred = host->scsi.SCp.scsi_xferred;
/* 33C93 gives next interrupt indicating bus phase */
- asr = sbic_arm_read (host->scsi.io_port, ASR);
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
if (!(asr & ASR_INT))
break;
- ssr = sbic_arm_read (host->scsi.io_port, SSR);
+ ssr = sbic_arm_read(host->scsi.io_port, SSR);
ADD_STATUS(8, ssr, host->scsi.phase, 1);
ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1);
goto connected;
case 0x42: /* select timed out */
/* -> PHASE_IDLE */
- acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT);
+ acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
return INTR_NEXT_COMMAND;
case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */
/* BUS FREE -> RESELECTION */
host->origSCpnt = host->SCpnt;
host->SCpnt = NULL;
- msgqueue_flush (&host->scsi.msgs);
- acornscsi_reconnect (host);
+ msgqueue_flush(&host->scsi.msgs);
+ acornscsi_reconnect(host);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+ acornscsi_abortcmd(host, host->SCpnt->tag);
}
return INTR_PROCESSING;
@@ -1977,12 +2068,12 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
#ifdef NONSTANDARD
case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */
/* SELECTION -> COMMAND */
- acornscsi_sendcommand (host);
+ acornscsi_sendcommand(host);
break;
case 0x8b: /* -> PHASE_STATUS */
/* SELECTION -> STATUS */
- acornscsi_readstatusbyte (host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
#endif
@@ -1990,55 +2081,57 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
case 0x8e: /* -> PHASE_MSGOUT */
/* SELECTION ->MESSAGE OUT */
host->scsi.phase = PHASE_MSGOUT;
- acornscsi_buildmessages (host);
- acornscsi_sendmessage (host);
+ acornscsi_buildmessages(host);
+ acornscsi_sendmessage(host);
break;
/* these should not happen */
case 0x85: /* target disconnected */
- acornscsi_done (host, &host->SCpnt, DID_ERROR);
+ acornscsi_done(host, &host->SCpnt, DID_ERROR);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+ acornscsi_abortcmd(host, host->SCpnt->tag);
}
return INTR_PROCESSING;
case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */
/*
- * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase
+ * SCSI standard says that MESSAGE OUT phases can be followed by a
+ * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
*/
switch (ssr) {
- case 0x8a:
+ case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */
case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */
/* MESSAGE OUT -> COMMAND */
- acornscsi_sendcommand (host);
+ acornscsi_sendcommand(host);
break;
+ case 0x8b: /* -> PHASE_STATUS */
case 0x1b: /* -> PHASE_STATUS */
/* MESSAGE OUT -> STATUS */
- acornscsi_readstatusbyte (host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
case 0x8e: /* -> PHASE_MSGOUT */
/* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
- case 0x4f:
+ case 0x4f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */
case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */
/* MESSAGE OUT -> MESSAGE IN */
- acornscsi_message (host);
+ acornscsi_message(host);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2047,43 +2140,43 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
case 0x18: /* -> PHASE_DATAOUT */
/* COMMAND -> DATA OUT */
if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
- acornscsi_abortcmd (host, host->SCpnt->tag);
- acornscsi_dma_setup (host, DMA_OUT);
- if (!acornscsi_starttransfer (host))
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ acornscsi_abortcmd(host, host->SCpnt->tag);
+ acornscsi_dma_setup(host, DMA_OUT);
+ if (!acornscsi_starttransfer(host))
+ acornscsi_abortcmd(host, host->SCpnt->tag);
host->scsi.phase = PHASE_DATAOUT;
return INTR_IDLE;
case 0x19: /* -> PHASE_DATAIN */
/* COMMAND -> DATA IN */
if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
- acornscsi_abortcmd (host, host->SCpnt->tag);
- acornscsi_dma_setup (host, DMA_IN);
- if (!acornscsi_starttransfer (host))
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ acornscsi_abortcmd(host, host->SCpnt->tag);
+ acornscsi_dma_setup(host, DMA_IN);
+ if (!acornscsi_starttransfer(host))
+ acornscsi_abortcmd(host, host->SCpnt->tag);
host->scsi.phase = PHASE_DATAIN;
return INTR_IDLE;
case 0x1b: /* -> PHASE_STATUS */
/* COMMAND -> STATUS */
- acornscsi_readstatusbyte (host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
case 0x1e: /* -> PHASE_MSGOUT */
/* COMMAND -> MESSAGE OUT */
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */
/* COMMAND -> MESSAGE IN */
- acornscsi_message (host);
+ acornscsi_message(host);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2094,19 +2187,19 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
host->scsi.phase = PHASE_IDLE;
host->stats.disconnects += 1;
} else {
- printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_NEXT_COMMAND;
case PHASE_IDLE: /* STATE: disconnected */
if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */
- acornscsi_reconnect (host);
+ acornscsi_reconnect(host);
else {
- printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2119,54 +2212,54 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
* If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
* reconnect I_T_L command
*/
- if (ssr != 0x8f && !acornscsi_reconnect_finish (host))
+ if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
return INTR_IDLE;
ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq);
switch (ssr) {
case 0x88: /* data out phase */
/* -> PHASE_DATAOUT */
/* MESSAGE IN -> DATA OUT */
- acornscsi_dma_setup (host, DMA_OUT);
- if (!acornscsi_starttransfer (host))
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ acornscsi_dma_setup(host, DMA_OUT);
+ if (!acornscsi_starttransfer(host))
+ acornscsi_abortcmd(host, host->SCpnt->tag);
host->scsi.phase = PHASE_DATAOUT;
return INTR_IDLE;
case 0x89: /* data in phase */
/* -> PHASE_DATAIN */
/* MESSAGE IN -> DATA IN */
- acornscsi_dma_setup (host, DMA_IN);
- if (!acornscsi_starttransfer (host))
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ acornscsi_dma_setup(host, DMA_IN);
+ if (!acornscsi_starttransfer(host))
+ acornscsi_abortcmd(host, host->SCpnt->tag);
host->scsi.phase = PHASE_DATAIN;
return INTR_IDLE;
case 0x8a: /* command out */
/* MESSAGE IN -> COMMAND */
- acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */
+ acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */
break;
case 0x8b: /* status in */
/* -> PHASE_STATUSIN */
/* MESSAGE IN -> STATUS */
- acornscsi_readstatusbyte (host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
case 0x8e: /* message out */
/* -> PHASE_MSGOUT */
/* MESSAGE IN -> MESSAGE OUT */
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
case 0x8f: /* message in */
- acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
+ acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2177,41 +2270,45 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
*/
switch (ssr) {
case 0x19: /* -> PHASE_DATAIN */
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ case 0x89: /* -> PHASE_DATAIN */
+ acornscsi_abortcmd(host, host->SCpnt->tag);
return INTR_IDLE;
- case 0x4b: /* -> PHASE_STATUSIN */
case 0x1b: /* -> PHASE_STATUSIN */
+ case 0x4b: /* -> PHASE_STATUSIN */
+ case 0x8b: /* -> PHASE_STATUSIN */
/* DATA IN -> STATUS */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_readstatusbyte (host);
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
case 0x1e: /* -> PHASE_MSGOUT */
case 0x4e: /* -> PHASE_MSGOUT */
+ case 0x8e: /* -> PHASE_MSGOUT */
/* DATA IN -> MESSAGE OUT */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_sendmessage (host);
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_sendmessage(host);
break;
case 0x1f: /* message in */
case 0x4f: /* message in */
+ case 0x8f: /* message in */
/* DATA IN -> MESSAGE IN */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2222,58 +2319,69 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
*/
switch (ssr) {
case 0x18: /* -> PHASE_DATAOUT */
- acornscsi_abortcmd (host, host->SCpnt->tag);
+ case 0x88: /* -> PHASE_DATAOUT */
+ acornscsi_abortcmd(host, host->SCpnt->tag);
return INTR_IDLE;
- case 0x4b: /* -> PHASE_STATUSIN */
case 0x1b: /* -> PHASE_STATUSIN */
+ case 0x4b: /* -> PHASE_STATUSIN */
+ case 0x8b: /* -> PHASE_STATUSIN */
/* DATA OUT -> STATUS */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_dma_adjust (host);
- acornscsi_readstatusbyte (host);
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_dma_adjust(host);
+ acornscsi_readstatusbyte(host);
host->scsi.phase = PHASE_STATUSIN;
break;
case 0x1e: /* -> PHASE_MSGOUT */
case 0x4e: /* -> PHASE_MSGOUT */
+ case 0x8e: /* -> PHASE_MSGOUT */
/* DATA OUT -> MESSAGE OUT */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_dma_adjust (host);
- acornscsi_sendmessage (host);
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_dma_adjust(host);
+ acornscsi_sendmessage(host);
break;
case 0x1f: /* message in */
case 0x4f: /* message in */
+ case 0x8f: /* message in */
/* DATA OUT -> MESSAGE IN */
host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
- acornscsi_sbic_xfcount (host);
- acornscsi_dma_stop (host);
- acornscsi_dma_adjust (host);
- acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
+ acornscsi_sbic_xfcount(host);
+ acornscsi_dma_stop(host);
+ acornscsi_dma_adjust(host);
+ acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
case PHASE_STATUSIN: /* STATE: status in complete */
- if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+ switch (ssr) {
+ case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+ case 0x8f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
/* STATUS -> MESSAGE IN */
- acornscsi_message (host);
- else if (ssr == 0x1e) /* -> PHASE_MSGOUT */
+ acornscsi_message(host);
+ break;
+
+ case 0x1e: /* -> PHASE_MSGOUT */
+ case 0x8e: /* -> PHASE_MSGOUT */
/* STATUS -> MESSAGE OUT */
- acornscsi_sendmessage (host);
- else {
- printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ acornscsi_sendmessage(host);
+ break;
+
+ default:
+ printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
@@ -2281,78 +2389,93 @@ intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq)
switch (ssr) {
case 0x1e: /* -> PHASE_MSGOUT */
case 0x4e: /* -> PHASE_MSGOUT */
+ case 0x8e: /* -> PHASE_MSGOUT */
/* MESSAGE IN -> MESSAGE OUT */
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
case 0x2f:
case 0x4f:
case 0x8f:
- acornscsi_message (host);
+ acornscsi_message(host);
+ break;
+
+ case 0x85:
+ printk("scsi%d.%c: strange message in disconnection\n",
+ host->host->host_no, acornscsi_target(host));
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
+ acornscsi_done(host, &host->SCpnt, DID_ERROR);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
case PHASE_DONE: /* STATE: received status & message */
switch (ssr) {
case 0x85: /* -> PHASE_IDLE */
- acornscsi_done (host, &host->SCpnt, DID_OK);
+ acornscsi_done(host, &host->SCpnt, DID_OK);
return INTR_NEXT_COMMAND;
+ case 0x1e:
case 0x8e:
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
case PHASE_ABORTED:
switch (ssr) {
case 0x85:
- acornscsi_done (host, &host->SCpnt, DID_ABORT);
+ if (host->SCpnt)
+ acornscsi_done(host, &host->SCpnt, DID_ABORT);
+ else {
+ clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
+ host->busyluns);
+ host->scsi.phase = PHASE_IDLE;
+ }
return INTR_NEXT_COMMAND;
case 0x1e:
case 0x2e:
case 0x4e:
case 0x8e:
- acornscsi_sendmessage (host);
+ acornscsi_sendmessage(host);
break;
default:
- printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
default:
- printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
- host->host->host_no, acornscsi_target (host), ssr);
- acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8);
+ printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
+ host->host->host_no, acornscsi_target(host), ssr);
+ acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
}
return INTR_PROCESSING;
}
/*
- * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
+ * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
* Purpose : handle interrupts from Acorn SCSI card
* Params : irq - interrupt number
* dev_id - device specific data (AS_Host structure)
* regs - processor registers when interrupt occurred
*/
static
-void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
+void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
{
AS_Host *host = (AS_Host *)dev_id;
intr_ret_t ret;
@@ -2360,21 +2483,21 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
int in_irq = 0;
if (host->scsi.interrupt)
- printk ("scsi%d: interrupt re-entered\n", host->host->host_no);
+ printk("scsi%d: interrupt re-entered\n", host->host->host_no);
host->scsi.interrupt = 1;
do {
ret = INTR_IDLE;
- iostatus = inb (host->card.io_intr);
+ iostatus = inb(host->card.io_intr);
if (iostatus & 2) {
- acornscsi_dma_intr (host);
- iostatus = inb (host->card.io_intr);
+ acornscsi_dma_intr(host);
+ iostatus = inb(host->card.io_intr);
}
if (iostatus & 8)
- ret = acornscsi_sbicintr (host, in_irq);
+ ret = acornscsi_sbicintr(host, in_irq);
/*
* If we have a transfer pending, start it.
@@ -2382,10 +2505,10 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
* it's data
*/
if (host->dma.xfer_required)
- acornscsi_dma_xfer (host);
+ acornscsi_dma_xfer(host);
if (ret == INTR_NEXT_COMMAND)
- ret = acornscsi_kick (host);
+ ret = acornscsi_kick(host);
in_irq = 1;
} while (ret != INTR_IDLE);
@@ -2398,29 +2521,29 @@ void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs)
*/
/*
- * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* Purpose : queues a SCSI command
* Params : cmd - SCSI command
* done - function called on completion, with pointer to command descriptor
* Returns : 0, or < 0 on error.
*/
-int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
if (!done) {
/* there should be some way of rejecting errors like this without panicing... */
- panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]",
+ panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
SCpnt->host->host_no, SCpnt);
return -EINVAL;
}
#if (DEBUG & DEBUG_NO_WRITE)
- if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) {
- printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
+ if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) {
+ printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
SCpnt->host->host_no, '0' + SCpnt->target);
SCpnt->result = DID_NO_CONNECT << 16;
- done (SCpnt);
+ done(SCpnt);
return 0;
}
#endif
@@ -2429,7 +2552,7 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->host_scribble = NULL;
SCpnt->result = 0;
SCpnt->tag = 0;
- SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]);
+ SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
SCpnt->SCp.sent_command = 0;
SCpnt->SCp.scsi_xferred = 0;
SCpnt->SCp.Status = 0;
@@ -2452,21 +2575,21 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
unsigned long flags;
- if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) {
+ if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
SCpnt->result = DID_ERROR << 16;
- done (SCpnt);
+ done(SCpnt);
return 0;
}
- save_flags_cli (flags);
+ save_flags_cli(flags);
if (host->scsi.phase == PHASE_IDLE)
- acornscsi_kick (host);
- restore_flags (flags);
+ acornscsi_kick(host);
+ restore_flags(flags);
}
return 0;
}
/*
- * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
* Params : SCpntp1 - pointer to command to return
* SCpntp2 - pointer to command to check
@@ -2474,7 +2597,7 @@ int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
* Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
*/
static inline
-void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
{
Scsi_Cmnd *SCpnt = *SCpntp1;
@@ -2482,80 +2605,203 @@ void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int resul
*SCpntp1 = NULL;
SCpnt->result = result;
- SCpnt->scsi_done (SCpnt);
+ SCpnt->scsi_done(SCpnt);
}
if (SCpnt == *SCpntp2)
*SCpntp2 = NULL;
}
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
/*
- * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt)
+ * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
* Purpose : abort a command on this host
* Params : SCpnt - command to abort
- * Returns : one of SCSI_ABORT_ macros
+ * Returns : our abort status
*/
-int acornscsi_abort (Scsi_Cmnd *SCpnt)
+static enum res_abort
+acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
{
- AS_Host *host = (AS_Host *) SCpnt->host->hostdata;
- int result = SCSI_ABORT_NOT_RUNNING;
+ enum res_abort res = res_not_running;
- host->stats.aborts += 1;
+ if (queue_removecmd(&host->queues.issue, SCpnt)) {
+ /*
+ * The command was on the issue queue, and has not been
+ * issued yet. We can remove the command from the queue,
+ * and acknowledge the abort. Neither the devices nor the
+ * interface know about the command.
+ */
+//#if (DEBUG & DEBUG_ABORT)
+ printk("on issue queue ");
+//#endif
+ res = res_success;
+ } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) {
+ /*
+ * The command was on the disconnected queue. Simply
+ * acknowledge the abort condition, and when the target
+ * reconnects, we will give it an ABORT message. The
+ * target should then disconnect, and we will clear
+ * the busylun bit.
+ */
+//#if (DEBUG & DEBUG_ABORT)
+ printk("on disconnected queue ");
+//#endif
+ res = res_success;
+ } else if (host->SCpnt == SCpnt) {
+ unsigned long flags;
+
+//#if (DEBUG & DEBUG_ABORT)
+ printk("executing ");
+//#endif
+
+ save_flags(flags);
+ cli();
+ switch (host->scsi.phase) {
+ /*
+ * If the interface is idle, and the command is 'disconnectable',
+ * then it is the same as on the disconnected queue. We simply
+ * remove all traces of the command. When the target reconnects,
+ * we will give it an ABORT message since the command could not
+ * be found. When the target finally disconnects, we will clear
+ * the busylun bit.
+ */
+ case PHASE_IDLE:
+ if (host->scsi.disconnectable) {
+ host->scsi.disconnectable = 0;
+ host->SCpnt = NULL;
+ res = res_success;
+ }
+ break;
-#if (DEBUG & DEBUG_ABORT)
- {
- int asr, ssr;
- asr = sbic_arm_read (host->scsi.io_port, ASR);
- ssr = sbic_arm_read (host->scsi.io_port, SSR);
+ /*
+ * If the command has connected and done nothing further,
+ * simply force a disconnect. We also need to clear the
+ * busylun bit.
+ */
+ case PHASE_CONNECTED:
+ sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT);
+ host->SCpnt = NULL;
+ res = res_success_clear;
+ break;
+
+ default:
+ acornscsi_abortcmd(host, host->SCpnt->tag);
+ res = res_snooze;
+ }
+ restore_flags(flags);
+ } else if (host->origSCpnt == SCpnt) {
+ /*
+ * The command will be executed next, but a command
+ * is currently using the interface. This is similar to
+ * being on the issue queue, except the busylun bit has
+ * been set.
+ */
+ host->origSCpnt = NULL;
+//#if (DEBUG & DEBUG_ABORT)
+ printk("waiting for execution ");
+//#endif
+ res = res_success_clear;
+ } else
+ printk("unknown ");
- printk (KERN_WARNING "acornscsi_abort: ");
- print_sbic_status(asr, ssr, host->scsi.phase);
- acornscsi_dumplog (host, SCpnt->target);
- }
-#endif
+ return res;
+}
+
+/*
+ * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort a command on this host
+ * Params : SCpnt - command to abort
+ * Returns : one of SCSI_ABORT_ macros
+ */
+int acornscsi_abort(Scsi_Cmnd *SCpnt)
+{
+ AS_Host *host = (AS_Host *) SCpnt->host->hostdata;
+ int result;
+
+ host->stats.aborts += 1;
- if (queue_removecmd (&host->queues.issue, SCpnt)) {
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done (SCpnt);
-#if (DEBUG & DEBUG_ABORT)
- printk ("scsi%d: command on issue queue\n", host->host->host_no);
-#endif
- result = SCSI_ABORT_SUCCESS;
- } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) {
- printk ("scsi%d: command on disconnected queue\n", host->host->host_no);
- result = SCSI_ABORT_SNOOZE;
- } else if (host->SCpnt == SCpnt) {
- acornscsi_abortcmd (host, host->SCpnt->tag);
- printk ("scsi%d: command executing\n", host->host->host_no);
- result = SCSI_ABORT_SNOOZE;
- } else if (host->origSCpnt == SCpnt) {
- host->origSCpnt = NULL;
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done (SCpnt);
#if (DEBUG & DEBUG_ABORT)
- printk ("scsi%d: command waiting for execution\n", host->host->host_no);
+ {
+ int asr, ssr;
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
+ ssr = sbic_arm_read(host->scsi.io_port, SSR);
+
+ printk(KERN_WARNING "acornscsi_abort: ");
+ print_sbic_status(asr, ssr, host->scsi.phase);
+ acornscsi_dumplog(host, SCpnt->target);
+ }
#endif
- result = SCSI_ABORT_SUCCESS;
- }
- if (result == SCSI_ABORT_NOT_RUNNING) {
- printk ("scsi%d: abort(): command not running\n", host->host->host_no);
- acornscsi_dumplog (host, SCpnt->target);
+ printk("scsi%d: ", host->host->host_no);
+
+ switch (acornscsi_do_abort(host, SCpnt)) {
+ /*
+ * We managed to find the command and cleared it out.
+ * We do not expect the command to be executing on the
+ * target, but we have set the busylun bit.
+ */
+ case res_success_clear:
+//#if (DEBUG & DEBUG_ABORT)
+ printk("clear ");
+//#endif
+ clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
+
+ /*
+ * We found the command, and cleared it out. Either
+ * the command is still known to be executing on the
+ * target, or the busylun bit is not set.
+ */
+ case res_success:
+//#if (DEBUG & DEBUG_ABORT)
+ printk("success\n");
+//#endif
+ SCpnt->result = DID_ABORT << 16;
+ SCpnt->scsi_done(SCpnt);
+ result = SCSI_ABORT_SUCCESS;
+ break;
+
+ /*
+ * We did find the command, but unfortunately we couldn't
+ * unhook it from ourselves. Wait some more, and if it
+ * still doesn't complete, reset the interface.
+ */
+ case res_snooze:
+//#if (DEBUG & DEBUG_ABORT)
+ printk("snooze\n");
+//#endif
+ result = SCSI_ABORT_SNOOZE;
+ break;
+
+ /*
+ * The command could not be found (either because it completed,
+ * or it got dropped.
+ */
+ default:
+ case res_not_running:
+ acornscsi_dumplog(host, SCpnt->target);
#if (DEBUG & DEBUG_ABORT)
- result = SCSI_ABORT_SNOOZE;
+ result = SCSI_ABORT_SNOOZE;
+#else
+ result = SCSI_ABORT_NOT_RUNNING;
#endif
- }
- return result;
+//#if (DEBUG & DEBUG_ABORT)
+ printk("not running\n");
+//#endif
+ break;
+ }
+
+ return result;
}
/*
- * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
* Purpose : reset a command on this host/reset this host
* Params : SCpnt - command causing reset
* result - what type of reset to perform
* Returns : one of SCSI_RESET_ macros
*/
-int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
{
AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
Scsi_Cmnd *SCptr;
@@ -2566,16 +2812,16 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
{
int asr, ssr;
- asr = sbic_arm_read (host->scsi.io_port, ASR);
- ssr = sbic_arm_read (host->scsi.io_port, SSR);
+ asr = sbic_arm_read(host->scsi.io_port, ASR);
+ ssr = sbic_arm_read(host->scsi.io_port, SSR);
- printk (KERN_WARNING "acornscsi_reset: ");
+ printk(KERN_WARNING "acornscsi_reset: ");
print_sbic_status(asr, ssr, host->scsi.phase);
- acornscsi_dumplog (host, SCpnt->target);
+ acornscsi_dumplog(host, SCpnt->target);
}
#endif
- acornscsi_dma_stop (host);
+ acornscsi_dma_stop(host);
SCptr = host->SCpnt;
@@ -2583,19 +2829,19 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
* do hard reset. This resets all devices on this host, and so we
* must set the reset status on all commands.
*/
- acornscsi_resetcard (host);
+ acornscsi_resetcard(host);
/*
* report reset on commands current connected/disconnected
*/
- acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET);
+ acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET);
- while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL)
- acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET);
+ while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
+ acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET);
if (SCpnt) {
SCpnt->result = DID_RESET << 16;
- SCpnt->scsi_done (SCpnt);
+ SCpnt->scsi_done(SCpnt);
}
return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
@@ -2607,19 +2853,19 @@ int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
static struct expansion_card *ecs[MAX_ECARDS];
/*
- * Prototype: void acornscsi_init (AS_Host *host)
+ * Prototype: void acornscsi_init(AS_Host *host)
* Purpose : initialise the AS_Host structure for one interface & setup hardware
* Params : host - host to setup
*/
static
-void acornscsi_init (AS_Host *host)
+void acornscsi_init(AS_Host *host)
{
- memset (&host->stats, 0, sizeof (host->stats));
- queue_initialise (&host->queues.issue);
- queue_initialise (&host->queues.disconnected);
- msgqueue_initialise (&host->scsi.msgs);
+ memset(&host->stats, 0, sizeof (host->stats));
+ queue_initialise(&host->queues.issue);
+ queue_initialise(&host->queues.disconnected);
+ msgqueue_initialise(&host->scsi.msgs);
- acornscsi_resetcard (host);
+ acornscsi_resetcard(host);
}
int acornscsi_detect(Scsi_Host_Template * tpnt)
@@ -2634,7 +2880,7 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
for (i = 0; i < MAX_ECARDS; i++)
ecs[i] = NULL;
- ecard_startfind ();
+ ecard_startfind();
while(1) {
ecs[count] = ecard_find(0, acornscsi_cids);
@@ -2642,37 +2888,37 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
break;
if (ecs[count]->irq == 0xff) {
- printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n");
+ printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n");
continue;
}
ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */
- instance = scsi_register (tpnt, sizeof(AS_Host));
+ instance = scsi_register(tpnt, sizeof(AS_Host));
host = (AS_Host *)instance->hostdata;
- instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0);
+ instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0);
instance->irq = ecs[count]->irq;
host->host = instance;
- host->scsi.io_port = ioaddr (instance->io_port + 0x800);
+ host->scsi.io_port = ioaddr(instance->io_port + 0x800);
host->scsi.irq = instance->irq;
host->card.io_intr = POD_SPACE(instance->io_port) + 0x800;
host->card.io_page = POD_SPACE(instance->io_port) + 0xc00;
- host->card.io_ram = ioaddr (instance->io_port);
+ host->card.io_ram = ioaddr(instance->io_port);
host->dma.io_port = instance->io_port + 0xc00;
host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800;
ecs[count]->irqaddr = (char *)ioaddr(host->card.io_intr);
ecs[count]->irqmask = 0x0a;
- request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)");
- request_region (host->card.io_intr, 1, "acornscsi(intr)");
- request_region (host->card.io_page, 1, "acornscsi(page)");
+ request_region(instance->io_port + 0x800, 2, "acornscsi(sbic)");
+ request_region(host->card.io_intr, 1, "acornscsi(intr)");
+ request_region(host->card.io_page, 1, "acornscsi(page)");
#ifdef USE_DMAC
- request_region (host->dma.io_port, 256, "acornscsi(dmac)");
+ request_region(host->dma.io_port, 256, "acornscsi(dmac)");
#endif
- request_region (instance->io_port, 2048, "acornscsi(ram)");
+ request_region(instance->io_port, 2048, "acornscsi(ram)");
if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) {
printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n",
@@ -2680,7 +2926,7 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
host->scsi.irq = NO_IRQ;
}
- acornscsi_init (host);
+ acornscsi_init(host);
++count;
}
@@ -2688,12 +2934,12 @@ int acornscsi_detect(Scsi_Host_Template * tpnt)
}
/*
- * Function: int acornscsi_release (struct Scsi_Host *host)
+ * Function: int acornscsi_release(struct Scsi_Host *host)
* Purpose : release all resources used by this adapter
* Params : host - driver structure to release
* Returns : nothing of any consequence
*/
-int acornscsi_release (struct Scsi_Host *instance)
+int acornscsi_release(struct Scsi_Host *instance)
{
AS_Host *host = (AS_Host *)instance->hostdata;
int i;
@@ -2701,30 +2947,30 @@ int acornscsi_release (struct Scsi_Host *instance)
/*
* Put card into RESET state
*/
- outb (0x80, host->card.io_page);
+ outb(0x80, host->card.io_page);
if (host->scsi.irq != NO_IRQ)
- free_irq (host->scsi.irq, host);
+ free_irq(host->scsi.irq, host);
- release_region (instance->io_port + 0x800, 2);
- release_region (host->card.io_intr, 1);
- release_region (host->card.io_page, 1);
- release_region (host->dma.io_port, 256);
- release_region (instance->io_port, 2048);
+ release_region(instance->io_port + 0x800, 2);
+ release_region(host->card.io_intr, 1);
+ release_region(host->card.io_page, 1);
+ release_region(host->dma.io_port, 256);
+ release_region(instance->io_port, 2048);
for (i = 0; i < MAX_ECARDS; i++)
- if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0))
- ecard_release (ecs[i]);
+ if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0))
+ ecard_release(ecs[i]);
- msgqueue_free (&host->scsi.msgs);
- queue_free (&host->queues.disconnected);
- queue_free (&host->queues.issue);
+ msgqueue_free(&host->scsi.msgs);
+ queue_free(&host->queues.disconnected);
+ queue_free(&host->queues.issue);
return 0;
}
/*
- * Function: char *acornscsi_info (struct Scsi_Host *host)
+ * Function: char *acornscsi_info(struct Scsi_Host *host)
* Purpose : return a string describing this interface
* Params : host - host to give information on
* Returns : a constant string
@@ -2736,7 +2982,7 @@ char *acornscsi_info(struct Scsi_Host *host)
p = string;
- p += sprintf (string, "%s at port %lX irq %d v%d.%d.%d"
+ p += sprintf(string, "%s at port %X irq %d v%d.%d.%d"
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
" SYNC"
#endif
@@ -2772,7 +3018,7 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
host = (AS_Host *)instance->hostdata;
- p += sprintf (p, "AcornSCSI driver v%d.%d.%d"
+ p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
" SYNC"
#endif
@@ -2787,14 +3033,14 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
#endif
"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
- p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n",
+ p += sprintf(p, "SBIC: WD33C93A Address: %08X IRQ : %d\n",
host->scsi.io_port, host->scsi.irq);
#ifdef USE_DMAC
- p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n",
+ p += sprintf(p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n",
host->dma.io_port, host->scsi.irq);
#endif
- p += sprintf (p, "Statistics:\n"
+ p += sprintf(p, "Statistics:\n"
"Queued commands: %-10u Issued commands: %-10u\n"
"Done commands : %-10u Reads : %-10u\n"
"Writes : %-10u Others : %-10u\n"
@@ -2809,47 +3055,47 @@ int acornscsi_proc_info(char *buffer, char **start, off_t offset,
for (devidx = 0; devidx < 9; devidx ++) {
unsigned int statptr, prev;
- p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
- statptr = status_ptr[devidx] - 10;
+ p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
+ statptr = host->status_ptr[devidx] - 10;
if ((signed int)statptr < 0)
- statptr += 16;
-
- prev = status[devidx][statptr].when;
-
- for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) {
- if (status[devidx][statptr].when) {
- p += sprintf (p, "%c%02X:%02X+%2ld",
- status[devidx][statptr].irq ? '-' : ' ',
- status[devidx][statptr].ph,
- status[devidx][statptr].ssr,
- (status[devidx][statptr].when - prev) < 100 ?
- (status[devidx][statptr].when - prev) : 99);
- prev = status[devidx][statptr].when;
+ statptr += STATUS_BUFFER_SIZE;
+
+ prev = host->status[devidx][statptr].when;
+
+ for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+ if (host->status[devidx][statptr].when) {
+ p += sprintf(p, "%c%02X:%02X+%2ld",
+ host->status[devidx][statptr].irq ? '-' : ' ',
+ host->status[devidx][statptr].ph,
+ host->status[devidx][statptr].ssr,
+ (host->status[devidx][statptr].when - prev) < 100 ?
+ (host->status[devidx][statptr].when - prev) : 99);
+ prev = host->status[devidx][statptr].when;
}
}
}
- p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none");
+ p += sprintf(p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none");
for (scd = instance->host_queue; scd; scd = scd->next) {
int len;
- proc_print_scsidevice (scd, p, &len, 0);
+ proc_print_scsidevice(scd, p, &len, 0);
p += len;
- p += sprintf (p, "Extensions: ");
+ p += sprintf(p, "Extensions: ");
if (scd->tagged_supported)
- p += sprintf (p, "TAG %sabled [%d] ",
+ p += sprintf(p, "TAG %sabled [%d] ",
scd->tagged_queue ? "en" : "dis", scd->current_tag);
- p += sprintf (p, "\nTransfers: ");
+ p += sprintf(p, "\nTransfers: ");
if (host->device[scd->id].sync_xfer & 15)
- p += sprintf (p, "sync, offset %d, %d ns\n",
+ p += sprintf(p, "sync, offset %d, %d ns\n",
host->device[scd->id].sync_xfer & 15,
- acornscsi_getperiod (host->device[scd->id].sync_xfer));
+ acornscsi_getperiod(host->device[scd->id].sync_xfer));
else
- p += sprintf (p, "async\n");
+ p += sprintf(p, "async\n");
pos = p - buffer;
if (pos + begin < offset) {
diff --git a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h
index ffaba7c2c..5470c6b6c 100644
--- a/drivers/acorn/scsi/acornscsi.h
+++ b/drivers/acorn/scsi/acornscsi.h
@@ -291,6 +291,27 @@ typedef enum { /* Data direction */
#include "queue.h"
#include "msgqueue.h"
+#define STATUS_BUFFER_SIZE 32
+/*
+ * This is used to dump the previous states of the SBIC
+ */
+struct status_entry {
+ unsigned long when;
+ unsigned char ssr;
+ unsigned char ph;
+ unsigned char irq;
+ unsigned char unused;
+};
+
+#define ADD_STATUS(_q,_ssr,_ph,_irq) \
+({ \
+ host->status[(_q)][host->status_ptr[(_q)]].when = jiffies; \
+ host->status[(_q)][host->status_ptr[(_q)]].ssr = (_ssr); \
+ host->status[(_q)][host->status_ptr[(_q)]].ph = (_ph); \
+ host->status[(_q)][host->status_ptr[(_q)]].irq = (_irq); \
+ host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \
+})
+
/*
* AcornSCSI host specific data
*/
@@ -303,7 +324,7 @@ typedef struct acornscsi_hostdata {
/* driver information */
struct {
unsigned int io_port; /* base address of WD33C93 */
- unsigned char irq; /* interrupt */
+ unsigned int irq; /* interrupt */
phase_t phase; /* current phase */
struct {
@@ -361,6 +382,7 @@ typedef struct acornscsi_hostdata {
char *xfer_ptr; /* pointer to area */
unsigned char xfer_required:1; /* set if we need to transfer something */
unsigned char xfer_setup:1; /* set if DMA is setup */
+ unsigned char xfer_done:1; /* set if DMA reached end of BH list */
} dma;
/* card info */
@@ -370,6 +392,9 @@ typedef struct acornscsi_hostdata {
unsigned int io_ram; /* base address of RAM access */
unsigned char page_reg; /* current setting of page reg */
} card;
+
+ unsigned char status_ptr[9];
+ struct status_entry status[9][STATUS_BUFFER_SIZE];
} AS_Host;
#endif /* ndef HOSTS_C */
diff --git a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
new file mode 100644
index 000000000..4afebe359
--- /dev/null
+++ b/drivers/acorn/scsi/arxescsi.c
@@ -0,0 +1,395 @@
+/*
+ * linux/arch/arm/drivers/scsi/cumana_2.c
+ *
+ * Copyright (C) 1997,1998 Russell King
+ *
+ * This driver is based on experimentation. Hence, it may have made
+ * assumptions about the particular card that I have available, and
+ * may not be reliable!
+ *
+ * Changelog:
+ * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c
+ * 22-01-1998 RMK 0.0.1 Updated to 2.1.80
+ * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it.
+ * 11-06-1998 0.0.2 Changed to support ARXE 16-bit SCSI card, enabled writing
+ * by Stefan Hanske
+ */
+
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+
+#include <asm/delay.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../../scsi/sd.h"
+#include "../../scsi/hosts.h"
+#include "arxescsi.h"
+#include "fas216.h"
+
+/* Hmm - this should go somewhere else */
+#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+
+/* Configuration */
+#define ARXESCSI_XTALFREQ 24
+#define ARXESCSI_ASYNC_PERIOD 200
+#define ARXESCSI_SYNC_DEPTH 0
+
+/*
+ * List of devices that the driver will recognise
+ */
+#define ARXESCSI_LIST { MANU_ARXE, PROD_ARXE_SCSI }
+
+/*
+ * Version
+ */
+#define VER_MAJOR 0
+#define VER_MINOR 0
+#define VER_PATCH 2
+
+static struct expansion_card *ecs[MAX_ECARDS];
+
+static struct proc_dir_entry proc_scsi_arxescsi = {
+ PROC_SCSI_QLOGICFAS, 6, "arxescsi",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/*
+ * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose : initialises DMA/PIO
+ * Params : host - host
+ * SCpnt - command
+ * direction - DMA on to/off of card
+ * min_type - minimum DMA support that we must have for this transfer
+ * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
+ */
+static fasdmatype_t
+arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+ fasdmadir_t direction, fasdmatype_t min_type)
+{
+ /*
+ * We don't do real DMA
+ */
+ return fasdma_pseudo;
+}
+
+
+
+/* Faster transfer routines, written by SH to speed up the loops */
+
+static __inline__ unsigned char getb(unsigned int address, unsigned int reg)
+{
+ unsigned char value;
+
+ __asm__ __volatile__(
+ "ldrb %0, [%1, %2, lsl #5]"
+ : "=r" (value)
+ : "r" (address), "r" (reg) );
+ return value;
+}
+
+static __inline__ unsigned int getw(unsigned int address, unsigned int reg)
+{
+ unsigned int value;
+
+ __asm__ __volatile__(
+ "ldr %0, [%1, %2, lsl #5]\n\t"
+ "mov %0, %0, lsl #16\n\t"
+ "mov %0, %0, lsr #16"
+ : "=r" (value)
+ : "r" (address), "r" (reg) );
+ return value;
+}
+
+static __inline__ void putw(unsigned int address, unsigned int reg, unsigned long value)
+{
+ __asm__ __volatile__(
+ "mov %0, %0, lsl #16\n\t"
+ "str %0, [%1, %2, lsl #5]"
+ :
+ : "r" (value), "r" (address), "r" (reg) );
+}
+
+
+/*
+ * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose : handles pseudo DMA
+ * Params : host - host
+ * SCpnt - command
+ * direction - DMA on to/off of card
+ * transfer - minimum number of bytes we expect to transfer
+ */
+void arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+ fasdmadir_t direction, int transfer)
+{
+ ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata;
+ unsigned int length, io, error=0;
+ unsigned char *addr;
+
+ length = SCp->this_residual;
+ addr = SCp->ptr;
+ io = __ioaddr(host->io_port);
+
+ if (direction == DMA_OUT) {
+ while (length > 0) {
+ unsigned long word;
+
+
+ word = *addr | *(addr + 1) << 8;
+ if (getb(io, 4) & STAT_INT)
+ break;
+
+ if (!(getb(io, 48) & CSTATUS_IRQ))
+ continue;
+
+ putw(io, 16, word);
+ if (length > 1) {
+ addr += 2;
+ length -= 2;
+ } else {
+ addr += 1;
+ length -= 1;
+ }
+ }
+ }
+ else {
+ if (transfer && (transfer & 255)) {
+ while (length >= 256) {
+ if (getb(io, 4) & STAT_INT) {
+ error=1;
+ break;
+ }
+
+ if (!(getb(io, 48) & CSTATUS_IRQ))
+ continue;
+
+ insw(info->dmaarea, addr, 256 >> 1);
+ addr += 256;
+ length -= 256;
+ }
+ }
+
+ if (!(error))
+ while (length > 0) {
+ unsigned long word;
+
+ if (getb(io, 4) & STAT_INT)
+ break;
+
+ if (!(getb(io, 48) & CSTATUS_IRQ))
+ continue;
+
+ word = getw(io, 16);
+ *addr++ = word;
+ if (--length > 0) {
+ *addr++ = word >> 8;
+ length --;
+ }
+ }
+ }
+}
+
+/*
+ * Function: int arxescsi_dma_stop(host, SCpnt)
+ * Purpose : stops DMA/PIO
+ * Params : host - host
+ * SCpnt - command
+ */
+static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+ /*
+ * no DMA to stop
+ */
+}
+
+/*
+ * Function: int arxescsi_detect(Scsi_Host_Template * tpnt)
+ * Purpose : initialises ARXE SCSI driver
+ * Params : tpnt - template for this SCSI adapter
+ * Returns : >0 if host found, 0 otherwise.
+ */
+int arxescsi_detect(Scsi_Host_Template *tpnt)
+{
+ static const card_ids arxescsi_cids[] = { ARXESCSI_LIST, { 0xffff, 0xffff} };
+ int count = 0;
+ struct Scsi_Host *host;
+
+ tpnt->proc_dir = &proc_scsi_arxescsi;
+ memset(ecs, 0, sizeof (ecs));
+
+ ecard_startfind();
+
+ while (1) {
+ ARXEScsi_Info *info;
+
+ ecs[count] = ecard_find(0, arxescsi_cids);
+ if (!ecs[count])
+ break;
+
+ ecard_claim(ecs[count]);
+
+ host = scsi_register(tpnt, sizeof (ARXEScsi_Info));
+ if (!host) {
+ ecard_release(ecs[count]);
+ break;
+ }
+
+ host->io_port = ecard_address(ecs[count], ECARD_MEMC, 0) + 0x0800;
+ host->irq = NO_IRQ;
+ host->dma_channel = NO_DMA;
+ host->can_queue = 0; /* no command queueing */
+ info = (ARXEScsi_Info *)host->hostdata;
+
+ info->info.scsi.io_port = host->io_port;
+ info->info.scsi.irq = host->irq;
+ info->info.scsi.io_shift = 3;
+ info->info.ifcfg.clockrate = ARXESCSI_XTALFREQ;
+ info->info.ifcfg.select_timeout = 255;
+ info->info.ifcfg.asyncperiod = ARXESCSI_ASYNC_PERIOD;
+ info->info.ifcfg.sync_max_depth = ARXESCSI_SYNC_DEPTH;
+ info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK;
+ info->info.ifcfg.disconnect_ok = 0;
+ info->info.ifcfg.wide_max_size = 0;
+ info->info.dma.setup = arxescsi_dma_setup;
+ info->info.dma.pseudo = arxescsi_dma_pseudo;
+ info->info.dma.stop = arxescsi_dma_stop;
+ info->dmaarea = host->io_port + 128;
+ info->cstatus = host->io_port + 384;
+
+ ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(host->io_port);
+ ecs[count]->irqmask = CSTATUS_IRQ;
+
+ request_region(host->io_port , 120, "arxescsi-fas");
+ request_region(host->io_port + 128, 384, "arxescsi-dma");
+
+ printk("scsi%d: Has no interrupts - using polling mode\n",
+ host->host_no);
+
+ fas216_init(host);
+ ++count;
+ }
+ return count;
+}
+
+/*
+ * Function: int arxescsi_release(struct Scsi_Host * host)
+ * Purpose : releases all resources used by this adapter
+ * Params : host - driver host structure to return info for.
+ * Returns : nothing
+ */
+int arxescsi_release(struct Scsi_Host *host)
+{
+ int i;
+
+ fas216_release(host);
+
+ release_region(host->io_port, 120);
+ release_region(host->io_port + 128, 384);
+
+ for (i = 0; i < MAX_ECARDS; i++)
+ if (ecs[i] && host->io_port == (ecard_address(ecs[i], ECARD_MEMC, 0) + 0x0800))
+ ecard_release(ecs[i]);
+ return 0;
+}
+
+/*
+ * Function: const char *arxescsi_info(struct Scsi_Host * host)
+ * Purpose : returns a descriptive string about this interface,
+ * Params : host - driver host structure to return info for.
+ * Returns : pointer to a static buffer containing null terminated string.
+ */
+const char *arxescsi_info(struct Scsi_Host *host)
+{
+ ARXEScsi_Info *info = (ARXEScsi_Info *)host->hostdata;
+ static char string[100], *p;
+
+ p = string;
+ p += sprintf(string, "%s at port %lX irq %d v%d.%d.%d scsi %s",
+ host->hostt->name, host->io_port, host->irq,
+ VER_MAJOR, VER_MINOR, VER_PATCH,
+ info->info.scsi.type);
+
+ return string;
+}
+
+/*
+ * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+ * int length, int host_no, int inout)
+ * Purpose : Return information about the driver to a user process accessing
+ * the /proc filesystem.
+ * Params : buffer - a buffer to write information to
+ * start - a pointer into this buffer set by this routine to the start
+ * of the required information.
+ * offset - offset into information that we have read upto.
+ * length - length of buffer
+ * host_no - host number to return information for
+ * inout - 0 for reading, 1 for writing.
+ * Returns : length of data written to buffer.
+ */
+int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+ int length, int host_no, int inout)
+{
+ int pos, begin;
+ struct Scsi_Host *host = scsi_hostlist;
+ ARXEScsi_Info *info;
+ Scsi_Device *scd;
+
+ while (host) {
+ if (host->host_no == host_no)
+ break;
+ host = host->next;
+ }
+ if (!host)
+ return 0;
+
+ info = (ARXEScsi_Info *)host->hostdata;
+ if (inout == 1)
+ return -EINVAL;
+
+ begin = 0;
+ pos = sprintf(buffer,
+ "ARXE 16-bit SCSI driver version %d.%d.%d\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ pos += sprintf(buffer + pos,
+ "Address: %08lX IRQ : %d\n"
+ "FAS : %s\n\n"
+ "Statistics:\n",
+ host->io_port, host->irq, info->info.scsi.type);
+
+ pos += fas216_print_stats(&info->info, buffer + pos);
+
+ pos += sprintf (buffer+pos, "\nAttached devices:\n");
+
+ for (scd = host->host_queue; scd; scd = scd->next) {
+ pos += fas216_print_device(&info->info, scd, buffer + pos);
+
+ if (pos + begin < offset) {
+ begin += pos;
+ pos = 0;
+ }
+ if (pos + begin > offset + length)
+ break;
+ }
+
+ *start = buffer + (offset - begin);
+ pos -= offset - begin;
+ if (pos > length)
+ pos = length;
+
+ return pos;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = ARXEScsi;
+
+#include "../../scsi/scsi_module.c"
+#endif
diff --git a/drivers/acorn/scsi/arxescsi.h b/drivers/acorn/scsi/arxescsi.h
new file mode 100644
index 000000000..11dc6b6e3
--- /dev/null
+++ b/drivers/acorn/scsi/arxescsi.h
@@ -0,0 +1,80 @@
+/*
+ * ARXE SCSI card driver
+ *
+ * Copyright (C) 1997 Russell King
+ * Changes to support ARXE 16-bit SCSI card by Stefan Hanske
+ */
+#ifndef ARXE_SCSI_H
+#define ARXE_SCSI_H
+
+#define MANU_ARXE 0x0041
+#define PROD_ARXE_SCSI 0x00be
+
+extern int arxescsi_detect (Scsi_Host_Template *);
+extern int arxescsi_release (struct Scsi_Host *);
+extern const char *arxescsi_info (struct Scsi_Host *);
+extern int arxescsi_proc_info (char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout);
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#ifndef CAN_QUEUE
+/*
+ * Default queue size
+ */
+#define CAN_QUEUE 1
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 1
+#endif
+
+#ifndef SCSI_ID
+/*
+ * Default SCSI host ID
+ */
+#define SCSI_ID 7
+#endif
+
+#include <scsi/scsicam.h>
+
+#ifndef HOSTS_C
+#include "fas216.h"
+#endif
+
+#define ARXEScsi { \
+proc_info: arxescsi_proc_info, \
+name: "ARXE SCSI card", \
+detect: arxescsi_detect, /* detect */ \
+release: arxescsi_release, /* release */ \
+info: arxescsi_info, /* info */ \
+command: fas216_command, /* command */ \
+queuecommand: fas216_queue_command, /* queuecommand */ \
+abort: fas216_abort, /* abort */ \
+reset: fas216_reset, /* reset */ \
+bios_param: scsicam_bios_param, /* biosparam */ \
+can_queue: CAN_QUEUE, /* can queue */ \
+this_id: SCSI_ID, /* scsi host id */ \
+sg_tablesize: SG_ALL, /* sg_tablesize */ \
+cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \
+use_clustering: DISABLE_CLUSTERING \
+ }
+
+#ifndef HOSTS_C
+
+typedef struct {
+ FAS216_Info info;
+
+ /* other info... */
+ unsigned int cstatus; /* card status register */
+ unsigned int dmaarea; /* Pseudo DMA area */
+} ARXEScsi_Info;
+
+#define CSTATUS_IRQ (1 << 0)
+#define CSTATUS_DRQ (1 << 0)
+
+#endif /* HOSTS_C */
+
+#endif /* ARXE_SCSI_H */
diff --git a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
index 797eaae06..c0edf3b64 100644
--- a/drivers/acorn/scsi/cumana_2.c
+++ b/drivers/acorn/scsi/cumana_2.c
@@ -4,12 +4,12 @@
* Copyright (C) 1997-1998 Russell King
*
* Changelog:
- * 30-08-1997 RMK 0.0.0 Created, READONLY version
- * 22-01-1998 RMK 0.0.1 Updated to 2.1.80
+ * 30-08-1997 RMK 0.0.0 Created, READONLY version.
+ * 22-01-1998 RMK 0.0.1 Updated to 2.1.80.
* 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it.
- * 02-05-1998 RMK 0.0.2 Updated & added DMA support
+ * 02-05-1998 RMK 0.0.2 Updated & added DMA support.
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
- * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth
+ * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth.
*/
#include <linux/module.h>
@@ -117,6 +117,8 @@ static const expansioncard_ops_t cumanascsi_2_ops = {
cumanascsi_2_irqenable,
cumanascsi_2_irqdisable,
NULL,
+ NULL,
+ NULL,
NULL
};
@@ -364,6 +366,7 @@ cumanascsi_2_detect(Scsi_Host_Template *tpnt)
info->info.ifcfg.sync_max_depth = CUMANASCSI2_SYNC_DEPTH;
info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
info->info.ifcfg.disconnect_ok = 1;
+ info->info.ifcfg.wide_max_size = 0;
info->info.dma.setup = cumanascsi_2_dma_setup;
info->info.dma.pseudo = cumanascsi_2_dma_pseudo;
info->info.dma.stop = cumanascsi_2_dma_stop;
diff --git a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c
index 301b83d05..8ed77e157 100644
--- a/drivers/acorn/scsi/eesox.c
+++ b/drivers/acorn/scsi/eesox.c
@@ -38,9 +38,6 @@
#include "../../scsi/hosts.h"
#include "eesox.h"
-#define NO_IRQ 255
-#define NO_DMA 255
-
/* Configuration */
#define EESOX_XTALFREQ 40
#define EESOX_ASYNC_PERIOD 200
@@ -123,6 +120,8 @@ static const expansioncard_ops_t eesoxscsi_ops = {
eesoxscsi_irqenable,
eesoxscsi_irqdisable,
NULL,
+ NULL,
+ NULL,
NULL
};
@@ -379,6 +378,7 @@ eesoxscsi_detect(Scsi_Host_Template *tpnt)
info->info.ifcfg.sync_max_depth = EESOX_SYNC_DEPTH;
info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
info->info.ifcfg.disconnect_ok = 1;
+ info->info.ifcfg.wide_max_size = 0;
info->info.dma.setup = eesoxscsi_dma_setup;
info->info.dma.pseudo = eesoxscsi_dma_pseudo;
info->info.dma.stop = eesoxscsi_dma_stop;
diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c
index 6cd638242..c89b74f1e 100644
--- a/drivers/acorn/scsi/fas216.c
+++ b/drivers/acorn/scsi/fas216.c
@@ -24,9 +24,9 @@
* 02-05-1998 RMK Added extra checks in fas216_reset
* 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns
* 27-06-1998 RMK Changed asm/delay.h to linux/delay.h
+ * 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT
*
* Todo:
- * - tighten up the MESSAGE_REJECT support.
* - allow individual devices to enable sync xfers.
*/
@@ -57,7 +57,7 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
#define VER_MAJOR 0
#define VER_MINOR 0
-#define VER_PATCH 4
+#define VER_PATCH 5
#define SCSI2_TAG
@@ -86,6 +86,8 @@ MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver");
*/
#define SCSI2_SYNC
+#define SCSI2_WIDE
+
#undef DEBUG_CONNECT
#undef DEBUG_BUSSERVICE
#undef DEBUG_FUNCTIONDONE
@@ -132,8 +134,8 @@ static void fas216_dumpinfo(FAS216_Info *info)
printk(" SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n",
info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual);
- printk(" msgs async_stp=%X last_message=%X disconnectable=%d aborting=%d }\n",
- info->scsi.async_stp, info->scsi.last_message,
+ printk(" msgs async_stp=%X disconnectable=%d aborting=%d }\n",
+ info->scsi.async_stp,
info->scsi.disconnectable, info->scsi.aborting);
printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
" disconnects=%X aborts=%X resets=%X }\n",
@@ -144,10 +146,10 @@ static void fas216_dumpinfo(FAS216_Info *info)
info->ifcfg.clockrate, info->ifcfg.select_timeout,
info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
for (i = 0; i < 8; i++) {
- printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X negstate=%X }\n",
+ printk(" busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
i, info->busyluns[i], i,
info->device[i].disconnect_ok, info->device[i].stp,
- info->device[i].sof, info->device[i].negstate);
+ info->device[i].sof, info->device[i].sync_state);
}
printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
info->dma.transfer_type, info->dma.setup,
@@ -192,19 +194,19 @@ static const char *fas216_bus_phase(int stat)
static const char *fas216_drv_phase(FAS216_Info *info)
{
switch (info->scsi.phase) {
- case PHASE_IDLE: return "idle";
- case PHASE_SELECTION: return "selection";
- case PHASE_MESSAGESENT: return "message sent";
- case PHASE_RECONNECTED: return "reconnected";
- case PHASE_DATAOUT: return "data out";
- case PHASE_DATAIN: return "data in";
- case PHASE_MSGOUT: return "message out";
- case PHASE_MSGIN: return "message in";
- case PHASE_AFTERMSGOUT: return "after message out";
- case PHASE_STATUS: return "status";
- case PHASE_DISCONNECT: return "disconnect";
- case PHASE_DONE: return "done";
- default: return "???";
+ case PHASE_IDLE: return "idle";
+ case PHASE_SELECTION: return "selection";
+ case PHASE_COMMAND: return "command";
+ case PHASE_RECONNECTED: return "reconnected";
+ case PHASE_DATAOUT: return "data out";
+ case PHASE_DATAIN: return "data in";
+ case PHASE_MSGIN: return "message in";
+ case PHASE_MSGIN_DISCONNECT: return "disconnect";
+ case PHASE_MSGOUT_EXPECT: return "expect message out";
+ case PHASE_MSGOUT: return "message out";
+ case PHASE_STATUS: return "status";
+ case PHASE_DONE: return "done";
+ default: return "???";
}
}
@@ -262,6 +264,37 @@ static int fas216_clockrate(int clock)
return clock;
}
+/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos)
+ * Purpose : retrieve a last message from the list, using position in fifo
+ * Params : info - interface to search
+ * : pos - current fifo position
+ */
+static inline unsigned short
+fas216_get_last_msg(FAS216_Info *info, int pos)
+{
+ unsigned short packed_msg = NOP;
+ struct message *msg;
+ int msgnr = 0;
+
+ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+ if (pos >= msg->fifo)
+ break;
+ }
+
+ if (msg) {
+ if (msg->msg[0] == EXTENDED_MESSAGE)
+ packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
+ else
+ packed_msg = msg->msg[0];
+ }
+
+#ifdef DEBUG_MESSAGES
+ printk("Message: %04X found at position %02X\n",
+ packed_msg, pos);
+#endif
+ return packed_msg;
+}
+
/* Function: int fas216_syncperiod(FAS216_Info *info, int ns)
* Purpose : Calculate value to be loaded into the STP register
* for a given period in ns
@@ -303,6 +336,240 @@ fas216_set_sync(FAS216_Info *info, int target)
outb(info->scsi.cfg[2], REG_CNTL3(info));
}
+/* Synchronous transfer support
+ *
+ * Note: The SCSI II r10 spec says (5.6.12):
+ *
+ * (2) Due to historical problems with early host adapters that could
+ * not accept an SDTR message, some targets may not initiate synchronous
+ * negotiation after a power cycle as required by this standard. Host
+ * adapters that support synchronous mode may avoid the ensuing failure
+ * modes when the target is independently power cycled by initiating a
+ * synchronous negotiation on each REQUEST SENSE and INQUIRY command.
+ * This approach increases the SCSI bus overhead and is not recommended
+ * for new implementations. The correct method is to respond to an
+ * SDTR message with a MESSAGE REJECT message if the either the
+ * initiator or target devices does not support synchronous transfers
+ * or does not want to negotiate for synchronous transfers at the time.
+ * Using the correct method assures compatibility with wide data
+ * transfers and future enhancements.
+ *
+ * We will always initiate a synchronous transfer negociation request on
+ * every INQUIRY or REQUEST SENSE message, unless the target itself has
+ * at some point performed a synchronous transfer negociation request, or
+ * we have synchronous transfers disabled for this device.
+ */
+
+/* Function: void fas216_handlesync(FAS216_Info *info, char *msg)
+ * Purpose : Handle a synchronous transfer message from the target
+ * Params : info - state structure for interface
+ * : msg - message from target
+ */
+static void
+fas216_handlesync(FAS216_Info *info, char *msg)
+{
+ struct fas216_device *dev = &info->device[info->SCpnt->target];
+ enum { sync, async, none, reject } res = none;
+
+#ifdef SCSI2_SYNC
+ switch (msg[0]) {
+ case MESSAGE_REJECT:
+ /* Synchronous transfer request failed.
+ * Note: SCSI II r10:
+ *
+ * SCSI devices that are capable of synchronous
+ * data transfers shall not respond to an SDTR
+ * message with a MESSAGE REJECT message.
+ *
+ * Hence, if we get this condition, we disable
+ * negociation for this device.
+ */
+ if (dev->sync_state == neg_inprogress) {
+ dev->sync_state = neg_invalid;
+ res = async;
+ }
+ break;
+
+ case EXTENDED_MESSAGE:
+ switch (dev->sync_state) {
+ /* We don't accept synchronous transfer requests.
+ * Respond with a MESSAGE_REJECT to prevent a
+ * synchronous transfer agreement from being reached.
+ */
+ case neg_invalid:
+ res = reject;
+ break;
+
+ /* We were not negociating a synchronous transfer,
+ * but the device sent us a negociation request.
+ * Honour the request by sending back a SDTR
+ * message containing our capability, limited by
+ * the targets capability.
+ */
+ default:
+ outb(CMD_SETATN, REG_CMD(info));
+ if (msg[4] > info->ifcfg.sync_max_depth)
+ msg[4] = info->ifcfg.sync_max_depth;
+ if (msg[3] < 1000 / info->ifcfg.clockrate)
+ msg[3] = 1000 / info->ifcfg.clockrate;
+
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 5,
+ EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+ msg[3], msg[4]);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+ /* This is wrong. The agreement is not in effect
+ * until this message is accepted by the device
+ */
+ dev->sync_state = neg_targcomplete;
+ res = sync;
+ break;
+
+ /* We initiated the synchronous transfer negociation,
+ * and have successfully received a response from the
+ * target. The synchronous transfer agreement has been
+ * reached. Note: if the values returned are out of our
+ * bounds, we must reject the message.
+ */
+ case neg_inprogress:
+ res = reject;
+ if (msg[4] <= info->ifcfg.sync_max_depth &&
+ msg[3] >= 1000 / info->ifcfg.clockrate) {
+ dev->sync_state = neg_complete;
+ res = sync;
+ }
+ break;
+ }
+ }
+#else
+ res = reject;
+#endif
+
+ switch (res) {
+ case sync:
+ dev->period = msg[3];
+ dev->sof = msg[4];
+ dev->stp = fas216_syncperiod(info, msg[3] * 4);
+ fas216_set_sync(info, info->SCpnt->target);
+ break;
+
+ case reject:
+ outb(CMD_SETATN, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+ case async:
+ dev->period = info->ifcfg.asyncperiod / 4;
+ dev->sof = 0;
+ dev->stp = info->scsi.async_stp;
+ fas216_set_sync(info, info->SCpnt->target);
+ break;
+
+ case none:
+ break;
+ }
+}
+
+/* Function: void fas216_handlewide(FAS216_Info *info, char *msg)
+ * Purpose : Handle a wide transfer message from the target
+ * Params : info - state structure for interface
+ * : msg - message from target
+ */
+static void
+fas216_handlewide(FAS216_Info *info, char *msg)
+{
+ struct fas216_device *dev = &info->device[info->SCpnt->target];
+ enum { wide, bit8, none, reject } res = none;
+
+#ifdef SCSI2_WIDE
+ switch (msg[0]) {
+ case MESSAGE_REJECT:
+ /* Wide transfer request failed.
+ * Note: SCSI II r10:
+ *
+ * SCSI devices that are capable of wide
+ * data transfers shall not respond to a
+ * WDTR message with a MESSAGE REJECT message.
+ *
+ * Hence, if we get this condition, we never
+ * reattempt negociation for this device.
+ */
+ if (dev->wide_state == neg_inprogress) {
+ dev->wide_state = neg_invalid;
+ res = bit8;
+ }
+ break;
+
+ case EXTENDED_MESSAGE:
+ switch (dev->wide_state) {
+ /* We don't accept wide data transfer requests.
+ * Respond with a MESSAGE REJECT to prevent a
+ * wide data transfer agreement from being reached.
+ */
+ case neg_invalid:
+ res = reject;
+ break;
+
+ /* We were not negociating a wide data transfer,
+ * but the device sent is a negociation request.
+ * Honour the request by sending back a WDTR
+ * message containing our capability, limited by
+ * the targets capability.
+ */
+ default:
+ outb(CMD_SETATN, REG_CMD(info));
+ if (msg[3] > info->ifcfg.wide_max_size)
+ msg[3] = info->ifcfg.wide_max_size;
+
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 4,
+ EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+ msg[3]);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
+ res = wide;
+ break;
+
+ /* We initiated the wide data transfer negociation,
+ * and have successfully received a response from the
+ * target. The synchronous transfer agreement has been
+ * reached. Note: if the values returned are out of our
+ * bounds, we must reject the message.
+ */
+ case neg_inprogress:
+ res = reject;
+ if (msg[3] <= info->ifcfg.wide_max_size) {
+ dev->wide_state = neg_complete;
+ res = wide;
+ }
+ break;
+ }
+ }
+#else
+ res = reject;
+#endif
+
+ switch (res) {
+ case wide:
+ dev->wide_xfer = msg[3];
+ break;
+
+ case reject:
+ outb(CMD_SETATN, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+ case bit8:
+ dev->wide_xfer = 0;
+ break;
+
+ case none:
+ break;
+ }
+}
+
/* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
* Purpose : update data pointers after transfer suspended/paused
* Params : info - interface's local pointer to update
@@ -338,6 +605,9 @@ fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
residual -= bytes_transferred;
ptr += bytes_transferred;
+ if (residual == 0)
+ ptr = NULL;
+
info->scsi.SCp.ptr = ptr;
info->scsi.SCp.this_residual = residual;
}
@@ -353,7 +623,7 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
{
unsigned int residual;
char *ptr;
- int correction;
+ int correction = 0;
fas216_checkmagic(info, "fas216_pio");
@@ -361,23 +631,24 @@ fas216_pio(FAS216_Info *info, fasdmadir_t direction)
ptr = info->scsi.SCp.ptr;
if (direction == DMA_OUT) {
- while (residual > 0) {
- if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
+// while (residual > 0) {
+// if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
outb(*ptr++, REG_FF(info));
residual -= 1;
- } else if (inb(REG_STAT(info)) & STAT_INT)
- break;
- }
- correction = inb(REG_CFIS(info)) & CFIS_CF;
+// }
+// if (inb(REG_STAT(info)) & STAT_INT)
+// break;
+// }
+// correction = inb(REG_CFIS(info)) & CFIS_CF;
} else {
- while (residual > 0) {
- if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
+// while (residual > 0) {
+// if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
*ptr++ = inb(REG_FF(info));
residual -= 1;
- } else if (inb(REG_STAT(info)) & STAT_INT)
- break;
- }
- correction = 0;
+// }
+// if (inb(REG_STAT(info)) & STAT_INT)
+// break;
+// }
}
ptr -= correction;
@@ -549,10 +820,11 @@ fas216_disconnect_intr(FAS216_Info *info)
switch (info->scsi.phase) {
case PHASE_SELECTION: /* while selecting - no target */
+ case PHASE_SELSTEPS:
fas216_done(info, DID_NO_CONNECT);
break;
- case PHASE_DISCONNECT: /* message in - disconnecting */
+ case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */
outb(CMD_ENABLESEL, REG_CMD(info));
info->scsi.disconnectable = 1;
info->scsi.reconnected.tag = 0;
@@ -564,8 +836,8 @@ fas216_disconnect_intr(FAS216_Info *info)
fas216_done(info, DID_OK);
break;
- case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */
- if (info->scsi.last_message == ABORT) {
+ case PHASE_MSGOUT: /* message out - possible ABORT message */
+ if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
info->scsi.aborting = 0;
fas216_done(info, DID_ABORT);
break;
@@ -592,14 +864,17 @@ fas216_reselected_intr(FAS216_Info *info)
fas216_checkmagic(info, "fas216_reselected_intr");
- if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) {
+ if ((info->scsi.phase == PHASE_SELECTION ||
+ info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
Scsi_Cmnd *SCpnt = info->SCpnt;
info->origSCpnt = SCpnt;
info->SCpnt = NULL;
- if (info->device[SCpnt->target].negstate == syncneg_sent)
- info->device[SCpnt->target].negstate = syncneg_start;
+ if (info->device[SCpnt->target].wide_state == neg_inprogress)
+ info->device[SCpnt->target].wide_state = neg_wait;
+ if (info->device[SCpnt->target].sync_state == neg_inprogress)
+ info->device[SCpnt->target].sync_state = neg_wait;
}
#ifdef DEBUG_CONNECT
@@ -607,15 +882,14 @@ fas216_reselected_intr(FAS216_Info *info)
fas216_target(info), info->scsi.phase);
#endif
- msgqueue_flush(&info->scsi.msgs);
-
if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) {
printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
info->host->host_no);
outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
- info->scsi.phase = PHASE_MSGOUT;
outb(CMD_MSGACCEPTED, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
return;
}
@@ -636,13 +910,14 @@ fas216_reselected_intr(FAS216_Info *info)
if (!ok) {
/*
- * Something went wrong - abort the command on
- * the target. Should this be INITIATOR_ERROR ?
+ * Something went wrong - send an initiator error to
+ * the target.
*/
outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
- info->scsi.phase = PHASE_MSGOUT;
outb(CMD_MSGACCEPTED, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
return;
}
@@ -672,17 +947,20 @@ fas216_reselected_intr(FAS216_Info *info)
if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg))
ok = 1;
+ msgqueue_flush(&info->scsi.msgs);
if (ok) {
info->scsi.phase = PHASE_RECONNECTED;
outb(target, REG_SDID(info));
} else {
/*
- * Our command structure not found - abort the command on the target
- * Should this be INITIATOR_ERROR ?
+ * Our command structure not found - abort the
+ * command on the target. Since we have no
+ * record of this command, we can't send
+ * an INITIATOR DETECTED ERROR message.
*/
outb(CMD_SETATN, REG_CMD(info));
msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
- info->scsi.phase = PHASE_MSGOUT;
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
}
outb(CMD_MSGACCEPTED, REG_CMD(info));
}
@@ -733,8 +1011,14 @@ fas216_finish_reconnect(FAS216_Info *info)
}
if (!info->SCpnt) {
outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
- info->scsi.phase = PHASE_MSGOUT;
+ msgqueue_flush(&info->scsi.msgs);
+#if 0
+ if (info->scsi.reconnected.tag)
+ msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag);
+ else
+#endif
+ msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
info->scsi.aborting = 1;
} else {
/*
@@ -751,6 +1035,28 @@ fas216_finish_reconnect(FAS216_Info *info)
#endif
}
+static unsigned char fas216_get_msg_byte(FAS216_Info *info)
+{
+ int tout;
+
+ outb(CMD_MSGACCEPTED, REG_CMD(info));
+ for (tout = 1000000; tout; tout --)
+ if (inb(REG_STAT(info)) & STAT_INT)
+ break;
+
+ inb(REG_INST(info));
+
+ outb(CMD_TRANSFERINFO, REG_CMD(info));
+
+ for (tout = 1000000; tout; tout --)
+ if (inb(REG_STAT(info)) & STAT_INT)
+ break;
+
+ inb(REG_INST(info));
+
+ return inb(REG_FF(info));
+}
+
/* Function: void fas216_message(FAS216_Info *info)
* Purpose : handle a function done interrupt from FAS216 chip
* Params : info - interface which caused function done interrupt
@@ -765,34 +1071,10 @@ static void fas216_message(FAS216_Info *info)
message[0] = inb(REG_FF(info));
if (message[0] == EXTENDED_MESSAGE) {
- int tout;
- outb(CMD_MSGACCEPTED, REG_CMD(info));
- for (tout = 1000000; tout; tout--)
- if (inb(REG_STAT(info)) & STAT_INT)
- break;
- inb(REG_INST(info));
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- for (tout = 1000000; tout; tout--)
- if (inb(REG_STAT(info)) & STAT_INT)
- break;
- inb(REG_INST(info));
-
- message[1] = inb(REG_FF(info));
+ message[1] = fas216_get_msg_byte(info);
- for (msglen = 2; msglen < message[1] + 2; msglen++) {
- outb(CMD_MSGACCEPTED, REG_CMD(info));
- for (tout = 1000000; tout; tout--)
- if (inb(REG_STAT(info)) & STAT_INT)
- break;
- inb(REG_INST(info));
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- for (tout = 1000000; tout; tout--)
- if (inb(REG_STAT(info)) & STAT_INT)
- break;
- inb(REG_INST(info));
-
- message[msglen] = inb(REG_FF(info));
- }
+ for (msglen = 2; msglen < message[1] + 2; msglen++)
+ message[msglen] = fas216_get_msg_byte(info);
}
#ifdef DEBUG_MESSAGES
@@ -806,6 +1088,7 @@ static void fas216_message(FAS216_Info *info)
printk("\n");
}
#endif
+
if (info->scsi.phase == PHASE_RECONNECTED) {
if (message[0] == SIMPLE_QUEUE_TAG)
info->scsi.reconnected.tag = message[1];
@@ -815,14 +1098,22 @@ static void fas216_message(FAS216_Info *info)
switch (message[0]) {
case COMMAND_COMPLETE:
- printk("fas216: command complete with no status in MESSAGE_IN?\n");
+ printk(KERN_ERR "scsi%d.%c: command complete with no "
+ "status in MESSAGE_IN?\n",
+ info->host->host_no, fas216_target(info));
break;
case SAVE_POINTERS:
/*
* Save current data pointer to SAVED data pointer
+ * SCSI II standard says that we must not acknowledge
+ * this until we have really saved pointers.
+ * NOTE: we DO NOT save the command nor status pointers
+ * as required by the SCSI II standard. These always
+ * point to the start of their respective areas.
*/
info->SCpnt->SCp = info->scsi.SCp;
+ info->SCpnt->SCp.sent_command = 0;
#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT)
printk("scsi%d.%c: save data pointers: [%p, %X]\n",
info->host->host_no, fas216_target(info),
@@ -843,13 +1134,27 @@ static void fas216_message(FAS216_Info *info)
break;
case DISCONNECT:
- info->scsi.phase = PHASE_DISCONNECT;
+ info->scsi.phase = PHASE_MSGIN_DISCONNECT;
break;
case MESSAGE_REJECT:
- printk("scsi%d.%c: reject, last message %04X\n",
- info->host->host_no, fas216_target(info),
- info->scsi.last_message);
+ switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
+ case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
+ fas216_handlesync(info, message);
+ break;
+
+ case EXTENDED_MESSAGE | EXTENDED_WDTR << 8:
+ fas216_handlewide(info, message);
+ break;
+
+ default:
+ printk("scsi%d.%c: reject, last message %04X\n",
+ info->host->host_no, fas216_target(info),
+ fas216_get_last_msg(info, info->scsi.msgin_fifo));
+ }
+ break;
+
+ case NOP:
break;
case SIMPLE_QUEUE_TAG:
@@ -862,49 +1167,18 @@ static void fas216_message(FAS216_Info *info)
case EXTENDED_MESSAGE:
switch (message[2]) {
case EXTENDED_SDTR: /* Sync transfer negociation request/reply */
- switch (info->device[info->SCpnt->target].negstate) {
- case syncneg_invalid:
- msgqueue_flush(&info->scsi.msgs);
- outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
- info->scsi.phase = PHASE_MSGOUT;
- break;
-
- default:
- if (message[4] > info->ifcfg.sync_max_depth)
- message[4] = info->ifcfg.sync_max_depth;
- if (message[3] < 1000 / info->ifcfg.clockrate)
- message[3] = 1000 / info->ifcfg.clockrate;
-
- outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 5,
- EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
- message[3], message[4]);
- info->scsi.phase = PHASE_MSGOUT;
- case syncneg_sent:
- info->device[info->SCpnt->target].negstate = syncneg_complete;
- info->device[info->SCpnt->target].period = message[3];
- info->device[info->SCpnt->target].sof = message[4];
- info->device[info->SCpnt->target].stp =
- fas216_syncperiod(info, message[3] * 4);
- printk(KERN_NOTICE "scsi%d.%c: using synchronous transfer, offset %d, %d ns\n",
- info->host->host_no, fas216_target(info), message[4], message[3] * 4);
- fas216_set_sync(info, info->SCpnt->target);
- break;
- }
+ fas216_handlesync(info, message);
break;
case EXTENDED_WDTR: /* Wide transfer negociation request/reply */
- /* We don't do wide transfers - reject message */
+ fas216_handlewide(info, message);
+ break;
+
default:
printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n",
info->host->host_no, fas216_target(info),
message[2]);
- msgqueue_flush(&info->scsi.msgs);
- outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
- info->scsi.phase = PHASE_MSGOUT;
- break;
+ goto reject_message;
}
break;
@@ -912,13 +1186,17 @@ static void fas216_message(FAS216_Info *info)
printk("scsi%d.%c: unrecognised message %02X, rejecting\n",
info->host->host_no, fas216_target(info),
message[0]);
- msgqueue_flush(&info->scsi.msgs);
- outb(CMD_SETATN, REG_CMD(info));
- msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
- info->scsi.phase = PHASE_MSGOUT;
- break;
+ goto reject_message;
}
outb(CMD_MSGACCEPTED, REG_CMD(info));
+ return;
+
+reject_message:
+ outb(CMD_SETATN, REG_CMD(info));
+ outb(CMD_MSGACCEPTED, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
}
/* Function: void fas216_send_command(FAS216_Info *info)
@@ -935,201 +1213,46 @@ static void fas216_send_command(FAS216_Info *info)
outb(CMD_FLUSHFIFO, REG_CMD(info));
/* load command */
- for (i = 0; i < info->SCpnt->cmd_len; i++)
+ for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
outb(info->SCpnt->cmnd[i], REG_FF(info));
outb(CMD_TRANSFERINFO, REG_CMD(info));
-}
-
-/* Function: int fas216_busservice_selection(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in selection phase
- * Params : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- */
-static int fas216_busservice_selection(FAS216_Info *info, unsigned int stat)
-{
- fas216_checkmagic(info, "fas216_busservice_selection");
-
- switch (stat & STAT_BUSMASK) {
- case STAT_DATAOUT: /* data out phase */
- fas216_starttransfer(info, DMA_OUT, 1);
- return 1;
-
- case STAT_DATAIN: /* data in phase */
- fas216_starttransfer(info, DMA_IN, 0);
- return 1;
-
- case STAT_STATUS: /* status phase */
- info->scsi.phase = PHASE_STATUS;
- outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
- return 1;
-
- case STAT_MESGIN: /* message in phase */
- info->scsi.phase = PHASE_MSGIN;
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- return 1;
-
- case STAT_MESGOUT:{ /* message out phase */
- char *msg;
- int start = 1, msglen;
-
- /* load message bytes, but don't forget to miss the first
- * byte!
- */
- while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
- int i;
-
- for (i = start; i < msglen; i++)
- outb(msg[i], REG_FF(info));
- start = 0;
- }
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- info->scsi.phase = PHASE_MESSAGESENT;
- return 1;
- }
- default:
- return 0;
- }
-}
-
-/* Function: int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service after the IDENTIFY message has been sent
- * Params : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- */
-static int fas216_busservice_messagesent(FAS216_Info *info, unsigned int stat)
-{
- fas216_checkmagic(info, "fas216_busservice_messagesent");
-
- switch (stat & STAT_BUSMASK) {
- case STAT_MESGIN: /* message in phase */
- info->scsi.phase = PHASE_MSGIN;
- outb(CMD_FLUSHFIFO, REG_CMD(info));
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- return 1;
- case STAT_COMMAND: /* command phase */
- fas216_send_command(info);
- return 1;
-
- default:
- return 0;
- }
+ info->scsi.phase = PHASE_COMMAND;
}
-/* Function: int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in a data in/out phase.
- * Params : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- * Note : We do not allow the device to change the data direction!
- */
-static int fas216_busservice_dataphase(FAS216_Info *info, unsigned int stat)
-{
- fas216_checkmagic(info, "fas216_busservice_dataphase");
-
- switch (stat & STAT_BUSMASK) {
- case STAT_DATAIN: /* continue data in phase */
- if (info->scsi.phase == PHASE_DATAIN) {
- fas216_starttransfer(info, DMA_IN, 0);
- return 1;
- } else
- return 0;
-
- case STAT_DATAOUT: /* continue data out phase */
- if (info->scsi.phase == PHASE_DATAOUT) {
- fas216_starttransfer(info, DMA_OUT, 0);
- return 1;
- } else
- return 0;
-
- case STAT_STATUS: /* status in phase */
- fas216_stoptransfer(info);
- info->scsi.phase = PHASE_STATUS;
- outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
- return 1;
-
- case STAT_MESGIN: /* message in phase */
- fas216_stoptransfer(info);
- info->scsi.phase = PHASE_MSGIN;
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- return 1;
-
- default:
- return 0;
- }
-}
-
-/* Function: int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service in after a reconnection
+/* Function: void fas216_send_messageout(FAS216_Info *info, int start)
+ * Purpose : handle bus service to send a message
* Params : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
* Note : We do not allow the device to change the data direction!
*/
-static int fas216_busservice_reconnected(FAS216_Info *info, unsigned int stat)
+static void fas216_send_messageout(FAS216_Info *info, int start)
{
- fas216_checkmagic(info, "fas216_busservice_reconnected");
-
- switch (stat & STAT_BUSMASK) {
- case STAT_MESGIN:
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- return 1;
-
- case STAT_STATUS:
- fas216_finish_reconnect(info);
- info->scsi.phase = PHASE_STATUS;
- outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
- return 1;
-
- case STAT_DATAOUT: /* data out phase */
- fas216_finish_reconnect(info);
- fas216_starttransfer(info, DMA_OUT, 1);
- return 1;
+ unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
- case STAT_DATAIN: /* data in phase */
- fas216_finish_reconnect(info);
- fas216_starttransfer(info, DMA_IN, 0);
- return 1;
+ fas216_checkmagic(info, "fas216_send_messageout");
- default:
- return 0;
- }
-}
+ outb(CMD_FLUSHFIFO, REG_CMD(info));
-/* Function: int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat)
- * Purpose : handle bus service to send a message
- * Params : info - interface which caused bus service
- * Returns : 0 if unable to service this interrupt
- * Note : We do not allow the device to change the data direction!
- */
-static int fas216_busservice_messageout(FAS216_Info *info, unsigned int stat)
-{
- fas216_checkmagic(info, "fas216_busservice_messageout");
+ if (tot_msglen) {
+ struct message *msg;
+ int msgnr = 0;
- if ((stat & STAT_BUSMASK) != STAT_MESGOUT) {
- printk("scsi%d.%c: didn't manage MESSAGE OUT phase\n",
- info->host->host_no, fas216_target(info));
- return 0;
- } else {
- unsigned int msglen = msgqueue_msglength(&info->scsi.msgs);
+ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+ int i;
- outb(CMD_FLUSHFIFO, REG_CMD(info));
+ for (i = start; i < msg->length; i++)
+ outb(msg->msg[i], REG_FF(info));
- if (msglen == 0)
- outb(NOP, REG_FF(info));
- else {
- char *msg;
+ msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
+ start = 0;
+ }
+ } else
+ outb(NOP, REG_FF(info));
- while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
- int i;
+ outb(CMD_TRANSFERINFO, REG_CMD(info));
- for (i = 0; i < msglen; i++)
- outb(msg[i], REG_FF(info));
- }
- }
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- info->scsi.phase = PHASE_AFTERMSGOUT;
- return 1;
- }
+ info->scsi.phase = PHASE_MSGOUT;
}
/* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
@@ -1151,91 +1274,150 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne
case IS_COMPLETE: /* last action completed */
outb(CMD_NOP, REG_CMD(info));
- switch (info->scsi.phase) {
- case PHASE_SELECTION: /* while selecting - selected target */
- if (!fas216_busservice_selection(info, stat))
- printk("scsi%d.%c: bus phase %s after connect?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat));
- break;
-
- case PHASE_MESSAGESENT:
- if (!fas216_busservice_messagesent(info, stat))
- printk("scsi%d.%c: bus phase %s after message sent?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat));
- break;
+#define STATE(st,ph) ((ph) << 3 | (st))
+ /* This table describes the legal SCSI state transitions,
+ * as described by the SCSI II spec.
+ */
+ switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
+ /* Reselmsgin -> Data In */
+ case STATE(STAT_DATAIN, PHASE_RECONNECTED):
+ fas216_finish_reconnect(info);
+ case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */
+ case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */
+ case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */
+ case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */
+ case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */
+ fas216_starttransfer(info, DMA_IN, 0);
+ return;
- case PHASE_DATAIN: /* while transfering data in */
- case PHASE_DATAOUT: /* while transfering data out */
- if (!fas216_busservice_dataphase(info, stat))
- printk("scsi%d.%c: bus phase %s after %s?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat), fas216_drv_phase(info));
- break;
+ case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */
+ fas216_starttransfer(info, DMA_OUT, 0);
+ return;
+
+ /* Reselmsgin -> Data Out */
+ case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
+ fas216_finish_reconnect(info);
+ case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */
+ case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */
+ case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */
+ case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */
+ fas216_starttransfer(info, DMA_OUT, 1);
+ return;
+
+ /* Reselmsgin -> Status */
+ case STATE(STAT_STATUS, PHASE_RECONNECTED):
+ fas216_finish_reconnect(info);
+ goto status;
+ case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */
+ case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */
+ fas216_stoptransfer(info);
+ case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */
+ case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */
+ case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */
+ case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */
+ status:
+ outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
+ info->scsi.phase = PHASE_STATUS;
+ return;
+
+ case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */
+ case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */
+ fas216_stoptransfer(info);
+ case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */
+ case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */
+ info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+ outb(CMD_TRANSFERINFO, REG_CMD(info));
+ info->scsi.phase = PHASE_MSGIN;
+ return;
- case PHASE_RECONNECTED: /* newly reconnected device */
- /*
- * Command reconnected - if MESGIN, get message - it may be
- * the tag. If not, get command out of the disconnected queue
+ /* Reselmsgin -> Message In */
+ case STATE(STAT_MESGIN, PHASE_RECONNECTED):
+ case STATE(STAT_MESGIN, PHASE_MSGIN):
+ info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
+ outb(CMD_TRANSFERINFO, REG_CMD(info));
+ return;
+
+ /* Reselmsgin -> Command */
+ case STATE(STAT_COMMAND, PHASE_RECONNECTED):
+ fas216_finish_reconnect(info);
+ case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */
+ case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */
+ fas216_send_command(info);
+ info->scsi.phase = PHASE_COMMAND;
+ return;
+ /* Selection -> Message Out */
+ case STATE(STAT_MESGOUT, PHASE_SELECTION):
+ fas216_send_messageout(info, 1);
+ return;
+ /* Any -> Message Out */
+ case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
+ fas216_send_messageout(info, 0);
+ return;
+
+ /* Error recovery rules.
+ * These either attempt to abort or retry the operation.
+ * TODO: we need more of these
+ */
+ case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */
+ /* error - we've sent out all the command bytes
+ * we have.
+ * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
+ * to include the command bytes sent for this to work
+ * correctly.
*/
- if (!fas216_busservice_reconnected(info, stat))
- printk("scsi%d.%c: bus phase %s after reconnect?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat));
- break;
-
- case PHASE_MSGIN:
- case PHASE_AFTERMSGOUT:
- switch (stat & STAT_BUSMASK) {
- case STAT_MESGIN:
- info->scsi.phase = PHASE_MSGIN;
- outb(CMD_TRANSFERINFO, REG_CMD(info));
- break;
-
- case STAT_COMMAND: /* command phase */
- fas216_send_command(info);
- info->scsi.phase = PHASE_SELECTION;
- break;
-
- default:
- printk("scsi%d.%c: bus phase %s after %s?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat),
- fas216_drv_phase(info));
- }
- break;
+ printk(KERN_ERR "scsi%d.%c: "
+ "target trying to receive more command bytes\n",
+ info->host->host_no, fas216_target(info));
+ outb(CMD_SETATN, REG_CMD(info));
+ outb(15, REG_STCL(info));
+ outb(0, REG_STCM(info));
+ outb(0, REG_STCH(info));
+ outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));
+ msgqueue_flush(&info->scsi.msgs);
+ msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
+ return;
+
+ /* Selection -> Message Out */
+ case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
+ case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out -> Message Out */
+ /* If we get another message out phase, this
+ * usually means some parity error occurred.
+ * Resend complete set of messages. If we have
+ * more than 1 byte to send, we need to assert
+ * ATN again.
+ */
+ if (msgqueue_msglength(&info->scsi.msgs) > 1)
+ outb(CMD_SETATN, REG_CMD(info));
- case PHASE_MSGOUT:
- if (!fas216_busservice_messageout(info, stat))
- printk("scsi%d.%c: bus phase %s instead of message out?\n",
- info->host->host_no, fas216_target(info),
- fas216_bus_phase(stat));
- break;
+ fas216_send_messageout(info, 0);
+ return;
+ }
- case PHASE_DISCONNECT:
- printk("scsi%d.%c: disconnect message received, but bus service %s?\n",
+ if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
+ printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
info->host->host_no, fas216_target(info),
fas216_bus_phase(stat));
+ msgqueue_flush(&info->scsi.msgs);
outb(CMD_SETATN, REG_CMD(info));
msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
- info->scsi.phase = PHASE_MSGOUT;
+ info->scsi.phase = PHASE_MSGOUT_EXPECT;
info->scsi.aborting = 1;
outb(CMD_TRANSFERINFO, REG_CMD(info));
- break;
-
- default:
- printk("scsi%d.%c: internal phase %s for bus service?"
- " What do I do with this?\n",
- info->host->host_no, fas216_target(info),
- fas216_drv_phase(info));
+ return;
}
- break;
+ printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
+ info->host->host_no, fas216_target(info),
+ fas216_bus_phase(stat),
+ fas216_drv_phase(info));
+ print_debug_list();
+ return;
default:
printk("scsi%d.%c: bus service at step %d?\n",
info->host->host_no, fas216_target(info),
ssr & IS_BITS);
+ print_debug_list();
}
}
@@ -1269,6 +1451,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned
case PHASE_MSGIN: /* message in phase */
case PHASE_RECONNECTED: /* reconnected command */
if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
+ info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
fas216_message(info);
break;
}
@@ -1300,10 +1483,11 @@ void fas216_intr(struct Scsi_Host *instance)
if (stat & STAT_INT) {
if (isr & INST_BUSRESET)
- printk("scsi%d.H: fas216: bus reset detected\n", instance->host_no);
- else if (isr & INST_ILLEGALCMD)
+ printk(KERN_DEBUG "scsi%d.H: bus reset detected\n", instance->host_no);
+ else if (isr & INST_ILLEGALCMD) {
printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
- else if (isr & INST_DISCONNECT)
+ fas216_dumpstate(info);
+ } else if (isr & INST_DISCONNECT)
fas216_disconnect_intr(info);
else if (isr & INST_RESELECTED) /* reselected */
fas216_reselected_intr(info);
@@ -1327,7 +1511,7 @@ void fas216_intr(struct Scsi_Host *instance)
static void fas216_kick(FAS216_Info *info)
{
Scsi_Cmnd *SCpnt;
- int i, msglen, from_queue = 0;
+ int tot_msglen, from_queue = 0;
fas216_checkmagic(info, "fas216_kick");
@@ -1380,7 +1564,8 @@ static void fas216_kick(FAS216_Info *info)
if (from_queue) {
#ifdef SCSI2_TAG
- if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
+ if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
+ SCpnt->cmnd[0] != INQUIRY) {
SCpnt->device->current_tag += 1;
if (SCpnt->device->current_tag == 0)
SCpnt->device->current_tag = 1;
@@ -1409,6 +1594,7 @@ static void fas216_kick(FAS216_Info *info)
/* build outgoing message bytes */
msgqueue_flush(&info->scsi.msgs);
+
if (info->device[SCpnt->target].disconnect_ok)
msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
else
@@ -1418,15 +1604,29 @@ static void fas216_kick(FAS216_Info *info)
if (SCpnt->tag)
msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
- /* add synchronous negociation */
- if (SCpnt->cmnd[0] == REQUEST_SENSE &&
- info->device[SCpnt->target].negstate == syncneg_start) {
- info->device[SCpnt->target].negstate = syncneg_sent;
+#ifdef SCSI2_WIDE
+ if (info->device[SCpnt->target].wide_state == neg_wait) {
+ info->device[SCpnt->target].wide_state = neg_inprogress;
+ msgqueue_addmsg(&info->scsi.msgs, 4,
+ EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
+ info->ifcfg.wide_max_size);
+ }
+#ifdef SCSI2_SYNC
+ else
+#endif
+#endif
+#ifdef SCSI2_SYNC
+ if ((info->device[SCpnt->target].sync_state == neg_wait ||
+ info->device[SCpnt->target].sync_state == neg_complete) &&
+ (SCpnt->cmnd[0] == REQUEST_SENSE ||
+ SCpnt->cmnd[0] == INQUIRY)) {
+ info->device[SCpnt->target].sync_state = neg_inprogress;
msgqueue_addmsg(&info->scsi.msgs, 5,
EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
1000 / info->ifcfg.clockrate,
info->ifcfg.sync_max_depth);
}
+#endif
/* following what the ESP driver says */
outb(0, REG_STCL(info));
@@ -1444,25 +1644,29 @@ static void fas216_kick(FAS216_Info *info)
/* synchronous transfers */
fas216_set_sync(info, SCpnt->target);
- msglen = msgqueue_msglength(&info->scsi.msgs);
+ tot_msglen = msgqueue_msglength(&info->scsi.msgs);
- if (msglen == 1 || msglen == 3) {
+ if (tot_msglen == 1 || tot_msglen == 3) {
/*
* We have an easy message length to send...
*/
- char *msg;
+ struct message *msg;
+ int msgnr = 0, i;
+
+ info->scsi.phase = PHASE_SELSTEPS;
/* load message bytes */
- while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) {
- for (i = 0; i < msglen; i++)
- outb(msg[i], REG_FF(info));
+ while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+ for (i = 0; i < msg->length; i++)
+ outb(msg->msg[i], REG_FF(info));
+ msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
}
/* load command */
for (i = 0; i < SCpnt->cmd_len; i++)
outb(SCpnt->cmnd[i], REG_FF(info));
- if (msglen == 1)
+ if (tot_msglen == 1)
outb(CMD_SELECTATN, REG_CMD(info));
else
outb(CMD_SELECTATN3, REG_CMD(info));
@@ -1471,17 +1675,11 @@ static void fas216_kick(FAS216_Info *info)
* We have an unusual number of message bytes to send.
* Load first byte into fifo, and issue SELECT with ATN and
* stop steps.
- * Note: we only peek at t his message - we need the rest
- * later on!
*/
- int thismsg;
- char *msg = msgqueue_peeknextmsg(&info->scsi.msgs, &thismsg);
+ struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
- if (!msg || thismsg < 1)
- printk(KERN_CRIT "scsi%d.%c: no message to send, but %d bytes\n",
- info->host->host_no, fas216_target(info), msglen);
- else
- outb(msg[0], REG_FF(info));
+ outb(msg->msg[0], REG_FF(info));
+ msg->fifo = 1;
outb(CMD_SELECTATNSTOP, REG_CMD(info));
}
@@ -1525,11 +1723,15 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
/*
* In theory, this should not happen, but just in case it does.
*/
- if (info->scsi.SCp.ptr && result == DID_OK) {
+ if (info->scsi.SCp.ptr &&
+ info->scsi.SCp.this_residual &&
+ result == DID_OK) {
switch (SCpnt->cmnd[0]) {
case INQUIRY:
case START_STOP:
case READ_CAPACITY:
+ case TEST_UNIT_READY:
+ case MODE_SENSE:
break;
default:
@@ -1579,6 +1781,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
+ unsigned long flags;
fas216_checkmagic(info, "fas216_queue_command");
@@ -1618,27 +1821,18 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
info->stats.queues += 1;
SCpnt->tag = 0;
- if (info->scsi.irq != NO_IRQ) {
- unsigned long flags;
-
- /* add command into execute queue and let it complete under
- * the drivers interrupts.
- */
- if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
- SCpnt->result = DID_ERROR << 16;
- done(SCpnt);
- }
- save_flags_cli(flags);
- if (!info->SCpnt || info->scsi.disconnectable)
- fas216_kick(info);
- restore_flags(flags);
- } else {
- /* no interrupts to rely on - we'll have to handle the
- * command ourselves. For now, we give up.
- */
+ /* add command into execute queue and let it complete under
+ * whatever scheme we're using.
+ */
+ if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
SCpnt->result = DID_ERROR << 16;
done(SCpnt);
}
+ save_flags_cli(flags);
+ if (!info->SCpnt || info->scsi.disconnectable)
+ fas216_kick(info);
+ restore_flags(flags);
+
return 0;
}
@@ -1672,15 +1866,28 @@ int fas216_command(Scsi_Cmnd *SCpnt)
/*
* This wastes time, since we can't return until the command is
- * complete. We can't seep either since we may get re-entered!
+ * complete. We can't sleep either since we may get re-entered!
* However, we must re-enable interrupts, or else we'll be
* waiting forever.
*/
save_flags(flags);
sti();
- while (!info->internal_done)
- barrier();
+ while (!info->internal_done) {
+ /*
+ * If we don't have an IRQ, then we must
+ * poll the card for it's interrupt, and
+ * use that to call this driver's interrupt
+ * routine. That way, we keep the command
+ * progressing.
+ */
+ if (info->scsi.irq == NO_IRQ) {
+ sti();
+ while (!(inb(REG_STAT(info)) & STAT_INT));
+ cli();
+ fas216_intr(info->host);
+ }
+ }
restore_flags(flags);
@@ -1752,6 +1959,95 @@ int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
return FAILED;
}
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
+/*
+ * Prototype: enum res_abort fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+ * Purpose : abort a command on this host
+ * Params : SCpnt - command to abort
+ * Returns : abort status
+ */
+static enum res_abort
+fas216_do_abort(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+ enum res_abort res = res_not_running;
+
+ if (queue_removecmd(&info->queues.issue, SCpnt)) {
+ /*
+ * The command was on the issue queue, and has not been
+ * issued yet. We can remove the command from the queue,
+ * and acknowledge the abort. Neither the devices nor the
+ * interface know about the command.
+ */
+ printk("on issue queue ");
+
+ res = res_success;
+ } else if (queue_removecmd(&info->queues.disconnected, SCpnt)) {
+ /*
+ * The command was on the disconnected queue. Simply
+ * acknowledge the abort condition, and when the target
+ * reconnects, we will give it an ABORT message. The
+ * target should then disconnect, and we will clear
+ * the busylun bit.
+ */
+ printk("on disconnected queue ");
+
+ res = res_success;
+ } else if (info->SCpnt == SCpnt) {
+ unsigned long flags;
+
+ printk("executing ");
+
+ save_flags(flags);
+ cli();
+ switch (info->scsi.phase) {
+ /*
+ * If the interface is idle, and the command is 'disconnectable',
+ * then it is the same as on the disconnected queue. We simply
+ * remove all traces of the command. When the target reconnects,
+ * we will give it an ABORT message since the command could not
+ * be found. When the target finally disconnects, we will clear
+ * the busylun bit.
+ */
+ case PHASE_IDLE:
+ if (info->scsi.disconnectable) {
+ info->scsi.disconnectable = 0;
+ info->SCpnt = NULL;
+ res = res_success;
+ }
+ break;
+
+ /*
+ * If the command has connected and done nothing futher,
+ * simply force a disconnect. We also need to clear the
+ * busylun bit.
+ */
+ case PHASE_SELECTION:
+// info->SCpnt = NULL;
+// res = res_success_clear;
+// break;
+
+ default:
+ res = res_snooze;
+ break;
+ }
+ restore_flags(flags);
+ } else if (info->origSCpnt == SCpnt) {
+ /*
+ * The command will be executed next, but a command
+ * is currently using the interface. This is similar to
+ * being on the issue queue, except the busylun bit has
+ * been set.
+ */
+ info->origSCpnt = NULL;
+ printk("waiting for execution ");
+ res = res_success_clear;
+ } else
+ printk("unknown ");
+
+ return res;
+}
+
/* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
* Purpose : abort a command if something horrible happens.
* Params : SCpnt - Command that is believed to be causing a problem.
@@ -1769,46 +2065,51 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
print_debug_list();
fas216_dumpstate(info);
fas216_dumpinfo(info);
- printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no);
- do {
- /* If command is waiting in the issue queue, then we can
- * simply remove the command and return abort status
- */
- if (queue_removecmd(&info->queues.issue, SCpnt)) {
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done(SCpnt);
- printk("command on issue queue");
- result = SCSI_ABORT_SUCCESS;
- break;
- }
+ printk(KERN_WARNING "scsi%d: abort ", info->host->host_no);
- /* If the command is on the disconencted queue, we need to
- * reconnect to the device
- */
- if (queue_cmdonqueue(&info->queues.disconnected, SCpnt))
- printk("command on disconnected queue");
+ switch (fas216_do_abort(info, SCpnt)) {
+ /*
+ * We managed to find the command and cleared it out.
+ * We do not expect the command to be executing on the
+ * target, but we have set the busylun bit.
+ */
+ case res_success_clear:
+ printk("clear ");
+ clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
- /* If the command is connected, we need to flag that the
- * command needs to be aborted
- */
- if (info->SCpnt == SCpnt)
- printk("command executing");
+ /*
+ * We found the command, and cleared it out. Either
+ * the command is still known to be executing on the
+ * target, or the busylun bit is not set.
+ */
+ case res_success:
+ printk("success\n");
+ SCpnt->result = DID_ABORT << 16;
+ SCpnt->scsi_done(SCpnt);
+ result = SCSI_ABORT_SUCCESS;
+ break;
- /* If the command is pending for execution, then again
- * this is simple - we remove it and report abort status
- */
- if (info->origSCpnt == SCpnt) {
- info->origSCpnt = NULL;
- SCpnt->result = DID_ABORT << 16;
- SCpnt->scsi_done(SCpnt);
- printk("command waiting for execution");
- result = SCSI_ABORT_SUCCESS;
- break;
- }
- } while (0);
+ /*
+ * We did find the command, but unfortunately we couldn't
+ * unhook it from ourselves. Wait some more, and if it
+ * still doesn't complete, reset the interface.
+ */
+ case res_snooze:
+ printk("snooze\n");
+ result = SCSI_ABORT_SNOOZE;
+ break;
- printk("\n");
+ /*
+ * The command could not be found (either because it completed,
+ * or it got dropped.
+ */
+ default:
+ case res_not_running:
+ result = SCSI_ABORT_SNOOZE;
+ printk("not running\n");
+ break;
+ }
return result;
}
@@ -1819,7 +2120,7 @@ int fas216_abort(Scsi_Cmnd *SCpnt)
*/
static void fas216_reset_state(FAS216_Info *info)
{
- syncneg_t negstate;
+ neg_t sync_state, wide_state;
int i;
fas216_checkmagic(info, "fas216_reset_state");
@@ -1833,26 +2134,37 @@ static void fas216_reset_state(FAS216_Info *info)
info->scsi.reconnected.lun = 0;
info->scsi.reconnected.tag = 0;
info->scsi.disconnectable = 0;
- info->scsi.last_message = 0;
info->scsi.aborting = 0;
info->scsi.phase = PHASE_IDLE;
- info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
+ info->scsi.async_stp =
+ fas216_syncperiod(info, info->ifcfg.asyncperiod);
+
+ if (info->ifcfg.wide_max_size == 0)
+ wide_state = neg_invalid;
+ else
+#ifdef SCSI2_WIDE
+ wide_state = neg_wait;
+#else
+ wide_state = neg_invalid;
+#endif
if (info->host->dma_channel == NO_DMA || !info->dma.setup)
- negstate = syncneg_invalid;
+ sync_state = neg_invalid;
else
#ifdef SCSI2_SYNC
- negstate = syncneg_start;
+ sync_state = neg_wait;
#else
- negstate = syncneg_invalid;
+ sync_state = neg_invalid;
#endif
for (i = 0; i < 8; i++) {
- info->device[i].disconnect_ok = info->ifcfg.disconnect_ok;
- info->device[i].negstate = negstate;
- info->device[i].period = info->ifcfg.asyncperiod / 4;
- info->device[i].stp = info->scsi.async_stp;
- info->device[i].sof = 0;
+ info->device[i].disconnect_ok = info->ifcfg.disconnect_ok;
+ info->device[i].sync_state = sync_state;
+ info->device[i].wide_state = wide_state;
+ info->device[i].period = info->ifcfg.asyncperiod / 4;
+ info->device[i].stp = info->scsi.async_stp;
+ info->device[i].sof = 0;
+ info->device[i].wide_xfer = 0;
}
}
@@ -1908,9 +2220,11 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
info->stats.resets += 1;
print_debug_list();
- printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no);
+ printk(KERN_WARNING "scsi%d: reset ", info->host->host_no);
if (SCpnt)
- printk(" for target %d ", SCpnt->target);
+ printk("for target %d ", SCpnt->target);
+
+ printk("\n");
outb(info->scsi.cfg[3], REG_CNTL3(info));
@@ -1963,8 +2277,6 @@ int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
SCpnt->scsi_done(SCpnt);
}
- printk("\n");
-
return result | SCSI_RESET_SUCCESS;
}
@@ -2083,6 +2395,49 @@ int fas216_release(struct Scsi_Host *instance)
return 0;
}
+int fas216_print_stats(FAS216_Info *info, char *buffer)
+{
+ return sprintf(buffer,
+ "Queued commands: %-10u Issued commands: %-10u\n"
+ "Done commands : %-10u Reads : %-10u\n"
+ "Writes : %-10u Others : %-10u\n"
+ "Disconnects : %-10u Aborts : %-10u\n"
+ "Resets : %-10u\n",
+ info->stats.queues, info->stats.removes,
+ info->stats.fins, info->stats.reads,
+ info->stats.writes, info->stats.miscs,
+ info->stats.disconnects, info->stats.aborts,
+ info->stats.resets);
+}
+
+int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
+{
+ struct fas216_device *dev = &info->device[scd->id];
+ int len = 0;
+ char *p;
+
+ proc_print_scsidevice(scd, buffer, &len, 0);
+ p = buffer + len;
+
+ p += sprintf(p, " Extensions: ");
+
+ if (scd->tagged_supported)
+ p += sprintf(p, "TAG %sabled [%d] ",
+ scd->tagged_queue ? "en" : "dis",
+ scd->current_tag);
+
+ p += sprintf(p, "\n Transfers : %d-bit ",
+ 8 << dev->wide_xfer);
+
+ if (dev->sof)
+ p += sprintf(p, "sync offset %d, %d ns\n",
+ dev->sof, dev->period * 4);
+ else
+ p += sprintf(p, "async\n");
+
+ return p - buffer;
+}
+
EXPORT_SYMBOL(fas216_init);
EXPORT_SYMBOL(fas216_abort);
EXPORT_SYMBOL(fas216_reset);
@@ -2094,7 +2449,8 @@ EXPORT_SYMBOL(fas216_eh_abort);
EXPORT_SYMBOL(fas216_eh_device_reset);
EXPORT_SYMBOL(fas216_eh_bus_reset);
EXPORT_SYMBOL(fas216_eh_host_reset);
-
+EXPORT_SYMBOL(fas216_print_stats);
+EXPORT_SYMBOL(fas216_print_device);
#ifdef MODULE
int init_module(void)
diff --git a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h
index 6518fbb42..351666638 100644
--- a/drivers/acorn/scsi/fas216.h
+++ b/drivers/acorn/scsi/fas216.h
@@ -40,6 +40,7 @@
#define CMD_TRANSFERINFO 0x10
#define CMD_INITCMDCOMPLETE 0x11
#define CMD_MSGACCEPTED 0x12
+#define CMD_PADBYTES 0x18
#define CMD_SETATN 0x1a
#define CMD_RSETATN 0x1b
@@ -171,15 +172,17 @@
typedef enum {
PHASE_IDLE, /* we're not planning on doing anything */
PHASE_SELECTION, /* selecting a device */
+ PHASE_SELSTEPS, /* selection with command steps */
+ PHASE_COMMAND, /* command sent */
PHASE_MESSAGESENT, /* selected, and we're sending cmd */
PHASE_RECONNECTED, /* reconnected */
PHASE_DATAOUT, /* data out to device */
PHASE_DATAIN, /* data in from device */
PHASE_MSGIN, /* message in from device */
- PHASE_MSGOUT, /* message out to device */
- PHASE_AFTERMSGOUT, /* after message out phase */
+ PHASE_MSGIN_DISCONNECT, /* disconnecting from bus */
+ PHASE_MSGOUT, /* after message out phase */
+ PHASE_MSGOUT_EXPECT, /* expecting message out */
PHASE_STATUS, /* status from device */
- PHASE_DISCONNECT, /* disconnecting from bus */
PHASE_DONE /* Command complete */
} phase_t;
@@ -197,13 +200,15 @@ typedef enum {
} fasdmatype_t;
typedef enum {
- syncneg_start, /* Negociate with device for Sync xfers */
- syncneg_sent, /* Sync Xfer negociation sent */
- syncneg_complete, /* Sync Xfer complete */
- syncneg_invalid /* Sync Xfer not supported */
-} syncneg_t;
+ neg_wait, /* Negociate with device */
+ neg_inprogress, /* Negociation sent */
+ neg_complete, /* Negociation complete */
+ neg_targcomplete, /* Target completed negociation */
+ neg_invalid /* Negociation not supported */
+} neg_t;
#define MAGIC 0x441296bdUL
+#define NR_MSGS 8
typedef struct {
unsigned long magic_start;
@@ -231,7 +236,7 @@ typedef struct {
MsgQueue_t msgs; /* message queue for connected device */
unsigned int async_stp; /* Async transfer STP value */
- unsigned short last_message; /* last message to be sent */
+ unsigned char msgin_fifo; /* bytes in fifo at time of message in */
unsigned char disconnectable:1; /* this command can be disconnected */
unsigned char aborting:1; /* aborting command */
@@ -255,6 +260,7 @@ typedef struct {
unsigned char clockrate; /* clock rate of FAS device (MHz) */
unsigned char select_timeout; /* timeout (R5) */
unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */
+ unsigned char wide_max_size; /* Maximum wide transfer size */
unsigned char cntl3; /* Control Reg 3 */
unsigned int asyncperiod; /* Async transfer period (ns) */
unsigned int disconnect_ok:1; /* Disconnects allowed? */
@@ -267,12 +273,14 @@ typedef struct {
} queues;
/* per-device info */
- struct {
+ struct fas216_device {
unsigned char disconnect_ok:1; /* device can disconnect */
- unsigned int period; /* sync xfer period (*4ns) */
+ unsigned char period; /* sync xfer period in (*4ns) */
unsigned char stp; /* synchronous transfer period */
unsigned char sof; /* synchronous offset register */
- syncneg_t negstate; /* synchronous transfer mode */
+ unsigned char wide_xfer; /* currently negociated wide transfer */
+ neg_t sync_state; /* synchronous transfer mode */
+ neg_t wide_state; /* wide transfer mode */
} device[8];
unsigned char busyluns[8]; /* array of bits indicating LUNs busy */
@@ -340,6 +348,9 @@ extern void fas216_intr (struct Scsi_Host *instance);
*/
extern int fas216_release (struct Scsi_Host *instance);
+extern int fas216_print_stats(FAS216_Info *info, char *buffer);
+extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
+
/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
* Purpose : abort this command
* Params : SCpnt - command to abort
diff --git a/drivers/acorn/scsi/msgqueue.c b/drivers/acorn/scsi/msgqueue.c
index 7621b4d2b..f28784496 100644
--- a/drivers/acorn/scsi/msgqueue.c
+++ b/drivers/acorn/scsi/msgqueue.c
@@ -83,45 +83,25 @@ int msgqueue_msglength(MsgQueue_t *msgq)
int length = 0;
for (mq = msgq->qe; mq; mq = mq->next)
- length += mq->length;
+ length += mq->msg.length;
return length;
}
/*
- * Function: char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return a message & its length
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message
* Params : msgq - queue to obtain message from
- * length - pointer to int for message length
+ * : msgno - message number
* Returns : pointer to message string, or NULL
*/
-char *msgqueue_getnextmsg(MsgQueue_t *msgq, int *length)
+struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
{
struct msgqueue_entry *mq;
- if ((mq = msgq->qe) != NULL) {
- msgq->qe = mq->next;
- mqe_free(msgq, mq);
- *length = mq->length;
- }
-
- return mq ? mq->msg : NULL;
-}
-
-/*
- * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return next message & length without removing it from the list
- * Params : msgq - queue to obtain message from
- * : length - pointer to int for message length
- * Returns : pointer to message string, or NULL
- */
-char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
-{
- struct msgqueue_entry *mq = msgq->qe;
-
- *length = mq ? mq->length : 0;
+ for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
- return mq ? mq->msg : NULL;
+ return mq ? &mq->msg : NULL;
}
/*
@@ -143,10 +123,11 @@ int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
va_start(ap, length);
for (i = 0; i < length; i++)
- mq->msg[i] = va_arg(ap, unsigned char);
+ mq->msg.msg[i] = va_arg(ap, unsigned char);
va_end(ap);
- mq->length = length;
+ mq->msg.length = length;
+ mq->msg.fifo = 0;
mq->next = NULL;
mqp = &msgq->qe;
@@ -178,8 +159,7 @@ void msgqueue_flush(MsgQueue_t *msgq)
EXPORT_SYMBOL(msgqueue_initialise);
EXPORT_SYMBOL(msgqueue_free);
EXPORT_SYMBOL(msgqueue_msglength);
-EXPORT_SYMBOL(msgqueue_getnextmsg);
-EXPORT_SYMBOL(msgqueue_peeknextmsg);
+EXPORT_SYMBOL(msgqueue_getmsg);
EXPORT_SYMBOL(msgqueue_addmsg);
EXPORT_SYMBOL(msgqueue_flush);
diff --git a/drivers/acorn/scsi/msgqueue.h b/drivers/acorn/scsi/msgqueue.h
index cca30255c..8016dcf4e 100644
--- a/drivers/acorn/scsi/msgqueue.h
+++ b/drivers/acorn/scsi/msgqueue.h
@@ -6,9 +6,14 @@
#ifndef MSGQUEUE_H
#define MSGQUEUE_H
-struct msgqueue_entry {
+struct message {
char msg[8];
int length;
+ int fifo;
+};
+
+struct msgqueue_entry {
+ struct message msg;
struct msgqueue_entry *next;
};
@@ -21,60 +26,51 @@ typedef struct {
} MsgQueue_t;
/*
- * Function: void msgqueue_initialise (MsgQueue_t *msgq)
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
* Purpose : initialise a message queue
* Params : msgq - queue to initialise
*/
-extern void msgqueue_initialise (MsgQueue_t *msgq);
+extern void msgqueue_initialise(MsgQueue_t *msgq);
/*
- * Function: void msgqueue_free (MsgQueue_t *msgq)
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
* Purpose : free a queue
* Params : msgq - queue to free
*/
-extern void msgqueue_free (MsgQueue_t *msgq);
+extern void msgqueue_free(MsgQueue_t *msgq);
/*
- * Function: int msgqueue_msglength (MsgQueue_t *msgq)
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
* Purpose : calculate the total length of all messages on the message queue
* Params : msgq - queue to examine
* Returns : number of bytes of messages in queue
*/
-extern int msgqueue_msglength (MsgQueue_t *msgq);
+extern int msgqueue_msglength(MsgQueue_t *msgq);
/*
- * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length)
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
* Purpose : return a message & its length
* Params : msgq - queue to obtain message from
- * length - pointer to int for message length
- * Returns : pointer to message string, or NULL
- */
-extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length);
-
-/*
- * Function: char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length)
- * Purpose : return next message & length without removing it from the list
- * Params : msgq - queue to obtain message from
- * : length - pointer to int for message length
+ * : msgno - message number
* Returns : pointer to message string, or NULL
*/
-extern char *msgqueue_peeknextmsg(MsgQueue_t *msgq, int *length);
+extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno);
/*
- * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...)
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
* Purpose : add a message onto a message queue
* Params : msgq - queue to add message on
* length - length of message
* ... - message bytes
* Returns : != 0 if successful
*/
-extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...);
+extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...);
/*
- * Function: void msgqueue_flush (MsgQueue_t *msgq)
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
* Purpose : flush all messages from message queue
* Params : msgq - queue to flush
*/
-extern void msgqueue_flush (MsgQueue_t *msgq);
+extern void msgqueue_flush(MsgQueue_t *msgq);
#endif
diff --git a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c
index caae8a8ba..95dbc3050 100644
--- a/drivers/acorn/scsi/powertec.c
+++ b/drivers/acorn/scsi/powertec.c
@@ -114,6 +114,8 @@ static const expansioncard_ops_t powertecscsi_ops = {
powertecscsi_irqenable,
powertecscsi_irqdisable,
NULL,
+ NULL,
+ NULL,
NULL
};
@@ -271,8 +273,9 @@ powertecscsi_detect(Scsi_Host_Template *tpnt)
info->info.ifcfg.select_timeout = 255;
info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD;
info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH;
- info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+ info->info.ifcfg.cntl3 = /*CNTL3_BS8 |*/ CNTL3_FASTSCSI | CNTL3_FASTCLK;
info->info.ifcfg.disconnect_ok = 1;
+ info->info.ifcfg.wide_max_size = 0;
info->info.dma.setup = powertecscsi_dma_setup;
info->info.dma.pseudo = NULL;
info->info.dma.stop = powertecscsi_dma_stop;
@@ -443,31 +446,12 @@ int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
host->io_port, host->irq, host->dma_channel,
info->info.scsi.type, info->control.terms ? "on" : "off");
- pos += sprintf(buffer+pos,
- "Queued commands: %-10u Issued commands: %-10u\n"
- "Done commands : %-10u Reads : %-10u\n"
- "Writes : %-10u Others : %-10u\n"
- "Disconnects : %-10u Aborts : %-10u\n"
- "Resets : %-10u\n",
- info->info.stats.queues, info->info.stats.removes,
- info->info.stats.fins, info->info.stats.reads,
- info->info.stats.writes, info->info.stats.miscs,
- info->info.stats.disconnects, info->info.stats.aborts,
- info->info.stats.resets);
+ pos += fas216_print_stats(&info->info, buffer + pos);
- pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none");
+ pos += sprintf (buffer+pos, "\nAttached devices:\n");
for (scd = host->host_queue; scd; scd = scd->next) {
- int len;
-
- proc_print_scsidevice (scd, buffer, &len, pos);
- pos += len;
- pos += sprintf (buffer+pos, "Extensions: ");
- if (scd->tagged_supported)
- pos += sprintf (buffer+pos, "TAG %sabled [%d] ",
- scd->tagged_queue ? "en" : "dis",
- scd->current_tag);
- pos += sprintf (buffer+pos, "\n");
+ pos += fas216_print_device(&info->info, scd, buffer + pos);
if (pos + begin < offset) {
begin += pos;
diff --git a/drivers/acorn/scsi/queue.c b/drivers/acorn/scsi/queue.c
index b8f5ba0ad..31e9d3dfc 100644
--- a/drivers/acorn/scsi/queue.c
+++ b/drivers/acorn/scsi/queue.c
@@ -55,6 +55,7 @@ int queue_initialise (Queue_t *queue)
q->magic = QUEUE_MAGIC_FREE;
q->SCpnt = NULL;
}
+ q -= 1;
q->next = NULL;
}
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 47fc9eac1..a9b9a000f 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -38,16 +38,16 @@ else
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
- bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
+ 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
+ fi
bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210
- if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
- bool ' Use DMA by default when available' CONFIG_IDEDMA_AUTO
- fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
bool ' Intel PIIXn chipsets support (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX
- if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+ if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
@@ -66,7 +66,7 @@ else
fi
fi
fi
- if [ "$CONFIG_PPC" = "y" ]; then
+ if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
fi
fi
@@ -75,11 +75,25 @@ else
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
- define_bool CONFIG_BLK_DEV_IDEDMA y
bool ' Use DMA by default' CONFIG_PMAC_IDEDMA_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
+ 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'
@@ -170,7 +184,8 @@ if [ "$CONFIG_BLK_DEV_CMD640" = "y" -o \
"$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
"$CONFIG_BLK_DEV_CY82C693" = "y" -o \
"$CONFIG_BLK_DEV_HPT343" = "y" -o \
- "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
+ "$CONFIG_BLK_DEV_PIIX" = "y" -o \
+ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then
define_bool CONFIG_BLK_DEV_IDE_MODES y
else
define_bool CONFIG_BLK_DEV_IDE_MODES n
diff --git a/drivers/block/icside.c b/drivers/block/icside.c
new file mode 100644
index 000000000..299bce7a6
--- /dev/null
+++ b/drivers/block/icside.c
@@ -0,0 +1,634 @@
+/*
+ * linux/drivers/block/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ * 08-Jun-1996 RMK Created
+ * 12-Sep-1997 RMK Added interrupt enable/disable
+ * 17-Apr-1999 RMK Added support for V6 EASI
+ * 22-May-1999 RMK Added support for V6 DMA
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS 2
+
+#define ICS_IDENT_OFFSET 0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT 0x000
+#define ICS_ARCIN_V5_INTROFFSET 0x001
+#define ICS_ARCIN_V5_IDEOFFSET 0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET 0xae0
+#define ICS_ARCIN_V5_IDESTEPPING 4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1 0x800
+#define ICS_ARCIN_V6_INTROFFSET_1 0x880
+#define ICS_ARCIN_V6_INTRSTAT_1 0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2 0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2 0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2 0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0
+#define ICS_ARCIN_V6_IDESTEPPING 4
+
+struct cardinfo {
+ unsigned int dataoffset;
+ unsigned int ctrloffset;
+ unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+ ICS_ARCIN_V5_IDEOFFSET,
+ ICS_ARCIN_V5_IDEALTOFFSET,
+ ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+ ICS_ARCIN_V6_IDEOFFSET_1,
+ ICS_ARCIN_V6_IDEALTOFFSET_1,
+ ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+ ICS_ARCIN_V6_IDEOFFSET_2,
+ ICS_ARCIN_V6_IDEALTOFFSET_2,
+ ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+ { MANU_ICS, PROD_ICS_IDE },
+ { MANU_ICS2, PROD_ICS2_IDE },
+ { 0xffff, 0xffff }
+};
+
+typedef enum {
+ ics_if_unknown,
+ ics_if_arcin_v5,
+ ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int memc_port = (unsigned int)ec->irq_data;
+ outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int memc_port = (unsigned int)ec->irq_data;
+ inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+ icside_irqenable_arcin_v5,
+ icside_irqdisable_arcin_v5,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+ outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+ outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+ inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+ unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+ return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+ inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+ icside_irqenable_arcin_v6,
+ icside_irqdisable_arcin_v6,
+ icside_irqpending_arcin_v6,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose : identify IDE interface type
+ * Notes : checks the description string
+ */
+static iftype_t icside_identifyif (struct expansion_card *ec)
+{
+ unsigned int addr;
+ iftype_t iftype;
+ int id = 0;
+
+ iftype = ics_if_unknown;
+
+ addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+ id = inb (addr) & 1;
+ id |= (inb (addr + 1) & 1) << 1;
+ id |= (inb (addr + 2) & 1) << 2;
+ id |= (inb (addr + 3) & 1) << 3;
+
+ switch (id) {
+ case 0: /* A3IN */
+ printk("icside: A3IN unsupported\n");
+ break;
+
+ case 1: /* A3USER */
+ printk("icside: A3USER unsupported\n");
+ break;
+
+ case 3: /* ARCIN V6 */
+ printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+ iftype = ics_if_arcin_v6;
+ break;
+
+ case 15:/* ARCIN V5 (no id) */
+ printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+ iftype = ics_if_arcin_v5;
+ break;
+
+ default:/* we don't know - complain very loudly */
+ printk("icside: ***********************************\n");
+ printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+ printk("icside: ***********************************\n");
+ printk("icside: please report this to linux@arm.linux.org.uk\n");
+ printk("icside: defaulting to ARCIN V5\n");
+ iftype = ics_if_arcin_v5;
+ break;
+ }
+
+ return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD
+ * DMA controllers. There is only one DMA controller
+ * per card, which means that only one drive can be
+ * accessed at one time. NOTE! We do not inforce that
+ * here, but we rely on the main IDE driver spotting
+ * that both interfaces use the same IRQ, which should
+ * guarantee this.
+ *
+ * We are limited by the drives IOR/IOW pulse time.
+ * The closest that we can get to the requirements is
+ * a type C cycle for both mode 1 and mode 2. However,
+ * this does give a burst of 8MB/s.
+ *
+ * This has been tested with a couple of Conner
+ * Peripherals 1080MB CFS1081A drives, one on each
+ * interface, which deliver about 2MB/s each. I
+ * believe that this is limited by the lack of
+ * on-board drive cache.
+ */
+#define TABLE_SIZE 2048
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int reading)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ struct buffer_head *bh = rq->bh;
+ unsigned long addr, size;
+ unsigned char *virt_addr;
+ unsigned int count = 0;
+ dmasg_t *sg = (dmasg_t *)HWIF(drive)->dmatable;
+
+ do {
+ if (bh == NULL) {
+ /* paging requests have (rq->bh == NULL) */
+ virt_addr = rq->buffer;
+ addr = virt_to_bus (virt_addr);
+ size = rq->nr_sectors << 9;
+ } else {
+ /* group sequential buffers into one large buffer */
+ virt_addr = bh->b_data;
+ addr = virt_to_bus (virt_addr);
+ size = bh->b_size;
+ while ((bh = bh->b_reqnext) != NULL) {
+ if ((addr + size) != virt_to_bus (bh->b_data))
+ break;
+ size += bh->b_size;
+ }
+ }
+
+ if (addr & 3) {
+ printk("%s: misaligned DMA buffer\n", drive->name);
+ return 0;
+ }
+
+ if (size) {
+ if (reading)
+ dma_cache_inv((unsigned int)virt_addr, size);
+ else
+ dma_cache_wback((unsigned int)virt_addr, size);
+ }
+
+ sg[count].address = addr;
+ sg[count].length = size;
+ if (++count >= (TABLE_SIZE / sizeof(dmasg_t))) {
+ printk("%s: DMA table too small\n", drive->name);
+ return 0;
+ }
+ } while (bh != NULL);
+
+ if (!count)
+ printk("%s: empty DMA table?\n", drive->name);
+
+ return count;
+}
+
+static int
+icside_config_drive(ide_drive_t *drive, int mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int speed, err;
+
+ if (mode == 2) {
+ speed = XFER_MW_DMA_2;
+ drive->drive_data = 250;
+ } else {
+ speed = XFER_MW_DMA_1;
+ drive->drive_data = 250;
+ }
+
+ /*
+ * Don't use ide_wait_cmd here - it will
+ * attempt to set_geometry and recalibrate,
+ * but for some reason these don't work at
+ * this point (lost interrupt).
+ */
+ SELECT_DRIVE(hwif, drive);
+ OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
+ OUT_BYTE(speed, IDE_NSECTOR_REG);
+ OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
+ OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
+
+ err = ide_wait_stat(drive, DRIVE_READY,
+ BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
+
+ if (err == 0) {
+ drive->id->dma_mword &= 0x00ff;
+ drive->id->dma_mword |= 256 << mode;
+ } else
+ drive->drive_data = 0;
+
+ return err;
+}
+
+static int
+icside_dma_check(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ int autodma = hwif->autodma;
+
+ if (id && (id->capability & 1) && autodma) {
+ int dma_mode = 0;
+
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive))
+ return hwif->dmaproc(ide_dma_off, drive);
+
+ /* Enable DMA on any drive that has
+ * UltraDMA (mode 0/1/2) enabled
+ */
+ if (id->field_valid & 4 && id->dma_ultra & 7)
+ dma_mode = 2;
+
+ /* Enable DMA on any drive that has mode1
+ * or mode2 multiword DMA enabled
+ */
+ if (id->field_valid & 2 && id->dma_mword & 6)
+ dma_mode = id->dma_mword & 4 ? 2 : 1;
+
+ /* Consult the list of known "good" drives */
+ if (ide_dmaproc(ide_dma_good_drive, drive))
+ dma_mode = 1;
+
+ if (dma_mode && icside_config_drive(drive, dma_mode) == 0)
+ return hwif->dmaproc(ide_dma_on, drive);
+ }
+ return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+static int
+icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int count, reading = 0;
+
+ switch (func) {
+ case ide_dma_check:
+ return icside_dma_check(drive);
+
+ case ide_dma_read:
+ reading = 1;
+ case ide_dma_write:
+ count = icside_build_dmatable(drive, reading);
+ if (!count)
+ return 1;
+ disable_dma(hwif->hw.dma);
+
+ /* Route the DMA signals to
+ * to the correct interface.
+ */
+ outb(hwif->select_data, hwif->config_data);
+
+ /* Select the correct timing
+ * for this drive
+ */
+ set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+ set_dma_sg(hwif->hw.dma, (dmasg_t *)hwif->dmatable, count);
+ set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
+ : DMA_MODE_WRITE);
+
+ drive->waiting_for_dma = 1;
+ if (drive->media != ide_disk)
+ return 0;
+
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
+ IDE_COMMAND_REG);
+
+ case ide_dma_begin:
+ enable_dma(hwif->hw.dma);
+ return 0;
+
+ case ide_dma_end:
+ drive->waiting_for_dma = 0;
+ disable_dma(hwif->hw.dma);
+ return get_dma_residue(hwif->hw.dma) != 0;
+
+ case ide_dma_test_irq:
+ return inb((unsigned long)hwif->hw.priv) & 1;
+
+ default:
+ return ide_dmaproc(func, drive);
+ }
+}
+
+static unsigned long
+icside_alloc_dmatable(void)
+{
+ static unsigned long dmatable;
+ static unsigned int leftover;
+ unsigned long table;
+
+ if (leftover < TABLE_SIZE) {
+#if PAGE_SIZE == TABLE_SIZE * 2
+ dmatable = __get_free_pages(GFP_KERNEL, 1);
+ leftover = PAGE_SIZE;
+#else
+ dmatable = kmalloc(TABLE_SIZE, GFP_KERNEL);
+ leftover = TABLE_SIZE;
+#endif
+ }
+
+ table = dmatable;
+ if (table) {
+ dmatable += TABLE_SIZE;
+ leftover -= TABLE_SIZE;
+ }
+
+ return table;
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+ unsigned long table = icside_alloc_dmatable();
+
+ printk(" %s: SG-DMA", hwif->name);
+
+ if (!table)
+ printk(" -- ERROR, unable to allocate DMA table\n");
+ else {
+ hwif->dmatable = (void *)table;
+ hwif->dmaproc = icside_dmaproc;
+ hwif->autodma = autodma;
+
+ printk(" capable%s\n", autodma ?
+ ", auto-enable" : "");
+ }
+
+ return hwif->dmatable != NULL;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+ ide_hwif_t *hwif;
+ int index;
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (hwif->hw.io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+ goto found;
+ }
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (!hwif->hw.io_ports[IDE_DATA_OFFSET])
+ goto found;
+ }
+
+ return NULL;
+found:
+ return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+ unsigned long port = base + info->dataoffset;
+ ide_hwif_t *hwif;
+
+ hwif = icside_find_hwif(base);
+ if (hwif) {
+ int i;
+
+ memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+ port += 1 << info->stepping;
+ }
+ hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+ hwif->hw.irq = irq;
+ hwif->hw.dma = NO_DMA;
+ hwif->noprobe = 0;
+ hwif->chipset = ide_acorn;
+ }
+
+ return hwif;
+}
+
+static int icside_register_v5(struct expansion_card *ec, int autodma)
+{
+ unsigned long slot_port;
+ ide_hwif_t *hwif;
+
+ slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+ ec->irqaddr = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+ ec->irqmask = 1;
+ ec->irq_data = (void *)slot_port;
+ ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+ hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+ return hwif ? 0 : -1;
+}
+
+static int icside_register_v6(struct expansion_card *ec, int autodma)
+{
+ unsigned long slot_port, port;
+ ide_hwif_t *hwif, *mate;
+ int sel = 0;
+
+ slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+ port = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+ if (port == 0)
+ port = slot_port;
+ else
+ sel = 1 << 5;
+
+ outb(sel, slot_port);
+
+ ec->irq_data = (void *)port;
+ ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+ inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+ hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+ mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+ if (ec->dma != NO_DMA) {
+ if (request_dma(ec->dma, hwif->name))
+ goto no_dma;
+
+ if (hwif) {
+ hwif->config_data = slot_port;
+ hwif->select_data = sel;
+ hwif->hw.dma = ec->dma;
+ hwif->hw.priv = (void *)
+ (port + ICS_ARCIN_V6_INTRSTAT_1);
+ hwif->channel = 0;
+ icside_setup_dma(hwif, autodma);
+ }
+ if (mate) {
+ mate->config_data = slot_port;
+ mate->select_data = sel | 1;
+ mate->hw.dma = ec->dma;
+ mate->hw.priv = (void *)
+ (port + ICS_ARCIN_V6_INTRSTAT_2);
+ mate->channel = 1;
+ icside_setup_dma(mate, autodma);
+ }
+ }
+#endif
+
+no_dma:
+ return hwif || mate ? 0 : -1;
+}
+
+int icside_init(void)
+{
+ int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+ autodma = 1;
+#endif
+
+ ecard_startfind ();
+
+ do {
+ struct expansion_card *ec;
+ int result;
+
+ ec = ecard_find(0, icside_cids);
+ if (ec == NULL)
+ break;
+
+ ecard_claim(ec);
+
+ switch (icside_identifyif(ec)) {
+ case ics_if_arcin_v5:
+ result = icside_register_v5(ec, autodma);
+ break;
+
+ case ics_if_arcin_v6:
+ result = icside_register_v6(ec, autodma);
+ break;
+
+ default:
+ result = -1;
+ break;
+ }
+
+ if (result)
+ ecard_release(ec);
+ } while (1);
+
+ return 0;
+}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 9b29f4f55..185591b3a 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -603,7 +603,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
/* Verify requested block sizes. */
for (i = 0; i < nr; i++) {
- if (bh[i] && bh[i]->b_size != correct_size) {
+ if (bh[i]->b_size != correct_size) {
printk(KERN_NOTICE "ll_rw_block: device %s: "
"only %d-char blocks implemented (%lu)\n",
kdevname(bh[0]->b_dev),
diff --git a/drivers/acorn/block/ide-rapide.c b/drivers/block/rapide.c
index d142cebff..468f2e3b1 100644
--- a/drivers/acorn/block/ide-rapide.c
+++ b/drivers/block/rapide.c
@@ -12,10 +12,9 @@
#include <linux/malloc.h>
#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <asm/ecard.h>
-#include <asm/ide.h>
+#include <linux/ide.h>
-#include "../../block/ide.h"
+#include <asm/ecard.h>
static const card_ids rapide_cids[] = {
{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
@@ -28,14 +27,20 @@ static int result[MAX_ECARDS];
static inline int rapide_register(struct expansion_card *ec)
{
unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
- ide_ioregspec_t spec;
+ hw_regs_t hw;
+
+ int i;
+
+ memset(&hw, 0, sizeof(hw));
- spec.base = port;
- spec.ctrl = port + 0x206;
- spec.offset = 1 << 4;
- spec.irq = ec->irq;
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw.io_ports[i] = (ide_ioreg_t)port;
+ port += 1 << 4;
+ }
+ hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+ hw.irq = ec->irq;
- return ide_register_port(&spec);
+ return ide_register_hw(&hw, NULL);
}
int rapide_init(void)
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 9319b777a..0dc5a7cca 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -9,6 +9,7 @@
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
+ * ==FILEDATE 19990524==
*
* This code is released under the GNU General Public License (GPL)
*
@@ -72,7 +73,7 @@
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.0"
+#define HDLC_VERSION "1.2"
#include <linux/version.h>
#include <linux/config.h>
@@ -813,6 +814,8 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
{
struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
int error = 0;
+ int count;
+ unsigned long flags;
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
@@ -824,21 +827,29 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
switch (cmd) {
case FIONREAD:
- {
- /* report count of read data available */
- /* in next available frame (if any) */
- int count;
- unsigned long flags;
- spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
- if (n_hdlc->rx_buf_list.head)
- count = n_hdlc->rx_buf_list.head->count;
- else
- count = 0;
- spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
- PUT_USER (error, count, (int *) arg);
- }
+ /* report count of read data available */
+ /* in next available frame (if any) */
+ spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+ if (n_hdlc->rx_buf_list.head)
+ count = n_hdlc->rx_buf_list.head->count;
+ else
+ count = 0;
+ spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+ PUT_USER (error, count, (int *) arg);
break;
-
+
+ case TIOCOUTQ:
+ /* get the pending tx byte count in the driver */
+ count = tty->driver.chars_in_buffer ?
+ tty->driver.chars_in_buffer(tty) : 0;
+ /* add size of next output frame in queue */
+ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+ if (n_hdlc->tx_buf_list.head)
+ count += n_hdlc->tx_buf_list.head->count;
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+ PUT_USER (error, count, (int*)arg);
+ break;
+
default:
error = n_tty_ioctl (tty, file, cmd, arg);
break;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 75c8a68b9..3b6c7eacf 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,6 +1,8 @@
/*
* linux/drivers/char/synclink.c
*
+ * ==FILEDATE 19990610==
+ *
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
*
@@ -43,14 +45,15 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
#define BREAKPOINT() asm(" int $3");
#define MAX_ISA_DEVICES 10
-#include <linux/config.h>
+#include <linux/config.h>
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -68,7 +71,7 @@
#include <linux/mm.h>
#include <linux/malloc.h>
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+#if LINUX_VERSION_CODE >= VERSION(2,1,0)
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <asm/serial.h>
@@ -209,8 +212,21 @@ typedef struct _BH_EVENT {
} BH_EVENT, *BH_QUEUE; /* Queue of BH actions to be done. */
#define MAX_BH_QUEUE_ENTRIES 200
+#define IO_PIN_SHUTDOWN_LIMIT (MAX_BH_QUEUE_ENTRIES/4)
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct _input_signal_events {
+ int ri_up;
+ int ri_down;
+ int dsr_up;
+ int dsr_down;
+ int dcd_up;
+ int dcd_down;
+ int cts_up;
+ int cts_down;
+};
+
/*
* Device instance data structure
*/
@@ -266,6 +282,11 @@ struct mgsl_struct {
int bh_running; /* Protection from multiple */
int isr_overflow;
int bh_requested;
+
+ int dcd_chkcount; /* check counts to prevent */
+ int cts_chkcount; /* too many IRQs if a signal */
+ int dsr_chkcount; /* is floating */
+ int ri_chkcount;
char *buffer_list; /* virtual address of Rx & Tx buffer lists */
unsigned long buffer_list_phys;
@@ -327,6 +348,11 @@ struct mgsl_struct {
char flag_buf[HDLC_MAX_FRAME_SIZE];
char char_buf[HDLC_MAX_FRAME_SIZE];
BOOLEAN drop_rts_on_tx_done;
+
+ BOOLEAN loopmode_insert_requested;
+ BOOLEAN loopmode_send_done_requested;
+
+ struct _input_signal_events input_signal_events;
};
#define MGSL_MAGIC 0x5401
@@ -712,6 +738,13 @@ void usc_loopback_frame( struct mgsl_struct *info );
void mgsl_tx_timeout(unsigned long context);
+
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info );
+void usc_loopmode_insert_request( struct mgsl_struct * info );
+int usc_loopmode_active( struct mgsl_struct * info);
+void usc_loopmode_send_done( struct mgsl_struct * info );
+int usc_loopmode_send_active( struct mgsl_struct * info );
+
/*
* Defines a BUS descriptor value for the PCI adapter
* local bus address ranges.
@@ -820,7 +853,8 @@ static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode);
static int mgsl_txenable(struct mgsl_struct * info, int enable);
static int mgsl_txabort(struct mgsl_struct * info);
static int mgsl_rxenable(struct mgsl_struct * info, int enable);
-static int mgsl_wait_event(struct mgsl_struct * info, int mask);
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask);
+static int mgsl_loopmode_send_done( struct mgsl_struct * info );
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
@@ -865,7 +899,7 @@ MODULE_PARM(debug_level,"i");
#endif
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.00";
+static char *driver_version = "1.7";
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
@@ -1001,6 +1035,7 @@ void mgsl_format_bh_queue( struct mgsl_struct *info )
/* As a safety measure, mark the end of the chain with a NULL */
info->free_bh_queue_tail->link = NULL;
+ info->isr_overflow=0;
} /* end of mgsl_format_bh_queue() */
@@ -1092,6 +1127,14 @@ int mgsl_bh_queue_get( struct mgsl_struct *info )
spin_unlock_irqrestore(&info->irq_spinlock,flags);
return 1;
}
+
+ if ( info->isr_overflow ) {
+ if (debug_level >= DEBUG_LEVEL_BH)
+ printk("ISR overflow cleared.\n");
+ info->isr_overflow=0;
+ usc_EnableMasterIrqBit(info);
+ usc_EnableDmaInterrupts(info,DICR_MASTER);
+ }
/* Mark BH routine as complete */
info->bh_running = 0;
@@ -1155,10 +1198,6 @@ void mgsl_bh_handler(void* Context)
}
}
- if ( info->isr_overflow ) {
- printk("ISR overflow detected.\n");
- }
-
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_handler(%s) exit\n",
__FILE__,__LINE__,info->device_name);
@@ -1199,6 +1238,7 @@ void mgsl_bh_receive_dma( struct mgsl_struct *info, unsigned short status )
void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount )
{
struct tty_struct *tty = info->tty;
+ unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_transmit_data() entry on %s\n",
@@ -1215,7 +1255,15 @@ void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount )
}
wake_up_interruptible(&tty->write_wait);
}
-
+
+ /* if transmitter idle and loopmode_send_done_requested
+ * then start echoing RxD to TxD
+ */
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ if ( !info->tx_active && info->loopmode_send_done_requested )
+ usc_loopmode_send_done( info );
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
} /* End Of mgsl_bh_transmit_data() */
/* mgsl_bh_status_handler()
@@ -1240,6 +1288,23 @@ void mgsl_bh_status_handler( struct mgsl_struct *info, unsigned short status )
printk( "%s(%d):mgsl_bh_status_handler() entry on %s\n",
__FILE__,__LINE__,info->device_name);
+ if (status & MISCSTATUS_RI_LATCHED) {
+ if (info->ri_chkcount)
+ (info->ri_chkcount)--;
+ }
+ if (status & MISCSTATUS_DSR_LATCHED) {
+ if (info->dsr_chkcount)
+ (info->dsr_chkcount)--;
+ }
+ if (status & MISCSTATUS_DCD_LATCHED) {
+ if (info->dcd_chkcount)
+ (info->dcd_chkcount)--;
+ }
+ if (status & MISCSTATUS_CTS_LATCHED) {
+ if (info->cts_chkcount)
+ (info->cts_chkcount)--;
+ }
+
} /* End Of mgsl_bh_status_handler() */
/* mgsl_isr_receive_status()
@@ -1259,8 +1324,21 @@ void mgsl_isr_receive_status( struct mgsl_struct *info )
printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
__FILE__,__LINE__,status);
- usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
- usc_UnlatchRxstatusBits( info, status );
+ if ( (status & RXSTATUS_ABORT_RECEIVED) &&
+ info->loopmode_insert_requested &&
+ usc_loopmode_active(info) )
+ {
+ ++info->icount.rxabort;
+ info->loopmode_insert_requested = FALSE;
+
+ /* clear CMR:13 to start echoing RxD to TxD */
+ info->cmr_value &= ~BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+
+ /* disable received abort irq (no longer required) */
+ usc_OutReg(info, RICR,
+ (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
+ }
if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
if (status & RXSTATUS_EXITED_HUNT)
@@ -1278,6 +1356,9 @@ void mgsl_isr_receive_status( struct mgsl_struct *info )
usc_RTCmd( info, RTCmd_PurgeRxFifo );
}
+ usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
+ usc_UnlatchRxstatusBits( info, status );
+
} /* end of mgsl_isr_receive_status() */
/* mgsl_isr_transmit_status()
@@ -1300,7 +1381,7 @@ void mgsl_isr_transmit_status( struct mgsl_struct *info )
usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
usc_UnlatchTxstatusBits( info, status );
-
+
if ( status & TXSTATUS_EOF_SENT )
info->icount.txok++;
else if ( status & TXSTATUS_UNDERRUN )
@@ -1356,12 +1437,32 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
icount = &info->icount;
/* update input line counters */
- if (status & MISCSTATUS_RI_LATCHED)
+ if (status & MISCSTATUS_RI_LATCHED) {
+ if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_RI);
icount->rng++;
- if (status & MISCSTATUS_DSR_LATCHED)
+ if ( status & MISCSTATUS_RI )
+ info->input_signal_events.ri_up++;
+ else
+ info->input_signal_events.ri_down++;
+ }
+ if (status & MISCSTATUS_DSR_LATCHED) {
+ if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_DSR);
icount->dsr++;
+ if ( status & MISCSTATUS_DSR )
+ info->input_signal_events.dsr_up++;
+ else
+ info->input_signal_events.dsr_down++;
+ }
if (status & MISCSTATUS_DCD_LATCHED) {
+ if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_DCD);
icount->dcd++;
+ if ( status & MISCSTATUS_DCD )
+ info->input_signal_events.dcd_up++;
+ else
+ info->input_signal_events.dcd_down++;
#ifdef CONFIG_HARD_PPS
if ((info->flags & ASYNC_HARDPPS_CD) &&
(status & MISCSTATUS_DCD_LATCHED))
@@ -1369,7 +1470,15 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
+ {
+ if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_CTS);
icount->cts++;
+ if ( status & MISCSTATUS_CTS )
+ info->input_signal_events.cts_up++;
+ else
+ info->input_signal_events.cts_down++;
+ }
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
@@ -1411,6 +1520,8 @@ void mgsl_isr_io_pin( struct mgsl_struct *info )
}
}
+ mgsl_bh_queue_put(info, BH_TYPE_STATUS, status);
+
/* for diagnostics set IRQ flag */
if ( status & MISCSTATUS_TXC_LATCHED ){
usc_OutReg( info, SICR,
@@ -1642,8 +1753,10 @@ void mgsl_isr_receive_dma( struct mgsl_struct *info )
/* Post a receive event for BH processing. */
mgsl_bh_queue_put( info, BH_TYPE_RECEIVE_DMA, status );
- if ( status & BIT3 )
+ if ( status & BIT3 ) {
info->rx_overflow = 1;
+ info->icount.buf_overrun++;
+ }
} /* end of mgsl_isr_receive_dma() */
@@ -1696,9 +1809,9 @@ static void mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if ( info->isr_overflow ) {
printk(KERN_ERR"%s(%d):%s isr overflow irq=%d\n",
__FILE__,__LINE__,info->device_name, irq);
- /* Interrupt overflow. Reset adapter and exit. */
-// UscReset(info);
-// break;
+ usc_DisableMasterIrqBit(info);
+ usc_DisableDmaInterrupts(info,DICR_MASTER);
+ break;
}
}
@@ -1980,6 +2093,11 @@ static void mgsl_change_params(struct mgsl_struct *info)
usc_set_async_mode(info);
usc_set_serial_signals(info);
+
+ info->dcd_chkcount = 0;
+ info->cts_chkcount = 0;
+ info->ri_chkcount = 0;
+ info->dsr_chkcount = 0;
/* enable modem signal IRQs and read initial signal states */
usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
@@ -2112,16 +2230,27 @@ static int mgsl_write(struct tty_struct * tty, int from_user,
if ( info->params.mode == MGSL_MODE_HDLC ) {
/* operating in synchronous (frame oriented) mode */
-
+
if (info->tx_active) {
ret = 0; goto cleanup;
}
-
+
+ /* if operating in HDLC LoopMode and the adapter */
+ /* has yet to be inserted into the loop, we can't */
+ /* transmit */
+
+ if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) &&
+ !usc_loopmode_active(info) )
+ {
+ ret = 0;
+ goto cleanup;
+ }
+
if ( info->xmit_cnt ) {
/* Send accumulated from send_char() calls */
/* as frame and wait before accepting more data. */
ret = 0;
-
+
/* copy data from circular xmit_buf to */
/* transmit DMA buffer. */
mgsl_load_tx_dma_buffer(info,
@@ -2578,8 +2707,19 @@ static int mgsl_txenable(struct mgsl_struct * info, int enable)
spin_lock_irqsave(&info->irq_spinlock,flags);
if ( enable ) {
- if ( !info->tx_enabled )
+ if ( !info->tx_enabled ) {
+
usc_start_transmitter(info);
+ /*--------------------------------------------------
+ * if HDLC/SDLC Loop mode, attempt to insert the
+ * station in the 'loop' by setting CMR:13. Upon
+ * receipt of the next GoAhead (RxAbort) sequence,
+ * the OnLoop indicator (CCSR:7) should go active
+ * to indicate that we are on the loop
+ *--------------------------------------------------*/
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_insert_request( info );
+ }
} else {
if ( info->tx_enabled )
usc_stop_transmitter(info);
@@ -2604,7 +2744,12 @@ static int mgsl_txabort(struct mgsl_struct * info)
spin_lock_irqsave(&info->irq_spinlock,flags);
if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC )
- usc_TCmd(info,TCmd_SendAbort);
+ {
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_cancel_transmit( info );
+ else
+ usc_TCmd(info,TCmd_SendAbort);
+ }
spin_unlock_irqrestore(&info->irq_spinlock,flags);
return 0;
@@ -2640,25 +2785,39 @@ static int mgsl_rxenable(struct mgsl_struct * info, int enable)
/* mgsl_wait_event() wait for specified event to occur
*
* Arguments: info pointer to device instance data
- * mask bitmask of events to wait for
- * Return Value: bit mask of triggering event, otherwise error code
+ * mask pointer to bitmask of events to wait for
+ * Return Value: 0 if successful and bit mask updated with
+ * of events triggerred,
+ * otherwise error code
*/
-static int mgsl_wait_event(struct mgsl_struct * info, int mask)
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask_ptr)
{
unsigned long flags;
int s;
int rc=0;
u16 regval;
struct mgsl_icount cprev, cnow;
+ int events = 0;
+ int mask;
+ struct _input_signal_events signal_events_prev, signal_events_now;
+
+ COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+ if (rc) {
+ return -EFAULT;
+ }
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__,
info->device_name, mask);
-
+
spin_lock_irqsave(&info->irq_spinlock,flags);
-
+
+ usc_get_serial_signals(info);
+ s = info->serial_signals;
+
/* note the counters on entry */
cprev = info->icount;
+ signal_events_prev = info->input_signal_events;
if (mask & MgslEvent_ExitHuntMode) {
/* enable exit hunt mode IRQ */
@@ -2676,7 +2835,22 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- while(!rc) {
+ /* Determine if any user requested events for input signals is currently TRUE */
+
+ events |= (mask & ((s & SerialSignal_DSR) ?
+ MgslEvent_DsrActive:MgslEvent_DsrInactive));
+
+ events |= (mask & ((s & SerialSignal_DCD) ?
+ MgslEvent_DcdActive:MgslEvent_DcdInactive));
+
+ events |= (mask & ((s & SerialSignal_CTS) ?
+ MgslEvent_CtsActive:MgslEvent_CtsInactive));
+
+ events |= (mask & ((s & SerialSignal_RI) ?
+ MgslEvent_RiActive:MgslEvent_RiInactive));
+
+
+ while(!events) {
/* sleep until event occurs */
interruptible_sleep_on(&info->event_wait_q);
@@ -2687,39 +2861,52 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
}
spin_lock_irqsave(&info->irq_spinlock,flags);
+
/* get icount and serial signal states */
cnow = info->icount;
- s = info->serial_signals;
+ signal_events_now = info->input_signal_events;
spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+ if (signal_events_now.dsr_up != signal_events_prev.dsr_up &&
+ mask & MgslEvent_DsrActive )
+ events |= MgslEvent_DsrActive;
- rc = 0;
+ if (signal_events_now.dsr_down != signal_events_prev.dsr_down &&
+ mask & MgslEvent_DsrInactive )
+ events |= MgslEvent_DsrInactive;
+
+ if (signal_events_now.dcd_up != signal_events_prev.dcd_up &&
+ mask & MgslEvent_DcdActive )
+ events |= MgslEvent_DcdActive;
- if (cnow.dsr != cprev.dsr)
- rc |= (mask & ((s & SerialSignal_DSR) ?
- MgslEvent_DsrActive:MgslEvent_DsrInactive));
+ if (signal_events_now.dcd_down != signal_events_prev.dcd_down &&
+ mask & MgslEvent_DcdInactive )
+ events |= MgslEvent_DcdInactive;
+
+ if (signal_events_now.cts_up != signal_events_prev.cts_up &&
+ mask & MgslEvent_CtsActive )
+ events |= MgslEvent_CtsActive;
+
+ if (signal_events_now.cts_down != signal_events_prev.cts_down &&
+ mask & MgslEvent_CtsInactive )
+ events |= MgslEvent_CtsInactive;
+
+ if (signal_events_now.ri_up != signal_events_prev.ri_up &&
+ mask & MgslEvent_RiActive )
+ events |= MgslEvent_RiActive;
+
+ if (signal_events_now.ri_down != signal_events_prev.ri_down &&
+ mask & MgslEvent_RiInactive )
+ events |= MgslEvent_RiInactive;
- if (cnow.dcd != cprev.dcd)
- rc |= (mask & ((s & SerialSignal_DCD) ?
- MgslEvent_DcdActive:MgslEvent_DcdInactive));
-
- if (cnow.cts != cprev.cts)
- rc |= (mask & ((s & SerialSignal_CTS) ?
- MgslEvent_CtsActive:MgslEvent_CtsInactive));
-
- if (cnow.rng != cprev.rng)
- rc |= (mask & ((s & SerialSignal_RI) ?
- MgslEvent_RiActive:MgslEvent_RiInactive));
-
if (cnow.exithunt != cprev.exithunt)
- rc |= (mask & MgslEvent_ExitHuntMode);
-
+ events |= (mask & MgslEvent_ExitHuntMode);
+
if (cnow.rxidle != cprev.rxidle)
- rc |= (mask & MgslEvent_ExitHuntMode);
-
- if (!rc)
- rc = -EIO; /* no change => error */
-
+ events |= (mask & MgslEvent_IdleReceived);
+
cprev = cnow;
+ signal_events_prev = signal_events_now;
}
if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
@@ -2732,7 +2919,10 @@ static int mgsl_wait_event(struct mgsl_struct * info, int mask)
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
+ if ( rc == 0 )
+ PUT_USER(rc, events, mask_ptr);
+
return rc;
} /* end of mgsl_wait_event() */
@@ -2772,7 +2962,7 @@ static int get_modem_info(struct mgsl_struct * info, unsigned int *value)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_get_modem_info %s value=%08X\n",
- __FILE__,__LINE__, info->device_name, *value );
+ __FILE__,__LINE__, info->device_name, result );
PUT_USER(err,result,value);
return err;
@@ -2928,7 +3118,9 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file,
case MGSL_IOCGSTATS:
return mgsl_get_stats(info,(struct mgsl_icount*)arg);
case MGSL_IOCWAITEVENT:
- return mgsl_wait_event(info,(int)arg);
+ return mgsl_wait_event(info,(int*)arg);
+ case MGSL_IOCLOOPTXDONE:
+ return mgsl_loopmode_send_done(info);
case MGSL_IOCCLRMODCOUNT:
while(MOD_IN_USE)
MOD_DEC_USE_COUNT;
@@ -3626,11 +3818,6 @@ static inline int line_info(char *buf, struct mgsl_struct *info)
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
-#if 0 && LINUX_VERSION_CODE >= VERSION(2,1,0)
- ret += sprintf(buf+ret, "irq_spinlock=%08X\n",
- info->irq_spinlock.lock );
-#endif
-
return ret;
} /* end of line_info() */
@@ -4227,6 +4414,18 @@ int mgsl_enumerate_devices()
if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
+#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+ struct pci_dev *pdev = pci_find_slot(bus,func);
+ irq_line = pdev->irq;
+#else
+ if (pcibios_read_config_byte(bus,func,
+ PCI_INTERRUPT_LINE,&irq_line) ) {
+ printk( "%s(%d):USC I/O addr not set.\n",
+ __FILE__,__LINE__);
+ continue;
+ }
+#endif
+
if (pcibios_read_config_dword(bus,func,
PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
printk( "%s(%d):Shared mem addr not set.\n",
@@ -4248,13 +4447,6 @@ int mgsl_enumerate_devices()
continue;
}
- if (pcibios_read_config_byte(bus,func,
- PCI_INTERRUPT_LINE,&irq_line) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
info = mgsl_allocate_device();
if ( !info ) {
/* error allocating device instance data */
@@ -4671,29 +4863,53 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
{
u16 RegValue;
- /* Channel mode Register (CMR)
- *
- * <15..14> 00 Tx Sub modes, Underrun Action
- * <13> 0 1 = Send Preamble before opening flag
- * <12> 0 1 = Consecutive Idles share common 0
- * <11..8> 0110 Transmitter mode = HDLC/SDLC
- * <7..4> 0000 Rx Sub modes, addr/ctrl field handling
- * <3..0> 0110 Receiver mode = HDLC/SDLC
- *
- * 0000 0110 0000 0110 = 0x0606
- */
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ {
+ /*
+ ** Channel Mode Register (CMR)
+ **
+ ** <15..14> 10 Tx Sub Modes, Send Flag on Underrun
+ ** <13> 0 0 = Transmit Disabled (initially)
+ ** <12> 0 1 = Consecutive Idles share common 0
+ ** <11..8> 1110 Transmitter Mode = HDLC/SDLC Loop
+ ** <7..4> 0000 Rx Sub Modes, addr/ctrl field handling
+ ** <3..0> 0110 Receiver Mode = HDLC/SDLC
+ **
+ ** 1000 1110 0000 0110 = 0x8e06
+ */
+ RegValue = 0x8e06;
+
+ /*--------------------------------------------------
+ * ignore user options for UnderRun Actions and
+ * preambles
+ *--------------------------------------------------*/
+ }
+ else
+ {
+ /* Channel mode Register (CMR)
+ *
+ * <15..14> 00 Tx Sub modes, Underrun Action
+ * <13> 0 1 = Send Preamble before opening flag
+ * <12> 0 1 = Consecutive Idles share common 0
+ * <11..8> 0110 Transmitter mode = HDLC/SDLC
+ * <7..4> 0000 Rx Sub modes, addr/ctrl field handling
+ * <3..0> 0110 Receiver mode = HDLC/SDLC
+ *
+ * 0000 0110 0000 0110 = 0x0606
+ */
- RegValue = 0x0606;
+ RegValue = 0x0606;
- if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
- RegValue |= BIT14;
- else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
- RegValue |= BIT15;
- else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
- RegValue |= BIT15 + BIT14;
+ if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
+ RegValue |= BIT14;
+ else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
+ RegValue |= BIT15;
+ else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
+ RegValue |= BIT15 + BIT14;
- if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
- RegValue |= BIT13;
+ if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
+ RegValue |= BIT13;
+ }
if ( info->params.flags & HDLC_FLAG_SHARE_ZERO )
RegValue |= BIT12;
@@ -4862,6 +5078,8 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
RegValue |= 0x0003; /* RxCLK from DPLL */
else if ( info->params.flags & HDLC_FLAG_RXC_BRG )
RegValue |= 0x0004; /* RxCLK from BRG0 */
+ else if ( info->params.flags & HDLC_FLAG_RXC_TXCPIN)
+ RegValue |= 0x0006; /* RxCLK from TXC Input */
else
RegValue |= 0x0007; /* RxCLK from Port1 */
@@ -4869,6 +5087,8 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
RegValue |= 0x0018; /* TxCLK from DPLL */
else if ( info->params.flags & HDLC_FLAG_TXC_BRG )
RegValue |= 0x0020; /* TxCLK from BRG0 */
+ else if ( info->params.flags & HDLC_FLAG_TXC_RXCPIN)
+ RegValue |= 0x0038; /* RxCLK from TXC Input */
else
RegValue |= 0x0030; /* TxCLK from Port0 */
@@ -4922,10 +5142,24 @@ void usc_set_sdlc_mode( struct mgsl_struct *info )
/* of rounding up and then subtracting 1 we just don't subtract */
/* the one in this case. */
- Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
- if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
- / info->params.clock_speed) )
- Tc--;
+ /*--------------------------------------------------
+ * ejz: for DPLL mode, application should use the
+ * same clock speed as the partner system, even
+ * though clocking is derived from the input RxData.
+ * In case the user uses a 0 for the clock speed,
+ * default to 0xffffffff and don't try to divide by
+ * zero
+ *--------------------------------------------------*/
+ if ( info->params.clock_speed )
+ {
+ Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
+ if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
+ / info->params.clock_speed) )
+ Tc--;
+ }
+ else
+ Tc = -1;
+
/* Write 16-bit Time Constant for BRG1 */
usc_OutReg( info, TC1R, Tc );
@@ -6328,6 +6562,13 @@ void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, const char *Buffer,
if ( debug_level >= DEBUG_LEVEL_DATA )
mgsl_trace_block(info,Buffer,BufferSize,1);
+ if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+ /* set CMR:13 to start transmit when
+ * next GoAhead (abort) is received
+ */
+ info->cmr_value |= BIT13;
+ }
+
/* Setup the status and RCC (Frame Size) fields of the 1st */
/* buffer entry in the transmit DMA buffer list. */
@@ -6381,7 +6622,7 @@ BOOLEAN mgsl_register_test( struct mgsl_struct *info )
unsigned int i;
BOOLEAN rc = TRUE;
unsigned long flags;
-
+
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_reset(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -6471,7 +6712,7 @@ BOOLEAN mgsl_irq_test( struct mgsl_struct *info )
usc_reset(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- if ( !info->irq_occurred )
+ if ( !info->irq_occurred )
return FALSE;
else
return TRUE;
@@ -6499,7 +6740,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
volatile unsigned long EndTime;
unsigned long flags;
MGSL_PARAMS tmp_params;
-
+
/* save current port options */
memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS));
/* load default port options */
@@ -6657,7 +6898,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
/**********************************/
/* WAIT FOR TRANSMIT FIFO TO FILL */
/**********************************/
-
+
/* Wait 100ms */
EndTime = jiffies + jiffies_from_ms(100);
@@ -6724,7 +6965,7 @@ BOOLEAN mgsl_dma_test( struct mgsl_struct *info )
if ( rc == TRUE ){
/* CHECK FOR TRANSMIT ERRORS */
- if ( status & (BIT5 + BIT1) )
+ if ( status & (BIT5 + BIT1) )
rc = FALSE;
}
@@ -6981,13 +7222,90 @@ void mgsl_tx_timeout(unsigned long context)
if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
info->icount.txtimeout++;
}
-
spin_lock_irqsave(&info->irq_spinlock,flags);
info->tx_active = 0;
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_cancel_transmit( info );
+
spin_unlock_irqrestore(&info->irq_spinlock,flags);
mgsl_bh_transmit_data(info,0);
} /* end of mgsl_tx_timeout() */
+/* signal that there are no more frames to send, so that
+ * line is 'released' by echoing RxD to TxD when current
+ * transmission is complete (or immediately if no tx in progress).
+ */
+static int mgsl_loopmode_send_done( struct mgsl_struct * info )
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+ if (info->tx_active)
+ info->loopmode_send_done_requested = TRUE;
+ else
+ usc_loopmode_send_done(info);
+ }
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+ return 0;
+}
+
+/* release the line by echoing RxD to TxD
+ * upon completion of a transmit frame
+ */
+void usc_loopmode_send_done( struct mgsl_struct * info )
+{
+ info->loopmode_send_done_requested = FALSE;
+ /* clear CMR:13 to 0 to start echoing RxData to TxData */
+ info->cmr_value &= ~BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* abort a transmit in progress while in HDLC LoopMode
+ */
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info )
+{
+ /* reset tx dma channel and purge TxFifo */
+ usc_RTCmd( info, RTCmd_PurgeTxFifo );
+ usc_DmaCmd( info, DmaCmd_ResetTxChannel );
+ usc_loopmode_send_done( info );
+}
+
+/* for HDLC/SDLC LoopMode, setting CMR:13 after the transmitter is enabled
+ * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort)
+ * we must clear CMR:13 to begin repeating TxData to RxData
+ */
+void usc_loopmode_insert_request( struct mgsl_struct * info )
+{
+ info->loopmode_insert_requested = TRUE;
+
+ /* enable RxAbort irq. On next RxAbort, clear CMR:13 to
+ * begin repeating TxData on RxData (complete insertion)
+ */
+ usc_OutReg( info, RICR,
+ (usc_InReg( info, RICR ) | RXSTATUS_ABORT_RECEIVED ) );
+
+ /* set CMR:13 to insert into loop on next GoAhead (RxAbort) */
+ info->cmr_value |= BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* return 1 if station is inserted into the loop, otherwise 0
+ */
+int usc_loopmode_active( struct mgsl_struct * info)
+{
+ return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ;
+}
+
+/* return 1 if USC is in loop send mode, otherwise 0
+ */
+int usc_loopmode_send_active( struct mgsl_struct * info )
+{
+ return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ;
+}
+
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 5007652d1..df5a8efc7 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -651,9 +651,7 @@ static inline ssize_t do_tty_write(
ssize_t ret = 0, written = 0;
struct inode *inode = file->f_dentry->d_inode;
- up(&inode->i_sem);
- if (down_interruptible(&inode->i_atomic_write)) {
- down(&inode->i_sem);
+ if (down_interruptible(&inode->i_sem)) {
return -ERESTARTSYS;
}
for (;;) {
@@ -678,8 +676,7 @@ static inline ssize_t do_tty_write(
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
ret = written;
}
- up(&inode->i_atomic_write);
- down(&inode->i_sem);
+ up(&inode->i_sem);
return ret;
}
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f0f990aad..5e2a45bce 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -143,14 +143,6 @@ else
endif
endif
-ifeq ($(CONFIG_ETHERH),y)
-CONFIG_8390_BUILTIN = y
-else
- ifeq ($(CONFIG_ETHERH),m)
- CONFIG_8390_MODULE = y
- endif
-endif
-
ifeq ($(CONFIG_WD80x3),y)
L_OBJS += wd.o
CONFIG_8390_BUILTIN = y
@@ -171,14 +163,6 @@ else
endif
endif
-ifeq ($(CONFIG_ETHERH),y)
-CONFIG_8390_BUILTIN = y
-else
- ifeq ($(CONFIG_ETHERH),m)
- CONFIG_8390_MODULE = y
- endif
-endif
-
ifeq ($(CONFIG_NE2K_PCI),y)
L_OBJS += ne2k-pci.o
CONFIG_8390_BUILTIN = y
diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c
index f8d53cea4..29356bbbf 100644
--- a/drivers/net/ibmtr.c
+++ b/drivers/net/ibmtr.c
@@ -515,7 +515,7 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
/* How much shared RAM is on adapter ? */
#ifdef PCMCIA
ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
- ibmtr_mem_base = ti->sram_base ;
+ ibmtr_mem_base = ti->sram_base << 12 ;
#else
ti->avail_shared_ram = get_sram_size(ti);
#endif
@@ -835,6 +835,9 @@ static int tok_close(struct device *dev)
(int)readb(ti->srb + offsetof(struct srb_close_adapter, ret_code)));
dev->start = 0;
+#ifdef PCMCIA
+ ti->sram = 0 ;
+#endif
DPRINTK("Adapter closed.\n");
MOD_DEC_USE_COUNT;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 5fb0cd4f2..e813fe8a4 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -321,7 +321,7 @@ void irport_change_speed(struct irda_device *idev, int speed)
/* Turn on interrups */
outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
- spin_unlock_irqrestore(&self->lock, flags);
+ spin_unlock_irqrestore(&idev->lock, flags);
}
/*
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4e1e3465d..9f5ecd98d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -47,13 +47,23 @@ pci_find_slot(unsigned int bus, unsigned int devfn)
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
{
- if (!from)
- from = pci_devices;
- else
- from = from->next;
- while (from && (from->vendor != vendor || from->device != device))
- from = from->next;
- return from;
+ struct pci_dev *next;
+
+ next = pci_devices;
+ if (from)
+ next = from->next;
+
+ while (next) {
+ struct pci_dev *dev = next;
+ next = next->next;
+ if (vendor != PCI_ANY_ID && dev->vendor != vendor)
+ continue;
+ if (device != PCI_ANY_ID && dev->device != device)
+ continue;
+
+ return dev;
+ }
+ return NULL;
}
@@ -178,10 +188,8 @@ __initfunc(unsigned int pci_scan_bus(struct pci_bus *bus))
if (pcibios_read_config_dword(bus->number, devfn, PCI_VENDOR_ID, &l) ||
/* some broken boards return 0 if a slot is empty: */
- l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) {
- is_multi = 0;
+ l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
continue;
- }
dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
memset(dev, 0, sizeof(*dev));
diff --git a/drivers/sbus/audio/cs4215.h b/drivers/sbus/audio/cs4215.h
index ff5367d6d..79d3945ef 100644
--- a/drivers/sbus/audio/cs4215.h
+++ b/drivers/sbus/audio/cs4215.h
@@ -11,11 +11,10 @@
struct cs4215 {
__u8 data[4]; /* Data mode: Time slots 5-8 */
__u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */
- __volatile__ struct dbri_mem td;
- __volatile__ struct dbri_mem rd;
__u8 onboard;
- __u32 status;
- __u32 version;
+ __u8 offset; /* Bit offset from frame sync to time slot 1 */
+ volatile __u32 status;
+ volatile __u32 version;
};
diff --git a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c
index 23afc72b4..9f76c92e6 100644
--- a/drivers/sbus/audio/dbri.c
+++ b/drivers/sbus/audio/dbri.c
@@ -79,25 +79,25 @@
#define D_CMD (1<<2)
#define D_MM (1<<3)
#define D_USR (1<<4)
+#define D_DESC (1<<5)
-/* static int dbri_debug = D_GEN|D_INT|D_CMD|D_MM|D_USR; */
static int dbri_debug = 0;
MODULE_PARM(dbri_debug, "i");
+static int dbri_trace = 0;
+MODULE_PARM(dbri_trace, "i");
+#define tprintk(x) if(dbri_trace) printk x
+
static char *cmds[] = {
"WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
"SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
};
-/* Bit hunting */
-#define dumpcmd {int i; for(i=0; i<n; i++) printk("DBRI: %x\n", dbri->dma->cmd[i]); }
-
#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value)
#else
#define dprintk(a, x)
-#define dumpcmd
#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value)
#endif /* DBRI_DEBUG */
@@ -114,41 +114,42 @@ static int num_drivers = 0;
****************************************************************************
************** DBRI initialization and command synchronization *************
****************************************************************************
-*/
+Commands are sent to the DBRI by building a list of them in memory,
+then writing the address of the first list item to DBRI register 8.
+The list is terminated with a WAIT command, which can generate a
+CPU interrupt if required.
+
+Since the DBRI can run in parallel with the CPU, several means of
+synchronization present themselves. The original scheme (Rudolf's)
+was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
+an interrupt signaled completion, and wait on a wait_queue if a routine
+attempted to cmdlock while the flag was set. The problems arose when
+we tried to cmdlock from inside an interrupt handler, which might
+cause scheduling in an interrupt (if we waited), etc, etc
+
+A more sophisticated scheme might involve a circular command buffer
+or an array of command buffers. A routine could fill one with
+commands and link it onto a list. When a interrupt signaled
+completion of the current command buffer, look on the list for
+the next one.
+
+I've decided to implement something much simpler - after each command,
+the CPU waits for the DBRI to finish the command by polling the P bit
+in DBRI register 0. I've tried to implement this in such a way
+that might make implementing a more sophisticated scheme easier.
+
+Every time a routine wants to write commands to the DBRI, it must
+first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
+in return. After the commands have been writen, dbri_cmdsend() is
+called with the final pointer value.
+
+Something a little more clever is required if this code is ever run
+on an SMP machine.
-/*
- * Commands are sent to the DBRI by building a list of them in memory,
- * then writing the address of the first list item to DBRI register 8.
- * The list is terminated with a WAIT command, which can generate a
- * CPU interrupt if required.
- *
- * Since the DBRI can run asynchronously to the CPU, several means of
- * synchronization present themselves. The original scheme (Rudolf's)
- * was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
- * an interrupt signaled completion, and wait on a wait_queue if a routine
- * attempted to cmdlock while the flag was set. The problems arose when
- * we tried to cmdlock from inside an interrupt handler, which might
- * cause scheduling in an interrupt (if we waited), etc, etc
- *
- * A more sophisticated scheme might involve a circular command buffer
- * or an array of command buffers. A routine could fill one with
- * commands and link it onto a list. When a interrupt signaled
- * completion of the current command buffer, look on the list for
- * the next one.
- *
- * I've decided to implement something much simpler - after each command,
- * the CPU waits for the DBRI to finish the command by polling the P bit
- * in DBRI register 0. I've tried to implement this in such a way
- * that might make implementing a more sophisticated scheme easier.
- *
- * Every time a routine wants to write commands to the DBRI, it must
- * first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
- * in return. After the commands have been writen, dbri_cmdsend() is
- * called with the final pointer value.
- */
+*/
-static int dbri_locked = 0; /* XXX not SMP safe! XXX */
+static int dbri_locked = 0;
static volatile int * dbri_cmdlock(struct dbri *dbri)
{
@@ -159,9 +160,21 @@ static volatile int * dbri_cmdlock(struct dbri *dbri)
return dbri->dma->cmd;
}
+static void dbri_process_interrupt_buffer(struct dbri *);
+
static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd)
{
- int maxloops = 1000000;
+ int MAXLOOPS = 1000000;
+ int maxloops = MAXLOOPS;
+ unsigned int flags;
+ volatile int * ptr;
+
+ for (ptr = dbri->dma->cmd; ptr < cmd; ptr ++) {
+ dprintk(D_CMD, ("DBRI cmd: %08x:%08x\n",
+ (unsigned int) ptr, *ptr));
+ }
+
+ save_and_cli(flags);
dbri_locked --;
if (dbri_locked != 0) {
@@ -170,14 +183,25 @@ static void dbri_cmdsend(struct dbri *dbri, volatile int * cmd)
printk("DBRI: Command buffer overflow! (bug in driver)\n");
} else {
*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
- *(cmd++) = DBRI_CMD(D_WAIT, 0, 0);
+ *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
+ dbri->wait_seen = 0;
dbri->regs->reg8 = (int)dbri->dma_dvma->cmd;
- while ((maxloops--) > 0 && (dbri->regs->reg0 & D_P));
+ while ((--maxloops) > 0 && (dbri->regs->reg0 & D_P));
+ if (maxloops == 0) {
+ printk("DBRI: Chip never completed command buffer\n");
+ } else {
+ while ((--maxloops) > 0 && (! dbri->wait_seen))
+ dbri_process_interrupt_buffer(dbri);
+ if (maxloops == 0) {
+ printk("DBRI: Chip never acked WAIT\n");
+ } else {
+ dprintk(D_INT, ("DBRI: Chip completed command buffer (%d)\n",
+ MAXLOOPS - maxloops));
+ }
+ }
}
- if (maxloops == 0) {
- printk("DBRI: Chip never completed command buffer\n");
- }
+ restore_flags(flags);
}
static void dbri_reset(struct dbri *dbri)
@@ -198,7 +222,7 @@ static void dbri_detach(struct dbri *dbri)
dbri_reset(dbri);
free_irq(dbri->irq, dbri);
sparc_free_io(dbri->regs, dbri->regs_size);
- /* Should we release the DMA structure dbri->dma here? */
+ release_region((unsigned long) dbri->dma, sizeof(struct dbri_dma));
kfree(dbri);
}
@@ -242,6 +266,17 @@ static void dbri_initialize(struct dbri *dbri)
****************************************************************************
*************************** DBRI interrupt handler *************************
****************************************************************************
+
+The DBRI communicates with the CPU mainly via a circular interrupt
+buffer. When an interrupt is signaled, the CPU walks through the
+buffer and calls dbri_process_one_interrupt() for each interrupt word.
+Complicated interrupts are handled by dedicated functions (which
+appear first in this file). Any pending interrupts can be serviced by
+calling dbri_process_interrupt_buffer(), which works even if the CPU's
+interrupts are disabled. This function is used by dbri_cmdsend()
+to make sure we're synced up with the chip after each command sequence,
+even if we're running cli'ed.
+
*/
@@ -263,6 +298,7 @@ static __u32 reverse_bytes(__u32 b, int len)
case 2:
b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
case 1:
+ case 0:
break;
default:
printk("DBRI reverse_bytes: unsupported length\n");
@@ -273,37 +309,39 @@ static __u32 reverse_bytes(__u32 b, int len)
/* transmission_complete_intr()
*
* Called by main interrupt handler when DBRI signals transmission complete
- * on a pipe.
+ * on a pipe (interrupt triggered by the B bit in a transmit descriptor).
*
* Walks through the pipe's list of transmit buffer descriptors, releasing
- * each one's DMA buffer (if present) and signaling its callback routine
- * (if present), before flaging the descriptor available and proceeding
- * to the next one.
- *
- * Assumes that only the last in a chain of descriptors will have FINT
- * sent to signal an interrupt, so that the chain will be completely
- * transmitted by the time we get here, and there's no need to save
- * any of the descriptors. In particular, use of the DBRI's CDP command
- * is precluded, but I've not been able to get CDP working reliably anyway.
+ * each one's DMA buffer (if present), flagging the descriptor available,
+ * and signaling its callback routine (if present), before proceeding
+ * to the next one. Stops when the first descriptor is found without
+ * TBC (Transmit Buffer Complete) set, or we've run through them all.
*/
static void transmission_complete_intr(struct dbri *dbri, int pipe)
{
- int td = dbri->pipes[pipe].desc;
+ int td;
int status;
void *buffer;
void (*callback)(void *, int);
+ void *callback_arg;
- dbri->pipes[pipe].desc = -1;
+ td = dbri->pipes[pipe].desc;
- for (; td >= 0; td = dbri->descs[td].next) {
+ while (td >= 0) {
if (td >= DBRI_NO_DESCS) {
printk("DBRI: invalid td on pipe %d\n", pipe);
return;
}
- status = dbri->dma->desc[td].word4;
+ status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);
+
+ if (! (status & DBRI_TD_TBC)) {
+ break;
+ }
+
+ dprintk(D_INT, ("DBRI: TD %d, status 0x%02x\n", td, status));
buffer = dbri->descs[td].buffer;
if (buffer) {
@@ -313,12 +351,16 @@ static void transmission_complete_intr(struct dbri *dbri, int pipe)
}
callback = dbri->descs[td].output_callback;
- if (callback != NULL) {
- callback(dbri->descs[td].output_callback_arg,
- DBRI_TD_STATUS(status) & 0xe);
- }
+ callback_arg = dbri->descs[td].output_callback_arg;
dbri->descs[td].inuse = 0;
+
+ td = dbri->descs[td].next;
+ dbri->pipes[pipe].desc = td;
+
+ if (callback != NULL) {
+ callback(callback_arg, status & 0xe);
+ }
}
}
@@ -335,7 +377,7 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
}
dbri->descs[rd].inuse = 0;
- dbri->pipes[pipe].desc = -1;
+ dbri->pipes[pipe].desc = dbri->descs[rd].next;
status = dbri->dma->desc[rd].word1;
buffer = dbri->descs[rd].buffer;
@@ -351,86 +393,147 @@ static void reception_complete_intr(struct dbri *dbri, int pipe)
DBRI_RD_STATUS(status),
DBRI_RD_CNT(status)-2);
}
+
+ dprintk(D_INT, ("DBRI: Recv RD %d, status 0x%02x, len %d\n",
+ rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)));
}
-static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
+static void dbri_process_one_interrupt(struct dbri *dbri, int x)
{
- struct dbri *dbri = (struct dbri *)opaque;
- int x;
-
- /*
- * Read it, so the interrupt goes away.
- */
- x = dbri->regs->reg1;
+ int val = D_INTR_GETVAL(x);
+ int channel = D_INTR_GETCHAN(x);
+ int command = D_INTR_GETCMD(x);
+ int code = D_INTR_GETCODE(x);
+ int rval = D_INTR_GETRVAL(x);
- if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
- /*
- * What should I do here ?
- */
- if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
- if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
- if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
- if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
+ if (channel == D_INTR_CMD) {
+ dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n",
+ cmds[command], val));
+ } else {
+ dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
+ channel, code, rval));
}
- if (!(x & D_IR)) /* Not for us */
- return;
+ if (channel == D_INTR_CMD && command == D_WAIT) {
+ dbri->wait_seen ++;
+ }
- x = dbri->dma->intr[dbri->dbri_irqp];
- while (x != 0) {
- int val = D_INTR_GETVAL(x);
- int channel = D_INTR_GETCHAN(x);
+ if (code == D_INTR_SBRI) {
- dbri->dma->intr[dbri->dbri_irqp] = 0;
+ /* SBRI - BRI status change */
- if(D_INTR_GETCHAN(x) == D_INTR_CMD) {
- dprintk(D_INT,("DBRI: INTR: Command: %-5s Value:%d\n",
- cmds[D_INTR_GETCMD(x)], D_INTR_GETVAL(x)));
- } else {
- dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
- D_INTR_GETCHAN(x), D_INTR_GETCODE(x),
- D_INTR_GETRVAL(x)));
- }
+ int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
+ dbri->liu_state = liu_states[val & 0x7];
+ if (dbri->liu_callback)
+ dbri->liu_callback(dbri->liu_callback_arg);
+ }
- if (D_INTR_GETCODE(x) == D_INTR_SBRI) {
+ if (code == D_INTR_BRDY) {
+ reception_complete_intr(dbri, channel);
+ }
- /* SBRI - BRI status change */
+ if (code == D_INTR_XCMP) {
+ transmission_complete_intr(dbri, channel);
+ }
- int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
- dbri->liu_state = liu_states[val & 0x7];
- if (dbri->liu_callback)
- dbri->liu_callback(dbri->liu_callback_arg);
- }
+ if (code == D_INTR_UNDR) {
- if (D_INTR_GETCODE(x) == D_INTR_BRDY) {
- reception_complete_intr(dbri, channel);
- }
+ /* UNDR - Transmission underrun
+ * resend SDP command with clear pipe bit (C) set
+ */
- if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
- transmission_complete_intr(dbri, channel);
- }
+ volatile int *cmd;
+ int pipe = channel;
+ int td = dbri->pipes[pipe].desc;
- if (D_INTR_GETCODE(x) == D_INTR_FXDT) {
+ dbri->dma->desc[td].word4 = 0;
- /* FXDT - Fixed data change */
+ cmd = dbri_cmdlock(dbri);
+ *(cmd++) = DBRI_CMD(D_SDP, 0,
+ dbri->pipes[pipe].sdp
+ | D_SDP_P | D_SDP_C | D_SDP_2SAME);
+ *(cmd++) = (int) & dbri->dma_dvma->desc[td];
+ dbri_cmdsend(dbri, cmd);
+ }
- if (dbri->pipes[D_INTR_GETCHAN(x)].sdp & D_SDP_MSB) {
- val = reverse_bytes(val, dbri->pipes[channel].length);
- }
+ if (code == D_INTR_FXDT) {
- if (dbri->pipes[D_INTR_GETCHAN(x)].recv_fixed_ptr) {
- * dbri->pipes[channel].recv_fixed_ptr = val;
- }
+ /* FXDT - Fixed data change */
+
+ if (dbri->pipes[channel].sdp & D_SDP_MSB) {
+ val = reverse_bytes(val, dbri->pipes[channel].length);
}
+ if (dbri->pipes[channel].recv_fixed_ptr) {
+ * dbri->pipes[channel].recv_fixed_ptr = val;
+ }
+ }
+}
+
+/* dbri_process_interrupt_buffer advances through the DBRI's interrupt
+ * buffer until it finds a zero word (indicating nothing more to do
+ * right now). Non-zero words require processing and are handed off
+ * to dbri_process_one_interrupt AFTER advancing the pointer. This
+ * order is important since we might recurse back into this function
+ * and need to make sure the pointer has been advanced first.
+ */
+
+static void dbri_process_interrupt_buffer(struct dbri *dbri)
+{
+ int x;
+
+ while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
+
+ dbri->dma->intr[dbri->dbri_irqp] = 0;
dbri->dbri_irqp++;
if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
dbri->dbri_irqp = 1;
else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0)
dbri->dbri_irqp++;
- x = dbri->dma->intr[dbri->dbri_irqp];
+
+ dbri_process_one_interrupt(dbri, x);
+ }
+}
+
+static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
+{
+ struct dbri *dbri = (struct dbri *)opaque;
+ int x;
+
+ /*
+ * Read it, so the interrupt goes away.
+ */
+ x = dbri->regs->reg1;
+
+ dprintk(D_INT, ("DBRI: Interrupt! (reg1=0x%08x)\n", x));
+
+ if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
+
+ if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
+ if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
+ if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
+ if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
+
+ /* Some of these SBus errors cause the chip's SBus circuitry
+ * to be disabled, so just re-enable and try to keep going.
+ *
+ * The only one I've seen is MRR, which will be triggered
+ * if you let a transmit pipe underrun, then try to CDP it.
+ *
+ * If these things persist, we should probably reset
+ * and re-init the chip.
+ */
+
+ dbri->regs->reg0 &= ~D_D;
}
+
+#if 0
+ if (!(x & D_IR)) /* Not for us */
+ return;
+#endif
+
+ dbri_process_interrupt_buffer(dbri);
}
@@ -438,8 +541,22 @@ static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
****************************************************************************
************************** DBRI data pipe management ***********************
****************************************************************************
+
+While DBRI control functions use the command and interrupt buffers, the
+main data path takes the form of data pipes, which can be short (command
+and interrupt driven), or long (attached to DMA buffers). These functions
+provide a rudimentary means of setting up and managing the DBRI's pipes,
+but the calling functions have to make sure they respect the pipes' linked
+list ordering, among other things. The transmit and receive functions
+here interface closely with the transmit and receive interrupt code.
+
*/
+static int pipe_active(struct dbri *dbri, int pipe)
+{
+ return (dbri->pipes[pipe].desc != -1);
+}
+
/* reset_pipe(dbri, pipe)
*
@@ -449,6 +566,7 @@ static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
static void reset_pipe(struct dbri *dbri, int pipe)
{
int sdp;
+ int desc;
volatile int *cmd;
if (pipe < 0 || pipe > 31) {
@@ -467,6 +585,35 @@ static void reset_pipe(struct dbri *dbri, int pipe)
*(cmd++) = 0;
dbri_cmdsend(dbri, cmd);
+ desc = dbri->pipes[pipe].desc;
+ while (desc != -1) {
+ void *buffer = dbri->descs[desc].buffer;
+ void (*output_callback) (void *, int)
+ = dbri->descs[desc].output_callback;
+ void *output_callback_arg
+ = dbri->descs[desc].output_callback_arg;
+ void (*input_callback) (void *, int, unsigned int)
+ = dbri->descs[desc].input_callback;
+ void *input_callback_arg
+ = dbri->descs[desc].input_callback_arg;
+
+ if (buffer) {
+ mmu_release_scsi_one(sbus_dvma_addr(buffer),
+ dbri->descs[desc].len,
+ dbri->sdev->my_bus);
+ }
+
+ dbri->descs[desc].inuse = 0;
+ desc = dbri->descs[desc].next;
+
+ if (output_callback) {
+ output_callback(output_callback_arg, -1);
+ }
+ if (input_callback) {
+ input_callback(input_callback_arg, -1, 0);
+ }
+ }
+
dbri->pipes[pipe].desc = -1;
}
@@ -482,140 +629,179 @@ static void setup_pipe(struct dbri *dbri, int pipe, int sdp)
/* sdp &= 0xf800; */
}
+ /* If this is a fixed receive pipe, arrange for an interrupt
+ * every time its data changes
+ */
+
+ if (D_SDP_MODE(sdp) == D_SDP_FIXED && ! (sdp & D_SDP_TO_SER)) {
+ sdp |= D_SDP_CHANGE;
+ }
+
sdp |= D_PIPE(pipe);
dbri->pipes[pipe].sdp = sdp;
+ dbri->pipes[pipe].desc = -1;
reset_pipe(dbri, pipe);
}
-enum master_or_slave { CHImaster, CHIslave };
-
-static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
- int bits_per_frame)
+static void link_time_slot(struct dbri *dbri, int pipe,
+ enum in_or_out direction, int basepipe,
+ int length, int cycle)
{
volatile int *cmd;
int val;
+ int prevpipe;
+ int nextpipe;
- cmd = dbri_cmdlock(dbri);
+ if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
+ printk("DBRI: link_time_slot called with illegal pipe number\n");
+ return;
+ }
- /* Set CHI Anchor: Pipe 16 */
+ if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
+ printk("DBRI: link_time_slot called on uninitialized pipe\n");
+ return;
+ }
- val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
- D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
- *(cmd++) = DBRI_CMD(D_DTS, 0, val);
- *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
- *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
+ /* Deal with CHI special case:
+ * "If transmission on edges 0 or 1 is desired, then cycle n
+ * (where n = # of bit times per frame...) must be used."
+ * - DBRI data sheet, page 11
+ */
- dbri->pipes[16].sdp = 1;
- dbri->pipes[16].nextpipe = 16;
+ if (basepipe == 16 && direction == PIPEoutput && cycle == 0) {
+ cycle = dbri->chi_bpf;
+ }
- if (master_or_slave == CHIslave) {
- /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
- *
- * CHICM = 0 (slave mode, 8 kHz frame rate)
- * IR = give immediate CHI status interrupt
- * EN = give CHI status interrupt upon change
- */
- *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0)
- | D_CHI_IR | D_CHI_EN);
+ if (basepipe == pipe) {
+ prevpipe = pipe;
+ nextpipe = pipe;
} else {
- /* Setup DBRI for CHI Master - generate clock, FS
- *
- * BPF = bits per 8 kHz frame
- * 12.288 MHz / CHICM_divisor = clock rate
- * FD = 1 - drive CHIFS on rising edge of CHICK
+
+ /* We're not initializing a new linked list (basepipe != pipe),
+ * so run through the linked list and find where this pipe
+ * should be sloted in, based on its cycle. CHI confuses
+ * things a bit, since it has a single anchor for both its
+ * transmit and receive lists.
*/
- int clockrate = bits_per_frame * 8;
- int divisor = 12288 / clockrate;
+ if (basepipe == 16) {
+ if (direction == PIPEinput) {
+ prevpipe = dbri->chi_in_pipe;
+ } else {
+ prevpipe = dbri->chi_out_pipe;
+ }
+ } else {
+ prevpipe = basepipe;
+ }
+
+ nextpipe = dbri->pipes[prevpipe].nextpipe;
- if (divisor > 255 || divisor * clockrate != 12288) {
- printk("DBRI: illegal bits_per_frame in setup_chi\n");
+ while (dbri->pipes[nextpipe].cycle < cycle
+ && dbri->pipes[nextpipe].nextpipe != basepipe) {
+ prevpipe = nextpipe;
+ nextpipe = dbri->pipes[nextpipe].nextpipe;
}
+ }
- *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
- | D_CHI_IR | D_CHI_EN
- | D_CHI_BPF(bits_per_frame));
+ if (prevpipe == 16) {
+ if (direction == PIPEinput) {
+ dbri->chi_in_pipe = pipe;
+ } else {
+ dbri->chi_out_pipe = pipe;
+ }
+ } else {
+ dbri->pipes[prevpipe].nextpipe = pipe;
}
- /* CHI Data Mode
- *
- * RCE = 0 - receive on falling edge of CHICK
- * XCE = 1 - transmit on rising edge of CHICK
- * XEN = 1 - enable transmitter
- * REN = 1 - enable receiver
- */
+ dbri->pipes[pipe].nextpipe = nextpipe;
+ dbri->pipes[pipe].cycle = cycle;
+ dbri->pipes[pipe].length = length;
- *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+ cmd = dbri_cmdlock(dbri);
- *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+ if (direction == PIPEinput) {
+ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ *(cmd++) = 0;
+ } else {
+ val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ }
dbri_cmdsend(dbri, cmd);
}
-enum in_or_out { PIPEinput, PIPEoutput };
+/* I don't use this function, so it's basically untested. */
-static void link_time_slot(struct dbri *dbri, int pipe,
- enum in_or_out direction, int prevpipe,
- int length, int cycle)
+static void unlink_time_slot(struct dbri *dbri, int pipe,
+ enum in_or_out direction, int prevpipe,
+ int nextpipe)
{
volatile int *cmd;
int val;
- int nextpipe;
if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
- printk("DBRI: link_time_slot called with illegal pipe number\n");
- return;
- }
-
- if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0) {
- printk("DBRI: link_time_slot called on uninitialized pipe\n");
+ printk("DBRI: unlink_time_slot called with illegal pipe number\n");
return;
}
- if (pipe == prevpipe) {
- nextpipe = pipe;
- } else {
- nextpipe = dbri->pipes[prevpipe].nextpipe;
- }
-
- dbri->pipes[pipe].nextpipe = nextpipe;
- dbri->pipes[pipe].cycle = cycle;
- dbri->pipes[pipe].length = length;
-
cmd = dbri_cmdlock(dbri);
if (direction == PIPEinput) {
- val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+ val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
- *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ *(cmd++) = D_TS_NEXT(nextpipe);
*(cmd++) = 0;
} else {
- val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+ val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
*(cmd++) = 0;
- *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ *(cmd++) = D_TS_NEXT(nextpipe);
}
dbri_cmdsend(dbri, cmd);
}
+/* xmit_fixed() / recv_fixed()
+ *
+ * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
+ * expected to change much, and which we don't need to buffer.
+ * The DBRI only interrupts us when the data changes (receive pipes),
+ * or only changes the data when this function is called (transmit pipes).
+ * Only short pipes (numbers 16-31) can be used in fixed data mode.
+ *
+ * These function operate on a 32-bit field, no matter how large
+ * the actual time slot is. The interrupt handler takes care of bit
+ * ordering and alignment. An 8-bit time slot will always end up
+ * in the low-order 8 bits, filled either MSB-first or LSB-first,
+ * depending on the settings passed to setup_pipe()
+ */
+
static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
{
volatile int *cmd;
if (pipe < 16 || pipe > 31) {
- printk("DBRI: xmit_fixed called with illegal pipe number\n");
+ printk("DBRI: xmit_fixed: Illegal pipe number\n");
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {
+ printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe);
return;
}
if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
- printk("DBRI: xmit_fixed called on non-fixed pipe\n");
+ printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);
return;
}
if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
- printk("DBRI: xmit_fixed called on receive pipe\n");
+ printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe);
return;
}
@@ -633,21 +819,7 @@ static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
dbri_cmdsend(dbri, cmd);
}
-/* recv_fixed()
- *
- * Receive data on a "fixed" pipe - i.e, one whose contents are not
- * expected to change much, and which we don't need to read constantly
- * into a buffer. The DBRI only interrupts us when the data changes.
- * Only short pipes (numbers 16-31) can be used in fixed data mode.
- *
- * Pass this function a pointer to a 32-bit field, no matter how large
- * the actual time slot is. The interrupt handler takes care of bit
- * ordering and alignment. An 8-bit time slot will always end up
- * in the low-order 8 bits, filled either MSB-first or LSB-first,
- * depending on the settings passed to setup_pipe()
- */
-
-static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
+static void recv_fixed(struct dbri *dbri, int pipe, volatile __u32 *ptr)
{
if (pipe < 16 || pipe > 31) {
printk("DBRI: recv_fixed called with illegal pipe number\n");
@@ -655,12 +827,12 @@ static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
}
if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
- printk("DBRI: recv_fixed called on non-fixed pipe\n");
+ printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe);
return;
}
if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
- printk("DBRI: recv_fixed called on transmit pipe\n");
+ printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe);
return;
}
@@ -668,37 +840,46 @@ static void recv_fixed(struct dbri *dbri, int pipe, __u32 *ptr)
}
+/* xmit_on_pipe() / recv_on_pipe()
+ *
+ * Transmit/receive data on a "long" pipe - i.e, one associated
+ * with a DMA buffer.
+ *
+ * Only pipe numbers 0-15 can be used in this mode.
+ *
+ * Both functions take pointer/len arguments pointing to a data buffer,
+ * and both provide callback functions (may be NULL) to notify higher
+ * level code when transmission/reception is complete.
+ *
+ * Both work by building chains of descriptors which identify the
+ * data buffers. Buffers too large for a single descriptor will
+ * be spread across multiple descriptors.
+ */
+
static void xmit_on_pipe(struct dbri *dbri, int pipe,
void * buffer, unsigned int len,
void (*callback)(void *, int), void * callback_arg)
{
volatile int *cmd;
+ register unsigned int flags;
int td = 0;
int first_td = -1;
- int last_td;
+ int last_td = -1;
__u32 dvma_buffer;
if (pipe < 0 || pipe > 15) {
- printk("DBRI: xmit_on_pipe called with illegal pipe number\n");
+ printk("DBRI: xmit_on_pipe: Illegal pipe number\n");
return;
}
if (dbri->pipes[pipe].sdp == 0) {
- printk("DBRI: xmit_on_pipe called on uninitialized pipe\n");
+ printk("DBRI: xmit_on_pipe: Uninitialized pipe %d\n", pipe);
return;
}
if (! dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
- printk("DBRI: xmit_on_pipe called on receive pipe\n");
- return;
- }
-
- /* XXX Fix this XXX
- * Should be able to queue multiple buffers to send on a pipe
- */
-
- if (dbri->pipes[pipe].desc != -1) {
- printk("DBRI: xmit_on_pipe called on active pipe\n");
+ printk("DBRI: xmit_on_pipe: Called on receive pipe %d\n",
+ pipe);
return;
}
@@ -707,10 +888,11 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
while (len > 0) {
int mylen;
- for (td; td < DBRI_NO_DESCS; td ++) {
+ for (; td < DBRI_NO_DESCS; td ++) {
if (! dbri->descs[td].inuse) break;
}
if (td == DBRI_NO_DESCS) {
+ printk("DBRI: xmit_on_pipe: No descriptors\n");
break;
}
@@ -744,15 +926,10 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
len -= mylen;
}
- if (first_td == -1) {
- printk("xmit_on_pipe: No descriptors available\n");
+ if (first_td == -1 || last_td == -1) {
return;
}
- if (len > 0) {
- printk("xmit_on_pipe: Insufficient descriptors; data truncated\n");
- }
-
dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
dbri->descs[last_td].buffer = buffer;
@@ -760,14 +937,54 @@ static void xmit_on_pipe(struct dbri *dbri, int pipe,
dbri->descs[last_td].output_callback = callback;
dbri->descs[last_td].output_callback_arg = callback_arg;
- dbri->pipes[pipe].desc = first_td;
+ for (td=first_td; td != -1; td = dbri->descs[td].next) {
+ dprintk(D_DESC, ("DBRI TD %d: %08x %08x %08x %08x\n",
+ td,
+ dbri->dma->desc[td].word1,
+ dbri->dma->desc[td].ba,
+ dbri->dma->desc[td].nda,
+ dbri->dma->desc[td].word4));
+ }
- cmd = dbri_cmdlock(dbri);
+ save_and_cli(flags);
- *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
- *(cmd++) = (int) & dbri->dma_dvma->desc[first_td];
+ if (pipe_active(dbri, pipe)) {
- dbri_cmdsend(dbri, cmd);
+ /* Pipe is already active - find last TD in use
+ * and link our first TD onto its end. Then issue
+ * a CDP command to let the DBRI know there's more data.
+ */
+
+ last_td = dbri->pipes[pipe].desc;
+ while (dbri->descs[last_td].next != -1)
+ last_td = dbri->descs[last_td].next;
+
+ dbri->descs[last_td].next = first_td;
+ dbri->dma->desc[last_td].nda =
+ (int) & dbri->dma_dvma->desc[first_td];
+
+ cmd = dbri_cmdlock(dbri);
+ *(cmd++) = DBRI_CMD(D_CDP, 0, pipe);
+ dbri_cmdsend(dbri,cmd);
+
+ } else {
+
+ /* Pipe isn't active - issue an SDP command to start
+ * our chain of TDs running.
+ */
+
+ dbri->pipes[pipe].desc = first_td;
+
+ cmd = dbri_cmdlock(dbri);
+ *(cmd++) = DBRI_CMD(D_SDP, 0,
+ dbri->pipes[pipe].sdp
+ | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+ *(cmd++) = (int) & dbri->dma_dvma->desc[first_td];
+ dbri_cmdsend(dbri, cmd);
+
+ }
+
+ restore_flags(flags);
}
static void recv_on_pipe(struct dbri *dbri, int pipe,
@@ -776,69 +993,107 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
void * callback_arg)
{
volatile int *cmd;
+ int first_rd = -1;
+ int last_rd = -1;
int rd;
+ __u32 bus_buffer;
if (pipe < 0 || pipe > 15) {
- printk("DBRI: recv_on_pipe called with illegal pipe number\n");
+ printk("DBRI: recv_on_pipe: Illegal pipe number\n");
return;
}
if (dbri->pipes[pipe].sdp == 0) {
- printk("DBRI: recv_on_pipe called on uninitialized pipe\n");
+ printk("DBRI: recv_on_pipe: Uninitialized pipe %d\n", pipe);
return;
}
if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
- printk("DBRI: recv_on_pipe called on transmit pipe\n");
+ printk("DBRI: recv_on_pipe: Called on transmit pipe %d\n",
+ pipe);
return;
}
/* XXX Fix this XXX
- * Should be able to queue multiple buffers to send on a pipe
+ * Should be able to queue multiple buffers to receive on a pipe
*/
if (dbri->pipes[pipe].desc != -1) {
- printk("DBRI: recv_on_pipe called on active pipe\n");
+ printk("DBRI: recv_on_pipe: Called on active pipe %d\n", pipe);
return;
}
- /* XXX Fix this XXX
- * Use multiple descriptors, if needed, to fit in all the data
- */
-
- if (len > (1 << 13) - 1) {
- printk("recv_on_pipe called with len=%d; truncated\n", len);
- len = (1 << 13) - 1;
- }
-
/* Make sure buffer size is multiple of four */
len &= ~3;
- for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
- if (! dbri->descs[rd].inuse) break;
+ bus_buffer = mmu_get_scsi_one(buffer, len, dbri->sdev->my_bus);
+
+ while (len > 0) {
+ int rd;
+ int mylen;
+
+ if (len > (1 << 13) - 4) {
+ mylen = (1 << 13) - 4;
+ } else {
+ mylen = len;
+ }
+
+ for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
+ if (! dbri->descs[rd].inuse) break;
+ }
+ if (rd == DBRI_NO_DESCS) {
+ printk("DBRI recv_on_pipe: No descriptors\n");
+ break;
+ }
+
+ dbri->dma->desc[rd].word1 = 0;
+ dbri->dma->desc[rd].ba = bus_buffer;
+ dbri->dma->desc[rd].nda = 0;
+ dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(mylen);
+
+ dbri->descs[rd].buffer = NULL;
+ dbri->descs[rd].len = 0;
+ dbri->descs[rd].input_callback = NULL;
+ dbri->descs[rd].output_callback = NULL;
+ dbri->descs[rd].next = -1;
+ dbri->descs[rd].inuse = 1;
+
+ if (first_rd == -1) first_rd = rd;
+ if (last_rd != -1) {
+ dbri->dma->desc[last_rd].nda =
+ (int) & dbri->dma_dvma->desc[rd];
+ dbri->descs[last_rd].next = rd;
+ }
+ last_rd = rd;
+
+ bus_buffer += mylen;
+ len -= mylen;
}
- if (rd == DBRI_NO_DESCS) {
- printk("DBRI xmit_on_pipe: No descriptors available\n");
+
+ if (last_rd == -1 || first_rd == -1) {
return;
}
- dbri->dma->desc[rd].word1 = 0;
- dbri->dma->desc[rd].ba = mmu_get_scsi_one(buffer, len,
- dbri->sdev->my_bus);
- dbri->dma->desc[rd].nda = 0;
- dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(len);
+ for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {
+ dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",
+ rd,
+ dbri->dma->desc[rd].word1,
+ dbri->dma->desc[rd].ba,
+ dbri->dma->desc[rd].nda,
+ dbri->dma->desc[rd].word4));
+ }
- dbri->descs[rd].buffer = buffer;
- dbri->descs[rd].len = len;
- dbri->descs[rd].input_callback = callback;
- dbri->descs[rd].input_callback_arg = callback_arg;
+ dbri->descs[last_rd].buffer = buffer;
+ dbri->descs[last_rd].len = len;
+ dbri->descs[last_rd].input_callback = callback;
+ dbri->descs[last_rd].input_callback_arg = callback_arg;
- dbri->pipes[pipe].desc = rd;
+ dbri->pipes[pipe].desc = first_rd;
cmd = dbri_cmdlock(dbri);
- *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P);
- *(cmd++) = (int) & dbri->dma_dvma->desc[rd];
+ *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
+ *(cmd++) = (int) & dbri->dma_dvma->desc[first_rd];
dbri_cmdsend(dbri, cmd);
}
@@ -846,8 +1101,123 @@ static void recv_on_pipe(struct dbri *dbri, int pipe,
/*
****************************************************************************
+************************** DBRI - CHI interface ****************************
+****************************************************************************
+
+The CHI is a four-wire (clock, frame sync, data in, data out) time-division
+multiplexed serial interface which the DBRI can operate in either master
+(give clock/frame sync) or slave (take clock/frame sync) mode.
+
+*/
+
+enum master_or_slave { CHImaster, CHIslave };
+
+static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
+ int bits_per_frame)
+{
+ volatile int *cmd;
+ int val;
+ static int chi_initialized=0;
+
+ if (!chi_initialized) {
+
+ cmd = dbri_cmdlock(dbri);
+
+ /* Set CHI Anchor: Pipe 16 */
+
+ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+ *(cmd++) = 0;
+
+ val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+
+ dbri->pipes[16].sdp = 1;
+ dbri->pipes[16].nextpipe = 16;
+ dbri->chi_in_pipe = 16;
+ dbri->chi_out_pipe = 16;
+
+#if 0
+ chi_initialized ++;
+#endif
+ } else {
+ int pipe;
+
+ for (pipe = dbri->chi_in_pipe;
+ pipe != 16;
+ pipe = dbri->pipes[pipe].nextpipe) {
+ unlink_time_slot(dbri, pipe, PIPEinput,
+ 16, dbri->pipes[pipe].nextpipe);
+ }
+ for (pipe = dbri->chi_out_pipe;
+ pipe != 16;
+ pipe = dbri->pipes[pipe].nextpipe) {
+ unlink_time_slot(dbri, pipe, PIPEoutput,
+ 16, dbri->pipes[pipe].nextpipe);
+ }
+
+ dbri->chi_in_pipe = 16;
+ dbri->chi_out_pipe = 16;
+
+ cmd = dbri_cmdlock(dbri);
+
+ }
+
+ if (master_or_slave == CHIslave) {
+ /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
+ *
+ * CHICM = 0 (slave mode, 8 kHz frame rate)
+ * IR = give immediate CHI status interrupt
+ * EN = give CHI status interrupt upon change
+ */
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
+ } else {
+ /* Setup DBRI for CHI Master - generate clock, FS
+ *
+ * BPF = bits per 8 kHz frame
+ * 12.288 MHz / CHICM_divisor = clock rate
+ * FD = 1 - drive CHIFS on rising edge of CHICK
+ */
+
+ int clockrate = bits_per_frame * 8;
+ int divisor = 12288 / clockrate;
+
+ if (divisor > 255 || divisor * clockrate != 12288) {
+ printk("DBRI: illegal bits_per_frame in setup_chi\n");
+ }
+
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
+ | D_CHI_BPF(bits_per_frame));
+ }
+
+ dbri->chi_bpf = bits_per_frame;
+
+ /* CHI Data Mode
+ *
+ * RCE = 0 - receive on falling edge of CHICK
+ * XCE = 1 - transmit on rising edge of CHICK
+ * XEN = 1 - enable transmitter
+ * REN = 1 - enable receiver
+ */
+
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+
+ *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+/*
+****************************************************************************
*********************** CS4215 audio codec management **********************
****************************************************************************
+
+In the standard SPARC audio configuration, the CS4215 codec is attached
+to the DBRI via the CHI interface and few of the DBRI's PIO pins.
+
*/
@@ -872,21 +1242,83 @@ static void mmcodec_default(struct cs4215 *mm)
* 2: Serial enable, CHI master, 128 bits per frame, clock 1
* 3: Tests disabled
*/
- mm->ctrl[0] = CS4215_RSRVD_1;
+ mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;
mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
mm->ctrl[2] = CS4215_XCLK |
CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
mm->ctrl[3] = 0;
}
+static void mmcodec_setup_pipes(struct dbri *dbri)
+{
+ /*
+ * Data mode:
+ * Pipe 4: Send timeslots 1-4 (audio data)
+ * Pipe 20: Send timeslots 5-8 (part of ctrl data)
+ * Pipe 6: Receive timeslots 1-4 (audio data)
+ * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
+ * interrupt, and the rest of the data (slot 5 and 8) is
+ * not relevant for us (only for doublechecking).
+ *
+ * Control mode:
+ * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
+ * Pipe 18: Receive timeslot 1 (clb).
+ * Pipe 19: Receive timeslot 7 (version).
+ */
+
+ setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+
+ setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+
+ dbri->mm.status = 0;
+
+ recv_fixed(dbri, 18, & dbri->mm.status);
+ recv_fixed(dbri, 19, & dbri->mm.version);
+}
+
+static void mmcodec_setgain(struct dbri *dbri, int muted)
+{
+ if (muted || dbri->perchip_info.output_muted) {
+ dbri->mm.data[0] = 63;
+ dbri->mm.data[1] = 63;
+ } else {
+ int left_gain = (dbri->perchip_info.play.gain / 4) % 64;
+ int right_gain = (dbri->perchip_info.play.gain / 4) % 64;
+
+ if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) {
+ right_gain *= dbri->perchip_info.play.balance;
+ right_gain /= AUDIO_MID_BALANCE;
+ } else {
+ left_gain *= AUDIO_RIGHT_BALANCE
+ - dbri->perchip_info.play.balance;
+ left_gain /= AUDIO_MID_BALANCE;
+ }
+
+ dprintk(D_MM, ("DBRI: Setting codec gain left: %d right: %d\n",
+ left_gain, right_gain));
+
+ dbri->mm.data[0] = CS4215_LE | CS4215_HE | (63 - left_gain);
+ dbri->mm.data[1] = CS4215_SE | (63 - right_gain);
+ }
+
+ xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
+}
+
static void mmcodec_init_data(struct dbri *dbri)
{
+ int data_width;
+
/*
* Data mode:
* Pipe 4: Send timeslots 1-4 (audio data)
- * Pipe 17: Send timeslots 5-8 (part of ctrl data)
+ * Pipe 20: Send timeslots 5-8 (part of ctrl data)
* Pipe 6: Receive timeslots 1-4 (audio data)
- * Pipe 20: Receive timeslots 6-7. We can only receive 20 bits via
+ * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
* interrupt, and the rest of the data (slot 5 and 8) is
* not relevant for us (only for doublechecking).
*
@@ -896,35 +1328,55 @@ static void mmcodec_init_data(struct dbri *dbri)
*/
+ dbri->regs->reg0 &= ~D_C; /* Disable CHI */
+
/* Switch CS4215 to data mode - set PIO3 to 1 */
dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
(dbri->mm.onboard ? D_PIO0 : D_PIO2);
- reset_chi(dbri, CHIslave, 0);
+ reset_chi(dbri, CHIslave, 128);
+
+ /* Note: this next doesn't work for 8-bit stereo, because the two
+ * channels would be on timeslots 1 and 3, with 2 and 4 idle.
+ * (See CS4215 datasheet Fig 15)
+ *
+ * DBRI non-contiguous mode would be required to make this work.
+ */
- setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);
- setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
- setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);
- setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+ data_width = dbri->perchip_info.play.channels
+ * dbri->perchip_info.play.precision;
- /* Pipes 4 and 6 - Single time slot, 8 bit mono */
+ link_time_slot(dbri, 20, PIPEoutput, 16,
+ 32, dbri->mm.offset + 32);
+ link_time_slot(dbri, 4, PIPEoutput, 16,
+ data_width, dbri->mm.offset);
+ link_time_slot(dbri, 6, PIPEinput, 16,
+ data_width, dbri->mm.offset);
+ link_time_slot(dbri, 21, PIPEinput, 16,
+ 16, dbri->mm.offset + 40);
- link_time_slot(dbri, 17, PIPEoutput, 16, 32, 32);
- link_time_slot(dbri, 4, PIPEoutput, 17, 8, 128);
- link_time_slot(dbri, 6, PIPEinput, 16, 8, 0);
- link_time_slot(dbri, 20, PIPEinput, 6, 16, 40);
+ mmcodec_setgain(dbri, 0);
- xmit_fixed(dbri, 17, *(int *)dbri->mm.data);
+ dbri->regs->reg0 |= D_C; /* Enable CHI */
}
/*
* Send the control information (i.e. audio format)
*/
-static void mmcodec_setctrl(struct dbri *dbri)
+static int mmcodec_setctrl(struct dbri *dbri)
{
int i, val;
+ /* XXX - let the CPU do something useful during these delays */
+
+ /* Temporarily mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+
+ mmcodec_setgain(dbri, 1);
+ udelay(125);
+
/*
* Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
* 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
@@ -952,6 +1404,8 @@ static void mmcodec_setctrl(struct dbri *dbri)
* frame sync signal by eight clock cycles. Anybody know why?
*/
+ dbri->regs->reg0 &= ~D_C; /* Disable CHI */
+
reset_chi(dbri, CHImaster, 128);
/*
@@ -961,27 +1415,26 @@ static void mmcodec_setctrl(struct dbri *dbri)
* Pipe 19: Receive timeslot 7 (version).
*/
- setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
- setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
- setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_CHANGE | D_SDP_MSB);
-
- link_time_slot(dbri, 17, PIPEoutput, 16, 32, 128);
- link_time_slot(dbri, 18, PIPEinput, 16, 8, 0);
- link_time_slot(dbri, 19, PIPEinput, 18, 8, 48);
-
- recv_fixed(dbri, 18, & dbri->mm.status);
- recv_fixed(dbri, 19, & dbri->mm.version);
+ link_time_slot(dbri, 17, PIPEoutput, 16,
+ 32, dbri->mm.offset);
+ link_time_slot(dbri, 18, PIPEinput, 16,
+ 8, dbri->mm.offset);
+ link_time_slot(dbri, 19, PIPEinput, 16,
+ 8, dbri->mm.offset + 48);
/* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
dbri->mm.ctrl[0] &= ~CS4215_CLB;
xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
- i = 1000000;
- while ((! dbri->mm.status & CS4215_CLB) && i--);
+ dbri->regs->reg0 |= D_C; /* Enable CHI */
+
+ i = 10;
+ while (((dbri->mm.status & 0xe4) != 0x20) && --i) udelay(125);
if (i == 0) {
- printk("CS4215 didn't respond to CLB\n");
- return;
+ dprintk(D_MM, ("DBRI: CS4215 didn't respond to CLB (0x%02x)\n",
+ dbri->mm.status));
+ return -1;
}
/* Terminate CS4215 control mode - data sheet says
@@ -993,6 +1446,10 @@ static void mmcodec_setctrl(struct dbri *dbri)
/* Two frames of control info @ 8kHz frame rate = 250 us delay */
udelay(250);
+
+ mmcodec_setgain(dbri, 0);
+
+ return 0;
}
static int mmcodec_init(struct sparcaudio_driver *drv)
@@ -1024,16 +1481,24 @@ static int mmcodec_init(struct sparcaudio_driver *drv)
}
- /* Now talk to our baby */
- dbri->regs->reg0 |= D_C; /* Enable CHI */
+ mmcodec_setup_pipes(dbri);
mmcodec_default(&dbri->mm);
dbri->mm.version = 0xff;
- mmcodec_setctrl(dbri);
- if(dbri->mm.version == 0xff)
+ dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
+ if (mmcodec_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
+ dprintk(D_MM, ("DBRI: CS4215 failed probe at offset %d\n",
+ dbri->mm.offset));
return -EIO;
+ }
+ dprintk(D_MM, ("DBRI: Found CS4215 at offset %d\n", dbri->mm.offset));
+
+ dbri->perchip_info.play.channels = 1;
+ dbri->perchip_info.play.precision = 8;
+ dbri->perchip_info.play.gain = 255;
+ dbri->perchip_info.play.balance = AUDIO_MID_BALANCE;
mmcodec_init_data(dbri);
return 0;
@@ -1044,37 +1509,25 @@ static int mmcodec_init(struct sparcaudio_driver *drv)
****************************************************************************
******************** Interface with sparcaudio midlevel ********************
****************************************************************************
-*/
+The sparcaudio midlevel is contained in the file audio.c. It interfaces
+to the user process and performs buffering, intercepts SunOS-style ioctl's,
+etc. It interfaces to a abstract audio device via a struct sparcaudio_driver.
+This code presents such an interface for the DBRI with an attached CS4215.
+All our routines are defined, and then comes our struct sparcaudio_driver.
-static int dbri_open(struct inode * inode, struct file * file,
- struct sparcaudio_driver *drv)
-{
- struct dbri *dbri = (struct dbri *)drv->private;
-
- MOD_INC_USE_COUNT;
+*/
- return 0;
-}
+/******************* sparcaudio midlevel - audio output *******************/
-static void dbri_release(struct inode * inode, struct file * file,
- struct sparcaudio_driver *drv)
-{
- MOD_DEC_USE_COUNT;
-}
-
-static int dbri_ioctl(struct inode * inode, struct file * file,
- unsigned int x, unsigned long y,
- struct sparcaudio_driver *drv)
-{
- return 0;
-}
static void dbri_audio_output_callback(void * callback_arg, int status)
{
struct sparcaudio_driver *drv = callback_arg;
- sparcaudio_output_done(drv, 1);
+ if (status != -1) {
+ sparcaudio_output_done(drv, 1);
+ }
}
static void dbri_start_output(struct sparcaudio_driver *drv,
@@ -1082,8 +1535,31 @@ static void dbri_start_output(struct sparcaudio_driver *drv,
{
struct dbri *dbri = (struct dbri *)drv->private;
+ dprintk(D_USR, ("DBRI: start audio output buf=%lx/%ld\n",
+ (unsigned long) buffer, count));
+
/* Pipe 4 is audio transmit */
- xmit_on_pipe(dbri, 4, buffer, count, &dbri_audio_output_callback, drv);
+
+ xmit_on_pipe(dbri, 4, buffer, count,
+ &dbri_audio_output_callback, drv);
+
+#if 0
+ /* Notify midlevel that we're a DMA-capable driver that
+ * can accept another buffer immediately. We should probably
+ * check that we've got enough resources (i.e, descriptors)
+ * available before doing this, but the default midlevel
+ * settings only buffer 64KB, which we can handle with 16
+ * of our DBRI_NO_DESCS (64) descriptors.
+ *
+ * This code is #ifdef'ed out because it's caused me more
+ * problems than it solved. It'd be nice to provide the
+ * DBRI with a chain of buffers, but the midlevel code is
+ * so tricky that I really don't want to deal with it.
+ */
+
+ sparcaudio_output_done(drv, 2);
+#endif
+
}
static void dbri_stop_output(struct sparcaudio_driver *drv)
@@ -1093,28 +1569,55 @@ static void dbri_stop_output(struct sparcaudio_driver *drv)
reset_pipe(dbri, 4);
}
+/******************* sparcaudio midlevel - audio input ********************/
+
+static void dbri_audio_input_callback(void * callback_arg, int status,
+ unsigned int len)
+{
+ struct sparcaudio_driver * drv =
+ (struct sparcaudio_driver *) callback_arg;
+
+ if (status != -1) {
+ sparcaudio_input_done(drv, 3);
+ }
+}
+
static void dbri_start_input(struct sparcaudio_driver *drv,
__u8 * buffer, unsigned long len)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ /* Pipe 6 is audio receive */
+ recv_on_pipe(dbri, 6, buffer, len,
+ &dbri_audio_input_callback, (void *)drv);
+ dprintk(D_USR, ("DBRI: start audio input buf=%lx/%ld\n",
+ (unsigned long) buffer, len));
}
static void dbri_stop_input(struct sparcaudio_driver *drv)
{
-}
+ struct dbri *dbri = (struct dbri *)drv->private;
-static void dbri_audio_getdev(struct sparcaudio_driver *drv,
- audio_device_t *devptr)
-{
+ reset_pipe(dbri, 6);
}
+/******************* sparcaudio midlevel - volume & balance ***************/
+
static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ dbri->perchip_info.play.gain = volume;
+ mmcodec_setgain(dbri, 0);
+
return 0;
}
static int dbri_get_output_volume(struct sparcaudio_driver *drv)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.gain;
}
static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume)
@@ -1139,12 +1642,19 @@ static int dbri_get_monitor_volume(struct sparcaudio_driver *drv)
static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ dbri->perchip_info.play.balance = balance;
+ mmcodec_setgain(dbri, 0);
+
return 0;
}
static int dbri_get_output_balance(struct sparcaudio_driver *drv)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.balance;
}
static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance)
@@ -1157,107 +1667,205 @@ static int dbri_get_input_balance(struct sparcaudio_driver *drv)
return 0;
}
+static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
+{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ dbri->perchip_info.output_muted = mute;
+
+ return 0;
+}
+
+static int dbri_get_output_muted(struct sparcaudio_driver *drv)
+{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.output_muted;
+}
+
+/******************* sparcaudio midlevel - encoding format ****************/
+
static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ switch (chan) {
+ case 0:
+ return 0;
+ case 1:
+ dbri->mm.ctrl[1] &= ~CS4215_DFR_STEREO;
+ break;
+ case 2:
+ dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
+ break;
+ default:
+ return -1;
+ }
+
+ dbri->perchip_info.play.channels = chan;
+ mmcodec_setctrl(dbri);
+ mmcodec_init_data(dbri);
return 0;
}
static int dbri_get_output_channels(struct sparcaudio_driver *drv)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.channels;
}
static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan)
{
- return 0;
+ return dbri_set_output_channels(drv, chan);
}
static int dbri_get_input_channels(struct sparcaudio_driver *drv)
{
- return 0;
+ return dbri_get_output_channels(drv);
}
static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec)
{
- return 8;
+ return 0;
}
static int dbri_get_output_precision(struct sparcaudio_driver *drv)
{
- return 8;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.precision;
}
static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec)
{
- return 8;
+ return 0;
}
static int dbri_get_input_precision(struct sparcaudio_driver *drv)
{
- return 8;
-}
+ struct dbri *dbri = (struct dbri *)drv->private;
-static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
-{
- return 0;
+ return dbri->perchip_info.play.precision;
}
-static int dbri_get_output_port(struct sparcaudio_driver *drv)
+static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ /* For ULAW and ALAW, audio.c enforces precision = 8,
+ * for LINEAR, precision must be 16
+ */
+
+ switch (enc) {
+ case AUDIO_ENCODING_NONE:
+ return 0;
+ case AUDIO_ENCODING_ULAW:
+ dbri->mm.ctrl[1] &= ~3;
+ dbri->mm.ctrl[1] |= CS4215_DFR_ULAW;
+ dbri->perchip_info.play.encoding = enc;
+ dbri->perchip_info.play.precision = 8;
+ break;
+ case AUDIO_ENCODING_ALAW:
+ dbri->mm.ctrl[1] &= ~3;
+ dbri->mm.ctrl[1] |= CS4215_DFR_ALAW;
+ dbri->perchip_info.play.encoding = enc;
+ dbri->perchip_info.play.precision = 8;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ dbri->mm.ctrl[1] &= ~3;
+ dbri->mm.ctrl[1] |= CS4215_DFR_LINEAR16;
+ dbri->perchip_info.play.encoding = enc;
+ dbri->perchip_info.play.precision = 16;
+ break;
+ default:
+ return -1;
+ }
+ mmcodec_setctrl(dbri);
+ mmcodec_init_data(dbri);
return 0;
}
-static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
+static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.encoding;
}
-static int dbri_get_input_port(struct sparcaudio_driver *drv)
+static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
{
- return 0;
+ return dbri_set_output_encoding(drv, enc);
}
-static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
+static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
{
- return 0;
+ return dbri_get_output_encoding(drv);
}
-static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
+static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
{
+ struct dbri *dbri = (struct dbri *)drv->private;
+ int i;
+
+ if (rate == 0) {
+ return 0;
+ }
+
+ for (i=0; CS4215_FREQ[i].freq; i++) {
+ if (CS4215_FREQ[i].freq == rate) break;
+ }
+ if (CS4215_FREQ[i].freq == 0) {
+ return -1;
+ }
+
+ dbri->mm.ctrl[1] &= ~ 0x38;
+ dbri->mm.ctrl[1] |= CS4215_FREQ[i].csval;
+ dbri->mm.ctrl[2] &= ~ 0x70;
+ dbri->mm.ctrl[2] |= CS4215_FREQ[i].xtal;
+
+ dbri->perchip_info.play.sample_rate = rate;
+
+ mmcodec_setctrl(dbri);
+ mmcodec_init_data(dbri);
return 0;
}
-static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
+static int dbri_get_output_rate(struct sparcaudio_driver *drv)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ return dbri->perchip_info.play.sample_rate;
}
-static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
+static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
{
- return 0;
+ return dbri_set_output_rate(drv, rate);
}
-static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
+static int dbri_get_input_rate(struct sparcaudio_driver *drv)
{
- return 0;
+ return dbri_get_output_rate(drv);
}
-static int dbri_get_output_rate(struct sparcaudio_driver *drv)
+/******************* sparcaudio midlevel - ports ***********************/
+
+static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
{
return 0;
}
-static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
+static int dbri_get_output_port(struct sparcaudio_driver *drv)
{
return 0;
}
-static int dbri_get_input_rate(struct sparcaudio_driver *drv)
+static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
{
return 0;
}
-static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
+static int dbri_get_input_port(struct sparcaudio_driver *drv)
{
return 0;
}
@@ -1272,17 +1880,66 @@ static int dbri_get_input_ports(struct sparcaudio_driver *drv)
return 0;
}
-static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
+/******************* sparcaudio midlevel - driver ID ********************/
+
+static void dbri_audio_getdev(struct sparcaudio_driver *drv,
+ audio_device_t *audinfo)
{
- return 0;
+ struct dbri *dbri = (struct dbri *)drv->private;
+
+ strncpy(audinfo->name, "SUNW,DBRI", sizeof(audinfo->name) - 1);
+
+ audinfo->version[0] = dbri->dbri_version;
+ audinfo->version[1] = '\0';
+
+ strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
}
-static int dbri_get_output_muted(struct sparcaudio_driver *drv)
+static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
{
- return 0;
+ return AUDIO_DEV_CODEC;
+}
+
+/******************* sparcaudio midlevel - open & close ******************/
+
+static int dbri_open(struct inode * inode, struct file * file,
+ struct sparcaudio_driver *drv)
+{
+ MOD_INC_USE_COUNT;
+
+ /* SunOS 5.5.1 audio(7I) man page says:
+ * "Upon the initial open() of the audio device, the driver
+ * will reset the data format of the device to the default
+ * state of 8-bit, 8KHz, mono u-law data."
+ *
+ * I've also taken the liberty of setting half gain and
+ * mid balance, to put the codec in a known state.
+ */
+
+ dbri_set_output_channels(drv, 1);
+ dbri_set_output_encoding(drv, AUDIO_ENCODING_ULAW);
+ dbri_set_output_rate(drv, 8000);
+
+ dbri_set_output_balance(drv, AUDIO_MID_BALANCE);
+ dbri_set_output_volume(drv, AUDIO_MAX_GAIN/2);
+
+ return 0;
}
+static void dbri_release(struct inode * inode, struct file * file,
+ struct sparcaudio_driver *drv)
+{
+ MOD_DEC_USE_COUNT;
+}
+static int dbri_ioctl(struct inode * inode, struct file * file,
+ unsigned int x, unsigned long y,
+ struct sparcaudio_driver *drv)
+{
+ return -EINVAL;
+}
+
+/*********** sparcaudio midlevel - struct sparcaudio_driver ************/
static struct sparcaudio_operations dbri_ops = {
dbri_open,
@@ -1357,8 +2014,8 @@ void dbri_isdn_init(struct dbri *dbri)
setup_pipe(dbri,11, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
link_time_slot(dbri, 0, PIPEinput, 0, 2, 17);
- link_time_slot(dbri, 8, PIPEinput, 8, 8, 0);
- link_time_slot(dbri, 9, PIPEinput, 9, 8, 8);
+ link_time_slot(dbri, 8, PIPEinput, 0, 8, 0);
+ link_time_slot(dbri, 9, PIPEinput, 8, 8, 8);
link_time_slot(dbri, 1, PIPEoutput, 1, 2, 17);
link_time_slot(dbri, 10, PIPEoutput, 1, 8, 0);
@@ -1375,6 +2032,8 @@ int dbri_get_irqnum(int dev)
dbri = (struct dbri *) drivers[dev].private;
+ tprintk(("dbri_get_irqnum()\n"));
+
/* On the sparc, the cpu's irq number is only part of the "irq" */
return (dbri->irq & NR_IRQS);
}
@@ -1389,6 +2048,8 @@ int dbri_get_liu_state(int dev)
dbri = (struct dbri *) drivers[dev].private;
+ tprintk(("dbri_get_liu_state() returns %d\n", dbri->liu_state));
+
return dbri->liu_state;
}
@@ -1404,12 +2065,14 @@ void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg)
dbri = (struct dbri *) drivers[dev].private;
+ tprintk(("dbri_liu_init()\n"));
+
/* Set callback for LIU state change */
- dbri->liu_callback = callback;
+ dbri->liu_callback = callback;
dbri->liu_callback_arg = callback_arg;
- dbri_isdn_init(dbri);
- dbri_liu_activate(dev, 0);
+ dbri_isdn_init(dbri);
+ dbri_liu_activate(dev, 0);
}
void dbri_liu_activate(int dev, int priority)
@@ -1424,16 +2087,24 @@ void dbri_liu_activate(int dev, int priority)
dbri = (struct dbri *) drivers[dev].private;
- cmd = dbri_cmdlock(dbri);
+ tprintk(("dbri_liu_activate()\n"));
- /* Turn on the ISDN TE interface and request activation */
- val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
- *(cmd++) = DBRI_CMD(D_TE, 0, val);
+ if (dbri->liu_state <= 3) {
- dbri_cmdsend(dbri, cmd);
+ cmd = dbri_cmdlock(dbri);
+
+ /* Turn on the ISDN TE interface and request activation */
+ val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
+#ifdef LOOPBACK_D
+ val |= D_NT_LLB(4);
+#endif
+ *(cmd++) = DBRI_CMD(D_TE, 0, val);
- /* Activate the interface */
- dbri->regs->reg0 |= D_T;
+ dbri_cmdsend(dbri, cmd);
+
+ /* Activate the interface */
+ dbri->regs->reg0 |= D_T;
+ }
}
void dbri_liu_deactivate(int dev)
@@ -1446,8 +2117,14 @@ void dbri_liu_deactivate(int dev)
dbri = (struct dbri *) drivers[dev].private;
+ tprintk(("dbri_liu_deactivate()\n"));
+
+#if 0
/* Turn off the ISDN TE interface */
dbri->regs->reg0 &= ~D_T;
+
+ dbri->liu_state = 0;
+#endif
}
void dbri_dxmit(int dev, __u8 *buffer, unsigned int count,
@@ -1613,6 +2290,11 @@ static int dbri_attach(struct sparcaudio_driver *drv,
"DBRI DMA Cmd Block", &dma_dvma);
dbri->dma_dvma = (struct dbri_dma *) dma_dvma;
+ memset((void *) dbri->dma, 0, sizeof(struct dbri_dma));
+
+ dprintk(D_GEN, ("DBRI: DMA Cmd Block 0x%08x (0x%08x)\n",
+ (int)dbri->dma, (int)dbri->dma_dvma));
+
dbri->dbri_version = sdev->prom_name[9];
dbri->sdev = sdev;
@@ -1625,6 +2307,8 @@ static int dbri_attach(struct sparcaudio_driver *drv,
"DBRI Registers", sdev->reg_addrs[0].which_io, 0);
if (!dbri->regs) {
printk(KERN_ERR "DBRI: could not allocate registers\n");
+ release_region((unsigned long) dbri->dma,
+ sizeof(struct dbri_dma));
kfree(drv->private);
return -EIO;
}
@@ -1637,6 +2321,8 @@ static int dbri_attach(struct sparcaudio_driver *drv,
if (err) {
printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
sparc_free_io(dbri->regs, dbri->regs_size);
+ release_region((unsigned long) dbri->dma,
+ sizeof(struct dbri_dma));
kfree(drv->private);
return err;
}
diff --git a/drivers/sbus/audio/dbri.h b/drivers/sbus/audio/dbri.h
index 1cd598743..7b29bf533 100644
--- a/drivers/sbus/audio/dbri.h
+++ b/drivers/sbus/audio/dbri.h
@@ -46,13 +46,19 @@ struct dbri_dma {
struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */
};
+enum in_or_out { PIPEinput, PIPEoutput };
+
+enum direction { in, out };
+
struct dbri_pipe {
u32 sdp; /* SDP command word */
+ enum direction direction;
int nextpipe; /* Next pipe in linked list */
+ int prevpipe;
int cycle; /* Offset of timeslot (bits) */
int length; /* Length of timeslot (bits) */
int desc; /* Index of active descriptor*/
- __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
+ volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
};
struct dbri_desc {
@@ -78,10 +84,15 @@ struct dbri {
struct dbri_regs *regs; /* dbri HW regs */
int dbri_version; /* 'e' and up is OK */
int dbri_irqp; /* intr queue pointer */
+ int wait_seen;
struct dbri_pipe pipes[32]; /* DBRI's 32 data pipes */
struct dbri_desc descs[DBRI_NO_DESCS];
+ int chi_in_pipe;
+ int chi_out_pipe;
+ int chi_bpf;
+
struct cs4215 mm; /* mmcodec special info */
#if 0
@@ -190,7 +201,7 @@ struct dbri {
/* Time Slot defines */
#define D_TS_LEN(v) ((v)<<24) /* Number of bits in this time slot */
#define D_TS_CYCLE(v) ((v)<<14) /* Bit Count at start of TS */
-#define D_TS_DI(v) (1<<13) /* Data Invert */
+#define D_TS_DI (1<<13) /* Data Invert */
#define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */
#define D_TS_MONITOR (2<<10) /* Monitor pipe */
#define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */
@@ -218,8 +229,8 @@ struct dbri {
#define D_NT_IFA (1<<10) /* Inhibit Final Activation */
#define D_NT_ACT (1<<9) /* Activate Interface */
#define D_NT_MFE (1<<8) /* Multiframe Enable */
-#define D_NT_RLB(v) (1<<5) /* Remote Loopback */
-#define D_NT_LLB(v) (1<<2) /* Local Loopback */
+#define D_NT_RLB(v) ((v)<<5) /* Remote Loopback */
+#define D_NT_LLB(v) ((v)<<2) /* Local Loopback */
#define D_NT_FACT (1<<1) /* Force Activation */
#define D_NT_ABV (1<<0) /* Activate Bipolar Violation */
diff --git a/drivers/sbus/char/su.c b/drivers/sbus/char/su.c
index a79dc6b6f..b80b93e92 100644
--- a/drivers/sbus/char/su.c
+++ b/drivers/sbus/char/su.c
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.20 1999/06/03 15:02:40 davem Exp $
+/* $Id: su.c,v 1.21 1999/06/11 10:23:42 davem Exp $
* su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -1133,9 +1133,9 @@ static void su_put_char_kbd(unsigned char c)
struct su_struct *info = su_table;
int lsr;
- if (!info->port_type != SU_PORT_KBD)
+ if (info->port_type != SU_PORT_KBD)
++info;
- if (!info->port_type != SU_PORT_KBD)
+ if (info->port_type != SU_PORT_KBD)
return;
do {
@@ -1151,9 +1151,9 @@ su_change_mouse_baud(int baud)
{
struct su_struct *info = su_table;
- if (!info->port_type != SU_PORT_MS)
+ if (info->port_type != SU_PORT_MS)
++info;
- if (!info->port_type != SU_PORT_MS)
+ if (info->port_type != SU_PORT_MS)
return;
info->cflag &= ~(CBAUDEX | CBAUD);
@@ -2215,7 +2215,7 @@ done:
*/
__initfunc(static __inline__ void show_su_version(void))
{
- char *revision = "$Revision: 1.20 $";
+ char *revision = "$Revision: 1.21 $";
char *version, *p;
version = strchr(revision, ' ');
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index 2a6ad2949..6388b2e8e 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -67,7 +67,7 @@
orl %%ecx, %%ecx \n \
jz 1f \n \
rep \n \
- insw %%dx \n \
+ insw (%%dx),%%es:(%%edi) \n \
1: " \
: "=D" (sp) /* output */ \
: "d" (f), "D" (sp), "c" (i) /* input */ \
@@ -79,7 +79,7 @@
orl %%ecx, %%ecx \n \
jz 1f \n \
rep \n \
- outsw %%dx \n \
+ outsw %%ds:(%%esi),(%%dx) \n \
1: " \
: "=S" (sp) /* output */ \
: "d" (f), "S" (sp), "c" (i) /* input */ \
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 9bb08ce58..d71509548 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1926,6 +1926,7 @@ scsi_error_handler(void * data)
int rtn;
DECLARE_MUTEX_LOCKED(sem);
unsigned long flags;
+ struct fs_struct *fs;
lock_kernel();
@@ -1936,16 +1937,18 @@ scsi_error_handler(void * data)
*/
exit_mm(current);
-
current->session = 1;
current->pgrp = 1;
- /*
- * FIXME(eric) this is still a child process of the one that did the insmod.
- * This needs to be attached to task[0] instead.
- */
+
+ /* Become as one with the init task */
+
+ exit_fs(current); /* current->fs->count--; */
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
- current->fs->umask = 0;
+
/*
* Set the name of this process.
diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c
index ace8f3098..d7579ffa4 100644
--- a/drivers/sound/es1370.c
+++ b/drivers/sound/es1370.c
@@ -98,6 +98,8 @@
* (micz). From Kim.Berts@fisub.mail.abb.com
* 11.05.99 0.22 Implemented the IMIX call to mute recording monitor.
* Guenter Geiger <geiger@epy.co.at>
+ * 15.06.99 0.23 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
*
* some important things missing in Ensoniq documentation:
*
@@ -531,8 +533,9 @@ static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate,
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--)
- db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order);
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+ break;
if (!db->rawbuf)
return -ENOMEM;
db->buforder = order;
@@ -2317,7 +2320,7 @@ __initfunc(int init_es1370(void))
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1370: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1370: version v0.23 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
if (pcidev->base_address[0] == 0 ||
diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c
index d416d0e28..a0f3969e0 100644
--- a/drivers/sound/es1371.c
+++ b/drivers/sound/es1371.c
@@ -65,6 +65,8 @@
* reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru>
* Note: joystick address handling might still be wrong on archs
* other than i386
+ * 15.06.99 0.12 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
*
*/
@@ -759,8 +761,9 @@ static int prog_dmabuf(struct es1371_state *s, struct dmabuf *db, unsigned rate,
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--)
- db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order);
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+ break;
if (!db->rawbuf)
return -ENOMEM;
db->buforder = order;
@@ -2732,7 +2735,7 @@ __initfunc(int init_es1371(void))
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1371: version v0.11 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1371: version v0.12 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
if (pcidev->base_address[0] == 0 ||
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index af5ddcea0..83c5c88c0 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -68,6 +68,8 @@
* SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
* Alpha fixes reported by Peter Jones <pjones@redhat.com>
* Note: dmaio hack might still be wrong on archs other than i386
+ * 15.06.99 0.15 Fix bad allocation bug.
+ * Thanks to Deti Fliegl <fliegl@in.tum.de>
*
*/
@@ -699,8 +701,9 @@ static int prog_dmabuf(struct sv_state *s, unsigned rec)
db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
if (!db->rawbuf) {
db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--)
- db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order);
+ for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+ if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)))
+ break;
if (!db->rawbuf)
return -ENOMEM;
db->buforder = order;
@@ -2321,7 +2324,7 @@ __initfunc(int init_sonicvibes(void))
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.14 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.15 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c
index 36a4eafb1..04fcd3413 100644
--- a/drivers/sound/vidc.c
+++ b/drivers/sound/vidc.c
@@ -24,7 +24,7 @@ void vidc_update_filler(int format, int channels)
#define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
fillertype = TYPE(format, channels);
-printk("filler type: %X\n", fillertype);
+
switch (fillertype)
{
default:
@@ -61,10 +61,13 @@ void attach_vidc(struct address_info *hw_config)
sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
conf_printf(name, hw_config);
+ memset(dma_buf, 0, sizeof(dma_buf));
for (i = 0; i < 2; i++)
{
dma_buf[i] = get_free_page(GFP_KERNEL);
+ if (!dma_buf[i])
+ goto nomem;
dma_pbuf[i] = virt_to_phys(dma_buf[i]);
}
@@ -78,9 +81,16 @@ void attach_vidc(struct address_info *hw_config)
printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n");
return;
}
+
// vidc_synth_init(hw_config);
vidc_audio_init(hw_config);
vidc_mixer_init(hw_config);
+ return;
+
+nomem:
+ for (i = 0; i < 2; i++)
+ free_page(dma_buf[i]);
+ printk(KERN_ERR "VIDCsound: can't allocate required buffers\n");
}
int probe_vidc(struct address_info *hw_config)
diff --git a/drivers/sound/vidc_audio.c b/drivers/sound/vidc_audio.c
index 7aa275084..3a1f162fb 100644
--- a/drivers/sound/vidc_audio.c
+++ b/drivers/sound/vidc_audio.c
@@ -9,6 +9,7 @@
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/iomd.h>
#include "sound_config.h"
#include "vidc.h"
@@ -42,7 +43,6 @@ int vidc_audio_set_volume(int newvol)
static int vidc_audio_set_bits(int fmt)
{
-printk("setting format: %d\n", fmt);
switch (fmt)
{
case AFMT_QUERY:
@@ -219,10 +219,11 @@ static void vidc_audio_output_block(int dev, unsigned long buf, int total_count,
if (!(adev->flags & DMA_ACTIVE))
{
unsigned long flags;
-printk("kicking output: %lX+%lX [%lX]\n", dma_start, dma_count, *(unsigned long *)dma_start);
save_flags_cli(flags);
+
vidc_sound_dma_irq(0, NULL, NULL);
outb(DMA_CR_E | 0x10, IOMD_SD0CR);
+
restore_flags(flags);
}
}
diff --git a/drivers/sound/vidc_fill.S b/drivers/sound/vidc_fill.S
index b8b1e6620..53fc2ed01 100644
--- a/drivers/sound/vidc_fill.S
+++ b/drivers/sound/vidc_fill.S
@@ -9,6 +9,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
+#include <asm/iomd.h>
.text
diff --git a/drivers/sound/waveartist.c b/drivers/sound/waveartist.c
index 5a707a4b7..85a9efaec 100644
--- a/drivers/sound/waveartist.c
+++ b/drivers/sound/waveartist.c
@@ -40,12 +40,20 @@
#include <linux/delay.h>
#include <linux/smp.h>
+#include <asm/dec21285.h>
#include <asm/hardware.h>
#include "soundmodule.h"
#include "sound_config.h"
#include "waveartist.h"
+#ifndef _ISA_DMA
+#define _ISA_DMA(x) (x)
+#endif
+#ifndef _ISA_IRQ
+#define _ISA_IRQ(x) (x)
+#endif
+
#define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec
#define MIXER_PRIVATE3_RESET 0x53570000
@@ -141,8 +149,269 @@ typedef struct wavnc_port_info {
static int nr_waveartist_devs;
static wavnc_info adev_info[MAX_AUDIO_DEV];
+
+static int waveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level);
+
+/*
+ * Corel Netwinder specifics...
+ */
static struct timer_list vnc_timer;
+extern spinlock_t gpio_lock;
+
+static void
+vnc_mute(wavnc_info *devc, int mute)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+ cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE);
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ devc->mute_state = mute;
+}
+
+static int
+vnc_volume_slider(wavnc_info *devc)
+{
+ static signed int old_slider_volume;
+ unsigned long flags;
+ signed int volume = 255;
+
+ *CSR_TIMER1_LOAD = 0x00ffffff;
+
+ save_flags(flags);
+ cli();
+
+ outb(0xFF, 0x201);
+ *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
+
+ while (volume && (inb(0x201) & 0x01))
+ volume--;
+
+ *CSR_TIMER1_CNTL = 0;
+
+ restore_flags(flags);
+
+ volume = 0x00ffffff - *CSR_TIMER1_VALUE;
+
+
+#ifndef REVERSE
+ volume = 150 - (volume >> 5);
+#else
+ volume = (volume >> 6) - 25;
+#endif
+
+ if (volume < 0)
+ volume = 0;
+
+ if (volume > 100)
+ volume = 100;
+
+ /*
+ * slider quite often reads +-8, so debounce this random noise
+ */
+ if ((volume - old_slider_volume) > 7 ||
+ (old_slider_volume - volume) > 7) {
+ old_slider_volume = volume;
+
+ DEB(printk("Slider volume: %d.\n", old_slider_volume));
+ }
+
+ return old_slider_volume;
+}
+
+static int
+vnc_slider(wavnc_info *devc)
+{
+ signed int slider_volume;
+ unsigned int temp;
+
+ /*
+ * read the "buttons" state.
+ * Bit 4 = handset present,
+ * Bit 5 = offhook
+ */
+ // the state should be "querable" via a private IOCTL call
+ temp = inb(0x201) & 0x30;
+
+ if (!devc->handset_mute_sw &&
+ (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) {
+ devc->handset_state = temp;
+ devc->handset_mute_sw = 0;
+
+ vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0);
+ }
+
+ slider_volume = vnc_volume_slider(devc);
+
+ /*
+ * If we're using software controlled volume, and
+ * the slider moves by more than 20%, then we
+ * switch back to slider controlled volume.
+ */
+ if (devc->slider_vol > slider_volume) {
+ if (devc->slider_vol - slider_volume > 20)
+ devc->use_slider = 1;
+ } else {
+ if (slider_volume - devc->slider_vol > 20)
+ devc->use_slider = 1;
+ }
+
+ /*
+ * use only left channel
+ */
+ temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
+
+ if (slider_volume != temp && devc->use_slider) {
+ devc->slider_vol = slider_volume;
+
+ waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
+ slider_volume | slider_volume << 8);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+vnc_slider_tick(unsigned long data)
+{
+ int next_timeout;
+
+ if (vnc_slider(adev_info + data))
+ next_timeout = 5; // mixer reported change
+ else
+ next_timeout = VNC_TIMER_PERIOD;
+
+ mod_timer(&vnc_timer, jiffies + next_timeout);
+}
+
+static int
+vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+ wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+ int val, temp;
+
+ if (cmd == SOUND_MIXER_PRIVATE1) {
+ /*
+ * Use this call to override the automatic handset
+ * behaviour - ignore handset.
+ * bit 7 = total control over handset - do not
+ * to plug/unplug
+ * bit 4 = internal mic
+ * bit 0 = mute internal speaker
+ */
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ devc->handset_mute_sw = val;
+
+ temp = val & VNC_INTERNAL_SPKR;
+ if (devc->mute_state != temp)
+ vnc_mute(devc, temp);
+
+ devc->handset_state = val & VNC_INTERNAL_MIC;
+ waveartist_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
+ return 0;
+ }
+#if 0
+ if (cmd == SOUND_MIXER_PRIVATE2) {
+#define VNC_SOUND_PAUSE 0x53 //to pause the DSP
+#define VNC_SOUND_RESUME 0x57 //to unpause the DSP
+ int val;
+
+ val = *(int *) arg;
+
+ printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val);
+ if (val == VNC_SOUND_PAUSE) {
+ wa_sendcmd(0x16); //PAUSE the ADC
+ } else if (val == VNC_SOUND_RESUME) {
+ wa_sendcmd(0x18); //RESUME the ADC
+ } else {
+ return -EINVAL; //invalid parameters...
+ }
+ return 0;
+ }
+
+ if (cmd == SOUND_MIXER_PRIVATE3) {
+ long unsigned flags;
+ int mixer_reg[15]; //reg 14 is actually a command: read,write,reset
+
+ int val;
+ int i;
+
+ val = *(int *) arg;
+
+ if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT))
+ return (-EFAULT);
+
+ memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg));
+
+ if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) { //reset command??
+ wavnc_mixer_reset(devc);
+ return (0);
+ } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) { //write command??
+// printk("WaveArtist Mixer: Private write command.\n");
+
+ wa_sendcmd(0x32); //Pair1 - word 1 and 5
+ wa_sendcmd(mixer_reg[0]);
+ wa_sendcmd(mixer_reg[4]);
+
+ wa_sendcmd(0x32); //Pair2 - word 2 and 6
+ wa_sendcmd(mixer_reg[1]);
+ wa_sendcmd(mixer_reg[5]);
+
+ wa_sendcmd(0x32); //Pair3 - word 3 and 7
+ wa_sendcmd(mixer_reg[2]);
+ wa_sendcmd(mixer_reg[6]);
+
+ wa_sendcmd(0x32); //Pair4 - word 4 and 8
+ wa_sendcmd(mixer_reg[3]);
+ wa_sendcmd(mixer_reg[7]);
+
+ wa_sendcmd(0x32); //Pair5 - word 9 and 10
+ wa_sendcmd(mixer_reg[8]);
+ wa_sendcmd(mixer_reg[9]);
+
+ wa_sendcmd(0x0031); //set left and right PCM
+ wa_sendcmd(mixer_reg[0x0A]);
+ wa_sendcmd(mixer_reg[0x0B]);
+
+ wa_sendcmd(0x0131); //set left and right FM
+ wa_sendcmd(mixer_reg[0x0C]);
+ wa_sendcmd(mixer_reg[0x0D]);
+
+ return 0;
+ } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) { //read command?
+// printk("WaveArtist Mixer: Private read command.\n");
+
+ //first read all current values...
+ save_flags(flags);
+ cli();
+
+ for (i = 0; i < 14; i++) {
+ wa_sendcmd((i << 8) + 0x30); // get ready for command nn30H
+
+ while (!(inb(STATR) & CMD_RF)) {
+ }; //wait for response ready...
+
+ mixer_reg[i] = inw(CMDR);
+ }
+ restore_flags(flags);
+
+ if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT))
+ return (-EFAULT);
+
+ memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg));
+ return 0;
+ } else
+ return -EINVAL;
+ }
+#endif
+ return -EINVAL;
+}
static inline void
waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set)
@@ -1368,138 +1637,12 @@ static int
waveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
{
wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
-#if 0
- //use this call to override the automatic handset behaviour - ignore handset
- //bit 0x80 = total control over handset - do not react to plug/unplug
- //bit 0x10 = 1 == internal mic, otherwise handset mic
- //bit 0x01 = 1 == mute internal speaker, otherwise unmute
-
- if (cmd == SOUND_MIXER_PRIVATE1) {
- int val, temp;
-
- val = *(int *) arg;
-
-// printk("MIXER_PRIVATE1: passed parameter = 0x%X.\n",val);
- return -EINVAL; //check if parameter is logical...
-
- devc->soft_mute_flag = val;
-
- temp = val & VNC_INTERNAL_SPKR;
- if (temp != devc->mute_state) {
-// printk("MIXER_PRIVATE1: mute_mono(0x%X).\n",temp);
- vnc_mute(devc, temp);
- }
-
-// temp = devc->handset_state;
-
- // do not check if it is not already in
- // the right setting, since we are
- // laying about the current state...
-
-// if ((val & VNC_INTERNAL_MIC) != temp) {
- devc->handset_state = val & VNC_INTERNAL_MIC;
-// printk("MIXER_PRIVATE1: mixer_set(0x%X).\n",devc->handset_state);
- wa_mixer_set(devc, SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
-// devc->handset_state = temp;
- }
- return 0;
- }
-#if 0
- if (cmd == SOUND_MIXER_PRIVATE2) {
-#define VNC_SOUND_PAUSE 0x53 //to pause the DSP
-#define VNC_SOUND_RESUME 0x57 //to unpause the DSP
- int val;
-
- val = *(int *) arg;
-
- printk("MIXER_PRIVATE2: passed parameter = 0x%X.\n",val);
-
- if (val == VNC_SOUND_PAUSE) {
- wa_sendcmd(0x16); //PAUSE the ADC
- } else if (val == VNC_SOUND_RESUME) {
- wa_sendcmd(0x18); //RESUME the ADC
- } else {
- return -EINVAL; //invalid parameters...
- }
- return 0;
- }
-#endif
- if (cmd == SOUND_MIXER_PRIVATE3) {
- long unsigned flags;
- int mixer_reg[15]; //reg 14 is actually a command: read,write,reset
-
- int val;
- int i;
-
- val = *(int *) arg;
-
- if (verify_area(VERIFY_READ, (void *) val, sizeof(mixer_reg) == -EFAULT))
- return (-EFAULT);
-
- memcpy_fromfs(&mixer_reg, (void *) val, sizeof(mixer_reg));
-
- if (mixer_reg[0x0E] == MIXER_PRIVATE3_RESET) { //reset command??
- wavnc_mixer_reset(devc);
- return (0);
- } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_WRITE) { //write command??
-// printk("WaveArtist Mixer: Private write command.\n");
-
- wa_sendcmd(0x32); //Pair1 - word 1 and 5
- wa_sendcmd(mixer_reg[0]);
- wa_sendcmd(mixer_reg[4]);
+ if (cmd == SOUND_MIXER_PRIVATE1 ||
+ cmd == SOUND_MIXER_PRIVATE2 ||
+ cmd == SOUND_MIXER_PRIVATE3)
+ return vnc_private_ioctl(dev, cmd, arg);
- wa_sendcmd(0x32); //Pair2 - word 2 and 6
- wa_sendcmd(mixer_reg[1]);
- wa_sendcmd(mixer_reg[5]);
-
- wa_sendcmd(0x32); //Pair3 - word 3 and 7
- wa_sendcmd(mixer_reg[2]);
- wa_sendcmd(mixer_reg[6]);
-
- wa_sendcmd(0x32); //Pair4 - word 4 and 8
- wa_sendcmd(mixer_reg[3]);
- wa_sendcmd(mixer_reg[7]);
-
- wa_sendcmd(0x32); //Pair5 - word 9 and 10
- wa_sendcmd(mixer_reg[8]);
- wa_sendcmd(mixer_reg[9]);
-
- wa_sendcmd(0x0031); //set left and right PCM
- wa_sendcmd(mixer_reg[0x0A]);
- wa_sendcmd(mixer_reg[0x0B]);
-
- wa_sendcmd(0x0131); //set left and right FM
- wa_sendcmd(mixer_reg[0x0C]);
- wa_sendcmd(mixer_reg[0x0D]);
-
- return 0;
- } else if (mixer_reg[0x0E] == MIXER_PRIVATE3_READ) { //read command?
-// printk("WaveArtist Mixer: Private read command.\n");
-
- //first read all current values...
- save_flags(flags);
- cli();
-
- for (i = 0; i < 14; i++) {
- wa_sendcmd((i << 8) + 0x30); // get ready for command nn30H
-
- while (!(inb(STATR) & CMD_RF)) {
- }; //wait for response ready...
-
- mixer_reg[i] = inw(CMDR);
- }
- restore_flags(flags);
-
- if (verify_area(VERIFY_WRITE, (void *) val, sizeof(mixer_reg) == -EFAULT))
- return (-EFAULT);
-
- memcpy_tofs((void *) val, &mixer_reg, sizeof(mixer_reg));
- return 0;
- } else
- return -EINVAL;
- }
-#endif
if (((cmd >> 8) & 0xff) == 'M') {
if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
int val;
@@ -1660,139 +1803,6 @@ nomem:
return -1;
}
-/*
- * Corel Netwinder specifics...
- */
-static void
-vnc_mute(wavnc_info *devc, int mute)
-{
- extern spinlock_t gpio_lock;
- unsigned long flags;
-
- spin_lock_irqsave(&gpio_lock, flags);
- cpld_modify(CPLD_UNMUTE, mute ? 0 : CPLD_UNMUTE);
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- devc->mute_state = mute;
-}
-
-static int
-vnc_volume_slider(wavnc_info *devc)
-{
- static signed int old_slider_volume;
- unsigned long flags;
- signed int volume = 255;
-
- *CSR_TIMER1_LOAD = 0x00ffffff;
-
- save_flags(flags);
- cli();
-
- outb(0xFF, 0x201);
- *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;
-
- while (volume && (inb(0x201) & 0x01))
- volume--;
-
- *CSR_TIMER1_CNTL = 0;
-
- restore_flags(flags);
-
- volume = 0x00ffffff - *CSR_TIMER1_VALUE;
-
-
-#ifndef REVERSE
- volume = 150 - (volume >> 5);
-#else
- volume = (volume >> 6) - 25;
-#endif
-
- if (volume < 0)
- volume = 0;
-
- if (volume > 100)
- volume = 100;
-
- /*
- * slider quite often reads +-8, so debounce this random noise
- */
- if ((volume - old_slider_volume) > 7 ||
- (old_slider_volume - volume) > 7) {
- old_slider_volume = volume;
-
- DEB(printk("Slider volume: %d.\n", old_slider_volume));
- }
-
- return old_slider_volume;
-}
-
-static int
-vnc_slider(wavnc_info *devc)
-{
- signed int slider_volume;
- unsigned int temp;
-
- /*
- * read the "buttons" state.
- * Bit 4 = handset present,
- * Bit 5 = offhook
- */
- // the state should be "querable" via a private IOCTL call
- temp = inb(0x201) & 0x30;
-
- if (!devc->handset_mute_sw &&
- (temp ^ devc->handset_state) & VNC_INTERNAL_MIC) {
- devc->handset_state = temp;
- devc->handset_mute_sw = 0;
-
- vnc_mute(devc, (temp & VNC_INTERNAL_MIC) ? 1 : 0);
- }
-
- slider_volume = vnc_volume_slider(devc);
-
- /*
- * If we're using software controlled volume, and
- * the slider moves by more than 20%, then we
- * switch back to slider controlled volume.
- */
- if (devc->slider_vol > slider_volume) {
- if (devc->slider_vol - slider_volume > 20)
- devc->use_slider = 1;
- } else {
- if (slider_volume - devc->slider_vol > 20)
- devc->use_slider = 1;
- }
-
- /*
- * use only left channel
- */
- temp = levels[SOUND_MIXER_VOLUME] & 0xFF;
-
- if (slider_volume != temp && devc->use_slider) {
- devc->slider_vol = slider_volume;
-
- waveartist_mixer_set(devc, SOUND_MIXER_VOLUME,
- slider_volume | slider_volume << 8);
-
- return 1;
- }
-
- return 0;
-}
-
-static void
-vnc_slider_tick(unsigned long data)
-{
- int next_timeout;
-
- if (vnc_slider(adev_info + data))
- next_timeout = 5; // mixer reported change
- else
- next_timeout = VNC_TIMER_PERIOD;
-
- mod_timer(&vnc_timer, jiffies + next_timeout);
-}
-
int
probe_waveartist(struct address_info *hw_config)
{
@@ -1808,12 +1818,12 @@ probe_waveartist(struct address_info *hw_config)
return 0;
}
- if (hw_config->irq > 31 || hw_config->irq < 16) {
+ if (hw_config->irq > _ISA_IRQ(15) || hw_config->irq < _ISA_IRQ(0)) {
printk("WaveArtist: Bad IRQ %d\n", hw_config->irq);
return 0;
}
- if (hw_config->dma != 3) {
+ if (hw_config->dma != _ISA_DMA(3)) {
printk("WaveArtist: Bad DMA %d\n", hw_config->dma);
return 0;
}
diff --git a/drivers/sound/waveartist.h b/drivers/sound/waveartist.h
index 360bc95f1..45b62d1b5 100644
--- a/drivers/sound/waveartist.h
+++ b/drivers/sound/waveartist.h
@@ -2,16 +2,11 @@
// def file for Rockwell RWA010 chip set, as installed in Corel NetWinder
//registers
-#define WA_BASE 0
-//x250
-
-#define CMDR WA_BASE+0
-#define DATR WA_BASE+2
-
-#define CTLR WA_BASE+4
-#define STATR WA_BASE+5
-
-#define IRQSTAT WA_BASE+12
+#define CMDR 0
+#define DATR 2
+#define CTLR 4
+#define STATR 5
+#define IRQSTAT 12
//bit defs
//reg STATR
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index d4796e28c..10c837d5a 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -50,7 +50,7 @@ static struct acm_state static_acm_state;
spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
-static int acm_irq(int state, void *__buffer, void *dev_id)
+static int acm_irq(int state, void *__buffer, int len, void *dev_id)
{
// unsigned char *data = __buffer;
struct acm_state *acm = &static_acm_state;
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 45a276772..9743ec89e 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -27,7 +27,7 @@ static struct usb_driver usb_audio_driver =
};
-static int usb_audio_irq(int state, void *buffer, void *dev_id)
+static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_audio *aud = (struct usb_audio*) dev_id;
return 1;
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
index 87e1e4254..2402d3425 100644
--- a/drivers/usb/cpia.c
+++ b/drivers/usb/cpia.c
@@ -451,7 +451,7 @@ printk("copying\n");
}
}
-static int cpia_isoc_irq(int status, void *__buffer, void *dev_id)
+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;
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 1cd7d7ccb..0a1ec1f01 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -33,7 +33,7 @@ static int khubd_pid = 0;
* the low-level driver that it wants to be re-activated,
* or zero to say "I'm done".
*/
-static int hub_irq(int status, void *__buffer, void *dev_id)
+static int hub_irq(int status, void *__buffer, int len, void *dev_id)
{
struct usb_hub *hub = dev_id;
unsigned long flags;
diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c
index 5d93a5a84..e87519d9f 100644
--- a/drivers/usb/keyboard.c
+++ b/drivers/usb/keyboard.c
@@ -92,7 +92,7 @@ usb_kbd_repeat(unsigned long dev_id)
}
static int
-usb_kbd_irq(int state, void *buffer, void *dev_id)
+usb_kbd_irq(int state, void *buffer, int len, void *dev_id)
{
struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
unsigned long *down = (unsigned long*) buffer;
diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c
index f094c0b0d..a79c10a07 100644
--- a/drivers/usb/mouse.c
+++ b/drivers/usb/mouse.c
@@ -60,7 +60,7 @@ static struct mouse_state static_mouse_state;
spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
-static int mouse_irq(int state, void *__buffer, void *dev_id)
+static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
{
signed char *data = __buffer;
/* finding the mouse is easy when there's only one */
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
index 820efc5dc..8db61e08e 100644
--- a/drivers/usb/ohci-hcd.c
+++ b/drivers/usb/ohci-hcd.c
@@ -102,7 +102,7 @@ static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len,
OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
OHCI_DEBUG( printk(" ret_status: %x\n", status); })
- ret = handler(cc_to_status[status & 0xf], data, dev_id);
+ ret = handler(cc_to_status[status & 0xf], data, data_len, dev_id);
if(ret == 0) return 0; /* 0 .. do not requeue */
if(status > 0) return -1; /* error occured do not requeue ? */
ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c
index 4ef570abd..48191e11b 100644
--- a/drivers/usb/ohci.c
+++ b/drivers/usb/ohci.c
@@ -121,7 +121,7 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
u32 new_dummy;
if (ed->tail_td == 0) {
- printk("eek! an ED without a dummy_td\n");
+ printk(KERN_ERR "eek! an ED without a dummy_td\n");
return td;
}
@@ -234,8 +234,8 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
*/
int_ed = &root_hub->ed[ms_to_ed_int(period)];
#ifdef OHCI_DEBUG
- printk("usb-ohci: Using INT ED queue %d for %dms period\n",
- ms_to_ed_int(period), period);
+ printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n",
+ ms_to_ed_int(period), period);
#endif
spin_lock_irqsave(&ohci_edtd_lock, flags);
@@ -264,6 +264,21 @@ inline void ohci_add_isoc_ed(struct ohci *ohci, struct ohci_ed *ed)
*/
DECLARE_WAIT_QUEUE_HEAD(start_of_frame_wakeup);
+static void ohci_wait_sof(struct ohci_regs *regs)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&start_of_frame_wakeup, &wait);
+
+ /* clear the SOF interrupt status and enable it */
+ writel(OHCI_INTR_SF, &regs->intrstatus);
+ writel(OHCI_INTR_SF, &regs->intrenable);
+
+ schedule_timeout(HZ/10);
+
+ remove_wait_queue(&start_of_frame_wakeup, &wait);
+}
+
/*
* Guarantee that an ED is safe to be modified by the HCD (us).
*
@@ -296,21 +311,11 @@ void ohci_wait_for_ed_safe(struct ohci_regs *regs, struct ohci_ed *ed, int ed_ty
* at least the next frame.
*/
if (virt_to_bus(ed) == readl(hw_listcurrent)) {
- DECLARE_WAITQUEUE(wait, current);
-
#ifdef OHCI_DEBUG
- printk("Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed));
+ printk(KERN_INFO "Waiting a frame for OHC to finish with ED %p [%x %x %x %x]\n", ed, FIELDS_OF_ED(ed));
#endif
+ ohci_wait_sof(regs);
- add_wait_queue(&start_of_frame_wakeup, &wait);
-
- /* clear the SOF interrupt status and enable it */
- writel(OHCI_INTR_SF, &regs->intrstatus);
- writel(OHCI_INTR_SF, &regs->intrenable);
-
- schedule_timeout(HZ/10);
-
- remove_wait_queue(&start_of_frame_wakeup, &wait);
}
return; /* The ED is now safe */
@@ -334,6 +339,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
if (ed == NULL || !bus_ed)
return;
+ ed->status |= cpu_to_le32(OHCI_ED_SKIP);
switch (ed_type) {
case HCD_ED_CONTROL:
@@ -343,16 +349,10 @@ 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("Unknown HCD ED type %d.\n", ed_type);
+ printk(KERN_ERR "Unknown HCD ED type %d.\n", ed_type);
return;
}
- /*
- * Tell the controller to this skip ED and make sure it is not the
- * being accessed by the HC as we speak.
- */
- ohci_wait_for_ed_safe(regs, ed, ed_type);
-
bus_cur = readl(hw_listhead_p);
if (bus_cur == 0)
@@ -364,7 +364,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
/* if its the head ED, move the head */
if (bus_cur == bus_ed) {
- writel(cur->next_ed, hw_listhead_p);
+ writel(le32_to_cpup(&cur->next_ed), hw_listhead_p);
} else if (cur->next_ed != 0) {
struct ohci_ed *prev;
@@ -373,7 +373,7 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
prev = cur;
cur = bus_to_virt(le32_to_cpup(&cur->next_ed));
- if (virt_to_bus(cur) == bus_ed) {
+ if (cur == ed) {
/* unlink from the list */
prev->next_ed = cur->next_ed;
break;
@@ -381,6 +381,11 @@ void ohci_remove_norm_ed_from_hw(struct ohci *ohci, struct ohci_ed *ed, int ed_t
} while (cur->next_ed != 0);
}
+ /*
+ * Make sure this ED is not being accessed by the HC as we speak.
+ */
+ ohci_wait_for_ed_safe(regs, ed, ed_type);
+
/* clear any links from the ED for safety */
ed->next_ed = 0;
@@ -405,6 +410,68 @@ 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 all the EDs which have a given device address from a list.
+ * Used when the device is unplugged.
+ * Returns 1 if anything was changed.
+ */
+static int ohci_remove_device_list(__u32 *headp, int devnum)
+{
+ struct ohci_ed *ed;
+ __u32 *prevp = headp;
+ int removed = 0;
+
+ while (*prevp != 0) {
+ ed = bus_to_virt(le32_to_cpup(prevp));
+ if ((le32_to_cpup(&ed->status) & OHCI_ED_FA) == devnum) {
+ /* set the controller to skip this one
+ and remove it from the list */
+ ed->status |= cpu_to_le32(OHCI_ED_SKIP);
+ *prevp = ed->next_ed;
+ removed = 1;
+ } else {
+ prevp = &ed->next_ed;
+ }
+ }
+ wmb();
+
+ return removed;
+}
+
+/*
+ * Remove all the EDs for a given device from all lists.
+ */
+void ohci_remove_device(struct ohci *ohci, int devnum)
+{
+ unsigned long flags;
+ __u32 head;
+ struct ohci_regs *regs = ohci->regs;
+ struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
+
+ spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+ /* Control list */
+ head = cpu_to_le32(readl(&regs->ed_controlhead));
+ if (ohci_remove_device_list(&head, devnum))
+ writel(le32_to_cpup(&head), &regs->ed_controlhead);
+
+ /* Bulk list */
+ head = cpu_to_le32(readl(&regs->ed_bulkhead));
+ if (ohci_remove_device_list(&head, devnum))
+ writel(le32_to_cpup(&head), &regs->ed_bulkhead);
+
+ /* Interrupt/iso list */
+ head = cpu_to_le32(virt_to_bus(&root_hub->ed[ED_INT_32]));
+ ohci_remove_device_list(&head, devnum);
+
+ /*
+ * Wait until the start of the next frame to ensure
+ * that the HC has seen any changes.
+ */
+ ohci_wait_sof(ohci->regs);
+
+ spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+}
/*
* Remove a TD from the given EDs TD list.
@@ -494,7 +561,7 @@ static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
}
}
- printk("usb-ohci: unable to allocate a TD\n");
+ printk(KERN_ERR "usb-ohci: unable to allocate a TD\n");
return NULL;
} /* ohci_get_free_td() */
@@ -521,7 +588,7 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
}
}
- printk("usb-ohci: unable to allocate an ED\n");
+ printk(KERN_ERR "usb-ohci: unable to allocate an ED\n");
return NULL;
} /* ohci_get_free_ed() */
@@ -594,12 +661,12 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
struct ohci_td *dummy_td;
if (ed_head_td(ed) != ed_tail_td(ed))
- printk("Reusing a non-empty ED %p!\n", ed);
+ printk(KERN_ERR "Reusing a non-empty ED %p!\n", ed);
if (!ed->tail_td) {
dummy_td = ohci_get_free_td(dev);
if (dummy_td == NULL) {
- printk("Error allocating dummy TD for ED %p\n", ed);
+ printk(KERN_ERR "Error allocating dummy TD for ED %p\n", ed);
return NULL; /* no dummy available! */
}
make_dumb_td(dummy_td); /* flag it as a dummy */
@@ -607,7 +674,7 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
} else {
dummy_td = bus_to_virt(ed_tail_td(ed));
if (!td_dummy(*dummy_td))
- printk("ED %p's dummy %p is screwy\n", ed, dummy_td);
+ printk(KERN_ERR "ED %p's dummy %p is screwy\n", ed, dummy_td);
}
/* set the head TD to the dummy and clear the Carry & Halted bits */
@@ -650,13 +717,13 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
/* Get an ED and TD */
interrupt_ed = ohci_get_free_ed(dev);
if (!interrupt_ed) {
- printk("Out of EDs on device %p in ohci_request_irq\n", dev);
+ printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
return -1;
}
td = ohci_get_free_td(dev);
if (!td) {
- printk("Out of TDs in ohci_request_irq\n");
+ printk(KERN_ERR "Out of TDs in ohci_request_irq\n");
ohci_free_ed(interrupt_ed);
return -1;
}
@@ -710,7 +777,7 @@ static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
*
* This function is called from the interrupt handler.
*/
-static int ohci_control_completed(int stats, void *buffer, void *dev_id)
+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) {
@@ -759,14 +826,14 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
printk(KERN_DEBUG "ohci_control_msg %p (ohci_dev: %p) pipe %x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
#endif
if (!control_ed) {
- printk("usb-ohci: couldn't get ED for dev %p\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get ED for dev %p\n", dev);
return -1;
}
/* get a TD to send this control message with */
setup_td = ohci_get_free_td(dev);
if (!setup_td) {
- printk("usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl setup]\n", dev);
ohci_free_ed(control_ed);
return -1;
}
@@ -799,7 +866,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
/* allocate the next TD */
data_td = ohci_get_free_td(dev);
if (!data_td) {
- printk("usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
ohci_free_td(setup_td);
ohci_free_ed(control_ed);
return -1;
@@ -833,7 +900,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
status_td = ohci_get_free_td(dev); /* TODO check for NULL */
if (!status_td) {
- printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
+ printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
ohci_free_td(setup_td);
ohci_free_td(data_td);
ohci_free_ed(control_ed);
@@ -918,15 +985,17 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
#ifdef OHCI_DEBUG
if (completion_status != 0) {
- printk(KERN_ERR "ohci_control_msg: %s on cmd %x %x %x %x %x\n",
- cc_names[completion_status & 0xf], cmd->requesttype,
- cmd->request, cmd->value, cmd->index, cmd->length);
+ char *what = (completion_status < 0)? "timed out":
+ cc_names[completion_status & 0xf];
+ printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
+ what, pipe, cmd->requesttype, cmd->request,
+ cmd->value, cmd->index, cmd->length);
} else if (!usb_pipeout(pipe)) {
unsigned char *q = data;
int i;
- printk(KERN_DEBUG "ctrl msg %x %x %x %x %x returned:",
+ printk(KERN_DEBUG "ctrl msg %x %x %x %x %x on pipe %x returned:",
cmd->requesttype, cmd->request, cmd->value, cmd->index,
- cmd->length);
+ cmd->length, pipe);
for (i = 0; i < len; ++i) {
if (i % 16 == 0)
printk("\n" KERN_DEBUG);
@@ -1001,8 +1070,12 @@ static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
*/
static int ohci_usb_deallocate(struct usb_device *usb_dev)
{
- kfree(usb_to_ohci(usb_dev));
- kfree(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); */
return 0;
}
@@ -1042,13 +1115,13 @@ static int reset_hc(struct ohci *ohci)
while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
if (!--timeout) {
- printk("usb-ohci: USB HC reset timed out!\n");
+ printk(KERN_ERR "usb-ohci: USB HC reset timed out!\n");
return -1;
}
udelay(1);
}
- printk(KERN_INFO "usb-ohci: HC %p reset.\n", ohci);
+ printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
return 0;
} /* reset_hc() */
@@ -1080,7 +1153,8 @@ static int start_hc(struct ohci *ohci)
* XXX Should fminterval also be set here?
* The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
*/
- fminterval |= (0x2edf << 16);
+ /* fminterval |= (0x2edf << 16); */
+ fminterval = (10240 << 16) | 11999;
writel(fminterval, &ohci->regs->fminterval);
/* Start periodic transfers at 90% of fminterval (fmremaining
* counts down; this will put them in the first 10% of the
@@ -1122,7 +1196,7 @@ static int start_hc(struct ohci *ohci)
/* Turn on power to the root hub ports (thanks Roman!) */
writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
- printk("usb-ohci: host controller operational\n");
+ printk(KERN_INFO "usb-ohci: host controller operational\n");
return ret;
} /* start_hc() */
@@ -1137,7 +1211,7 @@ static void ohci_reset_port(struct ohci *ohci, unsigned int port)
/* Don't allow overflows. */
if (port >= MAX_ROOT_PORTS) {
- printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
+ printk(KERN_ERR "usb-ohci: bad port #%d in ohci_reset_port\n", port);
port = MAX_ROOT_PORTS-1;
}
@@ -1152,7 +1226,7 @@ static void ohci_reset_port(struct ohci *ohci, unsigned int port)
status = readl(&ohci->regs->roothub.portstatus[port]);
if (status & PORT_PRS) {
/* reset failed, try harder? */
- printk("usb-ohci: port %d reset failed, retrying\n", port);
+ printk(KERN_ERR "usb-ohci: port %d reset failed, retrying\n", port);
writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);
wait_ms(50);
}
@@ -1340,7 +1414,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info));
if (td_dummy(*td))
- printk("yikes! reaping a dummy TD\n");
+ printk(KERN_ERR "yikes! reaping a dummy TD\n");
/* FIXME: munge td->info into a future standard status format */
@@ -1382,7 +1456,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
/* Check if TD should be re-queued */
if ((td->completed != NULL) &&
- (td->completed(cc, td->data, td->dev_id))) {
+ (td->completed(cc, td->data, -1 /* XXX */, td->dev_id))) {
/* Mark the TD as active again:
* Set the not accessed condition code
* Reset the Error count
@@ -1598,14 +1672,14 @@ static struct ohci *alloc_ohci(void* mem_base)
/* Get the number of ports on the root hub */
usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
if (usb->maxchild > MAX_ROOT_PORTS) {
- printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
+ printk(KERN_INFO "usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
usb->maxchild = MAX_ROOT_PORTS;
}
if (usb->maxchild < 1) {
- printk("usb-ohci: Less than one root hub port? Impossible!\n");
+ printk(KERN_ERR "usb-ohci: Less than one root hub port? Impossible!\n");
usb->maxchild = 1;
}
- printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
+ printk(KERN_DEBUG "usb-ohci: %d root hub ports found\n", usb->maxchild);
/*
* Initialize the ED polling "tree" (for simplicity's sake in
@@ -1650,14 +1724,13 @@ static struct ohci *alloc_ohci(void* mem_base)
writel(0, &ohci->regs->ed_bulkhead);
#ifdef OHCI_DEBUG
- printk(KERN_INFO "alloc_ohci(): controller\n");
+ printk(KERN_DEBUG "alloc_ohci(): controller\n");
show_ohci_status(ohci);
#endif
#if 0
printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
#endif
-printk("alloc_ohci done\n");
return ohci;
} /* alloc_ohci() */
@@ -1722,7 +1795,7 @@ static int ohci_control_thread(void * __ohci)
* This thread doesn't need any user-level access,
* so get rid of all of our resources..
*/
- printk(KERN_INFO "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
+ printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
exit_mm(current);
exit_files(current);
exit_fs(current);
@@ -1735,7 +1808,7 @@ static int ohci_control_thread(void * __ohci)
* Damn the torpedoes, full speed ahead
*/
if (start_hc(ohci) < 0) {
- printk("usb-ohci: failed to start the controller\n");
+ printk(KERN_ERR "usb-ohci: failed to start the controller\n");
release_ohci(ohci);
usb_deregister_bus(ohci->bus);
printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci);
@@ -1756,7 +1829,7 @@ static int ohci_control_thread(void * __ohci)
writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
#endif
- printk(KERN_INFO "ohci-control thread sleeping\n");
+ printk(KERN_DEBUG "ohci-control thread sleeping\n");
interruptible_sleep_on(&ohci_configure);
#ifdef CONFIG_APM
if (apm_resume) {
@@ -1796,7 +1869,7 @@ static int ohci_control_thread(void * __ohci)
reset_hc(ohci);
release_ohci(ohci);
usb_deregister_bus(ohci->bus);
- printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci);
+ printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci);
return 0;
} /* ohci_control_thread() */
@@ -1891,7 +1964,7 @@ static int found_ohci(int irq, void* mem_base)
ohci->irq = irq;
#ifdef OHCI_DEBUG
- printk(KERN_INFO "usb-ohci: forking ohci-control thread for 0x%p\n", ohci);
+ printk(KERN_DEBUG "usb-ohci: forking ohci-control thread for 0x%p\n", ohci);
#endif
/* fork off the handler */
@@ -1903,7 +1976,7 @@ static int found_ohci(int irq, void* mem_base)
retval = pid;
} else {
- printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
+ printk(KERN_ERR "usb-ohci: Couldn't allocate interrupt %d\n", irq);
}
release_ohci(ohci);
@@ -1931,7 +2004,7 @@ static int init_ohci(struct pci_dev *dev)
/* no interrupt won't work... */
if (dev->irq == 0) {
- printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
+ printk(KERN_ERR "usb-ohci: no irq assigned? check your BIOS settings.\n");
return -ENODEV;
}
@@ -1944,14 +2017,14 @@ static int init_ohci(struct pci_dev *dev)
mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
if (!mem_base) {
- printk("Error mapping OHCI memory\n");
+ printk(KERN_ERR "Error mapping OHCI memory\n");
return -EFAULT;
}
MOD_INC_USE_COUNT;
#ifdef OHCI_DEBUG
- printk("usb-ohci: Warning! Gobs of debugging output has been enabled.\n");
- printk(" Check your kern.debug logs for the bulk of it.\n");
+ printk(KERN_INFO "usb-ohci: Warning! Gobs of debugging output has been enabled.\n");
+ printk(KERN_INFO " Check your kern.debug logs for the bulk of it.\n");
#endif
if (found_ohci(dev->irq, (void *) mem_base) < 0) {
@@ -1978,11 +2051,11 @@ int ohci_init(void)
/*u8 type;*/
if (sizeof(struct ohci_device) > 4096) {
- printk("usb-ohci: struct ohci_device to large\n");
+ printk(KERN_ERR "usb-ohci: struct ohci_device to large\n");
return -ENODEV;
}
- printk("OHCI USB Driver loading\n");
+ printk(KERN_INFO "OHCI USB Driver loading\n");
retval = -ENODEV;
for (;;) {
@@ -2022,7 +2095,7 @@ void cleanup_module(void){
# ifdef CONFIG_APM
apm_unregister_callback(&handle_apm_event);
# endif
- printk("usb-ohci: module unloaded\n");
+ printk(KERN_ERR "usb-ohci: module unloaded\n");
}
int init_module(void){
diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c
index 7c577a58f..32549763e 100644
--- a/drivers/usb/uhci-debug.c
+++ b/drivers/usb/uhci-debug.c
@@ -131,7 +131,7 @@ void show_queue(struct uhci_qh *qh)
#if 0
printk(" link = %p, element = %p\n", qh->link, qh->element);
#endif
- if(!qh->element) {
+ if(!(qh->element & ~0xF)) {
printk(" td 0 = NULL\n");
return;
}
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 73aab5fa1..c03ce5adf 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
tmp = td->first;
printk("uhci_td_result() failed with status %x\n", status);
- show_status(dev->uhci);
+ //show_status(dev->uhci);
do {
show_td(tmp);
if ((tmp->link & 1) || (tmp->link & 2))
@@ -422,7 +422,7 @@ static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_de
/* notify removal */
- td->completed(USB_ST_REMOVED, NULL, td->dev_id);
+ td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
/* this is DANGEROUS - not sure whether this is right */
@@ -645,7 +645,7 @@ void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
*/
static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
-static int uhci_control_completed(int status, void *buffer, void *dev_id)
+static int uhci_control_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&control_wakeup);
return 0; /* Don't re-instate */
@@ -692,7 +692,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
// show_status(dev->uhci);
// show_queues(dev->uhci);
- schedule_timeout(HZ/10);
+ schedule_timeout(HZ*5);
// control should be empty here...
// show_status(dev->uhci);
@@ -736,8 +736,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
* information, that's just ridiculously high. Most
* control messages have just a few bytes of data.
*/
-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, void *cmd, void *data, int len)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *first, *td, *prevtd;
@@ -805,17 +804,18 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
/*
- * Build the final TD for control status
+ * Build the final TD for control status
*/
destination ^= (0xE1 ^ 0x69); /* OUT -> IN */
destination |= 1 << 19; /* End in Data1 */
- td->link = 1; /* Terminate */
- td->status = status | (1 << 24); /* IOC */
+ td->backptr = &prevtd->link;
+ td->status = (status /* & ~(3 << 27) */) | (1 << 24); /* no limit on final packet */
td->info = destination | (0x7ff << 21); /* 0 bytes of data */
td->buffer = 0;
td->first = first;
- td->backptr = &prevtd->link;
+ td->link = 1; /* Terminate */
+
/* Start it up.. */
ret = uhci_run_control(dev, first, td);
@@ -841,7 +841,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
}
if (uhci_debug && ret) {
- __u8 *p = (__u8 *) cmd;
+ __u8 *p = cmd;
printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
@@ -860,7 +860,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe,
*/
static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
-static int uhci_bulk_completed(int status, void *buffer, void *dev_id)
+static int uhci_bulk_completed(int status, void *buffer, int len, void *dev_id)
{
wake_up(&bulk_wakeup);
return 0; /* Don't re-instate */
@@ -908,10 +908,11 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
// show_status(dev->uhci);
// show_queues(dev->uhci);
- schedule_timeout(HZ/10);
+ schedule_timeout(HZ*5);
// show_status(dev->uhci);
// show_queues(dev->uhci);
+ //show_queue(first->qh);
remove_wait_queue(&bulk_wakeup, &wait);
/* Clean up in case it failed.. */
@@ -1243,6 +1244,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
{
struct list_head *head = &uhci->interrupt_list;
struct list_head *tmp;
+ int status;
spin_lock(&irqlist_lock);
tmp = head->next;
@@ -1252,19 +1254,22 @@ static void uhci_interrupt_notify(struct uhci *uhci)
next = tmp->next;
- if (!(td->status & (1 << 23))) { /* No longer active? */
+ if (!((status = td->status) & (1 << 23)) || /* No longer active? */
+ ((td->qh->element & ~15) &&
+ !((status = uhci_link_to_td(td->qh->element)->status) & (1 <<23)) &&
+ (status & 0x760000) /* is in error state (Stall, db, babble, timeout, bitstuff) */)) {
/* remove from IRQ list */
__list_del(tmp->prev, next);
INIT_LIST_HEAD(tmp);
- if (td->completed(uhci_map_status((td->status & 0xff)>> 16, 0),
- bus_to_virt(td->buffer), td->dev_id)) {
+ if (td->completed(uhci_map_status(status, 0), bus_to_virt(td->buffer), -1, td->dev_id)) {
list_add(&td->irq_list, &uhci->interrupt_list);
if (!(td->status & (1 << 25))) {
struct uhci_qh *interrupt_qh = td->qh;
usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
- td->info |= 1 << 19; /* toggle between data0 and data1 */
+ td->info &= ~(1 << 19); /* clear data toggle */
+ td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info)) << 19; /* toggle between data0 and data1 */
td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
/* Remove then readd? Is that necessary */
@@ -1283,7 +1288,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
/* If completed wants to not reactivate, then it's */
/* responsible for free'ing the TD's and QH's */
/* or another function (such as run_control) */
- }
+ }
tmp = next;
}
spin_unlock(&irqlist_lock);
@@ -1563,6 +1568,7 @@ static int uhci_control_thread(void * __uhci)
{
struct uhci *uhci = (struct uhci *)__uhci;
struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub);
+
lock_kernel();
request_region(uhci->io_addr, 32, "usb-uhci");
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index f9f73a051..082549b6e 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -53,7 +53,7 @@ int usb_init(void)
usb_acm_init();
# endif
# ifdef CONFIG_USB_PRINTER
- usb_print_init();
+ usb_printer_init();
# endif
# ifdef CONFIG_USB_CPIA
usb_cpia_init();
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
index 63ebeffb9..a6bf78e4a 100644
--- a/drivers/usb/usb.h
+++ b/drivers/usb/usb.h
@@ -242,10 +242,12 @@ struct usb_driver {
* until we come up with a common meaning.
* void *buffer - This is a pointer to the data used in this
* USB transfer.
+ * int length - This is the number of bytes transferred in or out
+ * of the buffer by this transfer. (-1 = unknown/unsupported)
* void *dev_id - This is a user defined pointer set when the IRQ
* is requested that is passed back.
*/
-typedef int (*usb_device_irq)(int, void *, void *);
+typedef int (*usb_device_irq)(int, void *, int, void *);
struct usb_operations {
struct usb_device *(*allocate)(struct usb_device *);
diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c
index 655045bea..1a3e16b25 100644
--- a/drivers/usb/usb_scsi.c
+++ b/drivers/usb/usb_scsi.c
@@ -74,7 +74,9 @@ struct us_data {
__u8 ep_int; /* interrupt . */
__u8 subclass; /* as in overview */
__u8 protocol; /* .............. */
+ __u8 attention_done; /* force attention on first command */
int (*pop)(Scsi_Cmnd *); /* protocol specific do cmd */
+ int (*pop_reset)(struct us_data *); /* ................. device reset */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */
Scsi_Host_Template *htmplt; /* own host template */
@@ -142,6 +144,9 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
/* we want to retry if the device reported NAK */
if (result == USB_ST_TIMEOUT) {
+ if (partial != this_xfer) {
+ return 0; /* I do not like this */
+ }
if (!maxtry--)
break;
this_xfer -= partial;
@@ -150,6 +155,11 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
/* short data - assume end */
result = USB_ST_DATAUNDERRUN;
break;
+ } else if (result == USB_ST_STALL && us->protocol == US_PR_CB) {
+ if (!maxtry--)
+ break;
+ this_xfer -= partial;
+ buf += partial;
} else
break;
} while ( this_xfer );
@@ -216,27 +226,57 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
}
-static int pop_CBI_irq(int state, void *buffer, void *dev_id)
+static int pop_CBI_irq(int state, void *buffer, int len, void *dev_id)
{
struct us_data *us = (struct us_data *)dev_id;
if (state != USB_ST_REMOVED) {
us->ip_data = *(__u16 *)buffer;
- us->ip_wanted = 0;
+ US_DEBUGP("Interrupt Status %x\n", us->ip_data);
}
- wake_up(&us->ip_waitq);
+ if (us->ip_wanted)
+ wake_up(&us->ip_waitq);
+ us->ip_wanted = 0;
/* we dont want another interrupt */
return 0;
}
+
+static int pop_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ devrequest dr;
+ int result;
+
+ dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
+ dr.request = US_CBI_ADSC;
+ dr.value = 0;
+ dr.index = us->pusb_dev->ifnum;
+ dr.length = 12;
+ memset(cmd, -1, sizeof(cmd));
+ cmd[0] = SEND_DIAGNOSTIC;
+ cmd[1] = 4;
+ us->pusb_dev->bus->op->control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ &dr, cmd, 12);
+
+ usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
+ usb_clear_halt(us->pusb_dev, us->ep_out);
+
+ /* long wait for reset */
+
+ schedule_timeout(HZ*5);
+ return 0;
+}
+
static int pop_CB_command(Scsi_Cmnd *srb)
{
struct us_data *us = (struct us_data *)srb->host_scribble;
devrequest dr;
unsigned char cmd[16];
int result;
- int retry = 1;
+ int retry = 5;
int done_start = 0;
while (retry--) {
@@ -279,7 +319,8 @@ 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);
- if (!done_start && us->subclass == US_SC_UFI && cmd[0] == TEST_UNIT_READY && result) {
+ 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 */
done_start++;
@@ -302,35 +343,47 @@ static int pop_CB_command(Scsi_Cmnd *srb)
return result;
}
-/* Protocol command handlers */
+/*
+ * Control/Bulk status handler
+ */
-static int pop_CBI(Scsi_Cmnd *srb)
+static int pop_CB_status(Scsi_Cmnd *srb)
{
struct us_data *us = (struct us_data *)srb->host_scribble;
int result;
+ __u8 status[2];
+ devrequest dr;
+ int retry = 5;
- /* run the command */
-
- if ((result = pop_CB_command(srb))) {
- US_DEBUGP("CBI command %x\n", result);
- if (result == USB_ST_STALL || result == USB_ST_TIMEOUT)
- return (DID_OK << 16) | 2;
- return DID_ABORT << 16;
- }
-
- /* transfer the data */
-
- if (us_transfer_length(srb)) {
- result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
- if (result && result != USB_ST_DATAUNDERRUN) {
- US_DEBUGP("CBI transfer %x\n", result);
+ switch (us->protocol) {
+ case US_PR_CB:
+ /* get from control */
+
+ while (retry--) {
+ dr.requesttype = 0x80 | USB_TYPE_STANDARD | USB_RT_DEVICE;
+ dr.request = USB_REQ_GET_STATUS;
+ dr.index = 0;
+ dr.value = 0;
+ dr.length = 2;
+ result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
+ usb_rcvctrlpipe(us->pusb_dev,0),
+ &dr, status, sizeof(status));
+ if (result != USB_ST_TIMEOUT)
+ break;
+ }
+ if (result) {
+ US_DEBUGP("Bad AP status request %d\n", result);
return DID_ABORT << 16;
}
- }
-
- /* get status */
+ US_DEBUGP("Got AP status %x %x\n", status[0], status[1]);
+ if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY &&
+ ( (status[0] & ~3) || status[1]))
+ return (DID_OK << 16) | 2;
+ else
+ return DID_OK << 16;
+ break;
- if (us->protocol == US_PR_CBI) {
+ case US_PR_CBI:
/* get from interrupt pipe */
/* add interrupt transfer, marked for removal */
@@ -367,12 +420,48 @@ static int pop_CBI(Scsi_Cmnd *srb)
return DID_ABORT << 16;
}
return (DID_OK << 16) + ((us->ip_data & 0x300) ? 2 : 0);
- } else {
- /* get from where? */
}
return DID_ERROR << 16;
}
+/* Protocol command handlers */
+
+static int pop_CBI(Scsi_Cmnd *srb)
+{
+ struct us_data *us = (struct us_data *)srb->host_scribble;
+ int result;
+
+ /* run the command */
+
+ if ((result = pop_CB_command(srb))) {
+ US_DEBUGP("CBI command %x\n", result);
+ if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) {
+ return (DID_OK << 16) | 2;
+ }
+ return DID_ABORT << 16;
+ }
+
+ /* transfer the data */
+
+ if (us_transfer_length(srb)) {
+ result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
+ if (result && result != USB_ST_DATAUNDERRUN) {
+ US_DEBUGP("CBI transfer %x\n", result);
+ return DID_ABORT << 16;
+ } else if (result == USB_ST_DATAUNDERRUN) {
+ return DID_OK << 16;
+ }
+ } else {
+ if (!result) {
+ return DID_OK << 16;
+ }
+ }
+
+ /* get status */
+
+ return pop_CB_status(srb);
+}
+
static int pop_Bulk_reset(struct us_data *us)
{
devrequest dr;
@@ -380,21 +469,20 @@ static int pop_Bulk_reset(struct us_data *us)
dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
dr.request = US_BULK_RESET;
- dr.value = US_BULK_RESET_SOFT;
+ dr.value = US_BULK_RESET_HARD;
dr.index = 0;
dr.length = 0;
- US_DEBUGP("Bulk soft reset\n");
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0);
- if (result) {
- US_DEBUGP("Bulk soft reset failed %d\n", result);
- dr.value = US_BULK_RESET_HARD;
- result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), &dr, NULL, 0);
- if (result)
- US_DEBUGP("Bulk hard reset failed %d\n", result);
- }
+ if (result)
+ US_DEBUGP("Bulk hard reset failed %d\n", result);
usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
usb_clear_halt(us->pusb_dev, us->ep_out);
+
+ /* long wait for reset */
+
+ schedule_timeout(HZ*5);
+
return result;
}
/*
@@ -453,8 +541,6 @@ static int pop_Bulk(Scsi_Cmnd *srb)
stall = 0;
do {
- //usb_settoggle(us->pusb_dev, us->ep_in, 0); /* AAARgh!! */
- US_DEBUGP("Toggle is %d\n", usb_gettoggle(us->pusb_dev, us->ep_in));
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);
@@ -564,6 +650,9 @@ static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
struct us_data *us = (struct us_data *)srb->host->hostdata[0];
US_DEBUGP("Command wakeup\n");
+ if (us->srb) {
+ /* busy */
+ }
srb->host_scribble = (unsigned char *)us;
us->srb = srb;
srb->scsi_done = done;
@@ -581,9 +670,12 @@ static int us_abort( Scsi_Cmnd *srb )
return 0;
}
-static int us_device_reset( Scsi_Cmnd *srb )
+static int us_bus_reset( Scsi_Cmnd *srb )
{
- return 0;
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ us->pop_reset(us);
+ return SUCCESS;
}
static int us_host_reset( Scsi_Cmnd *srb )
@@ -591,10 +683,6 @@ static int us_host_reset( Scsi_Cmnd *srb )
return 0;
}
-static int us_bus_reset( Scsi_Cmnd *srb )
-{
- return 0;
-}
#undef SPRINTF
#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
@@ -623,9 +711,9 @@ int usb_scsi_proc_info (char *buffer, char **start, off_t offset, int length, in
if (inout)
return length;
- if (!(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
+ if (!us->pusb_dev || !(vendor = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer)))
vendor = "?";
- if (!(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
+ if (!us->pusb_dev || !(product = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct)))
product = "?";
switch (us->protocol) {
@@ -677,7 +765,7 @@ static Scsi_Host_Template my_host_template = {
us_queuecommand,
NULL, /* eh_strategy */
us_abort,
- us_device_reset,
+ us_bus_reset,
us_bus_reset,
us_host_reset,
NULL, /* abort */
@@ -695,6 +783,25 @@ static Scsi_Host_Template my_host_template = {
TRUE /* emulated */
};
+static unsigned char sense_notready[] = {
+ 0x70, /* current error */
+ 0x00,
+ 0x02, /* not ready */
+ 0x00,
+ 0x00,
+ 10, /* additional length */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x04, /* not ready */
+ 0x03, /* manual intervention */
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+};
+
static int usbscsi_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
@@ -710,7 +817,7 @@ static int usbscsi_control_thread(void * __us)
exit_files(current);
//exit_fs(current);
- sprintf(current->comm, "usbscsi%d", us->host_no);
+ sprintf(current->comm, "usbscsi%d", us->host_number);
unlock_kernel();
@@ -727,18 +834,160 @@ static int usbscsi_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND :
- if (!us->pusb_dev || us->srb->target || us->srb->lun) {
+ if (us->srb->target || us->srb->lun) {
/* bad device */
US_DEBUGP( "Bad device number (%d/%d) or dev %x\n", us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
us->srb->result = DID_BAD_TARGET << 16;
+ } else if (!us->pusb_dev) {
+
+ /* our device has gone - pretend not ready */
+
+ if (us->srb->cmnd[0] == REQUEST_SENSE) {
+ memcpy(us->srb->request_buffer, sense_notready, sizeof(sense_notready));
+ us->srb->result = DID_OK << 16;
+ } else {
+ us->srb->result = (DID_OK << 16) | 2;
+ }
} else {
US_DEBUG(us_show_command(us->srb));
+
+ /* check for variable length - do properly if so */
+
if (us->filter && us->filter->command)
us->srb->result = us->filter->command(us->fdata, us->srb);
- else
+ else if (us->srb->cmnd[0] == START_STOP &&
+ us->pusb_dev->descriptor.idProduct == 0x0001 &&
+ us->pusb_dev->descriptor.idVendor == 0x04e6)
+ us->srb->result = DID_OK << 16;
+ else {
+ unsigned int savelen = us->srb->request_bufflen;
+ unsigned int saveallocation;
+
+ switch (us->srb->cmnd[0]) {
+ case REQUEST_SENSE:
+ if (us->srb->request_bufflen > 18)
+ us->srb->request_bufflen = 18;
+ else
+ break;
+ saveallocation = us->srb->cmnd[4];
+ us->srb->cmnd[4] = 18;
+ break;
+
+ case INQUIRY:
+ if (us->srb->request_bufflen > 36)
+ us->srb->request_bufflen = 36;
+ else
+ break;
+ saveallocation = us->srb->cmnd[4];
+ us->srb->cmnd[4] = 36;
+ break;
+
+ case MODE_SENSE:
+ if (us->srb->request_bufflen > 4)
+ us->srb->request_bufflen = 4;
+ else
+ break;
+ saveallocation = us->srb->cmnd[4];
+ us->srb->cmnd[4] = 4;
+ break;
+
+ case LOG_SENSE:
+ case MODE_SENSE_10:
+ if (us->srb->request_bufflen > 8)
+ us->srb->request_bufflen = 8;
+ else
+ break;
+ saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8];
+ us->srb->cmnd[7] = 0;
+ us->srb->cmnd[8] = 8;
+ break;
+
+ default:
+ break;
+ }
us->srb->result = us->pop(us->srb);
+
+ if (savelen != us->srb->request_bufflen &&
+ us->srb->result == (DID_OK << 16)) {
+ unsigned char *p = (unsigned char *)us->srb->request_buffer;
+ unsigned int length;
+
+ /* set correct length and retry */
+ switch (us->srb->cmnd[0]) {
+ case REQUEST_SENSE:
+ /* simply return 18 bytes */
+ p[7] = 10;
+ length = us->srb->request_bufflen;;
+ break;
+
+ case INQUIRY:
+ length = p[4] + 5 > savelen ? savelen : p[4] + 5;
+ us->srb->cmnd[4] = length;
+ break;
+
+ case MODE_SENSE:
+ length = p[0] + 4 > savelen ? savelen : p[0] + 4;
+ us->srb->cmnd[4] = 4;
+ break;
+
+ case LOG_SENSE:
+ length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4;
+ us->srb->cmnd[7] = length >> 8;
+ us->srb->cmnd[8] = length;
+ break;
+
+ case MODE_SENSE_10:
+ length = ((p[0] << 8) + p[1]) + 8 > savelen ? savelen : ((p[0] << 8) + p[1]) + 8;
+ us->srb->cmnd[7] = length >> 8;
+ us->srb->cmnd[8] = length;
+ break;
+ }
+
+ US_DEBUGP("Old/New length = %d/%d\n", savelen, length);
+
+ if (us->srb->request_bufflen != length) {
+ us->srb->request_bufflen = length;
+ us->srb->result = us->pop(us->srb);
+ }
+ /* reset back to original values */
+
+ us->srb->request_bufflen = savelen;
+ switch (us->srb->cmnd[0]) {
+ case REQUEST_SENSE:
+ case INQUIRY:
+ case MODE_SENSE:
+ us->srb->cmnd[4] = saveallocation;
+ break;
+
+ case LOG_SENSE:
+ case MODE_SENSE_10:
+ us->srb->cmnd[7] = saveallocation >> 8;
+ us->srb->cmnd[8] = saveallocation;
+ break;
+ }
+ }
+ /* force attention on first command */
+ if (!us->attention_done) {
+ if (us->srb->cmnd[0] == REQUEST_SENSE) {
+ if (us->srb->result == (DID_OK << 16)) {
+ unsigned char *p = (unsigned char *)us->srb->request_buffer;
+
+ us->attention_done = 1;
+ if ((p[2] & 0x0f) != UNIT_ATTENTION) {
+ p[2] = UNIT_ATTENTION;
+ p[12] = 0x29; /* power on, reset or bus-reset */
+ p[13] = 0;
+ }
+ }
+ } else if (us->srb->cmnd[0] != INQUIRY &&
+ us->srb->result == (DID_OK << 16)) {
+ us->srb->result |= 2; /* force check condition */
+ }
+ }
+ }
}
us->srb->scsi_done(us->srb);
+ us->srb = NULL;
break;
case US_ACT_ABORT :
@@ -820,7 +1069,7 @@ static int scsi_probe(struct usb_device *dev)
if (dev->descriptor.idVendor == 0x04e6 &&
dev->descriptor.idProduct == 0x0001) {
/* shuttle E-USB */
- protocol = US_PR_ZIP;
+ protocol = US_PR_CB;
subclass = US_SC_8070; /* an assumption */
} else if (dev->descriptor.bDeviceClass != 0 ||
dev->config->altsetting->interface->bInterfaceClass != 8 ||
@@ -835,11 +1084,15 @@ static int scsi_probe(struct usb_device *dev)
usb_string(dev, dev->descriptor.iSerialNumber) ) {
make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
usb_string(dev, dev->descriptor.iSerialNumber));
- for (ss = us_list; ss; ss = ss->next) {
- if (GUID_EQUAL(guid, ss->guid)) {
- US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
- break;
- }
+ } else {
+ make_guid(guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
+ "0");
+ }
+ for (ss = us_list; ss; ss = ss->next) {
+ if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) {
+ US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+ flags = ss->flags;
+ break;
}
}
}
@@ -865,6 +1118,7 @@ static int scsi_probe(struct usb_device *dev)
ss->subclass = interface->bInterfaceSubClass;
ss->protocol = interface->bInterfaceProtocol;
}
+ ss->attention_done = 0;
/* set the protocol op */
@@ -873,16 +1127,19 @@ static int scsi_probe(struct usb_device *dev)
case US_PR_CB:
US_DEBUGPX("Control/Bulk\n");
ss->pop = pop_CBI;
+ ss->pop_reset = pop_CB_reset;
break;
case US_PR_CBI:
US_DEBUGPX("Control/Bulk/Interrupt\n");
ss->pop = pop_CBI;
+ ss->pop_reset = pop_CB_reset;
break;
default:
US_DEBUGPX("Bulk\n");
ss->pop = pop_Bulk;
+ ss->pop_reset = pop_Bulk_reset;
break;
}
@@ -907,6 +1164,7 @@ static int scsi_probe(struct usb_device *dev)
/* exit if strange looking */
if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) ||
+ usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
!ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
US_DEBUGP("Problems with device\n");
if (ss->host) {
@@ -933,13 +1191,8 @@ static int scsi_probe(struct usb_device *dev)
/* make unique id if possible */
- if (dev->descriptor.iSerialNumber &&
- usb_string(dev, dev->descriptor.iSerialNumber) ) {
- make_guid(ss->guid, dev->descriptor.idVendor, dev->descriptor.idProduct,
- usb_string(dev, dev->descriptor.iSerialNumber));
- }
-
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+ memcpy(ss->guid, guid, sizeof(guid));
/* set class specific stuff */
@@ -986,9 +1239,30 @@ static int scsi_probe(struct usb_device *dev)
(struct us_data *)htmplt->proc_dir = ss;
- if (ss->protocol == US_PR_CBI)
+
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ devrequest dr;
+ __u8 qstat[2];
+
+ /* shuttle E-USB */
+ dr.requesttype = 0xC0;
+ dr.request = 1;
+ 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);
+ US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
+ init_waitqueue_head(&ss->ip_waitq);
+ ss->pusb_dev->bus->op->request_irq(ss->pusb_dev,
+ usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int),
+ pop_CBI_irq, 0, (void *)ss);
+ interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5);
+
+ } else if (ss->protocol == US_PR_CBI)
init_waitqueue_head(&ss->ip_waitq);
+
/* start up our thread */
{
diff --git a/drivers/usb/usb_scsi_debug.c b/drivers/usb/usb_scsi_debug.c
index 2ca847c08..634f4c0f6 100644
--- a/drivers/usb/usb_scsi_debug.c
+++ b/drivers/usb/usb_scsi_debug.c
@@ -95,7 +95,7 @@ void us_show_command(Scsi_Cmnd *srb)
case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
- default: what = "??"; break;
+ default: break;
}
printk(KERN_DEBUG USB_SCSI "Command %s (%d bytes)\n", what, srb->cmd_len);
printk(KERN_DEBUG USB_SCSI " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 991bed563..06dacf03f 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -178,11 +178,10 @@ if [ "$CONFIG_FB" = "y" ]; then
"$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_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_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
"$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
"$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
define_bool CONFIG_FBCON_CFB8 y
@@ -196,7 +195,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$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_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
"$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
"$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
define_bool CONFIG_FBCON_CFB8 m
@@ -220,9 +219,9 @@ if [ "$CONFIG_FB" = "y" ]; then
"$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_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
"$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
- "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
+ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "m" -o \
"$CONFIG_FB_CYBER2000" = "m" ]; then
define_bool CONFIG_FBCON_CFB16 m
fi
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index e1bc0857c..42485a999 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -254,7 +254,9 @@ acornfb_set_timing(struct fb_var_screeninfo *var)
bandwidth = var->pixclock * 8 / var->bits_per_pixel;
/* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
- if (bandwidth > 71750)
+ if (bandwidth > 143500)
+ vidc_ctl |= VIDC_CTRL_FIFO_3_7;
+ else if (bandwidth > 71750)
vidc_ctl |= VIDC_CTRL_FIFO_2_6;
else if (bandwidth > 35875)
vidc_ctl |= VIDC_CTRL_FIFO_1_5;
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index c24288124..d342304a3 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -121,7 +121,7 @@ static const struct res cyber2000_res[] = {
1600, 1200,
{
0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
- 0x00, 0x40,
+ 0x00, 0x40,
0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
},
0x1f,
@@ -154,54 +154,54 @@ static void cyber2000_init_hw(const struct res *res)
debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
cyber2000_outb(0xef, 0x3c2);
- cyber2000_crtcw(0x0b, 0x11);
- cyber2000_attrw(0x00, 0x11);
+ cyber2000_crtcw(0x11, 0x0b);
+ cyber2000_attrw(0x11, 0x00);
- cyber2000_seqw(0x01, 0x00);
+ cyber2000_seqw(0x00, 0x01);
cyber2000_seqw(0x01, 0x01);
- cyber2000_seqw(0x0f, 0x02);
- cyber2000_seqw(0x00, 0x03);
- cyber2000_seqw(0x0e, 0x04);
+ cyber2000_seqw(0x02, 0x0f);
cyber2000_seqw(0x03, 0x00);
+ cyber2000_seqw(0x04, 0x0e);
+ cyber2000_seqw(0x00, 0x03);
for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(res->crtc_regs[i], crtc_idx[i]);
+ cyber2000_crtcw(crtc_idx[i], res->crtc_regs[i]);
for (i = 0x0a; i < 0x10; i++)
- cyber2000_crtcw(0, i);
+ cyber2000_crtcw(i, 0);
- cyber2000_crtcw(0xff, 0x18);
+ cyber2000_crtcw(0x18, 0xff);
cyber2000_grphw(0x00, 0x00);
- cyber2000_grphw(0x00, 0x01);
- cyber2000_grphw(0x00, 0x02);
- cyber2000_grphw(0x00, 0x03);
- cyber2000_grphw(0x00, 0x04);
- cyber2000_grphw(0x60, 0x05);
- cyber2000_grphw(0x05, 0x06);
- cyber2000_grphw(0x0f, 0x07);
- cyber2000_grphw(0xff, 0x08);
+ cyber2000_grphw(0x01, 0x00);
+ cyber2000_grphw(0x02, 0x00);
+ cyber2000_grphw(0x03, 0x00);
+ cyber2000_grphw(0x04, 0x00);
+ cyber2000_grphw(0x05, 0x60);
+ cyber2000_grphw(0x06, 0x05);
+ cyber2000_grphw(0x07, 0x0f);
+ cyber2000_grphw(0x08, 0xff);
for (i = 0; i < 16; i++)
cyber2000_attrw(i, i);
- cyber2000_attrw(0x01, 0x10);
- cyber2000_attrw(0x00, 0x11);
- cyber2000_attrw(0x0f, 0x12);
- cyber2000_attrw(0x00, 0x13);
- cyber2000_attrw(0x00, 0x14);
+ cyber2000_attrw(0x10, 0x01);
+ cyber2000_attrw(0x11, 0x00);
+ cyber2000_attrw(0x12, 0x0f);
+ cyber2000_attrw(0x13, 0x00);
+ cyber2000_attrw(0x14, 0x00);
for (i = 0; i < sizeof(igs_regs); i += 2)
- cyber2000_grphw(igs_regs[i+1], igs_regs[i]);
+ cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
- cyber2000_grphw(res->crtc_ofl, 0x11);
+ cyber2000_grphw(0x11, res->crtc_ofl);
for (i = 0; i < 4; i += 1)
- cyber2000_grphw(res->clk_regs[i], 0xb0 + i);
+ cyber2000_grphw(0xb0 + i, res->clk_regs[i]);
- cyber2000_grphw(0x01, 0x90);
- cyber2000_grphw(0x80, 0xb9);
- cyber2000_grphw(0x00, 0xb9);
+ cyber2000_grphw(0x90, 0x01);
+ cyber2000_grphw(0xb9, 0x80);
+ cyber2000_grphw(0xb9, 0x00);
cyber2000_outb(0x56, 0x3ce);
i = cyber2000_inb(0x3cf);
@@ -311,6 +311,7 @@ cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
cyber2000_outw(height, 0xbf062);
switch (p->var.bits_per_pixel) {
+ case 15:
case 16:
bgx = ((u16 *)p->dispsw_data)[bgx];
case 8:
@@ -415,14 +416,27 @@ cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
current_par.palette[regno].blue = blue;
switch (fb_display[current_par.currcon].var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
case 8:
cyber2000_outb(regno, 0x3c8);
cyber2000_outb(red, 0x3c9);
cyber2000_outb(green, 0x3c9);
cyber2000_outb(blue, 0x3c9);
break;
+#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
+ if (regno < 32) {
+ cyber2000_outb(regno << 3, 0x3c8);
+ cyber2000_outb(red, 0x3c9);
+ cyber2000_outb(green, 0x3c9);
+ cyber2000_outb(blue, 0x3c9);
+ }
+ if (regno < 16)
+ current_par.c_table.cfb16[regno] = regno | regno << 5 | regno << 10;
+ break;
+
case 16:
if (regno < 64) {
/* write green */
@@ -464,36 +478,123 @@ cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
return 0;
}
-static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+static void cyber2000fb_calculate_timing(unsigned char *v, struct fb_var_screeninfo *var)
{
- int width = var->xres_virtual;
- int scr_pitch, fetchrow;
- int i;
- char b, col;
+ int Htotal, Hdispend, Hblankstart, Hblankend, Hsyncstart, Hsyncend;
+ int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+ Hdispend = var->xres;
+ Hsyncstart = var->xres + var->right_margin;
+ Hsyncend = var->xres + var->right_margin + var->hsync_len;
+ Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+
+ Hblankstart = var->xres;
+ Hblankend = Htotal - 4*8;
+
+ Vdispend = var->yres;
+ Vsyncstart = var->yres + var->lower_margin;
+ Vsyncend = var->yres + var->lower_margin + var->vsync_len;
+ Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+ Vblankstart = var->yres + 7;
+ Vblankend = Vtotal - 11;
+
+ Hdispend >>= 3;
+ Hsyncstart >>= 3;
+ Hsyncend >>= 3;
+ Htotal >>= 3;
+ Hblankstart >>= 3;
+ Hblankend >>= 3;
+
+ Htotal -= 5;
+ Hdispend -= 1;
+ Vtotal -= 2;
+ Vdispend -= 1;
+ Vblankstart -= 1;
+ Vblankend -= 1;
+
+ v[0] = Htotal;
+ v[1] = Hdispend;
+ v[2] = Hblankstart;
+ v[3] = BIT(Hblankend, 0, 0x1f, 0) |
+ BIT(1, 0, 0x01, 7);
+ v[4] = Hsyncstart;
+ v[5] = BIT(Hsyncend, 0, 0x1f, 0) |
+ BIT(Hblankend, 5, 0x01, 7);
+
+ v[6] = Vtotal;
+ v[7] = BIT(Vtotal, 8, 0x01, 0) |
+ BIT(Vdispend, 8, 0x01, 1) |
+ BIT(Vsyncstart, 8, 0x01, 2) |
+ BIT(Vblankstart,8, 0x01, 3) |
+ BIT(1, 0, 0x01, 4) |
+ BIT(Vtotal, 9, 0x01, 5) |
+ BIT(Vdispend, 9, 0x01, 6) |
+ BIT(Vsyncstart, 9, 0x01, 7);
+ v[8] = 0;
+ v[9] = BIT(0, 0, 0x1f, 0) |
+ BIT(Vblankstart,9, 0x01, 5) |
+ BIT(1, 0, 0x01, 6);
+ v[10] = Vsyncstart;
+ v[11] = BIT(Vsyncend, 0, 0x0f, 0) |
+ BIT(1, 0, 0x01, 7);
+ v[12] = Vdispend;
+ v[14] = 0;
+ v[15] = Vblankstart;
+ v[16] = Vblankend;
+ v[17] = 0xe3;
+
+ /* overflow - graphics reg 0x11 */
+ v[18] = BIT(Vtotal, 10, 0x01, 0) | /* guess */
+ BIT(Vdispend, 10, 0x01, 1) |
+ BIT(Vsyncstart, 10, 0x01, 2) | /* guess */
+ BIT(Vblankstart,10, 0x01, 3) | /* guess */
+ BIT(Hblankend, 6, 0x01, 4); /* guess */
+}
+
+static void cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+{
+ unsigned int width = var->xres_virtual;
+ unsigned int scr_pitch, fetchrow, i;
+ char b, graph_r77, crtc[32];
switch (var->bits_per_pixel) {
case 8: /* PSEUDOCOLOUR, 256 */
b = 0;
- col = 1;
- scr_pitch = var->xres_virtual / 8;
+ graph_r77 = 1;
+ scr_pitch = width;
+ break;
+
+ case 15:/* DIRECTCOLOUR, 32k */
+ b = 1;
+ graph_r77 = 6;
+ scr_pitch = width * 2;
break;
case 16:/* DIRECTCOLOUR, 64k */
b = 1;
- col = 2;
- scr_pitch = var->xres_virtual / 8 * 2;
+ graph_r77 = 2;
+ scr_pitch = width * 2;
break;
+
case 24:/* TRUECOLOUR, 16m */
b = 2;
- col = 4;
- scr_pitch = var->xres_virtual / 8 * 3;
+ graph_r77 = 4;
width *= 3;
+ scr_pitch = width;
break;
default:
- return 1;
+ return;
}
+ width -= 1;
+ scr_pitch >>= 3;
+ fetchrow = scr_pitch + 1;
+
+ cyber2000fb_calculate_timing(crtc, var);
+
for (i = 0; i < NUM_TOTAL_MODES; i++)
if (var->xres == cyber2000_res[i].xres &&
var->yres == cyber2000_res[i].yres)
@@ -502,30 +603,41 @@ static int cyber2000fb_set_timing(struct fb_var_screeninfo *var)
if (i < NUM_TOTAL_MODES)
cyber2000_init_hw(cyber2000_res + i);
- fetchrow = scr_pitch + 1;
+ crtc[13] = scr_pitch;
- debug_printf("Setting regs: pitch=%X, fetchrow=%X, col=%X, b=%X\n",
- scr_pitch, fetchrow, col, b);
+ /*
+ * reprogram the CRTC with the values we calculated
+ * above. This should be cleaned up once we're
+ * confident that we're generating the correct
+ * values. Disable this if you're having problems,
+ * and report the values obtained from the kernel
+ * messages.
+ */
+#if 1
+ cyber2000_crtcw(0x11, 0x0b);
+ for (i = 0; i < sizeof(crtc_idx); i++)
+ cyber2000_crtcw(crtc_idx[i], crtc[i]);
+#else
+ cyber2000_crtcw(0x13, crtc[13]);
+#endif
- cyber2000_outb(0x13, 0x3d4);
- cyber2000_outb(scr_pitch, 0x3d5);
- cyber2000_outb(0x14, 0x3ce);
- cyber2000_outb(fetchrow, 0x3cf);
- cyber2000_outb(0x15, 0x3ce);
+ cyber2000_grphw(0x14, fetchrow);
/* FIXME: is this the right way round? */
- cyber2000_outb(((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f), 0x3cf);
- cyber2000_outb(0x77, 0x3ce);
- cyber2000_outb(col, 0x3cf);
-
-
- cyber2000_outb(0x33, 0x3ce);
- cyber2000_outb(0x1c, 0x3cf);
-
- cyber2000_outw(width - 1, 0xbf018);
- cyber2000_outw(width - 1, 0xbf218);
- cyber2000_outb(b, 0xbf01c);
-
- return 0;
+ cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f));
+ cyber2000_grphw(0x77, graph_r77);
+ cyber2000_grphw(0x33, 0x1c);
+
+ cyber2000_outw(width, 0xbf018);
+ cyber2000_outw(width, 0xbf218);
+ cyber2000_outb(b, 0xbf01c);
+
+{ int j;
+ printk(KERN_DEBUG);
+ for (j = 0; j < 19; j++) printk("%2d ", j); printk("\n"KERN_DEBUG);
+ for (j = 0; j < 19; j++) printk("%02X ", crtc[j]); printk("\n"KERN_DEBUG);
+ for (j = 0; j < 18; j++) printk("%02X ", cyber2000_res[i].crtc_regs[j]);
+ printk("%02X\n", cyber2000_res[i].crtc_ofl);
+}
}
static inline void
@@ -536,13 +648,10 @@ cyber2000fb_update_start(struct fb_var_screeninfo *var)
base = var->yoffset * var->xres_virtual + var->xoffset;
- cyber2000_outb(0x0c, 0x3d4);
- cyber2000_outb(base, 0x3d5);
- cyber2000_outb(0x0d, 0x3d4);
- cyber2000_outb(base >> 8, 0x3d5);
+ cyber2000_crtcw(0x0c, base);
+ cyber2000_crtcw(0x0d, base >> 8);
/* FIXME: need the upper bits of the start offset */
-/* cyber2000_outb(0x??, 0x3d4);
- cyber2000_outb(base >> 16, 0x3d5);*/
+/* cyber2000_crtcw(0x??, base >> 16);*/
#endif
}
@@ -622,6 +731,7 @@ cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
break;
#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
case 16:
*visual = FB_VISUAL_DIRECTCOLOR;
break;
@@ -737,6 +847,10 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
}
display->var = *var;
+ display->var.activate &= ~FB_ACTIVATE_ALL;
+
+ if (var->activate & FB_ACTIVATE_ALL)
+ global_disp.var = display->var;
display->screen_base = (char *)current_par.screen_base;
display->visual = visual;
@@ -744,8 +858,6 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
display->type_aux = 0;
display->ypanstep = 0;
display->ywrapstep = 0;
- display->line_length =
- display->next_line = (var->xres_virtual * var->bits_per_pixel) / 8;
display->can_soft_blank = 1;
display->inverse = 0;
@@ -754,18 +866,22 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
case 8:
dispsw = &fbcon_cfb8;
display->dispsw_data = NULL;
+ display->next_line = var->xres_virtual;
break;
#endif
#ifdef FBCON_HAS_CFB16
+ case 15:
case 16:
dispsw = &fbcon_cfb16;
display->dispsw_data = current_par.c_table.cfb16;
+ display->next_line = var->xres_virtual * 2;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
dispsw = &fbcon_cfb24;
display->dispsw_data = current_par.c_table.cfb24;
+ display->next_line = var->xres_virtual * 3;
break;
#endif
default:
@@ -775,6 +891,8 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info
break;
}
+ display->line_length = display->next_line;
+
if (display->var.accel_flags & FB_ACCELF_TEXT &&
dispsw != &fbcon_dummy)
display->dispsw = &fbcon_cyber_accel;
@@ -818,6 +936,7 @@ static int cyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,
return -EINVAL;
if (y_bottom > fb_display[con].var.yres_virtual)
return -EINVAL;
+/*disabled until we can update the start address properly */
return -EINVAL;
cyber2000fb_update_start(var);
@@ -947,12 +1066,26 @@ cyber2000fb_init_fbinfo(void))
init_var.yres = DEFAULT_YRES;
init_var.bits_per_pixel = DEFAULT_BPP;
+ /*
+ * These parameters give
+ * 640x480, hsync 31.5kHz, vsync 60Hz
+ */
+ init_var.left_margin = 56;
+ init_var.right_margin = 16;
+ init_var.upper_margin = 34;
+ init_var.lower_margin = 9;
+ init_var.hsync_len = 88;
+ init_var.vsync_len = 2;
+ init_var.pixclock = 39722;
+
init_var.red.msb_right = 0;
init_var.green.msb_right = 0;
init_var.blue.msb_right = 0;
switch(init_var.bits_per_pixel) {
- case 8:
+ default:
+ init_var.bits_per_pixel = 8;
+ case 8: /* PSEUDOCOLOUR */
init_var.bits_per_pixel = 8;
init_var.red.offset = 0;
init_var.red.length = 8;
@@ -962,7 +1095,17 @@ cyber2000fb_init_fbinfo(void))
init_var.blue.length = 8;
break;
- case 16:
+ case 15: /* RGB555 */
+ init_var.bits_per_pixel = 15;
+ init_var.red.offset = 10;
+ init_var.red.length = 5;
+ init_var.green.offset = 5;
+ init_var.green.length = 5;
+ init_var.blue.offset = 0;
+ init_var.blue.length = 5;
+ break;
+
+ case 16: /* RGB565 */
init_var.bits_per_pixel = 16;
init_var.red.offset = 11;
init_var.red.length = 5;
@@ -972,7 +1115,7 @@ cyber2000fb_init_fbinfo(void))
init_var.blue.length = 5;
break;
- case 24:
+ case 24: /* RGB888 */
init_var.bits_per_pixel = 24;
init_var.red.offset = 16;
init_var.red.length = 8;
diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h
index f1e81dfa0..bbbd1edbb 100644
--- a/drivers/video/cyber2000fb.h
+++ b/drivers/video/cyber2000fb.h
@@ -13,19 +13,19 @@
#define cyber2000_inw(reg) (*(unsigned short *)&CyberRegs[reg])
#define cyber2000_inl(reg) (*(unsigned long *)&CyberRegs[reg])
-static inline void cyber2000_crtcw(int val, int reg)
+static inline void cyber2000_crtcw(int reg, int val)
{
cyber2000_outb(reg, 0x3d4);
cyber2000_outb(val, 0x3d5);
}
-static inline void cyber2000_grphw(int val, int reg)
+static inline void cyber2000_grphw(int reg, int val)
{
cyber2000_outb(reg, 0x3ce);
cyber2000_outb(val, 0x3cf);
}
-static inline void cyber2000_attrw(int val, int reg)
+static inline void cyber2000_attrw(int reg, int val)
{
cyber2000_inb(0x3da);
cyber2000_outb(reg, 0x3c0);
@@ -33,7 +33,7 @@ static inline void cyber2000_attrw(int val, int reg)
cyber2000_outb(val, 0x3c0);
}
-static inline void cyber2000_seqw(int val, int reg)
+static inline void cyber2000_seqw(int reg, int val)
{
cyber2000_outb(reg, 0x3c4);
cyber2000_outb(val, 0x3c5);
diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c
index 8823d2121..95a758dd1 100644
--- a/drivers/video/vgacon.c
+++ b/drivers/video/vgacon.c
@@ -135,9 +135,17 @@ void no_scroll(char *str, int *ints)
*/
static inline void write_vga(unsigned char reg, unsigned int val)
{
-#ifndef SLOW_VGA
unsigned int v1, v2;
+ unsigned long flags;
+
+ /*
+ * ddprintk might set the console position from interrupt
+ * handlers, thus the write has to be IRQ-atomic.
+ */
+ save_flags(flags);
+ cli();
+#ifndef SLOW_VGA
v1 = reg + (val & 0xff00);
v2 = reg + 1 + ((val << 8) & 0xff00);
outw(v1, vga_video_port_reg);
@@ -148,6 +156,7 @@ static inline void write_vga(unsigned char reg, unsigned int val)
outb_p(reg+1, vga_video_port_reg);
outb_p(val & 0xff, vga_video_port_val);
#endif
+ restore_flags(flags);
}
__initfunc(static const char *vgacon_startup(void))