summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:17:21 -0800
committerLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:17:21 -0800
commit7df131525f431f502873361fa2f8da2039d96c79 (patch)
treef7253fdcf2782e99998c5102f87b84fb966674ff /drivers
parent70a8be476e663526c3cb17a157c17ccf4fca5bd4 (diff)
v2.4.9.6 -> v2.4.9.7
- Alan Cox: big driver/mips sync - Andries Brouwer, Christoph Hellwig: more gendisk fixups - Tobias Ringstrom: tulip driver workaround for DC21143 erratum
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acorn/block/mfmhd.c16
-rw-r--r--drivers/block/DAC960.c1
-rw-r--r--drivers/block/Makefile2
-rw-r--r--drivers/block/acsi.c18
-rw-r--r--drivers/block/genhd.c63
-rw-r--r--drivers/block/paride/pd.c17
-rw-r--r--drivers/block/ps2esdi.c23
-rw-r--r--drivers/block/rd.c4
-rw-r--r--drivers/block/xd.c19
-rw-r--r--drivers/cdrom/aztcd.c3007
-rw-r--r--drivers/cdrom/mcd.c301
-rw-r--r--drivers/cdrom/mcd.h18
-rw-r--r--drivers/cdrom/optcd.c1
-rw-r--r--drivers/cdrom/sbpcd.c10
-rw-r--r--drivers/cdrom/sonycd535.c1
-rw-r--r--drivers/char/Config.in18
-rw-r--r--drivers/char/Makefile21
-rw-r--r--drivers/char/decserial.c98
-rw-r--r--drivers/char/dz.c1929
-rw-r--r--drivers/char/epca.c9
-rw-r--r--drivers/char/ite_gpio.c430
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/moxa.c55
-rw-r--r--drivers/char/qtronix.c20
-rw-r--r--drivers/char/rtc.c45
-rw-r--r--drivers/i2c/i2c-adap-ite.c319
-rw-r--r--drivers/i2c/i2c-algo-ite.c872
-rw-r--r--drivers/i2c/i2c-ite.h117
-rw-r--r--drivers/i2o/i2o_block.c18
-rw-r--r--drivers/ide/amd7409.c471
-rw-r--r--drivers/ide/hd.c19
-rw-r--r--drivers/ide/ide-dma.c20
-rw-r--r--drivers/ide/ide-pci.c4
-rw-r--r--drivers/ide/serverworks.c25
-rw-r--r--drivers/isdn/Config.in3
-rw-r--r--drivers/isdn/act2000/act2000_isa.c7
-rw-r--r--drivers/isdn/eicon/idi.c9
-rw-r--r--drivers/isdn/eicon/kprintf.c2
-rw-r--r--drivers/isdn/eicon/pc.h6
-rw-r--r--drivers/isdn/eicon/sys.h11
-rw-r--r--drivers/isdn/hisax/Makefile22
-rw-r--r--drivers/isdn/hisax/callc.c19
-rw-r--r--drivers/isdn/hisax/config.c399
-rw-r--r--drivers/isdn/hisax/elsa_ser.c23
-rw-r--r--drivers/isdn/hisax/fsm.c10
-rw-r--r--drivers/isdn/hisax/fsm.h48
-rw-r--r--drivers/isdn/hisax/hisax.h8
-rw-r--r--drivers/isdn/hisax/hisax_debug.h80
-rw-r--r--drivers/isdn/hisax/hisax_if.h54
-rw-r--r--drivers/isdn/hisax/isdnl1.c7
-rw-r--r--drivers/isdn/hisax/isdnl1.h3
-rw-r--r--drivers/isdn/hisax/st5481.h533
-rw-r--r--drivers/isdn/hisax/st5481_b.c367
-rw-r--r--drivers/isdn/hisax/st5481_d.c774
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.c620
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.h62
-rw-r--r--drivers/isdn/hisax/st5481_init.c215
-rw-r--r--drivers/isdn/hisax/st5481_usb.c639
-rw-r--r--drivers/isdn/isdn_common.c31
-rw-r--r--drivers/isdn/isdn_net.c9
-rw-r--r--drivers/isdn/isdn_net.h3
-rw-r--r--drivers/isdn/isdn_tty.c53
-rw-r--r--drivers/isdn/isdn_tty.h5
-rw-r--r--drivers/isdn/isdn_ttyfax.c6
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c8
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h4
-rw-r--r--drivers/md/lvm.c18
-rw-r--r--drivers/media/video/zr36067.c4
-rw-r--r--drivers/media/video/zr36120.c2
-rw-r--r--drivers/mtd/nftlcore.c23
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/appletalk/ipddp.c1
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/au1000_eth.c2
-rw-r--r--drivers/net/cs89x0.c2
-rw-r--r--drivers/net/declance.c10
-rw-r--r--drivers/net/dgrs.c1
-rw-r--r--drivers/net/dmfe.c2
-rw-r--r--drivers/net/gt96100eth.c5
-rw-r--r--drivers/net/gt96100eth.h3
-rw-r--r--drivers/net/irda/irda-usb.c1
-rw-r--r--drivers/net/irda/toshoboe.c6
-rw-r--r--drivers/net/jazzsonic.c314
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/ns83820.c1429
-rw-r--r--drivers/net/pcnet32.c20
-rw-r--r--drivers/net/ppp_generic.c2
-rw-r--r--drivers/net/sis900.c3
-rw-r--r--drivers/net/sk98lin/h/skdrv1st.h2
-rw-r--r--drivers/net/tulip/tulip_core.c4
-rw-r--r--drivers/net/wan/farsync.c1
-rw-r--r--drivers/net/wan/hostess_sv11.c5
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/sealevel.c4
-rw-r--r--drivers/net/wan/z85230.c6
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/scsi/53c700-mem.c1842
-rw-r--r--drivers/scsi/53c700.c1840
-rw-r--r--drivers/scsi/53c700.h534
-rw-r--r--drivers/scsi/53c700.scr404
-rw-r--r--drivers/scsi/Config.in12
-rw-r--r--drivers/scsi/Makefile26
-rw-r--r--drivers/scsi/NCR_D700.c326
-rw-r--r--drivers/scsi/NCR_D700.h45
-rw-r--r--drivers/scsi/README.53c70017
-rw-r--r--drivers/scsi/README.dpti83
-rw-r--r--drivers/scsi/dec_esp.c183
-rw-r--r--drivers/scsi/dpt_i2o.c3
-rw-r--r--drivers/scsi/lasi700.c188
-rw-r--r--drivers/scsi/lasi700.h57
-rw-r--r--drivers/scsi/megaraid.c18
-rw-r--r--drivers/scsi/scsi_error.c3
-rw-r--r--drivers/scsi/sd.c17
-rw-r--r--drivers/scsi/sgiwd93.c36
-rw-r--r--drivers/sound/i810_audio.c530
-rw-r--r--drivers/sound/opl3sa2.c2
-rw-r--r--drivers/sound/sound_core.c2
-rw-r--r--drivers/sound/via82cxxx_audio.c1
-rw-r--r--drivers/telephony/ixj.c5
-rw-r--r--drivers/video/radeon.h1
-rw-r--r--drivers/video/radeonfb.c12
121 files changed, 16465 insertions, 3640 deletions
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 5502165c4c2a..779a38ab5147 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -1311,15 +1311,13 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
}
static struct gendisk mfm_gendisk = {
- MAJOR_NR, /* Major number */
- "mfm", /* Major name */
- 6, /* Bits to shift to get real from partition */
- 1 << 6, /* Number of partitions per real */
- mfm, /* hd struct */
- mfm_sizes, /* block sizes */
- 0, /* number */
- (void *) mfm_info, /* internal */
- NULL /* next */
+ major: MAJOR_NR,
+ major_name: "mfm",
+ minor_shift: 6,
+ max_p: 1 << 6,
+ part: mfm,
+ sizes: mfm_sizes,
+ real_devices: (void *)mfm_info,
};
static struct block_device_operations mfm_fops =
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index afda5fa3a405..1f4b9bce5c72 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1883,7 +1883,6 @@ static int DAC960_MergeRequestsFunction(RequestQueue_T *RequestQueue,
static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
{
int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
- GenericDiskInfo_T *GenericDiskInfo;
RequestQueue_T *RequestQueue;
int MinorNumber;
/*
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index a98418e00263..04fb8fe66e37 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -10,7 +10,7 @@
O_TARGET := block.o
-export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o
+export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o
obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index dbd637a5e89f..6d44e211f1f8 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -1386,16 +1386,14 @@ static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd )
extern struct block_device_operations acsi_fops;
static struct gendisk acsi_gendisk = {
- MAJOR_NR, /* Major number */
- "ad", /* Major name */
- 4, /* Bits to shift to get real from partition */
- 1 << 4, /* Number of partitions per real */
- acsi_part, /* hd struct */
- acsi_sizes, /* block sizes */
- 0, /* number */
- (void *)acsi_info, /* internal */
- NULL, /* next */
- &acsi_fops, /* file operations */
+ major: MAJOR_NR,
+ major_name: "ad",
+ minor_shift: 4,
+ max_p: 1 << 4,
+ part: acsi_part,
+ sizes: acsi_sizes,
+ real_devices: (void *)acsi_info,
+ fops: &acsi_fops,
};
#define MAX_SCSI_DEVICE_CODE 10
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 4503fcdb2356..843dd8f8e21f 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -10,47 +10,101 @@
* (linux@arm.uk.linux.org)
*/
+/*
+ * TODO: rip out the remaining init crap from this file --hch
+ */
+
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/kernel.h>
#include <linux/blk.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
+
+
+static rwlock_t gendisk_lock;
+
+/*
+ * Global kernel list of partitioning information.
+ *
+ * XXX: you should _never_ access this directly.
+ * the only reason this is exported is source compatiblity.
+ */
+/*static*/ struct gendisk *gendisk_head;
+EXPORT_SYMBOL(gendisk_head);
-struct gendisk *gendisk_head;
+/**
+ * add_gendisk - add partitioning information to kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function registers the partitioning information in @gp
+ * with the kernel.
+ */
void
add_gendisk(struct gendisk *gp)
{
+ write_lock(&gendisk_lock);
gp->next = gendisk_head;
gendisk_head = gp;
+ write_unlock(&gendisk_lock);
}
+EXPORT_SYMBOL(add_gendisk);
+
+
+/**
+ * del_gendisk - remove partitioning information from kernel list
+ * @gp: per-device partitioning information
+ *
+ * This function unregisters the partitioning information in @gp
+ * with the kernel.
+ */
void
del_gendisk(struct gendisk *gp)
{
struct gendisk **gpp;
+ write_lock(&gendisk_lock);
for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
if (*gpp == gp)
break;
if (*gpp)
*gpp = (*gpp)->next;
+ write_unlock(&gendisk_lock);
}
+EXPORT_SYMBOL(del_gendisk);
+
+
+/**
+ * get_gendisk - get partitioning information for a given device
+ * @dev: device to get partitioning information for
+ *
+ * This function gets the structure containing partitioning
+ * information for the given device @dev.
+ */
struct gendisk *
get_gendisk(kdev_t dev)
{
struct gendisk *gp = NULL;
int maj = MAJOR(dev);
+ read_lock(&gendisk_lock);
for (gp = gendisk_head; gp; gp = gp->next)
if (gp->major == maj)
- return gp;
- return NULL;
+ break;
+ read_unlock(&gendisk_lock);
+
+ return gp;
}
+EXPORT_SYMBOL(get_gendisk);
+
+
#ifdef CONFIG_PROC_FS
int
get_partition_list(char *page, char **start, off_t offset, int count)
@@ -60,6 +114,7 @@ get_partition_list(char *page, char **start, off_t offset, int count)
int len, n;
len = sprintf(page, "major minor #blocks name\n\n");
+ read_lock(&gendisk_lock);
for (gp = gendisk_head; gp; gp = gp->next) {
for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
if (gp->part[n].nr_sects == 0)
@@ -77,6 +132,7 @@ get_partition_list(char *page, char **start, off_t offset, int count)
}
out:
+ read_unlock(&gendisk_lock);
*start = page + offset;
len -= offset;
if (len < 0)
@@ -102,6 +158,7 @@ extern int cpqarray_init(void);
int __init device_init(void)
{
+ rwlock_init(&gendisk_lock);
blk_dev_init();
sti();
#ifdef CONFIG_I2O
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 0d5763f242ed..43c6510f41cc 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -343,16 +343,13 @@ static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
extern struct block_device_operations pd_fops;
static struct gendisk pd_gendisk = {
- PD_MAJOR, /* Major number */
- PD_NAME, /* Major name */
- PD_BITS, /* Bits to shift to get real from partition */
- PD_PARTNS, /* Number of partitions per real */
- pd_hd, /* hd struct */
- pd_sizes, /* block sizes */
- 0, /* number */
- NULL, /* internal */
- NULL, /* next */
- &pd_fops, /* block device operations */
+ major: PD_MAJOR,
+ major_name: PD_NAME,
+ minor_shift: PD_BITS,
+ max_p: PD_PARTNS,
+ part: pd_hd,
+ sizes: pd_sizes,
+ fops: &pd_fops,
};
static struct block_device_operations pd_fops = {
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 9be57ac1558e..5845927e04ab 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -157,16 +157,14 @@ static struct block_device_operations ps2esdi_fops =
static struct gendisk ps2esdi_gendisk =
{
- MAJOR_NR, /* Major number */
- "ed", /* Major name */
- 6, /* Bits to shift to get real from partition */
- 1 << 6, /* Number of partitions per real disk */
- ps2esdi, /* hd struct */
- ps2esdi_sizes, /* block sizes */
- 0, /* number */
- (void *) ps2esdi_info, /* internal */
- NULL, /* next */
- &ps2esdi_fops, /* file operations */
+ major: MAJOR_NR,
+ major_name: "ed",
+ minor_shift: 6,
+ max_p: 1 << 6,
+ part: ps2esdi,
+ sizes: ps2esdi_sizes,
+ real_devices: (void *)ps2esdi_info,
+ fops: &ps2esdi_fops,
};
/* initialization routine called by ll_rw_blk.c */
@@ -222,14 +220,13 @@ int init_module(void) {
void
cleanup_module(void)
{
- if(ps2esdi_slot)
- {
+ if(ps2esdi_slot) {
mca_mark_as_unused(ps2esdi_slot);
mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);
}
release_region(io_base, 4);
free_dma(dma_arb_level);
- free_irq(PS2ESDI_IRQ, NULL)
+ free_irq(PS2ESDI_IRQ, NULL);
devfs_unregister_blkdev(MAJOR_NR, "ed");
del_gendisk(&ps2esdi_gendisk);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 843478e29de7..7ccda2a70567 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -259,7 +259,7 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
/* special: we want to release the ramdisk memory,
it's not like with the other blockdevices where
this ioctl only flushes away the buffer cache. */
- if ((atomic_read(rd_bdev[minor]->bd_openers) > 2))
+ if ((atomic_read(&rd_bdev[minor]->bd_openers) > 2))
return -EBUSY;
destroy_buffers(inode->i_rdev);
rd_blocksizes[minor] = 0;
@@ -372,7 +372,7 @@ static void __exit rd_cleanup (void)
struct block_device *bdev = rd_bdev[i];
rd_bdev[i] = NULL;
if (bdev) {
- blkdev_put(bdev);
+ blkdev_put(bdev, BDEV_FILE);
bdput(bdev);
}
destroy_buffers(MKDEV(MAJOR_NR, i));
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 905223a9ab33..12e4877cedd3 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -126,17 +126,16 @@ static int xd_maxsect[XD_MAXDRIVES << 6];
extern struct block_device_operations xd_fops;
static struct gendisk xd_gendisk = {
- MAJOR_NR, /* Major number */
- "xd", /* Major name */
- 6, /* Bits to shift to get real from partition */
- 1 << 6, /* Number of partitions per real */
- xd_struct, /* hd struct */
- xd_sizes, /* block sizes */
- 0, /* number */
- (void *) xd_info, /* internal */
- NULL, /* next */
- &xd_fops, /* file operations */
+ major: MAJOR_NR,
+ major_name: "xd",
+ minor_shift: 6,
+ max_p: 1 << 6,
+ part: xd_struct,
+ sizes: xd_sizes,
+ real_devices: (void *)xd_info,
+ fops: &xd_fops,
};
+
static struct block_device_operations xd_fops = {
open: xd_open,
release: xd_release,
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index 702f687709b8..6b35b013bf96 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -167,7 +167,7 @@
#include <linux/version.h>
-#define MAJOR_NR AZTECH_CDROM_MAJOR
+#define MAJOR_NR AZTECH_CDROM_MAJOR
#include <linux/blk.h>
#include "aztcd.h"
@@ -191,7 +191,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-static int aztcd_blocksizes[1] = {2048};
+static int aztcd_blocksizes[1] = { 2048 };
/*###########################################################################
@@ -200,7 +200,7 @@ static int aztcd_blocksizes[1] = {2048};
*/
#define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \
delay_timer.function = (void *) (func); \
- add_timer(&delay_timer);
+ add_timer(&delay_timer);
#define CLEAR_TIMER del_timer(&delay_timer);
@@ -213,17 +213,17 @@ static int aztcd_blocksizes[1] = {2048};
#define SWITCH_IDE_SLAVE outb_p(0xa0,azt_port+6); \
outb_p(0x10,azt_port+6); \
outb_p(0x00,azt_port+7); \
- outb_p(0x10,azt_port+6);
+ outb_p(0x10,azt_port+6);
#define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6);
#if 0
#define AZT_TEST
-#define AZT_TEST1 /* <int-..> */
-#define AZT_TEST2 /* do_aztcd_request */
-#define AZT_TEST3 /* AZT_S_state */
-#define AZT_TEST4 /* QUICK_LOOP-counter */
-#define AZT_TEST5 /* port(1) state */
+#define AZT_TEST1 /* <int-..> */
+#define AZT_TEST2 /* do_aztcd_request */
+#define AZT_TEST3 /* AZT_S_state */
+#define AZT_TEST4 /* QUICK_LOOP-counter */
+#define AZT_TEST5 /* port(1) state */
#define AZT_DEBUG
#define AZT_DEBUG_MULTISESSION
#endif
@@ -237,25 +237,23 @@ static int aztcd_blocksizes[1] = {2048};
#define READ_TIMEOUT 3000
-#define azt_port aztcd /*needed for the modutils*/
+#define azt_port aztcd /*needed for the modutils */
/*##########################################################################
Type Definitions
##########################################################################
*/
-enum azt_state_e
-{ AZT_S_IDLE, /* 0 */
- AZT_S_START, /* 1 */
- AZT_S_MODE, /* 2 */
- AZT_S_READ, /* 3 */
- AZT_S_DATA, /* 4 */
- AZT_S_STOP, /* 5 */
- AZT_S_STOPPING /* 6 */
+enum azt_state_e { AZT_S_IDLE, /* 0 */
+ AZT_S_START, /* 1 */
+ AZT_S_MODE, /* 2 */
+ AZT_S_READ, /* 3 */
+ AZT_S_DATA, /* 4 */
+ AZT_S_STOP, /* 5 */
+ AZT_S_STOPPING /* 6 */
};
-enum azt_read_modes
-{ AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware*/
- AZT_MODE_1, /*read mode for normal CD-ROMs*/
- AZT_MODE_2 /*read mode for XA CD-ROMs*/
+enum azt_read_modes { AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware */
+ AZT_MODE_1, /*read mode for normal CD-ROMs */
+ AZT_MODE_2 /*read mode for XA CD-ROMs */
};
/*##########################################################################
@@ -264,20 +262,20 @@ enum azt_read_modes
*/
static int aztPresent = 0;
-static volatile int azt_transfer_is_active=0;
+static volatile int azt_transfer_is_active = 0;
-static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/
+static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ]; /*buffer for block size conversion */
#if AZT_PRIVATE_IOCTLS
-static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls*/
+static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls */
#endif
static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
static volatile int azt_buf_in, azt_buf_out = -1;
-static volatile int azt_error=0;
-static int azt_open_count=0;
+static volatile int azt_error = 0;
+static int azt_open_count = 0;
static volatile enum azt_state_e azt_state = AZT_S_IDLE;
#ifdef AZT_TEST3
-static volatile enum azt_state_e azt_state_old = AZT_S_STOP;
+static volatile enum azt_state_e azt_state_old = AZT_S_STOP;
static volatile int azt_st_old = 0;
#endif
static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
@@ -291,9 +289,9 @@ MODULE_PARM(azt_port, "i");
static int azt_port_auto[16] = AZT_BASE_AUTO;
-static char azt_cont = 0;
-static char azt_init_end = 0;
-static char azt_auto_eject = AZT_AUTO_EJECT;
+static char azt_cont = 0;
+static char azt_init_end = 0;
+static char azt_auto_eject = AZT_AUTO_EJECT;
static int AztTimeout, AztTries;
static DECLARE_WAIT_QUEUE_HEAD(azt_waitq);
@@ -303,7 +301,7 @@ static struct azt_DiskInfo DiskInfo;
static struct azt_Toc Toc[MAX_TRACKS];
static struct azt_Play_msf azt_Play;
-static int aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+static int aztAudioStatus = CDROM_AUDIO_NO_STATUS;
static char aztDiskChanged = 1;
static char aztTocUpToDate = 0;
@@ -316,50 +314,51 @@ static int aztCmd = 0;
###########################################################################
*/
/* CDROM Drive Low Level I/O Functions */
-void op_ok(void);
-void pa_ok(void);
-void sten_low(void);
-void dten_low(void);
-void statusAzt(void);
+void op_ok(void);
+void pa_ok(void);
+void sten_low(void);
+void dten_low(void);
+void statusAzt(void);
static void aztStatTimer(void);
/* CDROM Drive Command Functions */
-static int aztSendCmd(int cmd);
-static int sendAztCmd(int cmd, struct azt_Play_msf *params);
-static int aztSeek(struct azt_Play_msf *params);
-static int aztSetDiskType(int type);
-static int aztStatus(void);
-static int getAztStatus(void);
-static int aztPlay(struct azt_Play_msf *arg);
+static int aztSendCmd(int cmd);
+static int sendAztCmd(int cmd, struct azt_Play_msf *params);
+static int aztSeek(struct azt_Play_msf *params);
+static int aztSetDiskType(int type);
+static int aztStatus(void);
+static int getAztStatus(void);
+static int aztPlay(struct azt_Play_msf *arg);
static void aztCloseDoor(void);
static void aztLockDoor(void);
static void aztUnlockDoor(void);
-static int aztGetValue(unsigned char *result);
-static int aztGetQChannelInfo(struct azt_Toc *qp);
-static int aztUpdateToc(void);
-static int aztGetDiskInfo(void);
-#if AZT_MULTISESSION
- static int aztGetMultiDiskInfo(void);
+static int aztGetValue(unsigned char *result);
+static int aztGetQChannelInfo(struct azt_Toc *qp);
+static int aztUpdateToc(void);
+static int aztGetDiskInfo(void);
+#if AZT_MULTISESSION
+static int aztGetMultiDiskInfo(void);
#endif
-static int aztGetToc(int multi);
+static int aztGetToc(int multi);
/* Kernel Interface Functions */
-static int check_aztcd_media_change(kdev_t full_dev);
-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
+static int check_aztcd_media_change(kdev_t full_dev);
+static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
+ unsigned long arg);
static void azt_transfer(void);
static void do_aztcd_request(request_queue_t *);
static void azt_invalidate_buffers(void);
-int aztcd_open(struct inode *ip, struct file *fp);
+int aztcd_open(struct inode *ip, struct file *fp);
-static int aztcd_release(struct inode * inode, struct file * file);
+static int aztcd_release(struct inode *inode, struct file *file);
-int aztcd_init(void);
+int aztcd_init(void);
static struct block_device_operations azt_fops = {
- open: aztcd_open,
- release: aztcd_release,
- ioctl: aztcd_ioctl,
- check_media_change: check_aztcd_media_change,
+ open:aztcd_open,
+ release:aztcd_release,
+ ioctl:aztcd_ioctl,
+ check_media_change:check_aztcd_media_change,
};
/* Aztcd State Machine: Controls Drive Operating State */
@@ -369,7 +368,7 @@ static void azt_poll(void);
static void azt_hsg2msf(long hsg, struct msf *msf);
static long azt_msf2hsg(struct msf *mp);
static void azt_bin2bcd(unsigned char *p);
-static int azt_bcd2bin(unsigned char bcd);
+static int azt_bcd2bin(unsigned char bcd);
/*##########################################################################
CDROM Drive Low Level I/O Functions
@@ -380,53 +379,64 @@ static int azt_bcd2bin(unsigned char bcd);
/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
# define OP_OK op_ok()
void op_ok(void)
-{ aztTimeOutCount=0;
- do { aztIndatum=inb(DATA_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { printk("aztcd: Error Wait OP_OK\n");
- break;
- }
- } while (aztIndatum!=AFL_OP_OK);
+{
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(DATA_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ printk("aztcd: Error Wait OP_OK\n");
+ break;
+ }
+ } while (aztIndatum != AFL_OP_OK);
}
/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
# define PA_OK pa_ok()
void pa_ok(void)
-{ aztTimeOutCount=0;
- do { aztIndatum=inb(DATA_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { printk("aztcd: Error Wait PA_OK\n");
- break;
- }
- } while (aztIndatum!=AFL_PA_OK);
+{
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(DATA_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ printk("aztcd: Error Wait PA_OK\n");
+ break;
+ }
+ } while (aztIndatum != AFL_PA_OK);
}
-
+
/* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/
# define STEN_LOW sten_low()
void sten_low(void)
-{ aztTimeOutCount=0;
- do { aztIndatum=inb(STATUS_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { if (azt_init_end) printk("aztcd: Error Wait STEN_LOW commands:%x\n",aztCmd);
- break;
- }
- } while (aztIndatum&AFL_STATUS);
+{
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(STATUS_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ if (azt_init_end)
+ printk
+ ("aztcd: Error Wait STEN_LOW commands:%x\n",
+ aztCmd);
+ break;
+ }
+ } while (aztIndatum & AFL_STATUS);
}
/* Wait for DTEN=Low = handshake signal 'Data available'*/
# define DTEN_LOW dten_low()
void dten_low(void)
-{ aztTimeOutCount=0;
- do { aztIndatum=inb(STATUS_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { printk("aztcd: Error Wait DTEN_OK\n");
- break;
- }
- } while (aztIndatum&AFL_DATA);
+{
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(STATUS_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ printk("aztcd: Error Wait DTEN_OK\n");
+ break;
+ }
+ } while (aztIndatum & AFL_DATA);
}
/*
@@ -435,25 +445,29 @@ void dten_low(void)
*/
#define STEN_LOW_WAIT statusAzt()
void statusAzt(void)
-{ AztTimeout = AZT_STATUS_DELAY;
- SET_TIMER(aztStatTimer, HZ/100);
- sleep_on(&azt_waitq);
- if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",aztCmd);
- return;
+{
+ AztTimeout = AZT_STATUS_DELAY;
+ SET_TIMER(aztStatTimer, HZ / 100);
+ sleep_on(&azt_waitq);
+ if (AztTimeout <= 0)
+ printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",
+ aztCmd);
+ return;
}
static void aztStatTimer(void)
-{ if (!(inb(STATUS_PORT) & AFL_STATUS))
- { wake_up(&azt_waitq);
- return;
- }
- AztTimeout--;
- if (AztTimeout <= 0)
- { wake_up(&azt_waitq);
- printk("aztcd: Error aztStatTimer: Timeout\n");
- return;
- }
- SET_TIMER(aztStatTimer, HZ/100);
+{
+ if (!(inb(STATUS_PORT) & AFL_STATUS)) {
+ wake_up(&azt_waitq);
+ return;
+ }
+ AztTimeout--;
+ if (AztTimeout <= 0) {
+ wake_up(&azt_waitq);
+ printk("aztcd: Error aztStatTimer: Timeout\n");
+ return;
+ }
+ SET_TIMER(aztStatTimer, HZ / 100);
}
/*##########################################################################
@@ -464,111 +478,125 @@ static void aztStatTimer(void)
* Send a single command, return -1 on error, else 0
*/
static int aztSendCmd(int cmd)
-{ unsigned char data;
- int retry;
+{
+ unsigned char data;
+ int retry;
#ifdef AZT_DEBUG
- printk("aztcd: Executing command %x\n",cmd);
+ printk("aztcd: Executing command %x\n", cmd);
#endif
- if ((azt_port==0x1f0)||(azt_port==0x170))
- SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration*/
-
- aztCmd=cmd;
- outb(POLLED,MODE_PORT);
- do { if (inb(STATUS_PORT)&AFL_STATUS) break;
- inb(DATA_PORT); /* if status left from last command, read and */
- } while (1); /* discard it */
- do { if (inb(STATUS_PORT)&AFL_DATA) break;
- inb(DATA_PORT); /* if data left from last command, read and */
- } while (1); /* discard it */
- for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
- { outb((unsigned char) cmd,CMD_PORT);
- STEN_LOW;
- data=inb(DATA_PORT);
- if (data==AFL_OP_OK)
- { return 0;} /*OP_OK?*/
- if (data==AFL_OP_ERR)
- { STEN_LOW;
- data=inb(DATA_PORT);
- printk("### Error 1 aztcd: aztSendCmd %x Error Code %x\n",cmd,data);
- }
- }
- if (retry>=AZT_RETRY_ATTEMPTS)
- { printk("### Error 2 aztcd: aztSendCmd %x \n",cmd);
- azt_error=0xA5;
- }
- RETURNM("aztSendCmd",-1);
+ if ((azt_port == 0x1f0) || (azt_port == 0x170))
+ SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
+
+ aztCmd = cmd;
+ outb(POLLED, MODE_PORT);
+ do {
+ if (inb(STATUS_PORT) & AFL_STATUS)
+ break;
+ inb(DATA_PORT); /* if status left from last command, read and */
+ } while (1); /* discard it */
+ do {
+ if (inb(STATUS_PORT) & AFL_DATA)
+ break;
+ inb(DATA_PORT); /* if data left from last command, read and */
+ } while (1); /* discard it */
+ for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
+ outb((unsigned char) cmd, CMD_PORT);
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ if (data == AFL_OP_OK) {
+ return 0;
+ } /*OP_OK? */
+ if (data == AFL_OP_ERR) {
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ printk
+ ("### Error 1 aztcd: aztSendCmd %x Error Code %x\n",
+ cmd, data);
+ }
+ }
+ if (retry >= AZT_RETRY_ATTEMPTS) {
+ printk("### Error 2 aztcd: aztSendCmd %x \n", cmd);
+ azt_error = 0xA5;
+ }
+ RETURNM("aztSendCmd", -1);
}
/*
* Send a play or read command to the drive, return -1 on error, else 0
*/
static int sendAztCmd(int cmd, struct azt_Play_msf *params)
-{ unsigned char data;
- int retry;
+{
+ unsigned char data;
+ int retry;
#ifdef AZT_DEBUG
- printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n", \
- params->start.min, params->start.sec, params->start.frame, \
- params->end.min, params->end.sec, params->end.frame);
-#endif
- for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
- { aztSendCmd(cmd);
- outb(params -> start.min,CMD_PORT);
- outb(params -> start.sec,CMD_PORT);
- outb(params -> start.frame,CMD_PORT);
- outb(params -> end.min,CMD_PORT);
- outb(params -> end.sec,CMD_PORT);
- outb(params -> end.frame,CMD_PORT);
- STEN_LOW;
- data=inb(DATA_PORT);
- if (data==AFL_PA_OK)
- { return 0;} /*PA_OK ?*/
- if (data==AFL_PA_ERR)
- { STEN_LOW;
- data=inb(DATA_PORT);
- printk("### Error 1 aztcd: sendAztCmd %x Error Code %x\n",cmd,data);
- }
- }
- if (retry>=AZT_RETRY_ATTEMPTS)
- { printk("### Error 2 aztcd: sendAztCmd %x\n ",cmd);
- azt_error=0xA5;
- }
- RETURNM("sendAztCmd",-1);
+ printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n",
+ params->start.min, params->start.sec, params->start.frame,
+ params->end.min, params->end.sec, params->end.frame);
+#endif
+ for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
+ aztSendCmd(cmd);
+ outb(params->start.min, CMD_PORT);
+ outb(params->start.sec, CMD_PORT);
+ outb(params->start.frame, CMD_PORT);
+ outb(params->end.min, CMD_PORT);
+ outb(params->end.sec, CMD_PORT);
+ outb(params->end.frame, CMD_PORT);
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ if (data == AFL_PA_OK) {
+ return 0;
+ } /*PA_OK ? */
+ if (data == AFL_PA_ERR) {
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ printk
+ ("### Error 1 aztcd: sendAztCmd %x Error Code %x\n",
+ cmd, data);
+ }
+ }
+ if (retry >= AZT_RETRY_ATTEMPTS) {
+ printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd);
+ azt_error = 0xA5;
+ }
+ RETURNM("sendAztCmd", -1);
}
/*
* Send a seek command to the drive, return -1 on error, else 0
*/
static int aztSeek(struct azt_Play_msf *params)
-{ unsigned char data;
- int retry;
+{
+ unsigned char data;
+ int retry;
#ifdef AZT_DEBUG
- printk("aztcd: aztSeek %02x:%02x:%02x\n", \
- params->start.min, params->start.sec, params->start.frame);
-#endif
- for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
- { aztSendCmd(ACMD_SEEK);
- outb(params -> start.min,CMD_PORT);
- outb(params -> start.sec,CMD_PORT);
- outb(params -> start.frame,CMD_PORT);
- STEN_LOW;
- data=inb(DATA_PORT);
- if (data==AFL_PA_OK)
- { return 0;} /*PA_OK ?*/
- if (data==AFL_PA_ERR)
- { STEN_LOW;
- data=inb(DATA_PORT);
- printk("### Error 1 aztcd: aztSeek\n");
- }
- }
- if (retry>=AZT_RETRY_ATTEMPTS)
- { printk("### Error 2 aztcd: aztSeek\n ");
- azt_error=0xA5;
- }
- RETURNM("aztSeek",-1);
+ printk("aztcd: aztSeek %02x:%02x:%02x\n",
+ params->start.min, params->start.sec, params->start.frame);
+#endif
+ for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
+ aztSendCmd(ACMD_SEEK);
+ outb(params->start.min, CMD_PORT);
+ outb(params->start.sec, CMD_PORT);
+ outb(params->start.frame, CMD_PORT);
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ if (data == AFL_PA_OK) {
+ return 0;
+ } /*PA_OK ? */
+ if (data == AFL_PA_ERR) {
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ printk("### Error 1 aztcd: aztSeek\n");
+ }
+ }
+ if (retry >= AZT_RETRY_ATTEMPTS) {
+ printk("### Error 2 aztcd: aztSeek\n ");
+ azt_error = 0xA5;
+ }
+ RETURNM("aztSeek", -1);
}
/* Send a Set Disk Type command
@@ -576,79 +604,86 @@ static int aztSeek(struct azt_Play_msf *params)
dent on which mode is set ???
*/
static int aztSetDiskType(int type)
-{ unsigned char data;
- int retry;
+{
+ unsigned char data;
+ int retry;
#ifdef AZT_DEBUG
- printk("aztcd: set disk type command: type= %i\n",type);
+ printk("aztcd: set disk type command: type= %i\n", type);
#endif
- for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
- { aztSendCmd(ACMD_SET_DISK_TYPE);
- outb(type,CMD_PORT);
- STEN_LOW;
- data=inb(DATA_PORT);
- if (data==AFL_PA_OK) /*PA_OK ?*/
- { azt_read_mode=type;
- return 0;
- }
- if (data==AFL_PA_ERR)
- { STEN_LOW;
- data=inb(DATA_PORT);
- printk("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",type,data);
- }
- }
- if (retry>=AZT_RETRY_ATTEMPTS)
- { printk("### Error 2 aztcd: aztSetDiskType %x\n ",type);
- azt_error=0xA5;
- }
- RETURNM("aztSetDiskType",-1);
+ for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) {
+ aztSendCmd(ACMD_SET_DISK_TYPE);
+ outb(type, CMD_PORT);
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ if (data == AFL_PA_OK) { /*PA_OK ? */
+ azt_read_mode = type;
+ return 0;
+ }
+ if (data == AFL_PA_ERR) {
+ STEN_LOW;
+ data = inb(DATA_PORT);
+ printk
+ ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",
+ type, data);
+ }
+ }
+ if (retry >= AZT_RETRY_ATTEMPTS) {
+ printk("### Error 2 aztcd: aztSetDiskType %x\n ", type);
+ azt_error = 0xA5;
+ }
+ RETURNM("aztSetDiskType", -1);
}
/* used in azt_poll to poll the status, expects another program to issue a
* ACMD_GET_STATUS directly before
*/
-static int aztStatus(void)
-{ int st;
+static int aztStatus(void)
+{
+ int st;
/* int i;
i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ???
if (!i)
-*/ STEN_LOW;
- if (aztTimeOutCount<AZT_TIMEOUT)
- { st = inb(DATA_PORT) & 0xFF;
+*/ STEN_LOW;
+ if (aztTimeOutCount < AZT_TIMEOUT) {
+ st = inb(DATA_PORT) & 0xFF;
return st;
- }
- else
- RETURNM("aztStatus",-1);
+ } else
+ RETURNM("aztStatus", -1);
}
/*
* Get the drive status
*/
static int getAztStatus(void)
-{ int st;
+{
+ int st;
- if (aztSendCmd(ACMD_GET_STATUS)) RETURNM("getAztStatus 1",-1);
+ if (aztSendCmd(ACMD_GET_STATUS))
+ RETURNM("getAztStatus 1", -1);
STEN_LOW;
st = inb(DATA_PORT) & 0xFF;
#ifdef AZT_DEBUG
- printk("aztcd: Status = %x\n",st);
+ printk("aztcd: Status = %x\n", st);
#endif
- if ((st == 0xFF)||(st&AST_CMD_CHECK))
- { printk("aztcd: AST_CMD_CHECK error or no status available\n");
- return -1;
- }
-
- if (((st&AST_MODE_BITS)!=AST_BUSY) && (aztAudioStatus == CDROM_AUDIO_PLAY))
- /* XXX might be an error? look at q-channel? */
- aztAudioStatus = CDROM_AUDIO_COMPLETED;
-
- if ((st & AST_DSK_CHG)||(st & AST_NOT_READY))
- { aztDiskChanged = 1;
- aztTocUpToDate = 0;
- aztAudioStatus = CDROM_AUDIO_NO_STATUS;
- }
+ if ((st == 0xFF) || (st & AST_CMD_CHECK)) {
+ printk
+ ("aztcd: AST_CMD_CHECK error or no status available\n");
+ return -1;
+ }
+
+ if (((st & AST_MODE_BITS) != AST_BUSY)
+ && (aztAudioStatus == CDROM_AUDIO_PLAY))
+ /* XXX might be an error? look at q-channel? */
+ aztAudioStatus = CDROM_AUDIO_COMPLETED;
+
+ if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+ }
return st;
}
@@ -657,7 +692,9 @@ static int getAztStatus(void)
* Send a 'Play' command and get the status. Use only from the top half.
*/
static int aztPlay(struct azt_Play_msf *arg)
-{ if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) RETURNM("aztPlay",-1);
+{
+ if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0)
+ RETURNM("aztPlay", -1);
return 0;
}
@@ -668,27 +705,27 @@ static int aztPlay(struct azt_Play_msf *arg)
*/
static void aztCloseDoor(void)
{
- aztSendCmd(ACMD_CLOSE);
- STEN_LOW;
- return;
+ aztSendCmd(ACMD_CLOSE);
+ STEN_LOW;
+ return;
}
static void aztLockDoor(void)
{
#if AZT_ALLOW_TRAY_LOCK
- aztSendCmd(ACMD_LOCK);
- STEN_LOW;
+ aztSendCmd(ACMD_LOCK);
+ STEN_LOW;
#endif
- return;
+ return;
}
static void aztUnlockDoor(void)
{
#if AZT_ALLOW_TRAY_LOCK
- aztSendCmd(ACMD_UNLOCK);
- STEN_LOW;
+ aztSendCmd(ACMD_UNLOCK);
+ STEN_LOW;
#endif
- return;
+ return;
}
/*
@@ -697,11 +734,12 @@ static void aztUnlockDoor(void)
* be issued with aztSendCmd() directly before
*/
static int aztGetValue(unsigned char *result)
-{ int s;
+{
+ int s;
STEN_LOW;
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { printk("aztcd: aztGetValue timeout\n");
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ printk("aztcd: aztGetValue timeout\n");
return -1;
}
s = inb(DATA_PORT) & 0xFF;
@@ -714,42 +752,55 @@ static int aztGetValue(unsigned char *result)
* table of contents.
*/
int aztGetQChannelInfo(struct azt_Toc *qp)
-{ unsigned char notUsed;
+{
+ unsigned char notUsed;
int st;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztGetQChannelInfo Time:%li\n",jiffies);
+ printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies);
#endif
- if ((st=getAztStatus())==-1) RETURNM("aztGetQChannelInfo 1",-1);
- if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1);
- /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/
- if (aztGetValue(&notUsed)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/
- if ((st&AST_MODE_BITS)==AST_INITIAL)
- { qp->ctrl_addr=0; /* when audio stop ACMD_GET_Q_CHANNEL returns */
- qp->track=0; /* only one byte with Aztech drives */
- qp->pointIndex=0;
- qp->trackTime.min=0;
- qp->trackTime.sec=0;
- qp->trackTime.frame=0;
- qp->diskTime.min=0;
- qp->diskTime.sec=0;
- qp->diskTime.frame=0;
- return 0;
- }
- else
- { if (aztGetValue(&qp -> ctrl_addr) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> track) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> pointIndex) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> trackTime.min) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> trackTime.sec) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&notUsed) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> diskTime.min) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> diskTime.sec) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- if (aztGetValue(&qp -> diskTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
- }
+ if ((st = getAztStatus()) == -1)
+ RETURNM("aztGetQChannelInfo 1", -1);
+ if (aztSendCmd(ACMD_GET_Q_CHANNEL))
+ RETURNM("aztGetQChannelInfo 2", -1);
+ /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */
+ if (aztGetValue(&notUsed))
+ RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */
+ if ((st & AST_MODE_BITS) == AST_INITIAL) {
+ qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */
+ qp->track = 0; /* only one byte with Aztech drives */
+ qp->pointIndex = 0;
+ qp->trackTime.min = 0;
+ qp->trackTime.sec = 0;
+ qp->trackTime.frame = 0;
+ qp->diskTime.min = 0;
+ qp->diskTime.sec = 0;
+ qp->diskTime.frame = 0;
+ return 0;
+ } else {
+ if (aztGetValue(&qp->ctrl_addr) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->track) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->pointIndex) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->trackTime.min) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->trackTime.sec) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->trackTime.frame) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&notUsed) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->diskTime.min) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->diskTime.sec) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ if (aztGetValue(&qp->diskTime.frame) < 0)
+ RETURNM("aztGetQChannelInfo 4", -1);
+ }
#ifdef AZT_DEBUG
- printk("aztcd: exiting aztGetQChannelInfo Time:%li\n",jiffies);
+ printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies);
#endif
return 0;
}
@@ -758,11 +809,12 @@ int aztGetQChannelInfo(struct azt_Toc *qp)
* Read the table of contents (TOC) and TOC header if necessary
*/
static int aztUpdateToc()
-{ int st;
+{
+ int st;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztUpdateToc Time:%li\n",jiffies);
-#endif
+ printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies);
+#endif
if (aztTocUpToDate)
return 0;
@@ -772,57 +824,63 @@ static int aztUpdateToc()
if (aztGetToc(0) < 0)
return -EIO;
- /*audio disk detection
- with my Aztech drive there is no audio status bit, so I use the copy
- protection bit of the first track. If this track is copy protected
- (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */
- if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
- DiskInfo.audio=1;
- else
- DiskInfo.audio=0;
-
- /* XA detection */
- if (! DiskInfo.audio)
- { azt_Play.start.min = 0; /*XA detection only seems to work*/
- azt_Play.start.sec = 2; /*when we play a track*/
- azt_Play.start.frame = 0;
- azt_Play.end.min = 0;
- azt_Play.end.sec = 0;
- azt_Play.end.frame = 1;
- if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
- DTEN_LOW;
- for (st=0;st<CD_FRAMESIZE;st++) inb(DATA_PORT);
- }
- DiskInfo.xa = getAztStatus() & AST_MODE;
- if (DiskInfo.xa)
- { printk("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
- }
-
- /*multisession detection
- support for multisession CDs is done automatically with Aztech drives,
- we don't have to take care about TOC redirection; if we want the isofs
- to take care about redirection, we have to set AZT_MULTISESSION to 1*/
- DiskInfo.multi=0;
+ /*audio disk detection
+ with my Aztech drive there is no audio status bit, so I use the copy
+ protection bit of the first track. If this track is copy protected
+ (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */
+ if (!(Toc[DiskInfo.first].ctrl_addr & 0x40))
+ DiskInfo.audio = 1;
+ else
+ DiskInfo.audio = 0;
+
+ /* XA detection */
+ if (!DiskInfo.audio) {
+ azt_Play.start.min = 0; /*XA detection only seems to work */
+ azt_Play.start.sec = 2; /*when we play a track */
+ azt_Play.start.frame = 0;
+ azt_Play.end.min = 0;
+ azt_Play.end.sec = 0;
+ azt_Play.end.frame = 1;
+ if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
+ return -1;
+ DTEN_LOW;
+ for (st = 0; st < CD_FRAMESIZE; st++)
+ inb(DATA_PORT);
+ }
+ DiskInfo.xa = getAztStatus() & AST_MODE;
+ if (DiskInfo.xa) {
+ printk
+ ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n");
+ }
+
+ /*multisession detection
+ support for multisession CDs is done automatically with Aztech drives,
+ we don't have to take care about TOC redirection; if we want the isofs
+ to take care about redirection, we have to set AZT_MULTISESSION to 1 */
+ DiskInfo.multi = 0;
#if AZT_MULTISESSION
- if (DiskInfo.xa)
- { aztGetMultiDiskInfo(); /*here Disk.Info.multi is set*/
- }
+ if (DiskInfo.xa) {
+ aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */
+ }
#endif
- if (DiskInfo.multi)
- { DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
- DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
- DiskInfo.lastSession.frame= Toc[DiskInfo.next].diskTime.frame;
- printk("aztcd: Multisession support experimental\n");
- }
- else
- { DiskInfo.lastSession.min = Toc[DiskInfo.first].diskTime.min;
- DiskInfo.lastSession.sec = Toc[DiskInfo.first].diskTime.sec;
- DiskInfo.lastSession.frame= Toc[DiskInfo.first].diskTime.frame;
- }
+ if (DiskInfo.multi) {
+ DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min;
+ DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec;
+ DiskInfo.lastSession.frame =
+ Toc[DiskInfo.next].diskTime.frame;
+ printk("aztcd: Multisession support experimental\n");
+ } else {
+ DiskInfo.lastSession.min =
+ Toc[DiskInfo.first].diskTime.min;
+ DiskInfo.lastSession.sec =
+ Toc[DiskInfo.first].diskTime.sec;
+ DiskInfo.lastSession.frame =
+ Toc[DiskInfo.first].diskTime.frame;
+ }
aztTocUpToDate = 1;
#ifdef AZT_DEBUG
- printk("aztcd: exiting aztUpdateToc Time:%li\n",jiffies);
+ printk("aztcd: exiting aztUpdateToc Time:%li\n", jiffies);
#endif
return 0;
}
@@ -832,56 +890,58 @@ static int aztUpdateToc()
* track
*/
static int aztGetDiskInfo()
-{ int limit;
- unsigned char test;
- struct azt_Toc qInfo;
+{
+ int limit;
+ unsigned char test;
+ struct azt_Toc qInfo;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztGetDiskInfo Time:%li\n",jiffies);
+ printk("aztcd: starting aztGetDiskInfo Time:%li\n", jiffies);
#endif
- if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1);
- STEN_LOW_WAIT;
- test=0;
- for (limit=300;limit>0;limit--)
- { if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1);
- if (qInfo.pointIndex==0xA0) /*Number of FirstTrack*/
- { DiskInfo.first = qInfo.diskTime.min;
- DiskInfo.first = azt_bcd2bin(DiskInfo.first);
- test=test|0x01;
- }
- if (qInfo.pointIndex==0xA1) /*Number of LastTrack*/
- { DiskInfo.last = qInfo.diskTime.min;
- DiskInfo.last = azt_bcd2bin(DiskInfo.last);
- test=test|0x02;
- }
- if (qInfo.pointIndex==0xA2) /*DiskLength*/
- { DiskInfo.diskLength.min=qInfo.diskTime.min;
- DiskInfo.diskLength.sec=qInfo.diskTime.sec;
- DiskInfo.diskLength.frame=qInfo.diskTime.frame;
- test=test|0x04;
- }
- if ((qInfo.pointIndex==DiskInfo.first)&&(test&0x01)) /*StartTime of First Track*/
- { DiskInfo.firstTrack.min=qInfo.diskTime.min;
- DiskInfo.firstTrack.sec=qInfo.diskTime.sec;
- DiskInfo.firstTrack.frame=qInfo.diskTime.frame;
- test=test|0x08;
+ if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
+ RETURNM("aztGetDiskInfo 1", -1);
+ STEN_LOW_WAIT;
+ test = 0;
+ for (limit = 300; limit > 0; limit--) {
+ if (aztGetQChannelInfo(&qInfo) < 0)
+ RETURNM("aztGetDiskInfo 2", -1);
+ if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */
+ DiskInfo.first = qInfo.diskTime.min;
+ DiskInfo.first = azt_bcd2bin(DiskInfo.first);
+ test = test | 0x01;
+ }
+ if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
+ DiskInfo.last = qInfo.diskTime.min;
+ DiskInfo.last = azt_bcd2bin(DiskInfo.last);
+ test = test | 0x02;
+ }
+ if (qInfo.pointIndex == 0xA2) { /*DiskLength */
+ DiskInfo.diskLength.min = qInfo.diskTime.min;
+ DiskInfo.diskLength.sec = qInfo.diskTime.sec;
+ DiskInfo.diskLength.frame = qInfo.diskTime.frame;
+ test = test | 0x04;
+ }
+ if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) { /*StartTime of First Track */
+ DiskInfo.firstTrack.min = qInfo.diskTime.min;
+ DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
+ DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
+ test = test | 0x08;
+ }
+ if (test == 0x0F)
+ break;
}
- if (test==0x0F) break;
- }
#ifdef AZT_DEBUG
- printk ("aztcd: exiting aztGetDiskInfo Time:%li\n",jiffies);
- printk("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n",
- DiskInfo.first,
- DiskInfo.last,
- DiskInfo.diskLength.min,
- DiskInfo.diskLength.sec,
- DiskInfo.diskLength.frame,
- DiskInfo.firstTrack.min,
- DiskInfo.firstTrack.sec,
- DiskInfo.firstTrack.frame);
+ printk("aztcd: exiting aztGetDiskInfo Time:%li\n", jiffies);
+ printk
+ ("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n",
+ DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
+ DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
+ DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
+ DiskInfo.firstTrack.frame);
#endif
- if (test!=0x0F) return -1;
- return 0;
+ if (test != 0x0F)
+ return -1;
+ return 0;
}
#if AZT_MULTISESSION
@@ -889,93 +949,105 @@ static int aztGetDiskInfo()
* Get Multisession Disk Info
*/
static int aztGetMultiDiskInfo(void)
-{ int limit, k=5;
- unsigned char test;
- struct azt_Toc qInfo;
+{
+ int limit, k = 5;
+ unsigned char test;
+ struct azt_Toc qInfo;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztGetMultiDiskInfo\n");
+ printk("aztcd: starting aztGetMultiDiskInfo\n");
#endif
- do { azt_Play.start.min = Toc[DiskInfo.last+1].diskTime.min;
- azt_Play.start.sec = Toc[DiskInfo.last+1].diskTime.sec;
- azt_Play.start.frame = Toc[DiskInfo.last+1].diskTime.frame;
- test=0;
-
- for (limit=30;limit>0;limit--) /*Seek for LeadIn of next session*/
- { if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 1",-1);
- if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 2",-1);
- if ((qInfo.track==0)&&(qInfo.pointIndex)) break; /*LeadIn found*/
- if ((azt_Play.start.sec+=10) > 59)
- { azt_Play.start.sec=0;
- azt_Play.start.min++;
- }
- }
- if (!limit) break; /*Check, if a leadin track was found, if not we're
- at the end of the disk*/
+ do {
+ azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min;
+ azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec;
+ azt_Play.start.frame =
+ Toc[DiskInfo.last + 1].diskTime.frame;
+ test = 0;
+
+ for (limit = 30; limit > 0; limit--) { /*Seek for LeadIn of next session */
+ if (aztSeek(&azt_Play))
+ RETURNM("aztGetMultiDiskInfo 1", -1);
+ if (aztGetQChannelInfo(&qInfo) < 0)
+ RETURNM("aztGetMultiDiskInfo 2", -1);
+ if ((qInfo.track == 0) && (qInfo.pointIndex))
+ break; /*LeadIn found */
+ if ((azt_Play.start.sec += 10) > 59) {
+ azt_Play.start.sec = 0;
+ azt_Play.start.min++;
+ }
+ }
+ if (!limit)
+ break; /*Check, if a leadin track was found, if not we're
+ at the end of the disk */
#ifdef AZT_DEBUG_MULTISESSION
- printk("leadin found track %d pointIndex %x limit %d\n",qInfo.track,qInfo.pointIndex,limit);
+ printk("leadin found track %d pointIndex %x limit %d\n",
+ qInfo.track, qInfo.pointIndex, limit);
#endif
- for (limit=300;limit>0;limit--)
- { if (++azt_Play.start.frame>74)
- { azt_Play.start.frame=0;
- if (azt_Play.start.sec > 59)
- { azt_Play.start.sec=0;
- azt_Play.start.min++;
- }
- }
- if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 3",-1);
- if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 4",-1);
- if (qInfo.pointIndex==0xA0) /*Number of NextTrack*/
- { DiskInfo.next = qInfo.diskTime.min;
- DiskInfo.next = azt_bcd2bin(DiskInfo.next);
- test=test|0x01;
- }
- if (qInfo.pointIndex==0xA1) /*Number of LastTrack*/
- { DiskInfo.last = qInfo.diskTime.min;
- DiskInfo.last = azt_bcd2bin(DiskInfo.last);
- test=test|0x02;
- }
- if (qInfo.pointIndex==0xA2) /*DiskLength*/
- { DiskInfo.diskLength.min =qInfo.diskTime.min;
- DiskInfo.diskLength.sec =qInfo.diskTime.sec;
- DiskInfo.diskLength.frame=qInfo.diskTime.frame;
- test=test|0x04;
- }
- if ((qInfo.pointIndex==DiskInfo.next)&&(test&0x01)) /*StartTime of Next Track*/
- { DiskInfo.nextSession.min=qInfo.diskTime.min;
- DiskInfo.nextSession.sec=qInfo.diskTime.sec;
- DiskInfo.nextSession.frame=qInfo.diskTime.frame;
- test=test|0x08;
+ for (limit = 300; limit > 0; limit--) {
+ if (++azt_Play.start.frame > 74) {
+ azt_Play.start.frame = 0;
+ if (azt_Play.start.sec > 59) {
+ azt_Play.start.sec = 0;
+ azt_Play.start.min++;
+ }
+ }
+ if (aztSeek(&azt_Play))
+ RETURNM("aztGetMultiDiskInfo 3", -1);
+ if (aztGetQChannelInfo(&qInfo) < 0)
+ RETURNM("aztGetMultiDiskInfo 4", -1);
+ if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */
+ DiskInfo.next = qInfo.diskTime.min;
+ DiskInfo.next = azt_bcd2bin(DiskInfo.next);
+ test = test | 0x01;
+ }
+ if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */
+ DiskInfo.last = qInfo.diskTime.min;
+ DiskInfo.last = azt_bcd2bin(DiskInfo.last);
+ test = test | 0x02;
+ }
+ if (qInfo.pointIndex == 0xA2) { /*DiskLength */
+ DiskInfo.diskLength.min =
+ qInfo.diskTime.min;
+ DiskInfo.diskLength.sec =
+ qInfo.diskTime.sec;
+ DiskInfo.diskLength.frame =
+ qInfo.diskTime.frame;
+ test = test | 0x04;
+ }
+ if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) { /*StartTime of Next Track */
+ DiskInfo.nextSession.min =
+ qInfo.diskTime.min;
+ DiskInfo.nextSession.sec =
+ qInfo.diskTime.sec;
+ DiskInfo.nextSession.frame =
+ qInfo.diskTime.frame;
+ test = test | 0x08;
+ }
+ if (test == 0x0F)
+ break;
}
- if (test==0x0F) break;
- }
#ifdef AZT_DEBUG_MULTISESSION
- printk ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n",
- DiskInfo.first,
- DiskInfo.next,
- DiskInfo.last,
- DiskInfo.diskLength.min,
- DiskInfo.diskLength.sec,
- DiskInfo.diskLength.frame,
- DiskInfo.firstTrack.min,
- DiskInfo.firstTrack.sec,
- DiskInfo.firstTrack.frame,
- DiskInfo.nextSession.min,
- DiskInfo.nextSession.sec,
- DiskInfo.nextSession.frame);
+ printk
+ ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n",
+ DiskInfo.first, DiskInfo.next, DiskInfo.last,
+ DiskInfo.diskLength.min, DiskInfo.diskLength.sec,
+ DiskInfo.diskLength.frame, DiskInfo.firstTrack.min,
+ DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame,
+ DiskInfo.nextSession.min, DiskInfo.nextSession.sec,
+ DiskInfo.nextSession.frame);
#endif
- if (test!=0x0F)
- break;
- else
- DiskInfo.multi=1; /*found TOC of more than one session*/
- aztGetToc(1);
- } while(--k);
+ if (test != 0x0F)
+ break;
+ else
+ DiskInfo.multi = 1; /*found TOC of more than one session */
+ aztGetToc(1);
+ } while (--k);
#ifdef AZT_DEBUG
- printk ("aztcd: exiting aztGetMultiDiskInfo Time:%li\n",jiffies);
+ printk("aztcd: exiting aztGetMultiDiskInfo Time:%li\n", jiffies);
#endif
- return 0;
+ return 0;
}
#endif
@@ -983,75 +1055,81 @@ static int aztGetMultiDiskInfo(void)
* Read the table of contents (TOC)
*/
static int aztGetToc(int multi)
-{ int i, px;
- int limit;
- struct azt_Toc qInfo;
+{
+ int i, px;
+ int limit;
+ struct azt_Toc qInfo;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztGetToc Time:%li\n",jiffies);
+ printk("aztcd: starting aztGetToc Time:%li\n", jiffies);
#endif
- if (!multi)
- { for (i = 0; i < MAX_TRACKS; i++)
- Toc[i].pointIndex = 0;
- i = DiskInfo.last + 3;
- }
- else
- { for (i = DiskInfo.next; i < MAX_TRACKS; i++)
- Toc[i].pointIndex = 0;
- i = DiskInfo.last + 4 - DiskInfo.next;
- }
+ if (!multi) {
+ for (i = 0; i < MAX_TRACKS; i++)
+ Toc[i].pointIndex = 0;
+ i = DiskInfo.last + 3;
+ } else {
+ for (i = DiskInfo.next; i < MAX_TRACKS; i++)
+ Toc[i].pointIndex = 0;
+ i = DiskInfo.last + 4 - DiskInfo.next;
+ }
/*Is there a good reason to stop motor before TOC read?
if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
STEN_LOW_WAIT;
*/
- if (!multi)
- { azt_mode = 0x05;
- if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1);
- STEN_LOW_WAIT;
- }
- for (limit = 300; limit > 0; limit--)
- { if (multi)
- { if (++azt_Play.start.sec > 59)
- { azt_Play.start.sec=0;
- azt_Play.start.min++;
- }
- if (aztSeek(&azt_Play)) RETURNM("aztGetToc 3",-1);
- }
- if (aztGetQChannelInfo(&qInfo) < 0)
- break;
-
- px = azt_bcd2bin(qInfo.pointIndex);
-
- if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
- if (Toc[px].pointIndex == 0)
- { Toc[px] = qInfo;
- i--;
- }
-
- if (i <= 0)
- break;
- }
-
- Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
- Toc[DiskInfo.last].trackTime = DiskInfo.diskLength;
-
-#ifdef AZT_DEBUG_MULTISESSION
- printk("aztcd: exiting aztGetToc\n");
- for (i = 1; i <= DiskInfo.last+1; i++)
- printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
- i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
- Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
- Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
- for (i = 100; i < 103; i++)
- printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
- i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
- Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
- Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
+ if (!multi) {
+ azt_mode = 0x05;
+ if (aztSendCmd(ACMD_SEEK_TO_LEADIN))
+ RETURNM("aztGetToc 2", -1);
+ STEN_LOW_WAIT;
+ }
+ for (limit = 300; limit > 0; limit--) {
+ if (multi) {
+ if (++azt_Play.start.sec > 59) {
+ azt_Play.start.sec = 0;
+ azt_Play.start.min++;
+ }
+ if (aztSeek(&azt_Play))
+ RETURNM("aztGetToc 3", -1);
+ }
+ if (aztGetQChannelInfo(&qInfo) < 0)
+ break;
+
+ px = azt_bcd2bin(qInfo.pointIndex);
+
+ if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
+ if (Toc[px].pointIndex == 0) {
+ Toc[px] = qInfo;
+ i--;
+ }
+
+ if (i <= 0)
+ break;
+ }
+
+ Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
+ Toc[DiskInfo.last].trackTime = DiskInfo.diskLength;
+
+#ifdef AZT_DEBUG_MULTISESSION
+ printk("aztcd: exiting aztGetToc\n");
+ for (i = 1; i <= DiskInfo.last + 1; i++)
+ printk
+ ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
+ i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
+ Toc[i].trackTime.min, Toc[i].trackTime.sec,
+ Toc[i].trackTime.frame, Toc[i].diskTime.min,
+ Toc[i].diskTime.sec, Toc[i].diskTime.frame);
+ for (i = 100; i < 103; i++)
+ printk
+ ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n",
+ i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
+ Toc[i].trackTime.min, Toc[i].trackTime.sec,
+ Toc[i].trackTime.frame, Toc[i].diskTime.min,
+ Toc[i].diskTime.sec, Toc[i].diskTime.frame);
#endif
- return limit > 0 ? 0 : -1;
+ return limit > 0 ? 0 : -1;
}
@@ -1063,160 +1141,185 @@ static int aztGetToc(int multi)
#ifndef MODULE
static int __init aztcd_setup(char *str)
{
- int ints[4];
-
- (void)get_options(str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0)
- azt_port = ints[1];
- if (ints[1] > 1)
- azt_cont = ints[2];
- return 1;
+ int ints[4];
+
+ (void) get_options(str, ARRAY_SIZE(ints), ints);
+
+ if (ints[0] > 0)
+ azt_port = ints[1];
+ if (ints[1] > 1)
+ azt_cont = ints[2];
+ return 1;
}
__setup("aztcd=", aztcd_setup);
-#endif /* !MODULE */
+#endif /* !MODULE */
/*
* Checking if the media has been changed
*/
static int check_aztcd_media_change(kdev_t full_dev)
-{ if (aztDiskChanged) /* disk changed */
- { aztDiskChanged=0;
- return 1;
- }
- else
- return 0; /* no change */
+{
+ if (aztDiskChanged) { /* disk changed */
+ aztDiskChanged = 0;
+ return 1;
+ } else
+ return 0; /* no change */
}
/*
* Kernel IO-controls
*/
-static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
-{ int i;
+static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ int i;
struct azt_Toc qInfo;
struct cdrom_ti ti;
struct cdrom_tochdr tocHdr;
struct cdrom_msf msf;
struct cdrom_tocentry entry;
- struct azt_Toc *tocPtr;
+ struct azt_Toc *tocPtr;
struct cdrom_subchnl subchnl;
- struct cdrom_volctrl volctrl;
+ struct cdrom_volctrl volctrl;
#ifdef AZT_DEBUG
- printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n",cmd, jiffies);
- printk("aztcd Status %x\n", getAztStatus());
+ printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n",
+ cmd, jiffies);
+ printk("aztcd Status %x\n", getAztStatus());
#endif
- if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
- if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
- if ((!aztTocUpToDate)||(aztDiskChanged))
- { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
+ if (!ip)
+ RETURNM("aztcd_ioctl 1", -EINVAL);
+ if (getAztStatus() < 0)
+ RETURNM("aztcd_ioctl 2", -EIO);
+ if ((!aztTocUpToDate) || (aztDiskChanged)) {
+ if ((i = aztUpdateToc()) < 0)
+ RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
}
- switch (cmd)
- {
- case CDROMSTART: /* Spin up the drive. Don't know, what to do,
- at least close the tray */
-#if AZT_PRIVATE_IOCTLS
- if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1);
- STEN_LOW_WAIT;
+ switch (cmd) {
+ case CDROMSTART: /* Spin up the drive. Don't know, what to do,
+ at least close the tray */
+#if AZT_PRIVATE_IOCTLS
+ if (aztSendCmd(ACMD_CLOSE))
+ RETURNM("aztcd_ioctl 4", -1);
+ STEN_LOW_WAIT;
#endif
break;
- case CDROMSTOP: /* Spin down the drive */
- if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1);
+ case CDROMSTOP: /* Spin down the drive */
+ if (aztSendCmd(ACMD_STOP))
+ RETURNM("aztcd_ioctl 5", -1);
STEN_LOW_WAIT;
/* should we do anything if it fails? */
aztAudioStatus = CDROM_AUDIO_NO_STATUS;
break;
- case CDROMPAUSE: /* Pause the drive */
- if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL;
+ case CDROMPAUSE: /* Pause the drive */
+ if (aztAudioStatus != CDROM_AUDIO_PLAY)
+ return -EINVAL;
- if (aztGetQChannelInfo(&qInfo) < 0)
- { /* didn't get q channel info */
- aztAudioStatus = CDROM_AUDIO_NO_STATUS;
- RETURNM("aztcd_ioctl 7",0);
+ if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */
+ aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+ RETURNM("aztcd_ioctl 7", 0);
}
- azt_Play.start = qInfo.diskTime; /* remember restart point */
+ azt_Play.start = qInfo.diskTime; /* remember restart point */
- if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1);
+ if (aztSendCmd(ACMD_PAUSE))
+ RETURNM("aztcd_ioctl 8", -1);
STEN_LOW_WAIT;
aztAudioStatus = CDROM_AUDIO_PAUSED;
break;
- case CDROMRESUME: /* Play it again, Sam */
- if (aztAudioStatus != CDROM_AUDIO_PAUSED) return -EINVAL;
+ case CDROMRESUME: /* Play it again, Sam */
+ if (aztAudioStatus != CDROM_AUDIO_PAUSED)
+ return -EINVAL;
/* restart the drive at the saved position. */
i = aztPlay(&azt_Play);
- if (i < 0)
- { aztAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
+ if (i < 0) {
+ aztAudioStatus = CDROM_AUDIO_ERROR;
+ return -EIO;
}
aztAudioStatus = CDROM_AUDIO_PLAY;
break;
- case CDROMMULTISESSION: /*multisession support -- experimental*/
- { struct cdrom_multisession ms;
+ case CDROMMULTISESSION: /*multisession support -- experimental */
+ {
+ struct cdrom_multisession ms;
#ifdef AZT_DEBUG
- printk("aztcd ioctl MULTISESSION\n");
+ printk("aztcd ioctl MULTISESSION\n");
#endif
- if(copy_from_user(&ms, (void*) arg, sizeof(struct cdrom_multisession)))
- return -EFAULT;
- if (ms.addr_format == CDROM_MSF)
- { ms.addr.msf.minute = azt_bcd2bin(DiskInfo.lastSession.min);
- ms.addr.msf.second = azt_bcd2bin(DiskInfo.lastSession.sec);
- ms.addr.msf.frame = azt_bcd2bin(DiskInfo.lastSession.frame);
- }
- else if (ms.addr_format == CDROM_LBA)
- ms.addr.lba = azt_msf2hsg(&DiskInfo.lastSession);
- else
- return -EINVAL;
- ms.xa_flag = DiskInfo.xa;
- if(copy_to_user((void*) arg, &ms, sizeof(struct cdrom_multisession)))
- return -EFAULT;
-#ifdef AZT_DEBUG
- if (ms.addr_format == CDROM_MSF)
- printk("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
- ms.xa_flag, ms.addr.msf.minute, ms.addr.msf.second,
- ms.addr.msf.frame, DiskInfo.lastSession.min,
- DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
- else
- printk("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
- ms.xa_flag, ms.addr.lba, DiskInfo.lastSession.min,
- DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
+ if (copy_from_user
+ (&ms, (void *) arg,
+ sizeof(struct cdrom_multisession)))
+ return -EFAULT;
+ if (ms.addr_format == CDROM_MSF) {
+ ms.addr.msf.minute =
+ azt_bcd2bin(DiskInfo.lastSession.min);
+ ms.addr.msf.second =
+ azt_bcd2bin(DiskInfo.lastSession.sec);
+ ms.addr.msf.frame =
+ azt_bcd2bin(DiskInfo.lastSession.
+ frame);
+ } else if (ms.addr_format == CDROM_LBA)
+ ms.addr.lba =
+ azt_msf2hsg(&DiskInfo.lastSession);
+ else
+ return -EINVAL;
+ ms.xa_flag = DiskInfo.xa;
+ if (copy_to_user
+ ((void *) arg, &ms,
+ sizeof(struct cdrom_multisession)))
+ return -EFAULT;
+#ifdef AZT_DEBUG
+ if (ms.addr_format == CDROM_MSF)
+ printk
+ ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
+ ms.xa_flag, ms.addr.msf.minute,
+ ms.addr.msf.second, ms.addr.msf.frame,
+ DiskInfo.lastSession.min,
+ DiskInfo.lastSession.sec,
+ DiskInfo.lastSession.frame);
+ else
+ printk
+ ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
+ ms.xa_flag, ms.addr.lba,
+ DiskInfo.lastSession.min,
+ DiskInfo.lastSession.sec,
+ DiskInfo.lastSession.frame);
#endif
- return 0;
+ return 0;
}
- case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
- if(copy_from_user(&ti, (void *) arg, sizeof ti))
+ case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
+ if (copy_from_user(&ti, (void *) arg, sizeof ti))
return -EFAULT;
if (ti.cdti_trk0 < DiskInfo.first
- || ti.cdti_trk0 > DiskInfo.last
- || ti.cdti_trk1 < ti.cdti_trk0)
- { return -EINVAL;
+ || ti.cdti_trk0 > DiskInfo.last
+ || ti.cdti_trk1 < ti.cdti_trk0) {
+ return -EINVAL;
}
if (ti.cdti_trk1 > DiskInfo.last)
- ti.cdti_trk1 = DiskInfo.last;
+ ti.cdti_trk1 = DiskInfo.last;
azt_Play.start = Toc[ti.cdti_trk0].diskTime;
azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
#ifdef AZT_DEBUG
-printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
- azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
- azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+ printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
+ azt_Play.start.min, azt_Play.start.sec,
+ azt_Play.start.frame, azt_Play.end.min,
+ azt_Play.end.sec, azt_Play.end.frame);
#endif
i = aztPlay(&azt_Play);
- if (i < 0)
- { aztAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
+ if (i < 0) {
+ aztAudioStatus = CDROM_AUDIO_ERROR;
+ return -EIO;
}
aztAudioStatus = CDROM_AUDIO_PLAY;
break;
- case CDROMPLAYMSF: /* Play starting at the given MSF address. */
+ case CDROMPLAYMSF: /* Play starting at the given MSF address. */
/* if (aztAudioStatus == CDROM_AUDIO_PLAY)
{ if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
STEN_LOW;
aztAudioStatus = CDROM_AUDIO_NO_STATUS;
}
*/
- if(copy_from_user(&msf, (void *) arg, sizeof msf))
+ if (copy_from_user(&msf, (void *) arg, sizeof msf))
return -EFAULT;
/* convert to bcd */
azt_bin2bcd(&msf.cdmsf_min0);
@@ -1232,163 +1335,189 @@ printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
azt_Play.end.sec = msf.cdmsf_sec1;
azt_Play.end.frame = msf.cdmsf_frame1;
#ifdef AZT_DEBUG
-printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
-azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
-azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
+ printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
+ azt_Play.start.min, azt_Play.start.sec,
+ azt_Play.start.frame, azt_Play.end.min,
+ azt_Play.end.sec, azt_Play.end.frame);
#endif
i = aztPlay(&azt_Play);
- if (i < 0)
- { aztAudioStatus = CDROM_AUDIO_ERROR;
- return -EIO;
+ if (i < 0) {
+ aztAudioStatus = CDROM_AUDIO_ERROR;
+ return -EIO;
}
aztAudioStatus = CDROM_AUDIO_PLAY;
break;
- case CDROMREADTOCHDR: /* Read the table of contents header */
+ case CDROMREADTOCHDR: /* Read the table of contents header */
tocHdr.cdth_trk0 = DiskInfo.first;
tocHdr.cdth_trk1 = DiskInfo.last;
- if(copy_to_user((void *) arg, &tocHdr, sizeof tocHdr))
+ if (copy_to_user((void *) arg, &tocHdr, sizeof tocHdr))
return -EFAULT;
break;
- case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
- if(copy_from_user(&entry, (void *) arg, sizeof entry))
+ case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
+ if (copy_from_user(&entry, (void *) arg, sizeof entry))
return -EFAULT;
- if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc();
+ if ((!aztTocUpToDate) || aztDiskChanged)
+ aztUpdateToc();
if (entry.cdte_track == CDROM_LEADOUT)
- tocPtr = &Toc[DiskInfo.last + 1];
+ tocPtr = &Toc[DiskInfo.last + 1];
else if (entry.cdte_track > DiskInfo.last
- || entry.cdte_track < DiskInfo.first)
- { return -EINVAL;
- }
- else
- tocPtr = &Toc[entry.cdte_track];
- entry.cdte_adr = tocPtr -> ctrl_addr;
- entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
+ || entry.cdte_track < DiskInfo.first) {
+ return -EINVAL;
+ } else
+ tocPtr = &Toc[entry.cdte_track];
+ entry.cdte_adr = tocPtr->ctrl_addr;
+ entry.cdte_ctrl = tocPtr->ctrl_addr >> 4;
if (entry.cdte_format == CDROM_LBA)
- entry.cdte_addr.lba = azt_msf2hsg(&tocPtr -> diskTime);
- else if (entry.cdte_format == CDROM_MSF)
- { entry.cdte_addr.msf.minute = azt_bcd2bin(tocPtr -> diskTime.min);
- entry.cdte_addr.msf.second = azt_bcd2bin(tocPtr -> diskTime.sec);
- entry.cdte_addr.msf.frame = azt_bcd2bin(tocPtr -> diskTime.frame);
+ entry.cdte_addr.lba =
+ azt_msf2hsg(&tocPtr->diskTime);
+ else if (entry.cdte_format == CDROM_MSF) {
+ entry.cdte_addr.msf.minute =
+ azt_bcd2bin(tocPtr->diskTime.min);
+ entry.cdte_addr.msf.second =
+ azt_bcd2bin(tocPtr->diskTime.sec);
+ entry.cdte_addr.msf.frame =
+ azt_bcd2bin(tocPtr->diskTime.frame);
+ } else {
+ return -EINVAL;
}
- else
- { return -EINVAL;
- }
- if(copy_to_user((void *) arg, &entry, sizeof entry))
+ if (copy_to_user((void *) arg, &entry, sizeof entry))
return -EFAULT;
break;
- case CDROMSUBCHNL: /* Get subchannel info */
- if(copy_from_user(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl)))
+ case CDROMSUBCHNL: /* Get subchannel info */
+ if (copy_from_user
+ (&subchnl, (void *) arg, sizeof(struct cdrom_subchnl)))
return -EFAULT;
if (aztGetQChannelInfo(&qInfo) < 0) {
#ifdef AZT_DEBUG
- printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd);
+ printk
+ ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",
+ cmd);
#endif
- return -EIO;
- }
+ return -EIO;
+ }
subchnl.cdsc_audiostatus = aztAudioStatus;
subchnl.cdsc_adr = qInfo.ctrl_addr;
subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
- if (subchnl.cdsc_format == CDROM_LBA)
- { subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime);
- subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime);
- }
- else /*default*/
- { subchnl.cdsc_format = CDROM_MSF;
- subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
- subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec);
- subchnl.cdsc_absaddr.msf.frame = azt_bcd2bin(qInfo.diskTime.frame);
- subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min);
- subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec);
- subchnl.cdsc_reladdr.msf.frame = azt_bcd2bin(qInfo.trackTime.frame);
+ if (subchnl.cdsc_format == CDROM_LBA) {
+ subchnl.cdsc_absaddr.lba =
+ azt_msf2hsg(&qInfo.diskTime);
+ subchnl.cdsc_reladdr.lba =
+ azt_msf2hsg(&qInfo.trackTime);
+ } else { /*default */
+ subchnl.cdsc_format = CDROM_MSF;
+ subchnl.cdsc_absaddr.msf.minute =
+ azt_bcd2bin(qInfo.diskTime.min);
+ subchnl.cdsc_absaddr.msf.second =
+ azt_bcd2bin(qInfo.diskTime.sec);
+ subchnl.cdsc_absaddr.msf.frame =
+ azt_bcd2bin(qInfo.diskTime.frame);
+ subchnl.cdsc_reladdr.msf.minute =
+ azt_bcd2bin(qInfo.trackTime.min);
+ subchnl.cdsc_reladdr.msf.second =
+ azt_bcd2bin(qInfo.trackTime.sec);
+ subchnl.cdsc_reladdr.msf.frame =
+ azt_bcd2bin(qInfo.trackTime.frame);
}
- if(copy_to_user((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)))
+ if (copy_to_user
+ ((void *) arg, &subchnl, sizeof(struct cdrom_subchnl)))
return -EFAULT;
break;
- case CDROMVOLCTRL: /* Volume control
- * With my Aztech CD268-01A volume control does not work, I can only
- turn the channels on (any value !=0) or off (value==0). Maybe it
- works better with your drive */
- if(copy_from_user(&volctrl,(char *) arg,sizeof(volctrl)))
- return -EFAULT;
+ case CDROMVOLCTRL: /* Volume control
+ * With my Aztech CD268-01A volume control does not work, I can only
+ turn the channels on (any value !=0) or off (value==0). Maybe it
+ works better with your drive */
+ if (copy_from_user
+ (&volctrl, (char *) arg, sizeof(volctrl)))
+ return -EFAULT;
azt_Play.start.min = 0x21;
azt_Play.start.sec = 0x84;
azt_Play.start.frame = volctrl.channel0;
- azt_Play.end.min = volctrl.channel1;
- azt_Play.end.sec = volctrl.channel2;
- azt_Play.end.frame = volctrl.channel3;
- sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
- STEN_LOW_WAIT;
- break;
+ azt_Play.end.min = volctrl.channel1;
+ azt_Play.end.sec = volctrl.channel2;
+ azt_Play.end.frame = volctrl.channel3;
+ sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
+ STEN_LOW_WAIT;
+ break;
case CDROMEJECT:
- aztUnlockDoor(); /* Assume user knows what they're doing */
- /* all drives can at least stop! */
- if (aztAudioStatus == CDROM_AUDIO_PLAY)
- { if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1);
- STEN_LOW_WAIT;
+ aztUnlockDoor(); /* Assume user knows what they're doing */
+ /* all drives can at least stop! */
+ if (aztAudioStatus == CDROM_AUDIO_PLAY) {
+ if (aztSendCmd(ACMD_STOP))
+ RETURNM("azt_ioctl 10", -1);
+ STEN_LOW_WAIT;
}
- if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1);
+ if (aztSendCmd(ACMD_EJECT))
+ RETURNM("azt_ioctl 11", -1);
STEN_LOW_WAIT;
aztAudioStatus = CDROM_AUDIO_NO_STATUS;
break;
case CDROMEJECT_SW:
azt_auto_eject = (char) arg;
- break;
- case CDROMRESET:
- outb(ACMD_SOFT_RESET,CMD_PORT); /*send reset*/
- STEN_LOW;
- if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK?*/
- { printk("aztcd: AZTECH CD-ROM drive does not respond\n");
- }
- break;
+ break;
+ case CDROMRESET:
+ outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */
+ STEN_LOW;
+ if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */
+ printk
+ ("aztcd: AZTECH CD-ROM drive does not respond\n");
+ }
+ break;
/*Take care, the following code is not compatible with other CD-ROM drivers,
use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
if you do not want to use it!
-*/
-#if AZT_PRIVATE_IOCTLS
- case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
- case CDROMREADRAW: /*read data in mode 2 (2336 Bytes)*/
- {
- if(copy_from_user(&msf, (void *) arg, sizeof msf))
- return -EFAULT;
- /* convert to bcd */
- azt_bin2bcd(&msf.cdmsf_min0);
- azt_bin2bcd(&msf.cdmsf_sec0);
- azt_bin2bcd(&msf.cdmsf_frame0);
- msf.cdmsf_min1=0;
- msf.cdmsf_sec1=0;
- msf.cdmsf_frame1=1; /*read only one frame*/
- azt_Play.start.min = msf.cdmsf_min0;
- azt_Play.start.sec = msf.cdmsf_sec0;
- azt_Play.start.frame = msf.cdmsf_frame0;
- azt_Play.end.min = msf.cdmsf_min1;
- azt_Play.end.sec = msf.cdmsf_sec1;
- azt_Play.end.frame = msf.cdmsf_frame1;
- if (cmd==CDROMREADRAW)
- { if (DiskInfo.xa)
- { return -1; /*XA Disks can't be read raw*/
- }
- else
- { if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) return -1;
- DTEN_LOW;
- insb(DATA_PORT,buf,CD_FRAMESIZE_RAW);
- if(copy_to_user((void *) arg, &buf, CD_FRAMESIZE_RAW))
- return -EFAULT;
- }
- }
- else /*CDROMREADCOOKED*/
- { if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
- DTEN_LOW;
- insb(DATA_PORT,buf,CD_FRAMESIZE);
- if(copy_to_user((void *) arg, &buf, CD_FRAMESIZE))
- return -EFAULT;
- }
- }
- break;
- case CDROMSEEK: /*seek msf address*/
- if(copy_from_user(&msf, (void *) arg, sizeof msf))
+*/
+#if AZT_PRIVATE_IOCTLS
+ case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */
+ case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */
+ {
+ if (copy_from_user(&msf, (void *) arg, sizeof msf))
+ return -EFAULT;
+ /* convert to bcd */
+ azt_bin2bcd(&msf.cdmsf_min0);
+ azt_bin2bcd(&msf.cdmsf_sec0);
+ azt_bin2bcd(&msf.cdmsf_frame0);
+ msf.cdmsf_min1 = 0;
+ msf.cdmsf_sec1 = 0;
+ msf.cdmsf_frame1 = 1; /*read only one frame */
+ azt_Play.start.min = msf.cdmsf_min0;
+ azt_Play.start.sec = msf.cdmsf_sec0;
+ azt_Play.start.frame = msf.cdmsf_frame0;
+ azt_Play.end.min = msf.cdmsf_min1;
+ azt_Play.end.sec = msf.cdmsf_sec1;
+ azt_Play.end.frame = msf.cdmsf_frame1;
+ if (cmd == CDROMREADRAW) {
+ if (DiskInfo.xa) {
+ return -1; /*XA Disks can't be read raw */
+ } else {
+ if (sendAztCmd
+ (ACMD_PLAY_READ_RAW,
+ &azt_Play))
+ return -1;
+ DTEN_LOW;
+ insb(DATA_PORT, buf,
+ CD_FRAMESIZE_RAW);
+ if (copy_to_user
+ ((void *) arg, &buf,
+ CD_FRAMESIZE_RAW))
+ return -EFAULT;
+ }
+ } else
+ /*CDROMREADCOOKED*/ {
+ if (sendAztCmd(ACMD_PLAY_READ, &azt_Play))
+ return -1;
+ DTEN_LOW;
+ insb(DATA_PORT, buf, CD_FRAMESIZE);
+ if (copy_to_user
+ ((void *) arg, &buf, CD_FRAMESIZE))
+ return -EFAULT;
+ }
+ }
+ break;
+ case CDROMSEEK: /*seek msf address */
+ if (copy_from_user(&msf, (void *) arg, sizeof msf))
return -EFAULT;
/* convert to bcd */
azt_bin2bcd(&msf.cdmsf_min0);
@@ -1397,18 +1526,20 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
azt_Play.start.min = msf.cdmsf_min0;
azt_Play.start.sec = msf.cdmsf_sec0;
azt_Play.start.frame = msf.cdmsf_frame0;
- if (aztSeek(&azt_Play)) return -1;
- break;
-#endif /*end of incompatible code*/
- case CDROMREADMODE1: /*set read data in mode 1*/
- return aztSetDiskType(AZT_MODE_1);
- case CDROMREADMODE2: /*set read data in mode 2*/
- return aztSetDiskType(AZT_MODE_2);
+ if (aztSeek(&azt_Play))
+ return -1;
+ break;
+#endif /*end of incompatible code */
+ case CDROMREADMODE1: /*set read data in mode 1 */
+ return aztSetDiskType(AZT_MODE_1);
+ case CDROMREADMODE2: /*set read data in mode 2 */
+ return aztSetDiskType(AZT_MODE_2);
default:
return -EINVAL;
}
#ifdef AZT_DEBUG
- printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n",cmd,jiffies);
+ printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n", cmd,
+ jiffies);
#endif
return 0;
}
@@ -1418,131 +1549,139 @@ azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
* When Linux gets variable block sizes this will probably go away.
*/
static void azt_transfer(void)
-{
+{
#ifdef AZT_TEST
- printk("aztcd: executing azt_transfer Time:%li\n",jiffies);
+ printk("aztcd: executing azt_transfer Time:%li\n", jiffies);
#endif
- if (CURRENT_VALID) {
- while (CURRENT -> nr_sectors) {
- int bn = CURRENT -> sector / 4;
- int i;
- for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i)
- ;
- if (i < AZT_BUF_SIZ) {
- int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
- int nr_sectors = 4 - (CURRENT -> sector & 3);
- if (azt_buf_out != i) {
- azt_buf_out = i;
- if (azt_buf_bn[i] != bn) {
- azt_buf_out = -1;
- continue;
- }
+ if (CURRENT_VALID) {
+ while (CURRENT->nr_sectors) {
+ int bn = CURRENT->sector / 4;
+ int i;
+ for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn;
+ ++i);
+ if (i < AZT_BUF_SIZ) {
+ int offs =
+ (i * 4 + (CURRENT->sector & 3)) * 512;
+ int nr_sectors = 4 - (CURRENT->sector & 3);
+ if (azt_buf_out != i) {
+ azt_buf_out = i;
+ if (azt_buf_bn[i] != bn) {
+ azt_buf_out = -1;
+ continue;
+ }
+ }
+ if (nr_sectors > CURRENT->nr_sectors)
+ nr_sectors = CURRENT->nr_sectors;
+ memcpy(CURRENT->buffer, azt_buf + offs,
+ nr_sectors * 512);
+ CURRENT->nr_sectors -= nr_sectors;
+ CURRENT->sector += nr_sectors;
+ CURRENT->buffer += nr_sectors * 512;
+ } else {
+ azt_buf_out = -1;
+ break;
+ }
+ }
}
- if (nr_sectors > CURRENT -> nr_sectors)
- nr_sectors = CURRENT -> nr_sectors;
- memcpy(CURRENT -> buffer, azt_buf + offs, nr_sectors * 512);
- CURRENT -> nr_sectors -= nr_sectors;
- CURRENT -> sector += nr_sectors;
- CURRENT -> buffer += nr_sectors * 512;
- } else {
- azt_buf_out = -1;
- break;
- }
- }
- }
}
static void do_aztcd_request(request_queue_t * q)
{
#ifdef AZT_TEST
- printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
+ printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector,
+ CURRENT->nr_sectors, jiffies);
#endif
- if (DiskInfo.audio)
- { printk("aztcd: Error, tried to mount an Audio CD\n");
- end_request(0);
- return;
- }
- azt_transfer_is_active = 1;
- while (CURRENT_VALID) {
- if (CURRENT->bh) {
- if (!buffer_locked(CURRENT->bh))
- panic(DEVICE_NAME ": block not locked");
- }
- azt_transfer();
- if (CURRENT -> nr_sectors == 0) {
- end_request(1);
- } else {
- azt_buf_out = -1; /* Want to read a block not in buffer */
- if (azt_state == AZT_S_IDLE) {
- if ((!aztTocUpToDate)||aztDiskChanged) {
- if (aztUpdateToc() < 0) {
- while (CURRENT_VALID)
- end_request(0);
- break;
- }
+ if (DiskInfo.audio) {
+ printk("aztcd: Error, tried to mount an Audio CD\n");
+ end_request(0);
+ return;
+ }
+ azt_transfer_is_active = 1;
+ while (CURRENT_VALID) {
+ if (CURRENT->bh) {
+ if (!buffer_locked(CURRENT->bh))
+ panic(DEVICE_NAME ": block not locked");
+ }
+ azt_transfer();
+ if (CURRENT->nr_sectors == 0) {
+ end_request(1);
+ } else {
+ azt_buf_out = -1; /* Want to read a block not in buffer */
+ if (azt_state == AZT_S_IDLE) {
+ if ((!aztTocUpToDate) || aztDiskChanged) {
+ if (aztUpdateToc() < 0) {
+ while (CURRENT_VALID)
+ end_request(0);
+ break;
+ }
+ }
+ azt_state = AZT_S_START;
+ AztTries = 5;
+ SET_TIMER(azt_poll, HZ / 100);
+ }
+ break;
+ }
}
- azt_state = AZT_S_START;
- AztTries = 5;
- SET_TIMER(azt_poll, HZ/100);
- }
- break;
- }
- }
- azt_transfer_is_active = 0;
+ azt_transfer_is_active = 0;
#ifdef AZT_TEST2
- printk("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", \
- azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
- printk(" do_aztcd_request ends Time:%li\n",jiffies);
+ printk
+ ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n",
+ azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
+ printk(" do_aztcd_request ends Time:%li\n", jiffies);
#endif
}
static void azt_invalidate_buffers(void)
-{ int i;
+{
+ int i;
#ifdef AZT_DEBUG
- printk("aztcd: executing azt_invalidate_buffers\n");
+ printk("aztcd: executing azt_invalidate_buffers\n");
#endif
- for (i = 0; i < AZT_BUF_SIZ; ++i)
- azt_buf_bn[i] = -1;
- azt_buf_out = -1;
+ for (i = 0; i < AZT_BUF_SIZ; ++i)
+ azt_buf_bn[i] = -1;
+ azt_buf_out = -1;
}
/*
* Open the device special file. Check that a disk is in.
*/
int aztcd_open(struct inode *ip, struct file *fp)
-{ int st;
+{
+ int st;
#ifdef AZT_DEBUG
printk("aztcd: starting aztcd_open\n");
#endif
if (aztPresent == 0)
- return -ENXIO; /* no hardware */
-
- MOD_INC_USE_COUNT;
-
- if (!azt_open_count && azt_state == AZT_S_IDLE)
- { azt_invalidate_buffers();
-
- st = getAztStatus(); /* check drive status */
- if (st == -1) goto err_out; /* drive doesn't respond */
-
- if (st & AST_DOOR_OPEN)
- { /* close door, then get the status again. */
- printk("aztcd: Door Open?\n");
- aztCloseDoor();
- st = getAztStatus();
- }
-
- if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) /*no disk in drive or changed*/
- { printk("aztcd: Disk Changed or No Disk in Drive?\n");
- aztTocUpToDate=0;
- }
- if (aztUpdateToc()) goto err_out;
-
- }
+ return -ENXIO; /* no hardware */
+
+ MOD_INC_USE_COUNT;
+
+ if (!azt_open_count && azt_state == AZT_S_IDLE) {
+ azt_invalidate_buffers();
+
+ st = getAztStatus(); /* check drive status */
+ if (st == -1)
+ goto err_out; /* drive doesn't respond */
+
+ if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */
+ printk("aztcd: Door Open?\n");
+ aztCloseDoor();
+ st = getAztStatus();
+ }
+
+ if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) { /*no disk in drive or changed */
+ printk
+ ("aztcd: Disk Changed or No Disk in Drive?\n");
+ aztTocUpToDate = 0;
+ }
+ if (aztUpdateToc())
+ goto err_out;
+
+ }
++azt_open_count;
aztLockDoor();
@@ -1551,7 +1690,7 @@ int aztcd_open(struct inode *ip, struct file *fp)
#endif
return 0;
-err_out:
+ err_out:
MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -1560,21 +1699,22 @@ err_out:
/*
* On close, we flush all azt blocks from the buffer cache.
*/
-static int aztcd_release(struct inode * inode, struct file * file)
-{
+static int aztcd_release(struct inode *inode, struct file *file)
+{
#ifdef AZT_DEBUG
- printk("aztcd: executing aztcd_release\n");
- printk("inode: %p, inode->i_rdev: %x file: %p\n",inode,inode->i_rdev,file);
+ printk("aztcd: executing aztcd_release\n");
+ printk("inode: %p, inode->i_rdev: %x file: %p\n", inode,
+ inode->i_rdev, file);
#endif
- MOD_DEC_USE_COUNT;
- if (!--azt_open_count) {
- azt_invalidate_buffers();
- aztUnlockDoor();
- if (azt_auto_eject)
- aztSendCmd(ACMD_EJECT);
- CLEAR_TIMER;
- }
- return 0;
+ MOD_DEC_USE_COUNT;
+ if (!--azt_open_count) {
+ azt_invalidate_buffers();
+ aztUnlockDoor();
+ if (azt_auto_eject)
+ aztSendCmd(ACMD_EJECT);
+ CLEAR_TIMER;
+ }
+ return 0;
}
@@ -1584,220 +1724,244 @@ static int aztcd_release(struct inode * inode, struct file * file)
*/
int __init aztcd_init(void)
-{ long int count, max_count;
+{
+ long int count, max_count;
unsigned char result[50];
int st;
int i = 0;
- if (azt_port == 0)
- { printk("aztcd: no Aztech CD-ROM Initialization");
- return -EIO;
+ if (azt_port == 0) {
+ printk("aztcd: no Aztech CD-ROM Initialization");
+ return -EIO;
}
- printk("aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM CD-ROM Driver\n");
+ printk
+ ("aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM CD-ROM Driver\n");
printk("aztcd: (C) 1994-98 W.Zimmermann\n");
- if (azt_port == -1)
- { printk("aztcd: KernelVersion=%s DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n",UTS_RELEASE,AZT_VERSION);
+ if (azt_port == -1) {
+ printk
+ ("aztcd: KernelVersion=%s DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n",
+ UTS_RELEASE, AZT_VERSION);
+ } else
+ printk
+ ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n",
+ AZT_VERSION, azt_port);
+ printk
+ ("aztcd: If you have problems, read /usr/src/linux/Documentation/cdrom/aztcd\n");
+
+
+#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */
+ if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) {
+ printk
+ ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
+ AZT_SW32_BASE_ADDR, AZT_SW32_INIT,
+ AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG);
+ return -EIO;
+ } else {
+ printk(KERN_INFO
+ "aztcd: Soundwave32 card detected at %x Version %x\n",
+ AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
+ outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG);
+ for (count = 0; count < 10000; count++); /*delay a bit */
}
- else
- printk("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n",AZT_VERSION,azt_port);
- printk("aztcd: If you have problems, read /usr/src/linux/Documentation/cdrom/aztcd\n");
-
-
-#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card*/
- if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500)
- { printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
- AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG);
- return -EIO;
- }
- else
- { printk(KERN_INFO "aztcd: Soundwave32 card detected at %x Version %x\n",
- AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
- outw(AZT_SW32_INIT,AZT_SW32_CONFIG_REG);
- for (count=0;count<10000;count++); /*delay a bit*/
- }
-#endif
+#endif
/* check for presence of drive */
- if (azt_port == -1) /* autoprobing */
- { for (i=0;(azt_port_auto[i]!=0)&&(i<16);i++)
- { azt_port = azt_port_auto[i];
- printk("aztcd: Autoprobing BaseAddress=0x%x \n",azt_port);
- st = check_region(azt_port, 4); /*proprietary interfaces need 4 bytes*/
- if (st) continue;
-
- outb(POLLED,MODE_PORT);
- inb(CMD_PORT);
- inb(CMD_PORT);
- outb(ACMD_GET_VERSION,CMD_PORT); /*Try to get version info*/
-
- aztTimeOutCount=0;
- do { aztIndatum=inb(STATUS_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break;
- } while (aztIndatum&AFL_STATUS);
- if (inb(DATA_PORT)==AFL_OP_OK)
- break;
- }
- if ((azt_port_auto[i]==0)||(i==16))
- { printk("aztcd: no AZTECH CD-ROM drive found\n");
- return -EIO;
- }
- }
- else /* no autoprobing */
- { if ((azt_port==0x1f0)||(azt_port==0x170))
- st = check_region(azt_port, 8); /*IDE-interfaces need 8 bytes*/
- else
- st = check_region(azt_port, 4); /*proprietary interfaces need 4 bytes*/
- if (st)
- { printk("aztcd: conflict, I/O port (%X) already used\n",azt_port);
- return -EIO;
- }
-
- if ((azt_port==0x1f0)||(azt_port==0x170))
- SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration*/
-
- outb(POLLED,MODE_PORT);
- inb(CMD_PORT);
- inb(CMD_PORT);
- outb(ACMD_GET_VERSION,CMD_PORT); /*Try to get version info*/
-
- aztTimeOutCount=0;
- do { aztIndatum=inb(STATUS_PORT);
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break;
- } while (aztIndatum&AFL_STATUS);
-
- if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK? If not, reset and try again*/
- {
+ if (azt_port == -1) { /* autoprobing */
+ for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) {
+ azt_port = azt_port_auto[i];
+ printk("aztcd: Autoprobing BaseAddress=0x%x \n",
+ azt_port);
+ st = check_region(azt_port, 4); /*proprietary interfaces need 4 bytes */
+ if (st)
+ continue;
+
+ outb(POLLED, MODE_PORT);
+ inb(CMD_PORT);
+ inb(CMD_PORT);
+ outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
+
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(STATUS_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
+ break;
+ } while (aztIndatum & AFL_STATUS);
+ if (inb(DATA_PORT) == AFL_OP_OK)
+ break;
+ }
+ if ((azt_port_auto[i] == 0) || (i == 16)) {
+ printk("aztcd: no AZTECH CD-ROM drive found\n");
+ return -EIO;
+ }
+ } else { /* no autoprobing */
+ if ((azt_port == 0x1f0) || (azt_port == 0x170))
+ st = check_region(azt_port, 8); /*IDE-interfaces need 8 bytes */
+ else
+ st = check_region(azt_port, 4); /*proprietary interfaces need 4 bytes */
+ if (st) {
+ printk
+ ("aztcd: conflict, I/O port (%X) already used\n",
+ azt_port);
+ return -EIO;
+ }
+
+ if ((azt_port == 0x1f0) || (azt_port == 0x170))
+ SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */
+
+ outb(POLLED, MODE_PORT);
+ inb(CMD_PORT);
+ inb(CMD_PORT);
+ outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */
+
+ aztTimeOutCount = 0;
+ do {
+ aztIndatum = inb(STATUS_PORT);
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
+ break;
+ } while (aztIndatum & AFL_STATUS);
+
+ if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */
#ifndef MODULE
- if (azt_cont!=0x79)
- { printk("aztcd: no AZTECH CD-ROM drive found-Try boot parameter aztcd=<BaseAddress>,0x79\n");
- return -EIO;
- }
-#else
- if (0)
- {
- }
-#endif
- else
- { printk("aztcd: drive reset - please wait\n");
- for (count=0;count<50;count++)
- { inb(STATUS_PORT); /*removing all data from earlier tries*/
- inb(DATA_PORT);
- }
- outb(POLLED,MODE_PORT);
- inb(CMD_PORT);
- inb(CMD_PORT);
- getAztStatus(); /*trap errors*/
- outb(ACMD_SOFT_RESET,CMD_PORT); /*send reset*/
- STEN_LOW;
- if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK?*/
- { printk("aztcd: no AZTECH CD-ROM drive found\n");
- return -EIO;
- }
-
- for (count = 0; count < AZT_TIMEOUT; count++)
- barrier(); /* Stop gcc 2.96 being smart */
-
- if ((st=getAztStatus())==-1)
- { printk("aztcd: Drive Status Error Status=%x\n",st);
- return -EIO;
- }
+ if (azt_cont != 0x79) {
+ printk
+ ("aztcd: no AZTECH CD-ROM drive found-Try boot parameter aztcd=<BaseAddress>,0x79\n");
+ return -EIO;
+ }
+#else
+ if (0) {
+ }
+#endif
+ else {
+ printk
+ ("aztcd: drive reset - please wait\n");
+ for (count = 0; count < 50; count++) {
+ inb(STATUS_PORT); /*removing all data from earlier tries */
+ inb(DATA_PORT);
+ }
+ outb(POLLED, MODE_PORT);
+ inb(CMD_PORT);
+ inb(CMD_PORT);
+ getAztStatus(); /*trap errors */
+ outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */
+ STEN_LOW;
+ if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */
+ printk
+ ("aztcd: no AZTECH CD-ROM drive found\n");
+ return -EIO;
+ }
+
+ for (count = 0; count < AZT_TIMEOUT;
+ count++)
+ barrier(); /* Stop gcc 2.96 being smart */
+
+ if ((st = getAztStatus()) == -1) {
+ printk
+ ("aztcd: Drive Status Error Status=%x\n",
+ st);
+ return -EIO;
+ }
#ifdef AZT_DEBUG
- printk("aztcd: Status = %x\n",st);
+ printk("aztcd: Status = %x\n", st);
#endif
- outb(POLLED,MODE_PORT);
- inb(CMD_PORT);
- inb(CMD_PORT);
- outb(ACMD_GET_VERSION,CMD_PORT); /*GetVersion*/
- STEN_LOW;
- OP_OK;
- }
- }
+ outb(POLLED, MODE_PORT);
+ inb(CMD_PORT);
+ inb(CMD_PORT);
+ outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */
+ STEN_LOW;
+ OP_OK;
+ }
+ }
}
-
- azt_init_end=1;
+
+ azt_init_end = 1;
STEN_LOW;
- result[0]=inb(DATA_PORT); /*reading in a null byte???*/
- for (count=1;count<50;count++) /*Reading version string*/
- { aztTimeOutCount=0; /*here we must implement STEN_LOW differently*/
- do { aztIndatum=inb(STATUS_PORT);/*because we want to exit by timeout*/
- aztTimeOutCount++;
- if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break;
- } while (aztIndatum&AFL_STATUS);
- if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break; /*all chars read?*/
- result[count]=inb(DATA_PORT);
- }
- if (count>30) max_count=30; /*print max.30 chars of the version string*/
- else max_count=count;
+ result[0] = inb(DATA_PORT); /*reading in a null byte??? */
+ for (count = 1; count < 50; count++) { /*Reading version string */
+ aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */
+ do {
+ aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */
+ aztTimeOutCount++;
+ if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
+ break;
+ } while (aztIndatum & AFL_STATUS);
+ if (aztTimeOutCount >= AZT_FAST_TIMEOUT)
+ break; /*all chars read? */
+ result[count] = inb(DATA_PORT);
+ }
+ if (count > 30)
+ max_count = 30; /*print max.30 chars of the version string */
+ else
+ max_count = count;
printk(KERN_INFO "aztcd: FirmwareVersion=");
- for (count=1;count<max_count;count++) printk("%c",result[count]);
+ for (count = 1; count < max_count; count++)
+ printk("%c", result[count]);
printk("<<>> ");
- if ((result[1]=='A')&&(result[2]=='Z')&&(result[3]=='T'))
- { printk("AZTECH drive detected\n"); /*AZTECH*/
- }
- else if ((result[2]=='C')&&(result[3]=='D')&&(result[4]=='D'))
- { printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/
- }
- else if ((result[1]==0x03)&&(result[2]=='5'))
- { printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM*/
- }
- else /*OTHERS or none*/
- { printk("\nunknown drive or firmware version detected\n");
- printk("aztcd may not run stable, if you want to try anyhow,\n");
- printk("boot with: aztcd=<BaseAddress>,0x79\n");
- if ((azt_cont!=0x79))
- { printk("aztcd: FirmwareVersion=");
- for (count=1;count<5;count++) printk("%c",result[count]);
- printk("<<>> ");
- printk("Aborted\n");
- return -EIO;
- }
- }
- devfs_register (NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
- S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
- if (devfs_register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
- {
+ if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) {
+ printk("AZTECH drive detected\n");
+ /*AZTECH*/}
+ else if ((result[2] == 'C') && (result[3] == 'D')
+ && (result[4] == 'D')) {
+ printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */
+ } else if ((result[1] == 0x03) && (result[2] == '5')) {
+ printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */
+ } else { /*OTHERS or none */
+ printk("\nunknown drive or firmware version detected\n");
+ printk
+ ("aztcd may not run stable, if you want to try anyhow,\n");
+ printk("boot with: aztcd=<BaseAddress>,0x79\n");
+ if ((azt_cont != 0x79)) {
+ printk("aztcd: FirmwareVersion=");
+ for (count = 1; count < 5; count++)
+ printk("%c", result[count]);
+ printk("<<>> ");
+ printk("Aborted\n");
+ return -EIO;
+ }
+ }
+ devfs_register(NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
+ S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
+ if (devfs_register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) {
printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
MAJOR_NR);
- return -EIO;
+ return -EIO;
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
blksize_size[MAJOR_NR] = aztcd_blocksizes;
read_ahead[MAJOR_NR] = 4;
- register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &azt_fops, 0);
+ register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &azt_fops, 0);
+
+ if ((azt_port == 0x1f0) || (azt_port == 0x170))
+ request_region(azt_port, 8, "aztcd"); /*IDE-interface */
+ else
+ request_region(azt_port, 4, "aztcd"); /*proprietary interface */
- if ((azt_port==0x1f0)||(azt_port==0x170))
- request_region(azt_port, 8, "aztcd"); /*IDE-interface*/
- else
- request_region(azt_port, 4, "aztcd"); /*proprietary interface*/
-
azt_invalidate_buffers();
aztPresent = 1;
aztCloseDoor();
- return (0);
+ return (0);
}
void __exit aztcd_exit(void)
{
- devfs_unregister(devfs_find_handle(NULL, "aztcd", 0, 0, DEVFS_SPECIAL_BLK,
- 0));
- if ((devfs_unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))
- { printk("What's that: can't unregister aztcd\n");
- return;
- }
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
- if ((azt_port==0x1f0)||(azt_port==0x170))
- { SWITCH_IDE_MASTER;
- release_region(azt_port,8); /*IDE-interface*/
- }
- else
- release_region(azt_port,4); /*proprietary interface*/
- printk(KERN_INFO "aztcd module released.\n");
-}
+ devfs_unregister(devfs_find_handle
+ (NULL, "aztcd", 0, 0, DEVFS_SPECIAL_BLK, 0));
+ if ((devfs_unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) {
+ printk("What's that: can't unregister aztcd\n");
+ return;
+ }
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ if ((azt_port == 0x1f0) || (azt_port == 0x170)) {
+ SWITCH_IDE_MASTER;
+ release_region(azt_port, 8); /*IDE-interface */
+ } else
+ release_region(azt_port, 4); /*proprietary interface */
+ printk(KERN_INFO "aztcd module released.\n");
+}
#ifdef MODULE
module_init(aztcd_init);
@@ -1810,405 +1974,485 @@ module_exit(aztcd_exit);
*/
static void azt_poll(void)
{
- int st = 0;
- int loop_ctl = 1;
- int skip = 0;
-
- if (azt_error) {
- if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1");
- STEN_LOW;
- azt_error=inb(DATA_PORT)&0xFF;
- printk("aztcd: I/O error 0x%02x\n", azt_error);
- azt_invalidate_buffers();
+ int st = 0;
+ int loop_ctl = 1;
+ int skip = 0;
+
+ if (azt_error) {
+ if (aztSendCmd(ACMD_GET_ERROR))
+ RETURN("azt_poll 1");
+ STEN_LOW;
+ azt_error = inb(DATA_PORT) & 0xFF;
+ printk("aztcd: I/O error 0x%02x\n", azt_error);
+ azt_invalidate_buffers();
#ifdef WARN_IF_READ_FAILURE
- if (AztTries == 5)
- printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn);
+ if (AztTries == 5)
+ printk
+ ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n",
+ azt_next_bn);
#endif
- if (!AztTries--) {
- printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn);
- if (azt_transfer_is_active) {
- AztTries = 0;
- loop_ctl = 0;
- }
- if (CURRENT_VALID)
- end_request(0);
- AztTries = 5;
+ if (!AztTries--) {
+ printk
+ ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n",
+ azt_next_bn);
+ if (azt_transfer_is_active) {
+ AztTries = 0;
+ loop_ctl = 0;
+ }
+ if (CURRENT_VALID)
+ end_request(0);
+ AztTries = 5;
+ }
+ azt_error = 0;
+ azt_state = AZT_S_STOP;
}
- azt_error = 0;
- azt_state = AZT_S_STOP;
- }
- while (loop_ctl)
- {
- loop_ctl = 0; /* each case must flip this back to 1 if we want
- to come back up here */
- switch (azt_state) {
+ while (loop_ctl) {
+ loop_ctl = 0; /* each case must flip this back to 1 if we want
+ to come back up here */
+ switch (azt_state) {
- case AZT_S_IDLE:
+ case AZT_S_IDLE:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_IDLE\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_IDLE\n");
+ }
#endif
- return;
+ return;
- case AZT_S_START:
+ case AZT_S_START:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_START\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_START\n");
+ }
#endif
- if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2"); /*result will be checked by aztStatus() */
- azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
- AztTimeout = 3000;
- break;
-
- case AZT_S_MODE:
+ if (aztSendCmd(ACMD_GET_STATUS))
+ RETURN("azt_poll 2"); /*result will be checked by aztStatus() */
+ azt_state =
+ azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
+ AztTimeout = 3000;
+ break;
+
+ case AZT_S_MODE:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_MODE\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_MODE\n");
+ }
#endif
- if (!skip) {
- if ((st = aztStatus()) != -1) {
- if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
- aztDiskChanged = 1;
- aztTocUpToDate = 0;
- azt_invalidate_buffers();
- end_request(0);
- printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
- }
- } else break;
- }
- skip = 0;
-
- if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
- aztDiskChanged = 1;
- aztTocUpToDate = 0;
- printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
- end_request(0);
- printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
- if (azt_transfer_is_active) {
- azt_state = AZT_S_START;
- loop_ctl = 1; /* goto immediately */
- break;
- }
- azt_state = AZT_S_IDLE;
- while (CURRENT_VALID)
- end_request(0);
- return;
- }
-
+ if (!skip) {
+ if ((st = aztStatus()) != -1) {
+ if ((st & AST_DSK_CHG)
+ || (st & AST_NOT_READY)) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ azt_invalidate_buffers();
+ end_request(0);
+ printk
+ ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
+ }
+ } else
+ break;
+ }
+ skip = 0;
+
+ if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ printk
+ ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
+ end_request(0);
+ printk((st & AST_DOOR_OPEN) ?
+ "aztcd: door open\n" :
+ "aztcd: disk removed\n");
+ if (azt_transfer_is_active) {
+ azt_state = AZT_S_START;
+ loop_ctl = 1; /* goto immediately */
+ break;
+ }
+ azt_state = AZT_S_IDLE;
+ while (CURRENT_VALID)
+ end_request(0);
+ return;
+ }
+
/* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
outb(0x01, DATA_PORT);
PA_OK;
STEN_LOW;
-*/ if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4");
- STEN_LOW;
- azt_mode = 1;
- azt_state = AZT_S_READ;
- AztTimeout = 3000;
+*/
+ if (aztSendCmd(ACMD_GET_STATUS))
+ RETURN("azt_poll 4");
+ STEN_LOW;
+ azt_mode = 1;
+ azt_state = AZT_S_READ;
+ AztTimeout = 3000;
- break;
+ break;
- case AZT_S_READ:
+ case AZT_S_READ:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_READ\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_READ\n");
+ }
#endif
- if (!skip) {
- if ((st = aztStatus()) != -1) {
- if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
- aztDiskChanged = 1;
- aztTocUpToDate = 0;
- azt_invalidate_buffers();
- printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
- end_request(0);
- }
- } else break;
- }
-
- skip = 0;
- if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
- aztDiskChanged = 1;
- aztTocUpToDate = 0;
- printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
- if (azt_transfer_is_active) {
- azt_state = AZT_S_START;
- loop_ctl = 1;
- break;
- }
- azt_state = AZT_S_IDLE;
- while (CURRENT_VALID)
- end_request(0);
- return;
- }
-
- if (CURRENT_VALID) {
- struct azt_Play_msf msf;
- int i;
- azt_next_bn = CURRENT -> sector / 4;
- azt_hsg2msf(azt_next_bn, &msf.start);
- i = 0;
- /* find out in which track we are */
- while (azt_msf2hsg(&msf.start)>azt_msf2hsg(&Toc[++i].trackTime)) {};
- if (azt_msf2hsg(&msf.start)<azt_msf2hsg(&Toc[i].trackTime)-AZT_BUF_SIZ)
- { azt_read_count=AZT_BUF_SIZ; /*fast, because we read ahead*/
- /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead*/
- }
- else /* don't read beyond end of track */
-#if AZT_MULTISESSION
- { azt_read_count=(azt_msf2hsg(&Toc[i].trackTime)/4)*4-azt_msf2hsg(&msf.start);
- if (azt_read_count < 0) azt_read_count=0;
- if (azt_read_count > AZT_BUF_SIZ) azt_read_count=AZT_BUF_SIZ;
- printk("aztcd: warning - trying to read beyond end of track\n");
+ if (!skip) {
+ if ((st = aztStatus()) != -1) {
+ if ((st & AST_DSK_CHG)
+ || (st & AST_NOT_READY)) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ azt_invalidate_buffers();
+ printk
+ ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
+ end_request(0);
+ }
+ } else
+ break;
+ }
+
+ skip = 0;
+ if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ printk((st & AST_DOOR_OPEN) ?
+ "aztcd: door open\n" :
+ "aztcd: disk removed\n");
+ if (azt_transfer_is_active) {
+ azt_state = AZT_S_START;
+ loop_ctl = 1;
+ break;
+ }
+ azt_state = AZT_S_IDLE;
+ while (CURRENT_VALID)
+ end_request(0);
+ return;
+ }
+
+ if (CURRENT_VALID) {
+ struct azt_Play_msf msf;
+ int i;
+ azt_next_bn = CURRENT->sector / 4;
+ azt_hsg2msf(azt_next_bn, &msf.start);
+ i = 0;
+ /* find out in which track we are */
+ while (azt_msf2hsg(&msf.start) >
+ azt_msf2hsg(&Toc[++i].trackTime)) {
+ };
+ if (azt_msf2hsg(&msf.start) <
+ azt_msf2hsg(&Toc[i].trackTime) -
+ AZT_BUF_SIZ) {
+ azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */
+ /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */
+ } else /* don't read beyond end of track */
+#if AZT_MULTISESSION
+ {
+ azt_read_count =
+ (azt_msf2hsg(&Toc[i].trackTime)
+ / 4) * 4 -
+ azt_msf2hsg(&msf.start);
+ if (azt_read_count < 0)
+ azt_read_count = 0;
+ if (azt_read_count > AZT_BUF_SIZ)
+ azt_read_count =
+ AZT_BUF_SIZ;
+ printk
+ ("aztcd: warning - trying to read beyond end of track\n");
/* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime));
-*/ }
+*/ }
#else
- { azt_read_count=AZT_BUF_SIZ;
- }
+ {
+ azt_read_count = AZT_BUF_SIZ;
+ }
#endif
- msf.end.min = 0;
- msf.end.sec = 0;
- msf.end.frame = azt_read_count ;/*Mitsumi here reads 0xffffff sectors*/
+ msf.end.min = 0;
+ msf.end.sec = 0;
+ msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */
#ifdef AZT_TEST3
- printk("---reading msf-address %x:%x:%x %x:%x:%x\n",msf.start.min,msf.start.sec,msf.start.frame,msf.end.min,msf.end.sec,msf.end.frame);
- printk("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", \
- azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-#endif
- if (azt_read_mode==AZT_MODE_2)
- { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/
- }
- else
- { sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode*/
- }
- azt_state = AZT_S_DATA;
- AztTimeout = READ_TIMEOUT;
- } else {
- azt_state = AZT_S_STOP;
- loop_ctl = 1;
- break;
- }
-
- break;
-
-
- case AZT_S_DATA:
+ printk
+ ("---reading msf-address %x:%x:%x %x:%x:%x\n",
+ msf.start.min, msf.start.sec,
+ msf.start.frame, msf.end.min,
+ msf.end.sec, msf.end.frame);
+ printk
+ ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n",
+ azt_next_bn, azt_buf_in, azt_buf_out,
+ azt_buf_bn[azt_buf_in]);
+#endif
+ if (azt_read_mode == AZT_MODE_2) {
+ sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */
+ } else {
+ sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */
+ }
+ azt_state = AZT_S_DATA;
+ AztTimeout = READ_TIMEOUT;
+ } else {
+ azt_state = AZT_S_STOP;
+ loop_ctl = 1;
+ break;
+ }
+
+ break;
+
+
+ case AZT_S_DATA:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_DATA\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_DATA\n");
+ }
#endif
- st = inb(STATUS_PORT) & AFL_STATUSorDATA;
+ st = inb(STATUS_PORT) & AFL_STATUSorDATA;
- switch (st) {
+ switch (st) {
- case AFL_DATA:
+ case AFL_DATA:
#ifdef AZT_TEST3
- if (st!=azt_st_old) {
- azt_st_old=st;
- printk("---AFL_DATA st:%x\n",st);
- }
+ if (st != azt_st_old) {
+ azt_st_old = st;
+ printk("---AFL_DATA st:%x\n", st);
+ }
#endif
- if (!AztTries--) {
- printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn);
- if (azt_transfer_is_active) {
- AztTries = 0;
- break;
- }
- if (CURRENT_VALID)
- end_request(0);
- AztTries = 5;
- }
- azt_state = AZT_S_START;
- AztTimeout = READ_TIMEOUT;
- loop_ctl = 1;
- break;
-
- case AFL_STATUSorDATA:
+ if (!AztTries--) {
+ printk
+ ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n",
+ azt_next_bn);
+ if (azt_transfer_is_active) {
+ AztTries = 0;
+ break;
+ }
+ if (CURRENT_VALID)
+ end_request(0);
+ AztTries = 5;
+ }
+ azt_state = AZT_S_START;
+ AztTimeout = READ_TIMEOUT;
+ loop_ctl = 1;
+ break;
+
+ case AFL_STATUSorDATA:
#ifdef AZT_TEST3
- if (st!=azt_st_old) {
- azt_st_old=st;
- printk("---AFL_STATUSorDATA st:%x\n",st);
- }
+ if (st != azt_st_old) {
+ azt_st_old = st;
+ printk
+ ("---AFL_STATUSorDATA st:%x\n",
+ st);
+ }
#endif
- break;
+ break;
- default:
+ default:
#ifdef AZT_TEST3
- if (st!=azt_st_old) {
- azt_st_old=st;
- printk("---default: st:%x\n",st);
- }
+ if (st != azt_st_old) {
+ azt_st_old = st;
+ printk("---default: st:%x\n", st);
+ }
#endif
- AztTries = 5;
- if (!CURRENT_VALID && azt_buf_in == azt_buf_out) {
- azt_state = AZT_S_STOP;
- loop_ctl = 1;
- break;
- }
- if (azt_read_count<=0)
- printk("aztcd: warning - try to read 0 frames\n");
- while (azt_read_count) /*??? fast read ahead loop*/
- { azt_buf_bn[azt_buf_in] = -1;
- DTEN_LOW; /*??? unsolved problem, very
- seldom we get timeouts
- here, don't now the real
- reason. With my drive this
- sometimes also happens with
- Aztech's original driver under
- DOS. Is it a hardware bug?
- I tried to recover from such
- situations here. Zimmermann*/
- if (aztTimeOutCount>=AZT_TIMEOUT)
- { printk("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", azt_read_count,CURRENT->nr_sectors,azt_buf_in);
- printk("azt_transfer_is_active:%x\n",azt_transfer_is_active);
- azt_read_count=0;
- azt_state = AZT_S_STOP;
- loop_ctl = 1;
- end_request(1); /*should we have here (1) or (0)? */
- }
- else
- { if (azt_read_mode==AZT_MODE_2)
- { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW);
- }
- else
- { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
- }
- azt_read_count--;
+ AztTries = 5;
+ if (!CURRENT_VALID
+ && azt_buf_in == azt_buf_out) {
+ azt_state = AZT_S_STOP;
+ loop_ctl = 1;
+ break;
+ }
+ if (azt_read_count <= 0)
+ printk
+ ("aztcd: warning - try to read 0 frames\n");
+ while (azt_read_count) { /*??? fast read ahead loop */
+ azt_buf_bn[azt_buf_in] = -1;
+ DTEN_LOW; /*??? unsolved problem, very
+ seldom we get timeouts
+ here, don't now the real
+ reason. With my drive this
+ sometimes also happens with
+ Aztech's original driver under
+ DOS. Is it a hardware bug?
+ I tried to recover from such
+ situations here. Zimmermann */
+ if (aztTimeOutCount >= AZT_TIMEOUT) {
+ printk
+ ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n",
+ azt_read_count,
+ CURRENT->nr_sectors,
+ azt_buf_in);
+ printk
+ ("azt_transfer_is_active:%x\n",
+ azt_transfer_is_active);
+ azt_read_count = 0;
+ azt_state = AZT_S_STOP;
+ loop_ctl = 1;
+ end_request(1); /*should we have here (1) or (0)? */
+ } else {
+ if (azt_read_mode ==
+ AZT_MODE_2) {
+ insb(DATA_PORT,
+ azt_buf +
+ CD_FRAMESIZE_RAW
+ * azt_buf_in,
+ CD_FRAMESIZE_RAW);
+ } else {
+ insb(DATA_PORT,
+ azt_buf +
+ CD_FRAMESIZE *
+ azt_buf_in,
+ CD_FRAMESIZE);
+ }
+ azt_read_count--;
#ifdef AZT_TEST3
- printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count);
- printk("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n", \
- azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
+ printk
+ ("AZT_S_DATA; ---I've read data- read_count: %d\n",
+ azt_read_count);
+ printk
+ ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n",
+ azt_next_bn,
+ azt_buf_in,
+ azt_buf_out,
+ azt_buf_bn
+ [azt_buf_in]);
#endif
- azt_buf_bn[azt_buf_in] = azt_next_bn++;
- if (azt_buf_out == -1)
- azt_buf_out = azt_buf_in;
- azt_buf_in = azt_buf_in + 1 == AZT_BUF_SIZ ? 0 : azt_buf_in + 1;
- }
- }
- if (!azt_transfer_is_active) {
- while (CURRENT_VALID) {
- azt_transfer();
- if (CURRENT -> nr_sectors == 0)
- end_request(1);
- else
- break;
- }
- }
-
- if (CURRENT_VALID
- && (CURRENT -> sector / 4 < azt_next_bn ||
- CURRENT -> sector / 4 > azt_next_bn + AZT_BUF_SIZ)) {
- azt_state = AZT_S_STOP;
- loop_ctl = 1;
- break;
- }
- AztTimeout = READ_TIMEOUT;
- if (azt_read_count==0) {
- azt_state = AZT_S_STOP;
- loop_ctl = 1;
- break;
- }
- break;
- }
- break;
-
-
- case AZT_S_STOP:
+ azt_buf_bn[azt_buf_in] =
+ azt_next_bn++;
+ if (azt_buf_out == -1)
+ azt_buf_out =
+ azt_buf_in;
+ azt_buf_in =
+ azt_buf_in + 1 ==
+ AZT_BUF_SIZ ? 0 :
+ azt_buf_in + 1;
+ }
+ }
+ if (!azt_transfer_is_active) {
+ while (CURRENT_VALID) {
+ azt_transfer();
+ if (CURRENT->nr_sectors ==
+ 0)
+ end_request(1);
+ else
+ break;
+ }
+ }
+
+ if (CURRENT_VALID
+ && (CURRENT->sector / 4 < azt_next_bn
+ || CURRENT->sector / 4 >
+ azt_next_bn + AZT_BUF_SIZ)) {
+ azt_state = AZT_S_STOP;
+ loop_ctl = 1;
+ break;
+ }
+ AztTimeout = READ_TIMEOUT;
+ if (azt_read_count == 0) {
+ azt_state = AZT_S_STOP;
+ loop_ctl = 1;
+ break;
+ }
+ break;
+ }
+ break;
+
+
+ case AZT_S_STOP:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_STOP\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_STOP\n");
+ }
#endif
- if (azt_read_count!=0) printk("aztcd: discard data=%x frames\n",azt_read_count);
- while (azt_read_count!=0) {
- int i;
- if ( !(inb(STATUS_PORT) & AFL_DATA) ) {
- if (azt_read_mode==AZT_MODE_2)
- for (i=0; i<CD_FRAMESIZE_RAW; i++) inb(DATA_PORT);
- else
- for (i=0; i<CD_FRAMESIZE; i++) inb(DATA_PORT);
- }
- azt_read_count--;
- }
- if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5");
- azt_state = AZT_S_STOPPING;
- AztTimeout = 1000;
- break;
-
- case AZT_S_STOPPING:
+ if (azt_read_count != 0)
+ printk("aztcd: discard data=%x frames\n",
+ azt_read_count);
+ while (azt_read_count != 0) {
+ int i;
+ if (!(inb(STATUS_PORT) & AFL_DATA)) {
+ if (azt_read_mode == AZT_MODE_2)
+ for (i = 0;
+ i < CD_FRAMESIZE_RAW;
+ i++)
+ inb(DATA_PORT);
+ else
+ for (i = 0;
+ i < CD_FRAMESIZE; i++)
+ inb(DATA_PORT);
+ }
+ azt_read_count--;
+ }
+ if (aztSendCmd(ACMD_GET_STATUS))
+ RETURN("azt_poll 5");
+ azt_state = AZT_S_STOPPING;
+ AztTimeout = 1000;
+ break;
+
+ case AZT_S_STOPPING:
#ifdef AZT_TEST3
- if (azt_state!=azt_state_old) {
- azt_state_old=azt_state;
- printk("AZT_S_STOPPING\n");
- }
+ if (azt_state != azt_state_old) {
+ azt_state_old = azt_state;
+ printk("AZT_S_STOPPING\n");
+ }
#endif
- if ((st = aztStatus()) == -1 && AztTimeout)
- break;
-
- if ((st != -1) && ((st & AST_DSK_CHG)||(st & AST_NOT_READY))) {
- aztDiskChanged = 1;
- aztTocUpToDate = 0;
- azt_invalidate_buffers();
- printk("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
- end_request(0);
- }
+ if ((st = aztStatus()) == -1 && AztTimeout)
+ break;
+ if ((st != -1)
+ && ((st & AST_DSK_CHG)
+ || (st & AST_NOT_READY))) {
+ aztDiskChanged = 1;
+ aztTocUpToDate = 0;
+ azt_invalidate_buffers();
+ printk
+ ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
+ end_request(0);
+ }
#ifdef AZT_TEST3
- printk("CURRENT_VALID %d azt_mode %d\n",
- CURRENT_VALID, azt_mode);
+ printk("CURRENT_VALID %d azt_mode %d\n",
+ CURRENT_VALID, azt_mode);
#endif
- if (CURRENT_VALID) {
- if (st != -1) {
- if (azt_mode == 1) {
- azt_state = AZT_S_READ;
- loop_ctl = 1;
- skip = 1;
- break;
- } else {
- azt_state = AZT_S_MODE;
- loop_ctl = 1;
- skip = 1;
- break;
- }
- } else {
- azt_state = AZT_S_START;
- AztTimeout = 1;
- }
- } else {
- azt_state = AZT_S_IDLE;
- return;
- }
- break;
+ if (CURRENT_VALID) {
+ if (st != -1) {
+ if (azt_mode == 1) {
+ azt_state = AZT_S_READ;
+ loop_ctl = 1;
+ skip = 1;
+ break;
+ } else {
+ azt_state = AZT_S_MODE;
+ loop_ctl = 1;
+ skip = 1;
+ break;
+ }
+ } else {
+ azt_state = AZT_S_START;
+ AztTimeout = 1;
+ }
+ } else {
+ azt_state = AZT_S_IDLE;
+ return;
+ }
+ break;
+
+ default:
+ printk("aztcd: invalid state %d\n", azt_state);
+ return;
+ } /* case */
+ } /* while */
+
+
+ if (!AztTimeout--) {
+ printk("aztcd: timeout in state %d\n", azt_state);
+ azt_state = AZT_S_STOP;
+ if (aztSendCmd(ACMD_STOP))
+ RETURN("azt_poll 6");
+ STEN_LOW_WAIT;
+ };
- default:
- printk("aztcd: invalid state %d\n", azt_state);
- return;
- } /* case */
- } /* while */
-
-
- if (!AztTimeout--)
- { printk("aztcd: timeout in state %d\n", azt_state);
- azt_state = AZT_S_STOP;
- if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6");
- STEN_LOW_WAIT;
- };
-
- SET_TIMER(azt_poll, HZ/100);
+ SET_TIMER(azt_poll, HZ / 100);
}
@@ -2217,28 +2461,34 @@ static void azt_poll(void)
###########################################################################
*/
static void azt_hsg2msf(long hsg, struct msf *msf)
-{ hsg += 150;
- msf -> min = hsg / 4500;
+{
+ hsg += 150;
+ msf->min = hsg / 4500;
hsg %= 4500;
- msf -> sec = hsg / 75;
- msf -> frame = hsg % 75;
+ msf->sec = hsg / 75;
+ msf->frame = hsg % 75;
#ifdef AZT_DEBUG
- if (msf->min >=70) printk("aztcd: Error hsg2msf address Minutes\n");
- if (msf->sec >=60) printk("aztcd: Error hsg2msf address Seconds\n");
- if (msf->frame>=75) printk("aztcd: Error hsg2msf address Frames\n");
+ if (msf->min >= 70)
+ printk("aztcd: Error hsg2msf address Minutes\n");
+ if (msf->sec >= 60)
+ printk("aztcd: Error hsg2msf address Seconds\n");
+ if (msf->frame >= 75)
+ printk("aztcd: Error hsg2msf address Frames\n");
#endif
- azt_bin2bcd(&msf -> min); /* convert to BCD */
- azt_bin2bcd(&msf -> sec);
- azt_bin2bcd(&msf -> frame);
+ azt_bin2bcd(&msf->min); /* convert to BCD */
+ azt_bin2bcd(&msf->sec);
+ azt_bin2bcd(&msf->frame);
}
static long azt_msf2hsg(struct msf *mp)
-{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75
- + azt_bcd2bin(mp -> min) * 4500 - CD_MSF_OFFSET;
+{
+ return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75
+ + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET;
}
static void azt_bin2bcd(unsigned char *p)
-{ int u, t;
+{
+ int u, t;
u = *p % 10;
t = *p / 10;
@@ -2246,7 +2496,8 @@ static void azt_bin2bcd(unsigned char *p)
}
static int azt_bcd2bin(unsigned char bcd)
-{ return (bcd >> 4) * 10 + (bcd & 0xF);
+{
+ return (bcd >> 4) * 10 + (bcd & 0xF);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index 85cc35b449e4..481297baf358 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -2,6 +2,7 @@
linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
Copyright (C) 1992 Martin Harriss
+ Portions Copyright (C) 2001 Red Hat
martin@bdsi.com (no longer valid - where are you now, Martin?)
@@ -74,7 +75,8 @@
module_init & module_exit.
Torben Mathiasen <tmm@image.dk>
-
+ September 2001 - Reformatted and cleaned up the code
+ Alan Cox <alan@redhat.com>
*/
#include <linux/module.h>
@@ -117,22 +119,8 @@ static int mcd1xhold;
/* Is the drive connected properly and responding?? */
static int mcdPresent;
-#if 0
-#define TEST1 /* <int-..> */
-#define TEST2 /* do_mcd_req */
-#define TEST3 */ /* MCD_S_state */
-#define TEST4 /* QUICK_LOOP-counter */
-#define TEST5 */ /* port(1) state */
-#endif
-
-#if 1
#define QUICK_LOOP_DELAY udelay(45) /* use udelay */
#define QUICK_LOOP_COUNT 20
-#else
-#define QUICK_LOOP_DELAY
-#define QUICK_LOOP_COUNT 140 /* better wait constant time */
-#endif
-/* #define DOUBLE_QUICK_ONLY */
#define CURRENT_VALID \
(!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
@@ -158,12 +146,10 @@ enum mcd_state_e {
static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
static int mcd_mode = -1;
static int MCMD_DATA_READ = MCMD_PLAY_READ;
+
#define READ_TIMEOUT 3000
-#define WORK_AROUND_MITSUMI_BUG_92
-#define WORK_AROUND_MITSUMI_BUG_93
-#ifdef WORK_AROUND_MITSUMI_BUG_93
+
int mitsumi_bug_93_wait;
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
@@ -234,10 +220,8 @@ static int __init mcd_setup(char *str)
mcd_port = ints[1];
if (ints[0] > 1)
mcd_irq = ints[2];
-#ifdef WORK_AROUND_MITSUMI_BUG_93
if (ints[0] > 2)
mitsumi_bug_93_wait = ints[3];
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
return 1;
}
@@ -248,23 +232,7 @@ __setup("mcd=", mcd_setup);
static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
{
- int retval;
-
-
-#if 1 /* the below is not reliable */
return 0;
-#endif
-
- if (cdi->dev) {
- printk
- ("mcd: Mitsumi CD-ROM request error: invalid device.\n");
- return 0;
- }
-
- retval = mcdDiskChanged;
- mcdDiskChanged = 0;
-
- return retval;
}
@@ -278,7 +246,8 @@ static int statusCmd(void)
int st = -1, retry;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
- outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
+ /* send get-status cmd */
+ outb(MCMD_GET_STATUS, MCDPORT(0));
st = getMcdStatus(MCD_STATUS_DELAY);
if (st != -1)
@@ -335,8 +304,7 @@ static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
long msf2hsg(struct msf *mp)
{
- return bcd2bin(mp->frame)
- + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
+ return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
}
@@ -538,18 +506,12 @@ int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
subchnl->cdsc_trk = bcd2bin(qInfo.track);
subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
- subchnl->cdsc_absaddr.msf.minute =
- bcd2bin(qInfo.diskTime.min);
- subchnl->cdsc_absaddr.msf.second =
- bcd2bin(qInfo.diskTime.sec);
- subchnl->cdsc_absaddr.msf.frame =
- bcd2bin(qInfo.diskTime.frame);
- subchnl->cdsc_reladdr.msf.minute =
- bcd2bin(qInfo.trackTime.min);
- subchnl->cdsc_reladdr.msf.second =
- bcd2bin(qInfo.trackTime.sec);
- subchnl->cdsc_reladdr.msf.frame =
- bcd2bin(qInfo.trackTime.frame);
+ subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
+ subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
+ subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
+ subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
+ subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
+ subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
return (0);
case CDROMVOLCTRL: /* Volume control */
@@ -594,8 +556,7 @@ static void mcd_transfer(void)
for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn;
++i);
if (i < MCD_BUF_SIZ) {
- int offs =
- (i * 4 + (CURRENT->sector & 3)) * 512;
+ int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
int nr_sectors = 4 - (CURRENT->sector & 3);
if (mcd_buf_out != i) {
mcd_buf_out = i;
@@ -630,14 +591,10 @@ static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int st;
st = inb(MCDPORT(1)) & 0xFF;
-#ifdef TEST1
- printk("<int1-%02X>", st);
-#endif
+ test1(printk("<int1-%02X>", st));
if (!(st & MFL_STATUS)) {
st = inb(MCDPORT(0)) & 0xFF;
-#ifdef TEST1
- printk("<int0-%02X>", st);
-#endif
+ test1(printk("<int0-%02X>", st));
if ((st & 0xFF) != 0xFF)
mcd_error = st ? st & 0xFF : -1;
}
@@ -646,11 +603,10 @@ static void mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void do_mcd_request(request_queue_t * q)
{
-#ifdef TEST2
- printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
- CURRENT->nr_sectors);
-#endif
- mcd_transfer_is_active = 1;
+ test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
+ CURRENT->nr_sectors));
+
+ mcd_transfer_is_active = 1;
while (CURRENT_VALID) {
if (CURRENT->bh) {
if (!buffer_locked(CURRENT->bh))
@@ -671,15 +627,14 @@ static void do_mcd_request(request_queue_t * q)
}
mcd_state = MCD_S_START;
McdTries = 5;
- SET_TIMER(mcd_poll, 1);
+ mcd_timer.function = mcd_poll;
+ mod_timer(&mcd_timer, jiffies + 1);
}
break;
}
}
mcd_transfer_is_active = 0;
-#ifdef TEST2
- printk(" do_mcd_request ends\n");
-#endif
+ test2(printk(" do_mcd_request ends\n"));
}
@@ -691,7 +646,7 @@ static void mcd_poll(unsigned long dummy)
if (mcd_error) {
if (mcd_error & 0xA5) {
- printk("mcd: I/O error 0x%02x", mcd_error);
+ printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
if (mcd_error & 0x80)
printk(" (Door open)");
if (mcd_error & 0x20)
@@ -718,14 +673,13 @@ static void mcd_poll(unsigned long dummy)
mcd_invalidate_buffers();
#ifdef WARN_IF_READ_FAILURE
if (McdTries == MCD_RETRY_ATTEMPTS)
- printk("mcd: read of block %d failed\n",
+ printk(KERN_ERR "mcd: read of block %d failed\n",
mcd_next_bn);
#endif
if (!McdTries--) {
/* Nuts! This cd is ready for recycling! */
/* When WAS the last time YOU cleaned it CORRECTLY?! */
- printk
- ("mcd: read of block %d failed, giving up\n",
+ printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
mcd_next_bn);
if (mcd_transfer_is_active) {
McdTries = 0;
@@ -747,54 +701,35 @@ static void mcd_poll(unsigned long dummy)
/* We ARE a double speed and we ARE bitching! */
if (mcd1xhold == 0) { /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
- printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
+ printk(KERN_INFO "mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
} else
mcd1xhold--; /* No?! Count down the good reads some more... */
/* and try, try again! */
}
-
-
- immediately:
+immediately:
switch (mcd_state) {
-
-
-
case MCD_S_IDLE:
-#ifdef TEST3
- printk("MCD_S_IDLE\n");
-#endif
+ test3(printk("MCD_S_IDLE\n"));
goto out;
-
-
case MCD_S_START:
-#ifdef TEST3
- printk("MCD_S_START\n");
-#endif
-
+ test3(printk("MCD_S_START\n"));
outb(MCMD_GET_STATUS, MCDPORT(0));
mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
McdTimeout = 3000;
break;
-
-
case MCD_S_MODE:
-#ifdef TEST3
- printk("MCD_S_MODE\n");
-#endif
-
+ test3(printk("MCD_S_MODE\n"));
if ((st = mcdStatus()) != -1) {
-
if (st & MST_DSK_CHG) {
mcdDiskChanged = 1;
tocUpToDate = 0;
mcd_invalidate_buffers();
}
- set_mode_immediately:
-
+set_mode_immediately:
if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
mcdDiskChanged = 1;
tocUpToDate = 0;
@@ -802,6 +737,7 @@ static void mcd_poll(unsigned long dummy)
mcd_state = MCD_S_START;
goto immediately;
}
+ printk(KERN_INFO);
printk((st & MST_DOOR_OPEN) ?
"mcd: door open\n" :
"mcd: disk removed\n");
@@ -810,33 +746,24 @@ static void mcd_poll(unsigned long dummy)
end_request(0);
goto out;
}
-
outb(MCMD_SET_MODE, MCDPORT(0));
outb(1, MCDPORT(0));
mcd_mode = 1;
mcd_state = MCD_S_READ;
McdTimeout = 3000;
-
}
break;
-
-
case MCD_S_READ:
-#ifdef TEST3
- printk("MCD_S_READ\n");
-#endif
-
+ test3(printk("MCD_S_READ\n"));
if ((st = mcdStatus()) != -1) {
-
if (st & MST_DSK_CHG) {
mcdDiskChanged = 1;
tocUpToDate = 0;
mcd_invalidate_buffers();
}
- read_immediately:
-
+read_immediately:
if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
mcdDiskChanged = 1;
tocUpToDate = 0;
@@ -844,6 +771,7 @@ static void mcd_poll(unsigned long dummy)
mcd_state = MCD_S_START;
goto immediately;
}
+ printk(KERN_INFO);
printk((st & MST_DOOR_OPEN) ?
"mcd: door open\n" :
"mcd: disk removed\n");
@@ -871,29 +799,20 @@ static void mcd_poll(unsigned long dummy)
}
break;
-
case MCD_S_DATA:
-#ifdef TEST3
- printk("MCD_S_DATA\n");
-#endif
-
+ test3(printk("MCD_S_DATA\n"));
st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
- data_immediately:
-#ifdef TEST5
- printk("Status %02x\n", st);
-#endif
+data_immediately:
+ test5(printk("Status %02x\n", st))
switch (st) {
-
case MFL_DATA:
#ifdef WARN_IF_READ_FAILURE
if (McdTries == 5)
- printk("mcd: read of block %d failed\n",
+ printk(KERN_WARNING "mcd: read of block %d failed\n",
mcd_next_bn);
#endif
if (!McdTries--) {
- printk
- ("mcd: read of block %d failed, giving up\n",
- mcd_next_bn);
+ printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
if (mcd_transfer_is_active) {
McdTries = 0;
break;
@@ -916,14 +835,12 @@ static void mcd_poll(unsigned long dummy)
goto immediately;
}
mcd_buf_bn[mcd_buf_in] = -1;
- READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
+ insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
2048);
mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
if (mcd_buf_out == -1)
mcd_buf_out = mcd_buf_in;
- mcd_buf_in =
- mcd_buf_in + 1 ==
- MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
+ mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
if (!mcd_transfer_is_active) {
while (CURRENT_VALID) {
mcd_transfer();
@@ -941,43 +858,23 @@ static void mcd_poll(unsigned long dummy)
goto immediately;
}
McdTimeout = READ_TIMEOUT;
-#ifdef DOUBLE_QUICK_ONLY
- if (MCMD_DATA_READ != MCMD_PLAY_READ)
-#endif
{
int count = QUICK_LOOP_COUNT;
while (count--) {
QUICK_LOOP_DELAY;
- if ((st =
- (inb(MCDPORT(1))) &
- (MFL_STATUSorDATA)) !=
- (MFL_STATUSorDATA)) {
-# ifdef TEST4
-/* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
- printk(" %d ",
- QUICK_LOOP_COUNT -
- count);
-# endif
+ if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
+ test4(printk(" %d ", QUICK_LOOP_COUNT - count));
goto data_immediately;
}
}
-# ifdef TEST4
-/* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
- printk("ended ");
-# endif
+ test4(printk("ended "));
}
break;
}
break;
-
-
case MCD_S_STOP:
-#ifdef TEST3
- printk("MCD_S_STOP\n");
-#endif
-
-#ifdef WORK_AROUND_MITSUMI_BUG_93
+ test3(printk("MCD_S_STOP\n"));
if (!mitsumi_bug_93_wait)
goto do_not_work_around_mitsumi_bug_93_1;
@@ -989,41 +886,29 @@ static void mcd_poll(unsigned long dummy)
if (McdTimeout)
break;
- do_not_work_around_mitsumi_bug_93_1:
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
-
+do_not_work_around_mitsumi_bug_93_1:
outb(MCMD_STOP, MCDPORT(0));
-
-#ifdef WORK_AROUND_MITSUMI_BUG_92
if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
int i = 4096;
do {
inb(MCDPORT(0));
- } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) ==
- MFL_STATUS && --i);
+ } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
outb(MCMD_STOP, MCDPORT(0));
- if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) ==
- MFL_STATUS) {
+ if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
i = 4096;
do {
inb(MCDPORT(0));
- } while ((inb(MCDPORT(1)) &
- MFL_STATUSorDATA) == MFL_STATUS
- && --i);
+ } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
outb(MCMD_STOP, MCDPORT(0));
}
}
-#endif /* WORK_AROUND_MITSUMI_BUG_92 */
mcd_state = MCD_S_STOPPING;
McdTimeout = 1000;
break;
case MCD_S_STOPPING:
-#ifdef TEST3
- printk("MCD_S_STOPPING\n");
-#endif
-
+ test3(printk("MCD_S_STOPPING\n"));
if ((st = mcdStatus()) == -1 && McdTimeout)
break;
@@ -1032,7 +917,6 @@ static void mcd_poll(unsigned long dummy)
tocUpToDate = 0;
mcd_invalidate_buffers();
}
-#ifdef WORK_AROUND_MITSUMI_BUG_93
if (!mitsumi_bug_93_wait)
goto do_not_work_around_mitsumi_bug_93_2;
@@ -1043,17 +927,10 @@ static void mcd_poll(unsigned long dummy)
case 9 + 3 + 2:
if (McdTimeout)
break;
-
st = -1;
- do_not_work_around_mitsumi_bug_93_2:
-#endif /* WORK_AROUND_MITSUMI_BUG_93 */
-
-#ifdef TEST3
- printk("CURRENT_VALID %d mcd_mode %d\n",
- CURRENT_VALID, mcd_mode);
-#endif
-
+do_not_work_around_mitsumi_bug_93_2:
+ test3(printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode));
if (CURRENT_VALID) {
if (st != -1) {
if (mcd_mode == 1)
@@ -1069,25 +946,21 @@ static void mcd_poll(unsigned long dummy)
goto out;
}
break;
-
default:
- printk("mcd: invalid state %d\n", mcd_state);
+ printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
goto out;
}
-
- ret:
+ret:
if (!McdTimeout--) {
- printk("mcd: timeout in state %d\n", mcd_state);
+ printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
mcd_state = MCD_S_STOP;
}
-
- SET_TIMER(mcd_poll, 1);
- out:
+ mcd_timer.function = mcd_poll;
+ mod_timer(&mcd_timer, jiffies + 1);
+out:
return;
}
-
-
static void mcd_invalidate_buffers(void)
{
int i;
@@ -1096,7 +969,6 @@ static void mcd_invalidate_buffers(void)
mcd_buf_out = -1;
}
-
/*
* Open the device special file. Check that a disk is in.
*/
@@ -1125,11 +997,11 @@ static int mcd_open(struct cdrom_device_info *cdi, int purpose)
if (updateToc() < 0)
goto err_out;
- bump_count:
+bump_count:
++mcd_open_count;
return 0;
- err_out:
+err_out:
MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -1140,10 +1012,10 @@ static int mcd_open(struct cdrom_device_info *cdi, int purpose)
*/
static void mcd_release(struct cdrom_device_info *cdi)
{
- MOD_DEC_USE_COUNT;
if (!--mcd_open_count) {
mcd_invalidate_buffers();
}
+ MOD_DEC_USE_COUNT;
}
@@ -1155,8 +1027,7 @@ static void cleanup(int level)
switch (level) {
case 3:
if (unregister_cdrom(&mcd_info)) {
- printk(KERN_WARNING
- "Can't unregister cdrom mcd\n");
+ printk(KERN_WARNING "Can't unregister cdrom mcd\n");
return;
}
free_irq(mcd_irq, NULL);
@@ -1164,8 +1035,7 @@ static void cleanup(int level)
release_region(mcd_port, 4);
case 1:
if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
- printk(KERN_WARNING
- "Can't unregister major mcd\n");
+ printk(KERN_WARNING "Can't unregister major mcd\n");
return;
}
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
@@ -1186,19 +1056,17 @@ int __init mcd_init(void)
char msg[80];
if (mcd_port <= 0 || mcd_irq <= 0) {
- printk("skip mcd_init\n");
+ printk(KERN_INFO "mcd: not probing.\n");
return -EIO;
}
if (devfs_register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0) {
- printk("Unable to get major %d for Mitsumi CD-ROM\n",
- MAJOR_NR);
+ printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR);
return -EIO;
}
if (check_region(mcd_port, 4)) {
cleanup(1);
- printk("Init failed, I/O port (%X) already in use\n",
- mcd_port);
+ printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
return -EIO;
}
@@ -1218,7 +1086,7 @@ int __init mcd_init(void)
break;
if (count >= 2000000) {
- printk("Init failed. No mcd device at 0x%x irq %d\n",
+ printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
mcd_port, mcd_irq);
cleanup(1);
return -EIO;
@@ -1228,7 +1096,7 @@ int __init mcd_init(void)
outb(MCMD_GET_VERSION, MCDPORT(0));
for (count = 0; count < 3; count++)
if (getValue(result + count)) {
- printk("mitsumi get version failed at 0x%x\n",
+ printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
mcd_port);
cleanup(1);
return -EIO;
@@ -1246,10 +1114,8 @@ int __init mcd_init(void)
/* don't get the IRQ until we know for sure the drive is there */
- if (request_irq
- (mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
- printk("Unable to get IRQ%d for Mitsumi CD-ROM\n",
- mcd_irq);
+ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
+ printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
cleanup(1);
return -EIO;
}
@@ -1282,7 +1148,7 @@ int __init mcd_init(void)
mcd_info.dev = MKDEV(MAJOR_NR, 0);
if (register_cdrom(&mcd_info) != 0) {
- printk("Cannot register Mitsumi CD-ROM!\n");
+ printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
cleanup(3);
return -EIO;
}
@@ -1373,8 +1239,8 @@ static void mcdStatTimer(unsigned long dummy)
wake_up(&mcd_waitq);
return;
}
-
- SET_TIMER(mcdStatTimer, 1);
+ mcd_timer.function = mcdStatTimer;
+ mod_timer(&mcd_timer, jiffies + 1);
}
@@ -1389,7 +1255,8 @@ static int getMcdStatus(int timeout)
int st;
McdTimeout = timeout;
- SET_TIMER(mcdStatTimer, 1);
+ mcd_timer.function = mcdStatTimer;
+ mod_timer(&mcd_timer, jiffies + 1);
sleep_on(&mcd_waitq);
if (McdTimeout <= 0)
return -1;
@@ -1414,6 +1281,7 @@ static int getMcdStatus(int timeout)
/* gives current state of the drive This function is quite unreliable,
and should probably be rewritten by someone, eventually... */
+
int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
{
int st;
@@ -1456,7 +1324,6 @@ static int getValue(unsigned char *result)
return 0;
}
-
/*
* Read the current Q-channel info. Also used for reading the
* table of contents.
@@ -1500,12 +1367,11 @@ int GetQChannelInfo(struct mcd_Toc *qp)
return 0;
}
-
/*
* Read the table of contents (TOC) and TOC header if necessary
*/
-static int updateToc()
+static int updateToc(void)
{
if (tocUpToDate)
return 0;
@@ -1520,12 +1386,11 @@ static int updateToc()
return 0;
}
-
/*
* Read the table of contents header
*/
-static int GetDiskInfo()
+static int GetDiskInfo(void)
{
int retry;
@@ -1571,12 +1436,11 @@ static int GetDiskInfo()
return 0;
}
-
/*
* Read the table of contents (TOC)
*/
-static int GetToc()
+static int GetToc(void)
{
int i, px;
int limit;
@@ -1653,7 +1517,6 @@ static int GetToc()
return limit > 0 ? 0 : -1;
}
-
void __exit mcd_exit(void)
{
cleanup(3);
diff --git a/drivers/cdrom/mcd.h b/drivers/cdrom/mcd.h
index ce903d2f2f3d..1e36c4192bb0 100644
--- a/drivers/cdrom/mcd.h
+++ b/drivers/cdrom/mcd.h
@@ -70,17 +70,6 @@
/* borrowed from hd.c */
-#define READ_DATA(port, buf, nr) \
-insb(port, buf, nr)
-
-#define SET_TIMER(func, jifs) \
- do { \
- mcd_timer.function = func; \
- mod_timer(&mcd_timer, jiffies + jifs); \
- } while (0)
-
-#define CLEAR_TIMER del_timer_async(&mcd_timer);
-
#define MAX_TRACKS 104
struct msf {
@@ -108,3 +97,10 @@ struct mcd_Toc {
struct msf trackTime;
struct msf diskTime;
};
+
+#define test1(x)
+#define test2(x)
+#define test3(x)
+#define test4(x)
+#define test5(x)
+
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 233e8efd5fce..5be72a8e29aa 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -2097,3 +2097,4 @@ module_init(optcd_init);
module_exit(optcd_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 127771813a60..e8e50a8ee40b 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -4272,6 +4272,12 @@ static int sbpcd_dev_ioctl(struct cdrom_device_info *cdi, u_int cmd,
D_S[d].aud_buf=NULL;
D_S[d].sbp_audsiz=arg;
+ if (D_S[d].sbp_audsiz>16)
+ {
+ D_S[d].sbp_audsiz = 0;
+ RETURN_UP(D_S[d].sbp_audsiz);
+ }
+
if (D_S[d].sbp_audsiz>0)
{
D_S[d].aud_buf=(u_char *) vmalloc(D_S[d].sbp_audsiz*CD_FRAMESIZE_RAW);
@@ -6016,6 +6022,9 @@ static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr)
{
return sbpcd_chk_disk_change(cdi->dev);
}
+
+MODULE_LICENSE("GPL");
+
/*==========================================================================*/
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
@@ -6033,3 +6042,4 @@ static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr)
* c-continued-brace-offset: 0
* End:
*/
+
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index a66fb5651284..6d8e6c331ca2 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1709,3 +1709,4 @@ module_init(sony535_init);
module_exit(sony535_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 3ee4c527858e..ba9b9bc37631 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -59,6 +59,24 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
fi
+ if [ "$CONFIG_MIPS" = "y" ]; then
+ bool ' TMPTX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
+ dep_bool ' Console on TMPTX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
+ bool ' Enable Au1000 UART Support' CONFIG_AU1000_UART
+ if [ "$CONFIG_AU1000_UART" = "y" ]; then
+ bool ' Enable Au1000 serial console' CONFIG_AU1000_SERIAL_CONSOLE
+ fi
+ fi
+fi
+if [ "$CONFIG_IT8712" = "y" ]; then
+ bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
+ if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then
+ define_bool CONFIG_IT8172_CIR y
+ else
+ bool ' Enable PS2 Keyboard Support' CONFIG_PC_KEYB
+ fi
+ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0
+ bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 4bce5b67caa8..f7f9d67746d6 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -41,6 +41,12 @@ ifeq ($(ARCH),s390)
SERIAL =
endif
+ifeq ($(ARCH),mips)
+ ifneq ($(CONFIG_PC_KEYB),y)
+ KEYBD =
+ endif
+endif
+
ifeq ($(ARCH),s390x)
KEYMAP =
KEYBD =
@@ -95,8 +101,9 @@ ifeq ($(ARCH),sh)
endif
ifeq ($(CONFIG_DECSTATION),y)
+ KEYMAP =
KEYBD =
- SERIAL =
+ SERIAL = decserial.o
endif
ifeq ($(CONFIG_BAGET_MIPS),y)
@@ -104,10 +111,18 @@ ifeq ($(CONFIG_BAGET_MIPS),y)
SERIAL =
endif
+ifeq ($(CONFIG_NINO),y)
+ SERIAL =
+endif
+
ifneq ($(CONFIG_SUN_SERIAL),)
SERIAL =
endif
+ifeq ($(CONFIG_QTRONIX_KEYBOARD),y)
+ KEYBD = qtronix.o
+ KEYMAP = qtronixmap.o
+endif
obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
obj-$(CONFIG_SERIAL) += $(SERIAL)
@@ -147,6 +162,7 @@ obj-$(CONFIG_SERIAL167) += serial167.o
obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
+obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
subdir-$(CONFIG_RIO) += rio
subdir-$(CONFIG_INPUT) += joystick
@@ -231,3 +247,6 @@ consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h
defkeymap.c: defkeymap.map
set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+
+qtronixmap.c: qtronixmap.map
+ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
new file mode 100644
index 000000000000..6c82b6cf816c
--- /dev/null
+++ b/drivers/char/decserial.c
@@ -0,0 +1,98 @@
+/*
+ * sercons.c
+ * choose the right serial device at boot time
+ *
+ * triemer 6-SEP-1998
+ * sercons.c is designed to allow the three different kinds
+ * of serial devices under the decstation world to co-exist
+ * in the same kernel. The idea here is to abstract
+ * the pieces of the drivers that are common to this file
+ * so that they do not clash at compile time and runtime.
+ *
+ * HK 16-SEP-1998 v0.002
+ * removed the PROM console as this is not a real serial
+ * device. Added support for PROM console in drivers/char/tty_io.c
+ * instead. Although it may work to enable more than one
+ * console device I strongly recommend to use only one.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/dec/machtype.h>
+
+#ifdef CONFIG_ZS
+extern int zs_init(void);
+#endif
+
+#ifdef CONFIG_DZ
+extern int dz_init(void);
+#endif
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#ifdef CONFIG_ZS
+extern void zs_serial_console_init(void);
+#endif
+
+#ifdef CONFIG_DZ
+extern void dz_serial_console_init(void);
+#endif
+
+#endif
+
+/* rs_init - starts up the serial interface -
+ handle normal case of starting up the serial interface */
+
+#ifdef CONFIG_SERIAL
+
+int __init rs_init(void)
+{
+
+#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+ if (IOASIC)
+ return zs_init();
+ else
+ return dz_init();
+#else
+
+#ifdef CONFIG_ZS
+ return zs_init();
+#endif
+
+#ifdef CONFIG_DZ
+ return dz_init();
+#endif
+
+#endif
+}
+
+__initcall(rs_init);
+
+#endif
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/* serial_console_init handles the special case of starting
+ * up the console on the serial port
+ */
+void __init serial_console_init(void)
+{
+#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+ if (IOASIC)
+ zs_serial_console_init();
+ else
+ dz_serial_console_init();
+#else
+
+#ifdef CONFIG_ZS
+ zs_serial_console_init();
+#endif
+
+#ifdef CONFIG_DZ
+ dz_serial_console_init();
+#endif
+
+#endif
+}
+
+#endif
diff --git a/drivers/char/dz.c b/drivers/char/dz.c
index 9104b838d41d..431e0fb34b29 100644
--- a/drivers/char/dz.c
+++ b/drivers/char/dz.c
@@ -21,15 +21,10 @@ Qua Jun 27 15:02:26 BRT 2001
* [07-SEP-99] Bugfixes
*/
-#define DEBUG_DZ 1
+/* #define DEBUG_DZ 1 */
-#ifdef MODULE
-#include <linux/module.h>
#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
+#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
@@ -41,9 +36,10 @@ Qua Jun 27 15:02:26 BRT 2001
#include <linux/param.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
#include <asm-mips/wbflush.h>
-/* for definition of SERIAL */
-#include <asm/dec/interrupts.h>
+#include <asm/dec/interrupts.h> /* for definition of SERIAL */
/* for definition of struct console */
#ifdef CONFIG_SERIAL_CONSOLE
@@ -91,13 +87,13 @@ static unsigned char tmp_buffer[256];
*/
static void debug_console( const char *s,int count)
{
- unsigned i;
+ unsigned i;
- for (i = 0; i < count; i++) {
- if (*s == 10)
- prom_printf("%c", 13);
- prom_printf("%c", *s++);
- }
+ for (i = 0; i < count; i++) {
+ if (*s == 10)
+ prom_printf("%c", 13);
+ prom_printf("%c", *s++);
+ }
}
#endif
@@ -112,16 +108,16 @@ static void debug_console( const char *s,int count)
static inline unsigned short dz_in (struct dz_serial *info, unsigned offset)
{
- volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
- return *addr;
+ volatile u16 *addr = (volatile u16 *)(info->port + offset);
+
+ return *addr;
}
-static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned short value)
+static inline void dz_out (struct dz_serial *info, unsigned offset,
+ unsigned short value)
{
-
- volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
- *addr = value;
-
+ volatile u16 *addr = (volatile u16 *)(info->port + offset);
+ *addr = value;
}
/*
@@ -136,33 +132,32 @@ static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned sho
static void dz_stop (struct tty_struct *tty)
{
- struct dz_serial *info;
- unsigned short mask, tmp;
+ struct dz_serial *info;
+ unsigned short mask, tmp;
- if (tty==0)
- return;
+ if (!tty)
+ return;
- info = (struct dz_serial *)tty->driver_data;
-
- mask = 1 << info->line;
- tmp = dz_in (info, DZ_TCR); /* read the TX flag */
+ info = (struct dz_serial *)tty->driver_data;
+
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR); /* read the TX flag */
- tmp &= ~mask; /* clear the TX flag */
- dz_out (info, DZ_TCR, tmp);
-}
+ tmp &= ~mask; /* clear the TX flag */
+ dz_out (info, DZ_TCR, tmp);
+}
static void dz_start (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- unsigned short mask, tmp;
-
- mask = 1 << info->line;
- tmp = dz_in (info, DZ_TCR); /* read the TX flag */
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned short mask, tmp;
- tmp |= mask; /* set the TX flag */
- dz_out (info, DZ_TCR, tmp);
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR); /* read the TX flag */
-}
+ tmp |= mask; /* set the TX flag */
+ dz_out (info, DZ_TCR, tmp);
+}
/*
* ------------------------------------------------------------
@@ -194,9 +189,9 @@ static void dz_start (struct tty_struct *tty)
*/
static inline void dz_sched_event (struct dz_serial *info, int event)
{
- info->event |= 1 << event;
- queue_task (&info->tqueue, &tq_serial);
- mark_bh (SERIAL_BH);
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
}
/*
@@ -208,98 +203,101 @@ static inline void dz_sched_event (struct dz_serial *info, int event)
*/
static inline void receive_chars (struct dz_serial *info_in)
{
+ struct dz_serial *info;
+ struct tty_struct *tty = 0;
+ struct async_icount *icount;
+ int ignore = 0;
+ unsigned short status, tmp;
+ unsigned char ch;
- struct dz_serial *info;
- struct tty_struct *tty = 0;
- struct async_icount *icount;
- int ignore = 0;
- unsigned short status, tmp;
- unsigned char ch;
-
- /* this code is going to be a problem...
- the call to tty_flip_buffer is going to need
- to be rethought...
- */
- do
- {
- status = dz_in (info_in, DZ_RBUF);
- info = lines[LINE(status)];
-
- /* punt so we don't get duplicate characters */
- if (!(status & DZ_DVAL))
- goto ignore_char;
+ /*
+ * This code is going to be a problem... the call to tty_flip_buffer
+ * is going to need to be rethought...
+ */
+ do {
+ status = dz_in (info_in, DZ_RBUF);
+ info = lines[LINE(status)];
+ /* punt so we don't get duplicate characters */
+ if (!(status & DZ_DVAL))
+ goto ignore_char;
- ch = UCHAR(status); /* grab the char */
+ ch = UCHAR(status); /* grab the char */
#if 0
- if (info->is_console) {
- if (ch == 0) return; /* it's a break ... */
+ if (info->is_console) {
+ if (ch == 0)
+ return; /* it's a break ... */
- wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */
- }
+ wake_up (&keypress_wait); /* It is a 'keyboard interrupt' ;-) */
+ }
#endif
- tty = info->tty; /* now tty points to the proper dev */
- icount = &info->icount;
-
- if (!tty) break;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
-
- *tty->flip.char_buf_ptr = ch;
- *tty->flip.flag_buf_ptr = 0;
- icount->rx++;
-
- /* keep track of the statistics */
- if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
- if (status & DZ_PERR) /* parity error */
- icount->parity++;
- else if (status & DZ_FERR) /* frame error */
- icount->frame++;
- if (status & DZ_OERR) /* overrun error */
- icount->overrun++;
-
- /* check to see if we should ignore the character
- and mask off conditions that should be ignored
- */
-
- if (status & info->ignore_status_mask) {
- if (++ignore > 100 ) break;
- goto ignore_char;
- }
-
- /* mask off the error conditions we want to ignore */
- tmp = status & info->read_status_mask;
-
- if (tmp & DZ_PERR)
- {
- *tty->flip.flag_buf_ptr = TTY_PARITY;
- debug_console("PERR\n",5);
- }
- else if (tmp & DZ_FERR)
- {
- *tty->flip.flag_buf_ptr = TTY_FRAME;
- debug_console("FERR\n",5);
- }
- if (tmp & DZ_OERR)
- {
- debug_console("OERR\n",5);
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
- tty->flip.count++;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
- }
- }
- }
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
- ignore_char:
- } while (status & DZ_DVAL);
-
- if (tty)
- tty_flip_buffer_push(tty);
+ tty = info->tty; /* now tty points to the proper dev */
+ icount = &info->icount;
+
+ if (!tty)
+ break;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
+
+ *tty->flip.char_buf_ptr = ch;
+ *tty->flip.flag_buf_ptr = 0;
+ icount->rx++;
+
+ /* keep track of the statistics */
+ if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
+ if (status & DZ_PERR) /* parity error */
+ icount->parity++;
+ else if (status & DZ_FERR) /* frame error */
+ icount->frame++;
+ if (status & DZ_OERR) /* overrun error */
+ icount->overrun++;
+
+ /*
+ * Check to see if we should ignore the character and
+ * mask off conditions that should be ignored
+ */
+
+ if (status & info->ignore_status_mask) {
+ if (++ignore > 100)
+ break;
+ goto ignore_char;
+ }
+
+ /* mask off the error conditions we want to ignore */
+ tmp = status & info->read_status_mask;
+
+ if (tmp & DZ_PERR) {
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+#ifdef DEBUG_DZ
+ debug_console("PERR\n",5);
+#endif /* DEBUG_DZ */
+ } else if (tmp & DZ_FERR) {
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+#ifdef DEBUG_DZ
+ debug_console("FERR\n",5);
+#endif /* DEBUG_DZ */
+ } if (tmp & DZ_OERR) {
+#ifdef DEBUG_DZ
+ debug_console("OERR\n",5);
+#endif /* DEBUG_DZ */
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ }
+ }
+ }
+ tty->flip.flag_buf_ptr++;
+ tty->flip.char_buf_ptr++;
+ tty->flip.count++;
+ignore_char:
+ ;
+ } while (status & DZ_DVAL);
+
+ if (tty)
+ tty_flip_buffer_push(tty);
}
/*
@@ -311,35 +309,37 @@ static inline void receive_chars (struct dz_serial *info_in)
*/
static inline void transmit_chars (struct dz_serial *info)
{
- unsigned char tmp;
-
-
+ unsigned char tmp;
- if (info->x_char) { /* XON/XOFF chars */
- dz_out (info, DZ_TDR, info->x_char);
- info->icount.tx++;
- info->x_char = 0;
- return;
- }
-
- /* if nothing to do or stopped or hardware stopped */
- if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) {
- dz_stop (info->tty);
- return;
- }
+ if (info->x_char) { /* XON/XOFF chars */
+ dz_out(info, DZ_TDR, info->x_char);
+ info->icount.tx++;
+ info->x_char = 0;
+ return;
+ }
- /* if something to do ... (rember the dz has no output fifo so we go one char at a time :-< */
- tmp = (unsigned short)info->xmit_buf[info->xmit_tail++];
- dz_out (info, DZ_TDR, tmp);
- info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1);
- info->icount.tx++;
+ /* if nothing to do or stopped or hardware stopped */
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ info->tty->hw_stopped) {
+ dz_stop(info->tty);
+ return;
+ }
- if (--info->xmit_cnt < WAKEUP_CHARS)
- dz_sched_event (info, DZ_EVENT_WRITE_WAKEUP);
+ /*
+ * If something to do ... (rember the dz has no output fifo so we go
+ * one char at a time :-<
+ */
+ tmp = (unsigned short) info->xmit_buf[info->xmit_tail++];
+ dz_out(info, DZ_TDR, tmp);
+ info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1);
+ info->icount.tx++;
+ if (--info->xmit_cnt < WAKEUP_CHARS)
+ dz_sched_event(info, DZ_EVENT_WRITE_WAKEUP);
- /* Are we done */
- if (info->xmit_cnt <= 0) dz_stop (info->tty);
+ /* Are we done */
+ if (info->xmit_cnt <= 0)
+ dz_stop(info->tty);
}
/*
@@ -351,15 +351,17 @@ static inline void transmit_chars (struct dz_serial *info)
*/
static inline void check_modem_status (struct dz_serial *info)
{
- unsigned short status;
+ unsigned short status;
- /* if not ne modem line just return */
- if (info->line != DZ_MODEM) return;
+ /* if not ne modem line just return */
+ if (info->line != DZ_MODEM)
+ return;
- status = dz_in (info, DZ_MSR);
+ status = dz_in(info, DZ_MSR);
- /* it's easy, since DSR2 is the only bit in the register */
- if (status) info->icount.dsr++;
+ /* it's easy, since DSR2 is the only bit in the register */
+ if (status)
+ info->icount.dsr++;
}
/*
@@ -372,17 +374,18 @@ static inline void check_modem_status (struct dz_serial *info)
*/
static void dz_interrupt (int irq, void *dev, struct pt_regs *regs)
{
- struct dz_serial *info;
- unsigned short status;
+ struct dz_serial *info;
+ unsigned short status;
- status = dz_in ((struct dz_serial *)dev, DZ_CSR); /* get the reason why we just got an irq */
- info = lines[LINE(status)]; /* re-arrange info the proper port */
+ /* get the reason why we just got an irq */
+ status = dz_in((struct dz_serial *)dev, DZ_CSR);
+ info = lines[LINE(status)]; /* re-arrange info the proper port */
- if (status & DZ_RDONE)
- receive_chars (info); /* the receive function */
+ if (status & DZ_RDONE)
+ receive_chars(info); /* the receive function */
- if (status & DZ_TRDY)
- transmit_chars (info);
+ if (status & DZ_TRDY)
+ transmit_chars (info);
}
/*
@@ -402,21 +405,23 @@ static void dz_interrupt (int irq, void *dev, struct pt_regs *regs)
*/
static void do_serial_bh (void)
{
- run_task_queue (&tq_serial);
+ run_task_queue (&tq_serial);
}
static void do_softint (void *private_data)
{
- struct dz_serial *info = (struct dz_serial *)private_data;
- struct tty_struct *tty = info->tty;
+ struct dz_serial *info = (struct dz_serial *) private_data;
+ struct tty_struct *tty = info->tty;
- if (!tty) return;
+ if (!tty)
+ return;
- if (test_and_clear_bit (DZ_EVENT_WRITE_WAKEUP, &info->event)) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible (&tty->write_wait);
- }
+ if (test_and_clear_bit(DZ_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible (&tty->write_wait);
+ }
}
/*
@@ -431,12 +436,13 @@ static void do_softint (void *private_data)
*/
static void do_serial_hangup (void *private_data)
{
- struct dz_serial *info = (struct dz_serial *)private_data;
- struct tty_struct *tty = info->tty;;
+ struct dz_serial *info = (struct dz_serial *) private_data;
+ struct tty_struct *tty = info->tty;;
- if (!tty) return;
+ if (!tty)
+ return;
- tty_hangup (tty);
+ tty_hangup(tty);
}
/*
@@ -448,57 +454,52 @@ static void do_serial_hangup (void *private_data)
*/
static int startup (struct dz_serial *info)
{
- unsigned long page, flags;
- unsigned short tmp;
+ unsigned long page, flags;
+ unsigned short tmp;
- if (info->is_initialized) return 0;
+ if (info->is_initialized)
+ return 0;
- save_flags (flags);
- cli ();
-
- if (!info->port) {
- if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
- restore_flags (flags);
- return -ENODEV;
- }
-
- if (!info->xmit_buf) {
- page = get_free_page (GFP_KERNEL);
- if (!page) {
- restore_flags (flags);
- return -ENOMEM;
- }
- info->xmit_buf = (unsigned char *)page;
- }
-
- if (info->tty) clear_bit (TTY_IO_ERROR, &info->tty->flags);
-
- /* enable the interrupt and the scanning */
- tmp = dz_in (info, DZ_CSR);
- tmp |= (DZ_RIE | DZ_TIE | DZ_MSE);
- dz_out (info, DZ_CSR, tmp);
-
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- /* set up the speed */
- change_speed (info);
-
- /* clear the line transmitter buffer
- I can't figure out why I need to do this - but
- its necessary - in order for the console portion
- and the interrupt portion to live happily side by side.
- */
-
- /* clear the line transmitter buffer
- I can't figure out why I need to do this - but
- its necessary - in order for the console portion
- and the interrupt portion to live happily side by side.
- */
-
- info->is_initialized = 1;
-
- restore_flags (flags);
- return 0;
+ save_and_cli(flags);
+
+ if (!info->port) {
+ if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
+ restore_flags(flags);
+ return -ENODEV;
+ }
+
+ if (!info->xmit_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+ restore_flags (flags);
+ return -ENOMEM;
+ }
+ info->xmit_buf = (unsigned char *)page;
+ }
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ /* enable the interrupt and the scanning */
+ tmp = dz_in(info, DZ_CSR);
+ tmp |= (DZ_RIE | DZ_TIE | DZ_MSE);
+ dz_out(info, DZ_CSR, tmp);
+
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ change_speed(info); /* set up the speed */
+
+ /*
+ * Clear the line transmitter buffer I can't figure out why I need to
+ * do this - but its necessary - in order for the console portion and
+ * the interrupt portion to live happily side by side.
+ */
+
+ info->is_initialized = 1;
+
+ restore_flags(flags);
+
+ return 0;
}
/*
@@ -511,38 +512,38 @@ static int startup (struct dz_serial *info)
*/
static void shutdown (struct dz_serial *info)
{
- unsigned long flags;
- unsigned short tmp;
+ unsigned long flags;
+ unsigned short tmp;
- if (!info->is_initialized) return;
+ if (!info->is_initialized)
+ return;
- save_flags (flags);
- cli ();
+ save_and_cli(flags);
- dz_stop (info->tty);
+ dz_stop (info->tty);
+ info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */
+ dz_out(info, DZ_LPR, info->cflags);
+ if (info->xmit_buf) { /* free Tx buffer */
+ free_page((unsigned long)info->xmit_buf);
+ info->xmit_buf = 0;
+ }
- info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */
- dz_out (info, DZ_LPR, info->cflags);
-
- if (info->xmit_buf) { /* free Tx buffer */
- free_page ((unsigned long)info->xmit_buf);
- info->xmit_buf = 0;
- }
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ tmp = dz_in(info, DZ_TCR);
+ if (tmp & DZ_MODEM_DTR) {
+ tmp &= ~DZ_MODEM_DTR;
+ dz_out(info, DZ_TCR, tmp);
+ }
+ }
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- tmp = dz_in (info, DZ_TCR);
- if (tmp & DZ_MODEM_DTR) {
- tmp &= ~DZ_MODEM_DTR;
- dz_out (info, DZ_TCR, tmp);
- }
- }
+ if (info->tty)
+ set_bit (TTY_IO_ERROR, &info->tty->flags);
- if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
+ info->is_initialized = 0;
- info->is_initialized = 0;
- restore_flags (flags);
+ restore_flags (flags);
}
/*
@@ -554,65 +555,104 @@ static void shutdown (struct dz_serial *info)
*/
static void change_speed (struct dz_serial *info)
{
- unsigned long flags;
- unsigned cflag;
- int baud;
+ unsigned long flags;
+ unsigned cflag;
+ int baud;
- if (!info->tty || !info->tty->termios) return;
+ if (!info->tty || !info->tty->termios)
+ return;
- save_flags (flags);
- cli ();
+ save_and_cli(flags);
- info->cflags = info->line;
+ info->cflags = info->line;
+
+ cflag = info->tty->termios->c_cflag;
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->cflags |= DZ_CS5;
+ break;
+ case CS6:
+ info->cflags |= DZ_CS6;
+ break;
+ case CS7:
+ info->cflags |= DZ_CS7;
+ break;
+ case CS8:
+ default:
+ info->cflags |= DZ_CS8;
+ }
- cflag = info->tty->termios->c_cflag;
+ if (cflag & CSTOPB)
+ info->cflags |= DZ_CSTOPB;
+ if (cflag & PARENB)
+ info->cflags |= DZ_PARENB;
+ if (cflag & PARODD)
+ info->cflags |= DZ_PARODD;
+
+ baud = tty_get_baud_rate(info->tty);
+ switch (baud) {
+ case 50:
+ info->cflags |= DZ_B50;
+ break;
+ case 75:
+ info->cflags |= DZ_B75;
+ break;
+ case 110:
+ info->cflags |= DZ_B110;
+ break;
+ case 134:
+ info->cflags |= DZ_B134;
+ break;
+ case 150:
+ info->cflags |= DZ_B150;
+ break;
+ case 300:
+ info->cflags |= DZ_B300;
+ break;
+ case 600:
+ info->cflags |= DZ_B600;
+ break;
+ case 1200:
+ info->cflags |= DZ_B1200;
+ break;
+ case 1800:
+ info->cflags |= DZ_B1800;
+ break;
+ case 2000:
+ info->cflags |= DZ_B2000;
+ break;
+ case 2400:
+ info->cflags |= DZ_B2400;
+ break;
+ case 3600:
+ info->cflags |= DZ_B3600;
+ break;
+ case 4800:
+ info->cflags |= DZ_B4800;
+ break;
+ case 7200:
+ info->cflags |= DZ_B7200;
+ break;
+ case 9600:
+ default:
+ info->cflags |= DZ_B9600;
+ }
- switch (cflag & CSIZE) {
- case CS5: info->cflags |= DZ_CS5; break;
- case CS6: info->cflags |= DZ_CS6; break;
- case CS7: info->cflags |= DZ_CS7; break;
- case CS8:
- default: info->cflags |= DZ_CS8;
- }
+ info->cflags |= DZ_RXENAB;
+ dz_out(info, DZ_LPR, info->cflags);
- if (cflag & CSTOPB) info->cflags |= DZ_CSTOPB;
- if (cflag & PARENB) info->cflags |= DZ_PARENB;
- if (cflag & PARODD) info->cflags |= DZ_PARODD;
-
- baud = tty_get_baud_rate (info->tty);
- switch (baud) {
- case 50 : info->cflags |= DZ_B50; break;
- case 75 : info->cflags |= DZ_B75; break;
- case 110 : info->cflags |= DZ_B110; break;
- case 134 : info->cflags |= DZ_B134; break;
- case 150 : info->cflags |= DZ_B150; break;
- case 300 : info->cflags |= DZ_B300; break;
- case 600 : info->cflags |= DZ_B600; break;
- case 1200: info->cflags |= DZ_B1200; break;
- case 1800: info->cflags |= DZ_B1800; break;
- case 2000: info->cflags |= DZ_B2000; break;
- case 2400: info->cflags |= DZ_B2400; break;
- case 3600: info->cflags |= DZ_B3600; break;
- case 4800: info->cflags |= DZ_B4800; break;
- case 7200: info->cflags |= DZ_B7200; break;
- case 9600:
- default : info->cflags |= DZ_B9600;
- }
-
- info->cflags |= DZ_RXENAB;
- dz_out (info, DZ_LPR, info->cflags);
-
- /* setup accept flag */
- info->read_status_mask = DZ_OERR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= (DZ_FERR | DZ_PERR);
+ /* setup accept flag */
+ info->read_status_mask = DZ_OERR;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= (DZ_FERR | DZ_PERR);
- /* characters to ignore */
- info->ignore_status_mask = 0;
- if (I_IGNPAR(info->tty))
- info->ignore_status_mask |= (DZ_FERR | DZ_PERR);
+ /* characters to ignore */
+ info->ignore_status_mask = 0;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= (DZ_FERR | DZ_PERR);
- restore_flags (flags);
+ restore_flags(flags);
}
/*
@@ -624,18 +664,16 @@ static void change_speed (struct dz_serial *info)
*/
static void dz_flush_chars (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- unsigned long flags;
-
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf)
- return;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
- save_flags (flags);
- cli ();
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !info->xmit_buf)
+ return;
- dz_start (info->tty);
-
- restore_flags (flags);
+ save_and_cli(flags);
+ dz_start (info->tty);
+ restore_flags(flags);
}
@@ -646,83 +684,81 @@ static void dz_flush_chars (struct tty_struct *tty)
* main output routine.
* -------------------------------------------------------------------
*/
-static int dz_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+static int dz_write (struct tty_struct *tty, int from_user,
+ const unsigned char *buf, int count)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- unsigned long flags;
- int c, ret = 0;
-
- if (!tty ) return ret;
- if (!info->xmit_buf) return ret;
- if (!tmp_buf) tmp_buf = tmp_buffer;
-
-
-
- if (from_user) {
-
- down (&tmp_buf_sem);
- while (1) {
- c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
- if (c <= 0) break;
-
- c -= copy_from_user (tmp_buf, buf, c);
- if (!c) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- save_flags (flags);
- cli ();
-
- c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1));
- info->xmit_cnt += c;
-
- restore_flags(flags);
-
- buf += c;
- count -= c;
- ret += c;
- }
-
- up (&tmp_buf_sem);
- } else {
-
-
- while (1) {
- save_flags (flags);
- cli ();
-
- c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
- restore_flags (flags);
- break;
- }
- memcpy (info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1));
- info->xmit_cnt += c;
-
- restore_flags (flags);
-
- buf += c;
- count -= c;
- ret += c;
- }
- }
-
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
+ int c, ret = 0;
+
+ if (!tty )
+ return ret;
+ if (!info->xmit_buf)
+ return ret;
+ if (!tmp_buf)
+ tmp_buf = tmp_buffer;
+
+ if (from_user) {
+ down (&tmp_buf_sem);
+ while (1) {
+ c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1,
+ DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user (tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+
+ save_and_cli(flags);
+
+ c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1,
+ DZ_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) &
+ (DZ_XMIT_SIZE - 1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ save_and_cli(flags);
+
+ c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1,
+ DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags (flags);
+ break;
+ }
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = ((info->xmit_head + c) &
+ (DZ_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
- if (info->xmit_cnt)
- {
- if (!tty->stopped)
- {
- if (!tty->hw_stopped)
- {
- dz_start (info->tty);
- }
+ if (info->xmit_cnt) {
+ if (!tty->stopped) {
+ if (!tty->hw_stopped) {
+ dz_start (info->tty);
+ }
+ }
}
- }
- return ret;
+
+ return ret;
}
/*
@@ -734,12 +770,14 @@ static int dz_write (struct tty_struct *tty, int from_user, const unsigned char
*/
static int dz_write_room (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- int ret;
-
- ret = DZ_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0) ret = 0;
- return ret;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ int ret;
+
+ ret = DZ_XMIT_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+
+ return ret;
}
/*
@@ -751,9 +789,9 @@ static int dz_write_room (struct tty_struct *tty)
*/
static int dz_chars_in_buffer (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- return info->xmit_cnt;
+ return info->xmit_cnt;
}
/*
@@ -765,16 +803,17 @@ static int dz_chars_in_buffer (struct tty_struct *tty)
*/
static void dz_flush_buffer (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- cli ();
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- sti ();
+ cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ sti();
- wake_up_interruptible (&tty->write_wait);
+ wake_up_interruptible (&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ tty->ldisc.write_wakeup(tty);
}
/*
@@ -787,31 +826,32 @@ static void dz_flush_buffer (struct tty_struct *tty)
*/
static void dz_throttle (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
+ if (I_IXOFF(tty))
+ info->x_char = STOP_CHAR(tty);
}
static void dz_unthrottle (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ info->x_char = START_CHAR(tty);
+ }
}
static void dz_send_xchar (struct tty_struct *tty, char ch)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- info->x_char = ch;
+ info->x_char = ch;
- if (ch) dz_start (info->tty);
+ if (ch)
+ dz_start(info->tty);
}
/*
@@ -819,59 +859,62 @@ static void dz_send_xchar (struct tty_struct *tty, char ch)
* rs_ioctl () and friends
* ------------------------------------------------------------
*/
-static int get_serial_info (struct dz_serial *info, struct serial_struct *retinfo)
+static int get_serial_info(struct dz_serial *info,
+ struct serial_struct *retinfo)
{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
-
- memset (&tmp, 0, sizeof(tmp));
-
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = SERIAL;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
+ struct serial_struct tmp;
- return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+ if (!retinfo)
+ return -EFAULT;
+
+ memset (&tmp, 0, sizeof(tmp));
+
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->port;
+ tmp.irq = SERIAL;
+ tmp.flags = info->flags;
+ tmp.baud_base = info->baud_base;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
-static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info)
+static int set_serial_info (struct dz_serial *info,
+ struct serial_struct *new_info)
{
- struct serial_struct new_serial;
- struct dz_serial old_info;
- int retval = 0;
+ struct serial_struct new_serial;
+ struct dz_serial old_info;
+ int retval = 0;
- if (!new_info)
- return -EFAULT;
+ if (!new_info)
+ return -EFAULT;
- if(copy_from_user (&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
-
- old_info = *info;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
+ old_info = *info;
- if (info->count > 1)
- return -EBUSY;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
- retval = startup (info);
- return retval;
+ info->baud_base = new_serial.baud_base;
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+
+ retval = startup(info);
+
+ return retval;
}
/*
@@ -886,9 +929,9 @@ static int set_serial_info (struct dz_serial *info, struct serial_struct *new_in
*/
static int get_lsr_info (struct dz_serial *info, unsigned int *value)
{
- unsigned short status = dz_in (info, DZ_LPR);
+ unsigned short status = dz_in (info, DZ_LPR);
- return put_user (status, value);
+ return put_user (status, value);
}
/*
@@ -896,106 +939,112 @@ static int get_lsr_info (struct dz_serial *info, unsigned int *value)
*/
static void send_break (struct dz_serial *info, int duration)
{
- unsigned long flags;
- unsigned short tmp, mask;
+ unsigned long flags;
+ unsigned short tmp, mask;
- if (!info->port)
- return;
+ if (!info->port)
+ return;
- mask = 1 << info->line;
- tmp = dz_in (info, DZ_TCR);
- tmp |= mask;
+ mask = 1 << info->line;
+ tmp = dz_in (info, DZ_TCR);
+ tmp |= mask;
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
- save_flags (flags);
- cli();
-
- dz_out (info, DZ_TCR, tmp);
-
- schedule_timeout(duration);
-
- tmp &= ~mask;
- dz_out (info, DZ_TCR, tmp);
-
- restore_flags (flags);
+ save_and_cli(flags);
+ dz_out(info, DZ_TCR, tmp);
+ schedule_timeout(duration);
+ tmp &= ~mask;
+ dz_out(info, DZ_TCR, tmp);
+ restore_flags(flags);
}
-static int dz_ioctl (struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int dz_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct dz_serial * info = (struct dz_serial *)tty->driver_data;
- int retval;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change (tty);
- if (retval)
- return retval;
- tty_wait_until_sent (tty, 0);
- if (!arg)
- send_break (info, HZ/4); /* 1/4 second */
- return 0;
-
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change (tty);
- if (retval)
- return retval;
- tty_wait_until_sent (tty, 0);
- send_break (info, arg ? arg*(HZ/10) : HZ/4);
- return 0;
-
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
-
- case TIOCSSOFTCAR:
- if (get_user (arg, (unsigned long *)arg))
- return -EFAULT;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return 0;
-
- case TIOCGSERIAL:
- return get_serial_info (info, (struct serial_struct *)arg);
-
- case TIOCSSERIAL:
- return set_serial_info (info, (struct serial_struct *) arg);
-
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info (info, (unsigned int *)arg);
-
- case TIOCSERGSTRUCT:
- return copy_to_user((struct dz_serial *)arg, info,
- sizeof(struct dz_serial)) ? -EFAULT : 0;
-
- default:
- return -ENOIOCTLCMD;
- }
+ int error;
+ struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+ int retval;
+
+ if (cmd != TIOCGSERIAL && cmd != TIOCSSERIAL &&
+ cmd != TIOCSERCONFIG && cmd != TIOCSERGWILD &&
+ cmd != TIOCSERSWILD && cmd != TIOCSERGSTRUCT) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
- return 0;
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ send_break(info, HZ/4); /* 1/4 second */
+ return 0;
+
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+ error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long));
+ if (error)
+ return error;
+ put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
+ return 0;
+
+ case TIOCSSOFTCAR:
+ if (get_user (arg, (unsigned long *)arg))
+ return -EFAULT;
+
+ tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0);
+ return 0;
+
+ case TIOCGSERIAL:
+ error = verify_area(VERIFY_WRITE, (void *)arg,
+ sizeof(struct serial_struct));
+ if (error)
+ return error;
+ return get_serial_info(info, (struct serial_struct *)arg);
+
+ case TIOCSSERIAL:
+ return set_serial_info(info, (struct serial_struct *) arg);
+
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info (info, (unsigned int *)arg);
+
+ case TIOCSERGSTRUCT:
+ return copy_to_user((struct dz_serial *)arg, info,
+ sizeof(struct dz_serial)) ? -EFAULT : 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
}
static void dz_set_termios (struct tty_struct *tty,
struct termios *old_termios)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
- change_speed (info);
+ change_speed (info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- dz_start (tty);
- }
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ dz_start(tty);
+ }
}
/*
@@ -1007,97 +1056,95 @@ static void dz_set_termios (struct tty_struct *tty,
* the transmit enable and receive enable flags.
* ------------------------------------------------------------
*/
-static void dz_close (struct tty_struct *tty, struct file *filp)
+static void dz_close(struct tty_struct *tty, struct file *filp)
{
- struct dz_serial * info = (struct dz_serial *)tty->driver_data;
- unsigned long flags;
+ struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+ unsigned long flags;
- if (!info) return;
-
- save_flags (flags);
- cli();
-
- if (tty_hung_up_p (filp)) {
- restore_flags (flags);
- return;
- }
-
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("dz_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
-
- if (--info->count < 0) {
- printk("ds_close: bad serial port count for ttys%d: %d\n",
- info->line, info->count);
- info->count = 0;
- }
-
- if (info->count) {
- restore_flags (flags);
- return;
- }
- info->flags |= DZ_CLOSING;
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & DZ_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & DZ_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
-
- if (info->closing_wait != DZ_CLOSING_WAIT_NONE)
- tty_wait_until_sent (tty, info->closing_wait);
-
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts.
- */
-
- shutdown (info);
-
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer (tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
-
- if (tty->ldisc.num != ldiscs[N_TTY].num) {
- if (tty->ldisc.close)
- (tty->ldisc.close)(tty);
- tty->ldisc = ldiscs[N_TTY];
- tty->termios->c_line = N_TTY;
- if (tty->ldisc.open)
- (tty->ldisc.open)(tty);
- }
- if (info->blocked_open) {
- if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(info->close_delay);
- }
- wake_up_interruptible (&info->open_wait);
- }
-
- info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING);
- wake_up_interruptible (&info->close_wait);
-
- restore_flags (flags);
+ if (!info)
+ return;
+
+ save_and_cli(flags);
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty structure
+ * will be freed. Info->count should always be one in these
+ * conditions. If it's greater than one, we've got real
+ * problems, since it means the serial port won't be shutdown.
+ */
+ printk("dz_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+
+ if (--info->count < 0) {
+ printk("ds_close: bad serial port count for ttyS%02d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+
+ if (info->count) {
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= DZ_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & DZ_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & DZ_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify the line
+ * discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+
+ if (info->closing_wait != DZ_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+
+ /*
+ * At this point we stop accepting input. To do this, we disable the
+ * receive line status interrupts.
+ */
+ shutdown(info);
+
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer (tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+
+ if (tty->ldisc.num != ldiscs[N_TTY].num) {
+ if (tty->ldisc.close)
+ tty->ldisc.close(tty);
+ tty->ldisc = ldiscs[N_TTY];
+ tty->termios->c_line = N_TTY;
+ if (tty->ldisc.open)
+ tty->ldisc.open(tty);
+ }
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+
+ info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+
+ restore_flags(flags);
}
/*
@@ -1105,15 +1152,15 @@ static void dz_close (struct tty_struct *tty, struct file *filp)
*/
static void dz_hangup (struct tty_struct *tty)
{
- struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+ struct dz_serial *info = (struct dz_serial *) tty->driver_data;
- dz_flush_buffer (tty);
- shutdown (info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE);
- info->tty = 0;
- wake_up_interruptible (&info->open_wait);
+ dz_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
}
/*
@@ -1121,101 +1168,103 @@ static void dz_hangup (struct tty_struct *tty)
* rs_open() and friends
* ------------------------------------------------------------
*/
-static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz_serial *info)
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct dz_serial *info)
{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & DZ_CLOSING) {
- interruptible_sleep_on (&info->close_wait);
- return -EAGAIN;
- }
-
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
- if (info->flags & DZ_NORMAL_ACTIVE)
- return -EBUSY;
+ DECLARE_WAITQUEUE(wait, current);
+ int retval;
+ int do_clocal = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & DZ_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ return -EAGAIN;
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & DZ_NORMAL_ACTIVE)
+ return -EBUSY;
- if ((info->flags & DZ_CALLOUT_ACTIVE) &&
- (info->flags & DZ_SESSION_LOCKOUT) &&
- (info->session != current->session))
- return -EBUSY;
+ if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+ (info->flags & DZ_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
- if ((info->flags & DZ_CALLOUT_ACTIVE) &&
- (info->flags & DZ_PGRP_LOCKOUT) &&
- (info->pgrp != current->pgrp))
- return -EBUSY;
- info->flags |= DZ_CALLOUT_ACTIVE;
- return 0;
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- if (info->flags & DZ_CALLOUT_ACTIVE)
- return -EBUSY;
- info->flags |= DZ_NORMAL_ACTIVE;
- return 0;
- }
-
- if (info->flags & DZ_CALLOUT_ACTIVE) {
- if (info->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * dz_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue (&info->open_wait, &wait);
-
- info->count--;
- info->blocked_open++;
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p (filp) || !(info->is_initialized)) {
- retval = -EAGAIN;
- break;
- }
- if (!(info->flags & DZ_CALLOUT_ACTIVE) &&
- !(info->flags & DZ_CLOSING) && do_clocal)
- break;
- if (signal_pending (current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
+ if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+ (info->flags & DZ_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+
+ info->flags |= DZ_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled, then make
+ * the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & DZ_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= DZ_NORMAL_ACTIVE;
+
+ return 0;
+ }
+
+ if (info->flags & DZ_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become free
+ * (i.e., not in use by the callout). While we are in this loop,
+ * info->count is dropped by one, so that dz_close() knows when to free
+ * things. We restore it upon exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+
+ info->count--;
+ info->blocked_open++;
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p (filp) || !(info->is_initialized)) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (!(info->flags & DZ_CALLOUT_ACTIVE) &&
+ !(info->flags & DZ_CLOSING) && do_clocal)
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
- current->state = TASK_RUNNING;
- remove_wait_queue (&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-
- if (retval)
- return retval;
- info->flags |= DZ_NORMAL_ACTIVE;
- return 0;
-}
+ current->state = TASK_RUNNING;
+ remove_wait_queue (&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ info->count++;
+ info->blocked_open--;
+
+ if (retval)
+ return retval;
+ info->flags |= DZ_NORMAL_ACTIVE;
+ return 0;
+}
/*
* This routine is called whenever a serial port is opened. It
@@ -1224,201 +1273,220 @@ static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz
*/
static int dz_open (struct tty_struct *tty, struct file *filp)
{
- struct dz_serial *info;
- int retval, line;
-
- line = MINOR(tty->device) - tty->driver.minor_start;
-
- /* The dz lines for the mouse/keyboard must be
- * opened using their respective drivers.
- */
- if ((line < 0) || (line >= DZ_NB_PORT))
- return -ENODEV;
+ struct dz_serial *info;
+ int retval, line;
- if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
- return -ENODEV;
+ line = MINOR(tty->device) - tty->driver.minor_start;
- info = lines[line];
- info->count++;
-
- tty->driver_data = info;
- info->tty = tty;
-
- /*
- * Start up serial port
- */
- retval = startup (info);
- if (retval)
- return retval;
+ /*
+ * The dz lines for the mouse/keyboard must be opened using their
+ * respective drivers.
+ */
+ if ((line < 0) || (line >= DZ_NB_PORT))
+ return -ENODEV;
+ if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
+ return -ENODEV;
+ info = lines[line];
+ info->count++;
- retval = block_til_ready (tty, filp, info);
- if (retval)
- return retval;
+ tty->driver_data = info;
+ info->tty = tty;
- if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- change_speed (info);
+ /*
+ * Start up serial port
+ */
+ retval = startup (info);
+ if (retval)
+ return retval;
+
+ retval = block_til_ready (tty, filp, info);
+ if (retval)
+ return retval;
+
+ if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+ }
- }
+ info->session = current->session;
+ info->pgrp = current->pgrp;
- info->session = current->session;
- info->pgrp = current->pgrp;
- return 0;
+ return 0;
}
static void show_serial_version (void)
{
- printk("%s%s\n", dz_name, dz_version);
+ printk("%s%s\n", dz_name, dz_version);
}
int __init dz_init(void)
{
- int i;
- unsigned long flags;
- struct dz_serial *info;
-
- /* Setup base handler, and timer table. */
- init_bh (SERIAL_BH, do_serial_bh);
-
- show_serial_version ();
-
- memset(&serial_driver, 0, sizeof(struct tty_driver));
- serial_driver.magic = TTY_DRIVER_MAGIC;
- serial_driver.name = "ttyS";
- serial_driver.major = TTY_MAJOR;
- serial_driver.minor_start = 64;
- serial_driver.num = DZ_NB_PORT;
- serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver.subtype = SERIAL_TYPE_NORMAL;
- serial_driver.init_termios = tty_std_termios;
-
- serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver.flags = TTY_DRIVER_REAL_RAW;
- serial_driver.refcount = &serial_refcount;
- serial_driver.table = serial_table;
- serial_driver.termios = serial_termios;
- serial_driver.termios_locked = serial_termios_locked;
-
- serial_driver.open = dz_open;
- serial_driver.close = dz_close;
- serial_driver.write = dz_write;
- serial_driver.flush_chars = dz_flush_chars;
- serial_driver.write_room = dz_write_room;
- serial_driver.chars_in_buffer = dz_chars_in_buffer;
- serial_driver.flush_buffer = dz_flush_buffer;
- serial_driver.ioctl = dz_ioctl;
- serial_driver.throttle = dz_throttle;
- serial_driver.unthrottle = dz_unthrottle;
- serial_driver.send_xchar = dz_send_xchar;
- serial_driver.set_termios = dz_set_termios;
- serial_driver.stop = dz_stop;
- serial_driver.start = dz_start;
- serial_driver.hangup = dz_hangup;
-
- /*
- * The callout device is just like normal device except for
- * major number and the subtype code.
- */
- callout_driver = serial_driver;
- callout_driver.name = "cua";
- callout_driver.major = TTYAUX_MAJOR;
- callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
- if (tty_register_driver (&serial_driver))
- panic("Couldn't register serial driver\n");
- if (tty_register_driver (&callout_driver))
- panic("Couldn't register callout driver\n");
- save_flags(flags); cli();
-
- for (i=0; i < DZ_NB_PORT; i++)
- {
- info = &multi[i];
- lines[i] = info;
- info->magic = SERIAL_MAGIC;
-
- if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
- info->port = (unsigned long) KN01_DZ11_BASE;
- else
- info->port = (unsigned long) KN02_DZ11_BASE;
-
- info->line = i;
- info->tty = 0;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
- info->tqueue_hangup.routine = do_serial_hangup;
- info->tqueue_hangup.data = info;
- info->callout_termios = callout_driver.init_termios;
- info->normal_termios = serial_driver.init_termios;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
-
- /* If we are pointing to address zero then punt - not correctly
- set up in setup.c to handle this. */
- if (! info->port)
- return 0;
-
- printk("ttyS%02d at 0x%04x (irq = %d)\n", info->line, info->port, SERIAL);
- }
-
- /* reset the chip */
+ int i, flags;
+ struct dz_serial *info;
+
+ /* Setup base handler, and timer table. */
+ init_bh(SERIAL_BH, do_serial_bh);
+
+ show_serial_version();
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+ serial_driver.name = "ttyS";
+#else
+ serial_driver.name = "tts/%d";
+#endif
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = DZ_NB_PORT;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+
+ serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
+ CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = dz_open;
+ serial_driver.close = dz_close;
+ serial_driver.write = dz_write;
+ serial_driver.flush_chars = dz_flush_chars;
+ serial_driver.write_room = dz_write_room;
+ serial_driver.chars_in_buffer = dz_chars_in_buffer;
+ serial_driver.flush_buffer = dz_flush_buffer;
+ serial_driver.ioctl = dz_ioctl;
+ serial_driver.throttle = dz_throttle;
+ serial_driver.unthrottle = dz_unthrottle;
+ serial_driver.send_xchar = dz_send_xchar;
+ serial_driver.set_termios = dz_set_termios;
+ serial_driver.stop = dz_stop;
+ serial_driver.start = dz_start;
+ serial_driver.hangup = dz_hangup;
+
+ /*
+ * The callout device is just like normal device except for major
+ * number and the subtype code.
+ */
+ callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+ callout_driver.name = "cua";
+#else
+ callout_driver.name = "cua/%d";
+#endif
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+ if (tty_register_driver (&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver (&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ save_flags(flags); cli();
+ for (i=0; i < DZ_NB_PORT; i++) {
+ info = &multi[i];
+ lines[i] = info;
+ info->magic = SERIAL_MAGIC;
+
+ if ((mips_machtype == MACH_DS23100) ||
+ (mips_machtype == MACH_DS5100))
+ info->port = (unsigned long) KN01_DZ11_BASE;
+ else
+ info->port = (unsigned long) KN02_DZ11_BASE;
+
+ info->line = i;
+ info->tty = 0;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->tqueue_hangup.routine = do_serial_hangup;
+ info->tqueue_hangup.data = info;
+ info->callout_termios = callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+
+ /*
+ * If we are pointing to address zero then punt - not correctly
+ * set up in setup.c to handle this.
+ */
+ if (! info->port)
+ return 0;
+
+ printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line,
+ info->port, SERIAL);
+
+ tty_register_devfs(&serial_driver, 0,
+ serial_driver.minor_start + info->line);
+ tty_register_devfs(&callout_driver, 0,
+ callout_driver.minor_start + info->line);
+ }
+
+ /* Reset the chip */
#ifndef CONFIG_SERIAL_CONSOLE
- dz_out(info, DZ_CSR, DZ_CLR);
- while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR) ;
- wbflush();
+ {
+ int tmp;
+ dz_out(info, DZ_CSR, DZ_CLR);
+ while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR);
+ wbflush();
- /* enable scanning */
- dz_out(info, DZ_CSR, DZ_MSE);
+ /* Enable scanning */
+ dz_out(info, DZ_CSR, DZ_MSE);
+ }
#endif
- /* order matters here... the trick is that flags
- is updated... in request_irq - to immediatedly obliterate
- it is unwise. */
- restore_flags(flags);
-
+ /*
+ * Order matters here... the trick is that flags is updated... in
+ * request_irq - to immediatedly obliterate it is unwise.
+ */
+ restore_flags(flags);
- if (request_irq (SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0]))
- panic ("Unable to register DZ interrupt\n");
+ if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0]))
+ panic("Unable to register DZ interrupt\n");
- return 0;
+ return 0;
}
#ifdef CONFIG_SERIAL_CONSOLE
static void dz_console_put_char (unsigned char ch)
{
- unsigned long flags;
- int loops = 2500;
- unsigned short tmp = ch;
- /* this code sends stuff out to serial device - spinning its
- wheels and waiting. */
+ unsigned long flags;
+ int loops = 2500;
+ unsigned short tmp = ch;
+ /*
+ * this code sends stuff out to serial device - spinning its wheels and
+ * waiting.
+ */
- /* force the issue - point it at lines[3]*/
- dz_console=&multi[CONSOLE_LINE];
+ /* force the issue - point it at lines[3]*/
+ dz_console = &multi[CONSOLE_LINE];
- save_flags(flags);
- cli();
-
+ save_and_cli(flags);
- /* spin our wheels */
- while (((dz_in(dz_console,DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--)
- ;
+ /* spin our wheels */
+ while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--)
+ ;
- /* Actually transmit the character. */
- dz_out (dz_console, DZ_TDR, tmp);
+ /* Actually transmit the character. */
+ dz_out(dz_console, DZ_TDR, tmp);
- restore_flags(flags);
+ restore_flags(flags);
}
+
/*
* -------------------------------------------------------------------
* dz_console_print ()
@@ -1432,19 +1500,18 @@ static void dz_console_print (struct console *cons,
unsigned int count)
{
#ifdef DEBUG_DZ
- prom_printf((char *)str);
+ prom_printf((char *)str);
#endif
- while (count--)
- {
- if (*str == '\n')
- dz_console_put_char ('\r');
- dz_console_put_char (*str++);
- }
+ while (count--) {
+ if (*str == '\n')
+ dz_console_put_char('\r');
+ dz_console_put_char(*str++);
+ }
}
static int dz_console_wait_key(struct console *co)
{
- return 0;
+ return 0;
}
static kdev_t dz_console_device(struct console *c)
@@ -1454,17 +1521,17 @@ static kdev_t dz_console_device(struct console *c)
static int __init dz_console_setup(struct console *co, char *options)
{
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- char *s;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
unsigned short mask,tmp;
if (options) {
baud = simple_strtoul(options, NULL, 10);
s = options;
- while(*s >= '0' && *s <= '9')
+ while (*s >= '0' && *s <= '9')
s++;
if (*s)
parity = *s++;
@@ -1473,9 +1540,9 @@ static int __init dz_console_setup(struct console *co, char *options)
}
/*
- * Now construct a cflag setting.
+ * Now construct a cflag setting.
*/
- switch(baud) {
+ switch (baud) {
case 1200:
cflag |= DZ_B1200;
break;
@@ -1490,7 +1557,7 @@ static int __init dz_console_setup(struct console *co, char *options)
cflag |= DZ_B9600;
break;
}
- switch(bits) {
+ switch (bits) {
case 7:
cflag |= DZ_CS7;
break;
@@ -1499,11 +1566,13 @@ static int __init dz_console_setup(struct console *co, char *options)
cflag |= DZ_CS8;
break;
}
- switch(parity) {
- case 'o': case 'O':
+ switch (parity) {
+ case 'o':
+ case 'O':
cflag |= DZ_PARODD;
break;
- case 'e': case 'E':
+ case 'e':
+ case 'E':
cflag |= DZ_PARENB;
break;
}
@@ -1511,45 +1580,44 @@ static int __init dz_console_setup(struct console *co, char *options)
/* TOFIX: force to console line */
dz_console = &multi[CONSOLE_LINE];
- if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
- dz_console->port = KN01_DZ11_BASE;
- else
- dz_console->port = KN02_DZ11_BASE;
+ if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
+ dz_console->port = KN01_DZ11_BASE;
+ else
+ dz_console->port = KN02_DZ11_BASE;
dz_console->line = CONSOLE_LINE;
dz_out(dz_console, DZ_CSR, DZ_CLR);
while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
- ;
+ ;
/* enable scanning */
dz_out(dz_console, DZ_CSR, DZ_MSE);
- /* Set up flags... */
+ /* Set up flags... */
dz_console->cflags = 0;
dz_console->cflags |= DZ_B9600;
dz_console->cflags |= DZ_CS8;
dz_console->cflags |= DZ_PARENB;
- dz_out (dz_console, DZ_LPR, dz_console->cflags);
+ dz_out(dz_console, DZ_LPR, dz_console->cflags);
mask = 1 << dz_console->line;
- tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */
+ tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */
if (!(tmp & mask)) {
- tmp |= mask; /* set the TX flag */
- dz_out (dz_console, DZ_TCR, tmp);
+ tmp |= mask; /* set the TX flag */
+ dz_out (dz_console, DZ_TCR, tmp);
}
-
return 0;
}
static struct console dz_sercons = {
- name: "ttyS",
- write: dz_console_print,
- device: dz_console_device,
- wait_key: dz_console_wait_key,
- setup: dz_console_setup,
- flags: CON_CONSDEV | CON_PRINTBUFFER,
- index: CONSOLE_LINE,
+ name: "ttyS",
+ write: dz_console_print,
+ device: dz_console_device,
+ wait_key: dz_console_wait_key,
+ setup: dz_console_setup,
+ flags: CON_CONSDEV | CON_PRINTBUFFER,
+ index: CONSOLE_LINE,
};
void __init dz_serial_console_init(void)
@@ -1559,3 +1627,4 @@ void __init dz_serial_console_init(void)
#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 2a4433adda4a..3d7d692a52ec 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -610,9 +610,7 @@ static void pc_close(struct tty_struct * tty, struct file * filp)
ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
-#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif
restore_flags(flags);
@@ -700,10 +698,8 @@ static void pc_hangup(struct tty_struct *tty)
shutdown(ch);
-#ifdef MODULE
if (ch->count)
MOD_DEC_USE_COUNT;
-#endif /* MODULE */
ch->tty = NULL;
@@ -1397,12 +1393,9 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
return(-ENODEV);
}
-#ifdef MODULE
MOD_INC_USE_COUNT;
-#endif
-
ch = &digi_channels[line];
boardnum = ch->boardnum;
@@ -4106,3 +4099,5 @@ int __init init_PCI (void)
} /* End init_PCI */
#endif /* ENABLE_PCI */
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
new file mode 100644
index 000000000000..1029ba80ed87
--- /dev/null
+++ b/drivers/char/ite_gpio.c
@@ -0,0 +1,430 @@
+/*
+ * FILE NAME ite_gpio.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ * API for ITE GPIO device.
+ * Driver for ITE GPIO device.
+ *
+ * Author: MontaVista Software, Inc. <source@mvista.com>
+ * Hai-Pao Fan <haipao@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/addrspace.h>
+#include <asm/it8172/it8172_int.h>
+#include <linux/sched.h>
+#include <linux/ite_gpio.h>
+
+#define ite_gpio_base 0x14013800
+
+#define ITE_GPADR (*(volatile __u8 *)(0x14013800 + KSEG1))
+#define ITE_GPBDR (*(volatile __u8 *)(0x14013808 + KSEG1))
+#define ITE_GPCDR (*(volatile __u8 *)(0x14013810 + KSEG1))
+#define ITE_GPACR (*(volatile __u16 *)(0x14013802 + KSEG1))
+#define ITE_GPBCR (*(volatile __u16 *)(0x1401380a + KSEG1))
+#define ITE_GPCCR (*(volatile __u16 *)(0x14013812 + KSEG1))
+#define ITE_GPAICR (*(volatile __u16 *)(0x14013804 + KSEG1))
+#define ITE_GPBICR (*(volatile __u16 *)(0x1401380c + KSEG1))
+#define ITE_GPCICR (*(volatile __u16 *)(0x14013814 + KSEG1))
+#define ITE_GPAISR (*(volatile __u8 *)(0x14013806 + KSEG1))
+#define ITE_GPBISR (*(volatile __u8 *)(0x1401380e + KSEG1))
+#define ITE_GPCISR (*(volatile __u8 *)(0x14013816 + KSEG1))
+#define ITE_GCR (*(volatile __u8 *)(0x14013818 + KSEG1))
+
+#define MAX_GPIO_LINE 21
+static int ite_gpio_irq=IT8172_GPIO_IRQ;
+
+static long ite_irq_counter[MAX_GPIO_LINE];
+wait_queue_head_t ite_gpio_wait[MAX_GPIO_LINE];
+static int ite_gpio_irq_pending[MAX_GPIO_LINE];
+
+static int ite_gpio_debug=0;
+#define DEB(x) if (ite_gpio_debug>=1) x
+
+int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data)
+{
+ DEB(printk("ite_gpio_in mask=0x%x\n",mask));
+
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ ITE_GPACR = (__u16)mask; /* 0xffff */
+ *data = ITE_GPADR;
+ break;
+ case ITE_GPIO_PORTB:
+ ITE_GPBCR = (__u16)mask; /* 0xffff */
+ *data = ITE_GPBDR;
+ break;
+ case ITE_GPIO_PORTC:
+ ITE_GPCCR = (__u16)mask; /* 0x03ff */
+ *data = ITE_GPCDR;
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+
+int ite_gpio_out(__u32 device, __u32 mask, __u32 data)
+{
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ ITE_GPACR = (__u16)mask; /* 0x5555 */
+ ITE_GPADR = (__u8)data;
+ break;
+ case ITE_GPIO_PORTB:
+ ITE_GPBCR = (__u16)mask; /* 0x5555 */
+ ITE_GPBDR = (__u8)data;
+ break;
+ case ITE_GPIO_PORTC:
+ ITE_GPCCR = (__u16)mask; /* 0x0155 */
+ ITE_GPCDR = (__u8)data;
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data)
+{
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ ITE_GPAICR = (ITE_GPAICR & ~mask) | (data & mask);
+ break;
+ case ITE_GPIO_PORTB:
+ ITE_GPBICR = (ITE_GPBICR & ~mask) | (data & mask);
+ break;
+ case ITE_GPIO_PORTC:
+ ITE_GPCICR = (ITE_GPCICR & ~mask) | (data & mask);
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data)
+{
+ int ret=-1;
+
+ if (MAX_GPIO_LINE > *data >= 0)
+ ret=ite_gpio_irq_pending[*data];
+
+ DEB(printk("ite_gpio_in_status %d ret=%d\n",*data, ret));
+
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ *data = ITE_GPAISR & mask;
+ break;
+ case ITE_GPIO_PORTB:
+ *data = ITE_GPBISR & mask;
+ break;
+ case ITE_GPIO_PORTC:
+ *data = ITE_GPCISR & mask;
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data)
+{
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ ITE_GPAISR = (ITE_GPAISR & ~mask) | (data & mask);
+ break;
+ case ITE_GPIO_PORTB:
+ ITE_GPBISR = (ITE_GPBISR & ~mask) | (data & mask);
+ break;
+ case ITE_GPIO_PORTC:
+ ITE_GPCISR = (ITE_GPCISR & ~mask) | (data & mask);
+ break;
+ default:
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data)
+{
+ ITE_GCR = (ITE_GCR & ~mask) | (data & mask);
+
+ return 0;
+}
+
+int ite_gpio_int_wait (__u32 device, __u32 mask, __u32 data)
+{
+ int i,line=0, ret=0;
+ unsigned long flags;
+
+ switch (device) {
+ case ITE_GPIO_PORTA:
+ line = data & mask;
+ break;
+ case ITE_GPIO_PORTB:
+ line = (data & mask) <<8;
+ break;
+ case ITE_GPIO_PORTC:
+ line = (data & mask) <<16;
+ break;
+ }
+ for (i=MAX_GPIO_LINE-1; i >= 0; i--) {
+ if ( (line) & (1 << i))
+ break;
+ }
+
+ DEB(printk("wait device=0x%d mask=0x%x data=0x%x index %d\n",
+ device, mask, data, i));
+
+ if (line & ~(1<<i))
+ return -EFAULT;
+
+ if (ite_gpio_irq_pending[i]==1)
+ return -EFAULT;
+
+ save_flags (flags);
+ cli();
+ ite_gpio_irq_pending[i] = 1;
+ ret = interruptible_sleep_on_timeout(&ite_gpio_wait[i], 3*HZ);
+ restore_flags (flags);
+ ite_gpio_irq_pending[i] = 0;
+
+ return ret;
+}
+
+EXPORT_SYMBOL(ite_gpio_in);
+EXPORT_SYMBOL(ite_gpio_out);
+EXPORT_SYMBOL(ite_gpio_int_ctrl);
+EXPORT_SYMBOL(ite_gpio_in_status);
+EXPORT_SYMBOL(ite_gpio_out_status);
+EXPORT_SYMBOL(ite_gpio_gen_ctrl);
+EXPORT_SYMBOL(ite_gpio_int_wait);
+
+static int ite_gpio_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = MINOR(inode->i_rdev);
+ if (minor != GPIO_MINOR)
+ return -ENODEV;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ return 0;
+}
+
+
+static int ite_gpio_release(struct inode *inode, struct file *file)
+{
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ return 0;
+}
+
+
+static int ite_gpio_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+
+ static struct ite_gpio_ioctl_data ioctl_data;
+
+ if (copy_from_user(&ioctl_data, (struct ite_gpio_ioctl_data *)arg,
+ sizeof(ioctl_data)))
+ return -EFAULT;
+ if ((ioctl_data.device < ITE_GPIO_PORTA) ||
+ (ioctl_data.device > ITE_GPIO_PORTC) )
+ return -EFAULT;
+
+ switch(cmd) {
+ case ITE_GPIO_IN:
+ if (ite_gpio_in(ioctl_data.device, ioctl_data.mask,
+ &ioctl_data.data))
+ return -EFAULT;
+
+ if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
+ &ioctl_data, sizeof(ioctl_data)))
+ return -EFAULT;
+ break;
+
+ case ITE_GPIO_OUT:
+ return ite_gpio_out(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+ break;
+
+ case ITE_GPIO_INT_CTRL:
+ return ite_gpio_int_ctrl(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+ break;
+
+ case ITE_GPIO_IN_STATUS:
+ if (ite_gpio_in_status(ioctl_data.device, ioctl_data.mask,
+ &ioctl_data.data))
+ return -EFAULT;
+ if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
+ &ioctl_data, sizeof(ioctl_data)))
+ return -EFAULT;
+ break;
+
+ case ITE_GPIO_OUT_STATUS:
+ return ite_gpio_out_status(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+ break;
+
+ case ITE_GPIO_GEN_CTRL:
+ return ite_gpio_gen_ctrl(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+ break;
+
+ case ITE_GPIO_INT_WAIT:
+ return ite_gpio_int_wait(ioctl_data.device,
+ ioctl_data.mask, ioctl_data.data);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ }
+ return 0;
+}
+
+static void ite_gpio_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+ int i,line;
+
+ line = ITE_GPCISR & 0x1f;
+ for (i=4; i >=0; i--) {
+ if ( line & (1 << i)) {
+ ++ite_irq_counter[i+16];
+ ite_gpio_irq_pending[i+16] = 2;
+ wake_up_interruptible(&ite_gpio_wait[i+16]);
+
+DEB(printk("interrupt 0x%x %d\n", &ite_gpio_wait[i+16], i+16));
+
+ ITE_GPCISR = ITE_GPCISR & (1<<i);
+ return;
+ }
+ }
+ line = ITE_GPBISR;
+ for (i=7; i >= 0; i--) {
+ if ( line & (1 << i)) {
+ ++ite_irq_counter[i+8];
+ ite_gpio_irq_pending[i+8] = 2;
+ wake_up_interruptible(&ite_gpio_wait[i+8]);
+
+DEB(printk("interrupt 0x%x %d\n",ITE_GPBISR, i+8));
+
+ ITE_GPBISR = ITE_GPBISR & (1<<i);
+ return;
+ }
+ }
+ line = ITE_GPAISR;
+ for (i=7; i >= 0; i--) {
+ if ( line & (1 << i)) {
+ ++ite_irq_counter[i];
+ ite_gpio_irq_pending[i] = 2;
+ wake_up_interruptible(&ite_gpio_wait[i]);
+
+DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i));
+
+ ITE_GPAISR = ITE_GPAISR & (1<<i);
+ return;
+ }
+ }
+}
+
+static struct file_operations ite_gpio_fops =
+{
+ owner: THIS_MODULE,
+ ioctl: ite_gpio_ioctl,
+ open: ite_gpio_open,
+ release: ite_gpio_release,
+};
+
+/* GPIO_MINOR in include/linux/miscdevice.h */
+static struct miscdevice ite_gpio_miscdev =
+{
+ GPIO_MINOR,
+ "ite_gpio",
+ &ite_gpio_fops
+};
+
+int __init ite_gpio_init(void)
+{
+ int i;
+
+ misc_register(&ite_gpio_miscdev);
+
+ if (check_region(ite_gpio_base, 0x1c) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(ite_gpio_base, 0x1c, "ITE GPIO");
+ }
+
+ /* initialize registers */
+ ITE_GPACR = 0xffff;
+ ITE_GPBCR = 0xffff;
+ ITE_GPCCR = 0xffff;
+ ITE_GPAICR = 0x00ff;
+ ITE_GPBICR = 0x00ff;
+ ITE_GPCICR = 0x00ff;
+ ITE_GCR = 0;
+
+ for (i = 0; i < MAX_GPIO_LINE; i++) {
+ ite_gpio_irq_pending[i]=0;
+ init_waitqueue_head(&ite_gpio_wait[i]);
+ }
+ if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, SA_SHIRQ, "gpio", 0) < 0)
+ return 0;
+ printk("GPIO at 0x%x (irq = %d)\n", ite_gpio_base, ite_gpio_irq);
+
+ return 0;
+}
+
+void __exit ite_gpio_exit(void)
+{
+ misc_deregister(&ite_gpio_miscdev);
+}
+
+module_init(ite_gpio_init);
+module_exit(ite_gpio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 6b0c3ee867c3..2f340ef36bcb 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -153,8 +153,6 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot)
/* Use no-cache mode, serialized */
else if (MMU_IS_040 || MMU_IS_060)
prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S;
-#elif defined(__mips__)
- prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
#endif
return __pgprot(prot);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 0f885ca302da..a9e22cb610e5 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -205,6 +205,7 @@ static int numports[] = {0, 0, 0, 0};
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
+MODULE_LICENSE("GPL");
MODULE_PARM(type, "1-4i");
MODULE_PARM(baseaddr, "1-4i");
MODULE_PARM(numports, "1-4i");
@@ -212,6 +213,8 @@ MODULE_PARM(ttymajor, "i");
MODULE_PARM(calloutmajor, "i");
MODULE_PARM(verbose, "i");
+EXPORT_NO_SYMBOLS;
+
#endif //MODULE
static struct tty_driver moxaDriver;
@@ -1717,27 +1720,6 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
if(copy_to_user((void *)arg, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS))
return -EFAULT;
return (0);
- case MOXA_LOAD_BIOS:
- if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
- return -EFAULT;
- i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
- return (i);
- case MOXA_FIND_BOARD:
- if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
- return -EFAULT;
- return moxafindcard(dltmp.cardno);
- case MOXA_LOAD_C320B:
- if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
- return -EFAULT;
- moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
- return (0);
- case MOXA_LOAD_CODE:
- if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
- return -EFAULT;
- i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
- if (i == -1)
- return (-EFAULT);
- return (i);
case MOXA_GET_OQUEUE:
i = MoxaPortTxQueue(port);
return put_user(i, (unsigned long *) arg);
@@ -1778,9 +1760,38 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
if(copy_to_user((void *)arg, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS))
return -EFAULT;
return 0;
+ default:
+ return (-ENOIOCTLCMD);
+ case MOXA_LOAD_BIOS:
+ case MOXA_FIND_BOARD:
+ case MOXA_LOAD_C320B:
+ case MOXA_LOAD_CODE:
+ break;
+ }
+
+ if(copy_from_user(&dltmp, (void *)arg, sizeof(struct dl_str)))
+ return -EFAULT;
+ if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS)
+ return -EINVAL;
+
+ switch(cmd)
+ {
+ case MOXA_LOAD_BIOS:
+ i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
+ return (i);
+ case MOXA_FIND_BOARD:
+ return moxafindcard(dltmp.cardno);
+ case MOXA_LOAD_C320B:
+ moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
+ default: /* to keep gcc happy */
+ return (0);
+ case MOXA_LOAD_CODE:
+ i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
+ if (i == -1)
+ return (-EFAULT);
+ return (i);
}
- return (-ENOIOCTLCMD);
}
int MoxaDriverPoll(void)
diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c
index c74aabf2b452..28e7668ce2df 100644
--- a/drivers/char/qtronix.c
+++ b/drivers/char/qtronix.c
@@ -6,7 +6,7 @@
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
- * ppopov@mvista.com or support@mvista.com
+ * ppopov@mvista.com or source@mvista.com
*
*
* The bottom portion of this driver was take from
@@ -71,7 +71,7 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/kbd_kern.h>
#include <linux/smp_lock.h>
#include <asm/io.h>
@@ -353,19 +353,19 @@ spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
static unsigned char handle_kbd_event(void);
-int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
+int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
{
- printk("pckbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
+ printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
return 0;
}
-int pckbd_getkeycode(unsigned int scancode)
+int kbd_getkeycode(unsigned int scancode)
{
return scancode;
}
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+int kbd_translate(unsigned char scancode, unsigned char *keycode,
char raw_mode)
{
static int prev_scancode = 0;
@@ -406,9 +406,9 @@ int pckbd_translate(unsigned char scancode, unsigned char *keycode,
return 1;
}
-char pckbd_unexpected_up(unsigned char keycode)
+char kbd_unexpected_up(unsigned char keycode)
{
- //printk("pckbd_unexpected_up\n");
+ //printk("kbd_unexpected_up\n");
return 0;
}
@@ -422,12 +422,12 @@ static inline void handle_keyboard_event(unsigned char scancode, int down)
}
-void pckbd_leds(unsigned char leds)
+void kbd_leds(unsigned char leds)
{
}
/* dummy */
-void pckbd_init_hw(void)
+void kbd_init_hw(void)
{
}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 0c3a4c4bec4d..33edd15a7b8f 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -40,9 +40,10 @@
* 1.10b Andrew Morton: SMP lock fix
* 1.10c Cesar Barros: SMP locking fixes and cleanup
* 1.10d Paul Gortmaker: delete paranoia check in rtc_exit
+ * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness.
*/
-#define RTC_VERSION "1.10d"
+#define RTC_VERSION "1.10e"
#define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */
@@ -361,6 +362,9 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned char mon, day, hrs, min, sec, leap_yr;
unsigned char save_control, save_freq_select;
unsigned int yrs;
+#ifdef CONFIG_DECSTATION
+ unsigned int real_yrs;
+#endif
if (!capable(CAP_SYS_TIME))
return -EACCES;
@@ -394,6 +398,20 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
spin_lock_irq(&rtc_lock);
+#ifdef CONFIG_DECSTATION
+ real_yrs = yrs;
+ yrs = 72;
+
+ /*
+ * We want to keep the year set to 73 until March
+ * for non-leap years, so that Feb, 29th is handled
+ * correctly.
+ */
+ if (!leap_yr && mon < 3) {
+ real_yrs--;
+ yrs = 73;
+ }
+#endif
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
if (yrs > 169) {
@@ -416,6 +434,9 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+#ifdef CONFIG_DECSTATION
+ CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
+#endif
CMOS_WRITE(yrs, RTC_YEAR);
CMOS_WRITE(mon, RTC_MONTH);
CMOS_WRITE(day, RTC_DAY_OF_MONTH);
@@ -469,7 +490,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
spin_unlock_irq(&rtc_lock);
return 0;
}
-#elif !defined(CONFIG_DECSTATION)
+#endif
case RTC_EPOCH_READ: /* Read the epoch. */
{
return put_user (epoch, (unsigned long *)arg);
@@ -488,7 +509,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
epoch = arg;
return 0;
}
-#endif
default:
return -EINVAL;
}
@@ -709,12 +729,12 @@ found:
} else if (year >= 20 && year < 48) {
epoch = 1980;
guess = "ARC console";
- } else if (year >= 48 && year < 70) {
+ } else if (year >= 48 && year < 72) {
epoch = 1952;
guess = "Digital UNIX";
#if defined(__mips__)
- } else if (year >= 70 && year < 100) {
- epoch = 1928;
+ } else if (year >= 72 && year < 74) {
+ epoch = 2000;
guess = "Digital DECstation";
#else
} else if (year >= 70) {
@@ -911,6 +931,9 @@ static void get_rtc_time(struct rtc_time *rtc_tm)
{
unsigned long uip_watchdog = jiffies;
unsigned char ctrl;
+#ifdef CONFIG_DECSTATION
+ unsigned int real_year;
+#endif
/*
* read RTC once any update in progress is done. The update
@@ -939,6 +962,9 @@ static void get_rtc_time(struct rtc_time *rtc_tm)
rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+#ifdef CONFIG_DECSTATION
+ real_year = CMOS_READ(RTC_DEC_YEAR);
+#endif
ctrl = CMOS_READ(RTC_CONTROL);
spin_unlock_irq(&rtc_lock);
@@ -952,6 +978,10 @@ static void get_rtc_time(struct rtc_time *rtc_tm)
BCD_TO_BIN(rtc_tm->tm_year);
}
+#ifdef CONFIG_DECSTATION
+ rtc_tm->tm_year += real_year - 72;
+#endif
+
/*
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
@@ -1024,3 +1054,6 @@ static void set_rtc_irq_bit(unsigned char bit)
spin_unlock_irq(&rtc_lock);
}
#endif
+
+MODULE_AUTHOR("Paul Gortmaker");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-adap-ite.c b/drivers/i2c/i2c-adap-ite.c
new file mode 100644
index 000000000000..c6a35dafcf32
--- /dev/null
+++ b/drivers/i2c/i2c-adap-ite.c
@@ -0,0 +1,319 @@
+/*
+ -------------------------------------------------------------------------
+ i2c-adap-ite.c i2c-hw access for the IIC peripheral on the ITE MIPS system
+ -------------------------------------------------------------------------
+ Hai-Pao Fan, MontaVista Software, Inc.
+ hpfan@mvista.com or source@mvista.com
+
+ Copyright 2001 MontaVista Software Inc.
+
+ ----------------------------------------------------------------------------
+ This file was highly leveraged from i2c-elektor.c, which was created
+ by Simon G. Vogl and Hans Berglund:
+
+
+ Copyright (C) 1995-97 Simon G. Vogl
+ 1998-99 Hans Berglund
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+ Frodo Looijaard <frodol@dds.nl> */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ite.h>
+#include <linux/i2c-adap-ite.h>
+#include "i2c-ite.h"
+
+#define DEFAULT_BASE 0x14014030
+#define ITE_IIC_IO_SIZE 0x40
+#define DEFAULT_IRQ 0
+#define DEFAULT_CLOCK 0x1b0e /* default 16MHz/(27+14) = 400KHz */
+#define DEFAULT_OWN 0x55
+
+static int base = 0;
+static int irq = 0;
+static int clock = 0;
+static int own = 0;
+
+static int i2c_debug=0;
+static struct iic_ite gpi;
+#if (LINUX_VERSION_CODE < 0x020301)
+static struct wait_queue *iic_wait = NULL;
+#else
+static wait_queue_head_t iic_wait;
+#endif
+static int iic_pending;
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x
+#define DEBE(x) x /* error messages */
+
+
+/* ----- local functions ---------------------------------------------- */
+
+static void iic_ite_setiic(void *data, int ctl, short val)
+{
+ unsigned long j = jiffies + 10;
+
+ DEB3(printk(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff));
+ DEB3({while (jiffies < j) schedule();})
+ outw(val,ctl);
+}
+
+static short iic_ite_getiic(void *data, int ctl)
+{
+ short val;
+
+ val = inw(ctl);
+ DEB3(printk("Read 0x%02x from 0x%x\n",(unsigned short)val, ctl&0xff));
+ return (val);
+}
+
+/* Return our slave address. This is the address
+ * put on the I2C bus when another master on the bus wants to address us
+ * as a slave
+ */
+static int iic_ite_getown(void *data)
+{
+ return (gpi.iic_own);
+}
+
+
+static int iic_ite_getclock(void *data)
+{
+ return (gpi.iic_clock);
+}
+
+
+#if 0
+static void iic_ite_sleep(unsigned long timeout)
+{
+ schedule_timeout( timeout * HZ);
+}
+#endif
+
+
+/* Put this process to sleep. We will wake up when the
+ * IIC controller interrupts.
+ */
+static void iic_ite_waitforpin(void) {
+
+ int timeout = 2;
+
+ /* If interrupts are enabled (which they are), then put the process to
+ * sleep. This process will be awakened by two events -- either the
+ * the IIC peripheral interrupts or the timeout expires.
+ * If interrupts are not enabled then delay for a reasonable amount
+ * of time and return.
+ */
+ if (gpi.iic_irq > 0) {
+ cli();
+ if (iic_pending == 0) {
+ interruptible_sleep_on_timeout(&iic_wait, timeout*HZ );
+ } else
+ iic_pending = 0;
+ sti();
+ } else {
+ udelay(100);
+ }
+}
+
+
+static void iic_ite_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+
+ iic_pending = 1;
+
+ DEB2(printk("iic_ite_handler: in interrupt handler\n"));
+ wake_up_interruptible(&iic_wait);
+}
+
+
+/* Lock the region of memory where I/O registers exist. Request our
+ * interrupt line and register its associated handler.
+ */
+static int iic_hw_resrc_init(void)
+{
+ if (check_region(gpi.iic_base, ITE_IIC_IO_SIZE) < 0 ) {
+ return -ENODEV;
+ } else {
+ request_region(gpi.iic_base, ITE_IIC_IO_SIZE,
+ "i2c (i2c bus adapter)");
+ }
+ if (gpi.iic_irq > 0) {
+ if (request_irq(gpi.iic_irq, iic_ite_handler, 0, "ITE IIC", 0) < 0) {
+ gpi.iic_irq = 0;
+ } else
+ DEB3(printk("Enabled IIC IRQ %d\n", gpi.iic_irq));
+ enable_irq(gpi.iic_irq);
+ }
+ return 0;
+}
+
+
+static void iic_ite_release(void)
+{
+ if (gpi.iic_irq > 0) {
+ disable_irq(gpi.iic_irq);
+ free_irq(gpi.iic_irq, 0);
+ }
+ release_region(gpi.iic_base , 2);
+}
+
+
+static int iic_ite_reg(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+static int iic_ite_unreg(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+static void iic_ite_inc_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+}
+
+
+static void iic_ite_dec_use(struct i2c_adapter *adap)
+{
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+static struct i2c_algo_iic_data iic_ite_data = {
+ NULL,
+ iic_ite_setiic,
+ iic_ite_getiic,
+ iic_ite_getown,
+ iic_ite_getclock,
+ iic_ite_waitforpin,
+ 80, 80, 100, /* waits, timeout */
+};
+
+static struct i2c_adapter iic_ite_ops = {
+ "ITE IIC adapter",
+ I2C_HW_I_IIC,
+ NULL,
+ &iic_ite_data,
+ iic_ite_inc_use,
+ iic_ite_dec_use,
+ iic_ite_reg,
+ iic_ite_unreg,
+};
+
+/* Called when the module is loaded. This function starts the
+ * cascade of calls up through the heirarchy of i2c modules (i.e. up to the
+ * algorithm layer and into to the core layer)
+ */
+static int __init iic_ite_init(void)
+{
+
+ struct iic_ite *piic = &gpi;
+
+ printk(KERN_INFO "Initialize ITE IIC adapter module\n");
+ if (base == 0)
+ piic->iic_base = DEFAULT_BASE;
+ else
+ piic->iic_base = base;
+
+ if (irq == 0)
+ piic->iic_irq = DEFAULT_IRQ;
+ else
+ piic->iic_irq = irq;
+
+ if (clock == 0)
+ piic->iic_clock = DEFAULT_CLOCK;
+ else
+ piic->iic_clock = clock;
+
+ if (own == 0)
+ piic->iic_own = DEFAULT_OWN;
+ else
+ piic->iic_own = own;
+
+ iic_ite_data.data = (void *)piic;
+#if (LINUX_VERSION_CODE >= 0x020301)
+ init_waitqueue_head(&iic_wait);
+#endif
+ if (iic_hw_resrc_init() == 0) {
+ if (i2c_iic_add_bus(&iic_ite_ops) < 0)
+ return -ENODEV;
+ } else {
+ return -ENODEV;
+ }
+ printk(KERN_INFO " found device at %#x irq %d.\n",
+ piic->iic_base, piic->iic_irq);
+ return 0;
+}
+
+
+static void iic_ite_exit(void)
+{
+ i2c_iic_del_bus(&iic_ite_ops);
+ iic_ite_release();
+}
+
+EXPORT_NO_SYMBOLS;
+
+/* If modules is NOT defined when this file is compiled, then the MODULE_*
+ * macros will resolve to nothing
+ */
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for ITE IIC bus adapter");
+
+MODULE_PARM(base, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(clock, "i");
+MODULE_PARM(own, "i");
+MODULE_PARM(i2c_debug,"i");
+
+
+/* Called when module is loaded or when kernel is intialized.
+ * If MODULES is defined when this file is compiled, then this function will
+ * resolve to init_module (the function called when insmod is invoked for a
+ * module). Otherwise, this function is called early in the boot, when the
+ * kernel is intialized. Check out /include/init.h to see how this works.
+ */
+module_init(iic_ite_init);
+
+/* Resolves to module_cleanup when MODULES is defined. */
+module_exit(iic_ite_exit);
diff --git a/drivers/i2c/i2c-algo-ite.c b/drivers/i2c/i2c-algo-ite.c
new file mode 100644
index 000000000000..194d1f78a732
--- /dev/null
+++ b/drivers/i2c/i2c-algo-ite.c
@@ -0,0 +1,872 @@
+/*
+ -------------------------------------------------------------------------
+ i2c-algo-ite.c i2c driver algorithms for ITE adapters
+
+ Hai-Pao Fan, MontaVista Software, Inc.
+ hpfan@mvista.com or source@mvista.com
+
+ Copyright 2000 MontaVista Software Inc.
+
+ ---------------------------------------------------------------------------
+ This file was highly leveraged from i2c-algo-pcf.c, which was created
+ by Simon G. Vogl and Hans Berglund:
+
+
+ Copyright (C) 1995-1997 Simon G. Vogl
+ 1998-2000 Hans Berglund
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+ <mbailey@littlefeet-inc.com> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-ite.h>
+#include "i2c-ite.h"
+
+#define PM_DSR IT8172_PCI_IO_BASE + IT_PM_DSR
+#define PM_IBSR IT8172_PCI_IO_BASE + IT_PM_DSR + 0x04
+#define GPIO_CCR IT8172_PCI_IO_BASE + IT_GPCCR
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x /* print several statistical values*/
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+ /* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 16
+
+/* debugging - slow down transfer to have a look at the data .. */
+/* I use this with two leds&resistors, each one connected to sda,scl */
+/* respectively. This makes sure that the algorithm works. Some chips */
+/* might not like this, as they have an internal timeout of some mils */
+/*
+#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+ if (need_resched) schedule();
+*/
+
+
+/* ----- global variables --------------------------------------------- */
+
+#ifdef SLO_IO
+ int jif;
+#endif
+
+/* module parameters:
+ */
+static int i2c_debug=1;
+static int iic_test=0; /* see if the line-setting functions work */
+static int iic_scan=0; /* have a look at what's hanging 'round */
+
+/* --- setting states on the bus with the right timing: --------------- */
+
+#define get_clock(adap) adap->getclock(adap->data)
+#define iic_outw(adap, reg, val) adap->setiic(adap->data, reg, val)
+#define iic_inw(adap, reg) adap->getiic(adap->data, reg)
+
+
+/* --- other auxiliary functions -------------------------------------- */
+
+static void iic_start(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap,ITE_I2CHCR,ITE_CMD);
+}
+
+static void iic_stop(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap,ITE_I2CHCR,0);
+ iic_outw(adap,ITE_I2CHSR,ITE_I2CHSR_TDI);
+}
+
+static void iic_reset(struct i2c_algo_iic_data *adap)
+{
+ iic_outw(adap, PM_IBSR, iic_inw(adap, PM_IBSR) | 0x80);
+}
+
+
+static int wait_for_bb(struct i2c_algo_iic_data *adap)
+{
+ int timeout = DEF_TIMEOUT;
+ short status;
+
+ status = iic_inw(adap, ITE_I2CHSR);
+#ifndef STUB_I2C
+ while (timeout-- && (status & ITE_I2CHSR_HB)) {
+ udelay(1000); /* How much is this? */
+ status = iic_inw(adap, ITE_I2CHSR);
+ }
+#endif
+ if (timeout<=0) {
+ printk(KERN_ERR "Timeout, host is busy\n");
+ iic_reset(adap);
+ }
+ return(timeout<=0);
+}
+
+/*
+ * Puts this process to sleep for a period equal to timeout
+ */
+static inline void iic_sleep(unsigned long timeout)
+{
+ schedule_timeout( timeout * HZ);
+}
+
+/* After we issue a transaction on the IIC bus, this function
+ * is called. It puts this process to sleep until we get an interrupt from
+ * from the controller telling us that the transaction we requested in complete.
+ */
+static int wait_for_pin(struct i2c_algo_iic_data *adap, short *status) {
+
+ int timeout = DEF_TIMEOUT;
+
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk("Timeout waiting for host not busy\n");)
+ return -EIO;
+ }
+ timeout = DEF_TIMEOUT;
+
+ *status = iic_inw(adap, ITE_I2CHSR);
+#ifndef STUB_I2C
+ while (timeout-- && !(*status & ITE_I2CHSR_TDI)) {
+ adap->waitforpin();
+ *status = iic_inw(adap, ITE_I2CHSR);
+ }
+#endif
+ if (timeout <= 0)
+ return(-1);
+ else
+ return(0);
+}
+
+static int wait_for_fe(struct i2c_algo_iic_data *adap, short *status)
+{
+ int timeout = DEF_TIMEOUT;
+
+ *status = iic_inw(adap, ITE_I2CFSR);
+#ifndef STUB_I2C
+ while (timeout-- && (*status & ITE_I2CFSR_FE)) {
+ udelay(1000);
+ iic_inw(adap, ITE_I2CFSR);
+ }
+#endif
+ if (timeout <= 0)
+ return(-1);
+ else
+ return(0);
+}
+
+static int iic_init (struct i2c_algo_iic_data *adap)
+{
+ short i;
+
+ /* Clear bit 7 to set I2C to normal operation mode */
+ i=iic_inw(adap, PM_DSR)& 0xff7f;
+ iic_outw(adap, PM_DSR, i);
+
+ /* set IT_GPCCR port C bit 2&3 as function 2 */
+ i = iic_inw(adap, GPIO_CCR) & 0xfc0f;
+ iic_outw(adap,GPIO_CCR,i);
+
+ /* Clear slave address/sub-address */
+ iic_outw(adap,ITE_I2CSAR, 0);
+ iic_outw(adap,ITE_I2CSSAR, 0);
+
+ /* Set clock counter register */
+ iic_outw(adap,ITE_I2CCKCNT, get_clock(adap));
+
+ /* Set START/reSTART/STOP time registers */
+ iic_outw(adap,ITE_I2CSHDR, 0x0a);
+ iic_outw(adap,ITE_I2CRSUR, 0x0a);
+ iic_outw(adap,ITE_I2CPSUR, 0x0a);
+
+ /* Enable interrupts on completing the current transaction */
+ iic_outw(adap,ITE_I2CHCR, ITE_I2CHCR_IE | ITE_I2CHCR_HCE);
+
+ /* Clear transfer count */
+ iic_outw(adap,ITE_I2CFBCR, 0x0);
+
+ DEB2(printk("iic_init: Initialized IIC on ITE 0x%x\n",
+ iic_inw(adap, ITE_I2CHSR)));
+ return 0;
+}
+
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
+#if 0
+ int scl,sda;
+ sda=getsda(adap);
+ if (adap->getscl==NULL) {
+ printk("test_bus: Warning: Adapter can't read from clock line - skipping test.\n");
+ return 0;
+ }
+ scl=getscl(adap);
+ printk("test_bus: Adapter: %s scl: %d sda: %d -- testing...\n",
+ name,getscl(adap),getsda(adap));
+ if (!scl || !sda ) {
+ printk("test_bus: %s seems to be busy.\n",adap->name);
+ goto bailout;
+ }
+ sdalo(adap);
+ printk("test_bus:1 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 != getsda(adap) ) {
+ printk("test_bus: %s SDA stuck high!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL unexpected low while pulling SDA low!\n",
+ name);
+ goto bailout;
+ }
+ sdahi(adap);
+ printk("test_bus:2 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA stuck low!\n",name);
+ sdahi(adap);
+ goto bailout;
+ }
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL unexpected low while SDA high!\n",
+ adap->name);
+ goto bailout;
+ }
+ scllo(adap);
+ printk("test_bus:3 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 != getscl(adap) ) {
+
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA unexpected low while pulling SCL low!\n",
+ name);
+ goto bailout;
+ }
+ sclhi(adap);
+ printk("test_bus:4 scl: %d sda: %d \n",getscl(adap),
+ getsda(adap));
+ if ( 0 == getscl(adap) ) {
+ printk("test_bus: %s SCL stuck low!\n",name);
+ sclhi(adap);
+ goto bailout;
+ }
+ if ( 0 == getsda(adap) ) {
+ printk("test_bus: %s SDA unexpected low while SCL high!\n",
+ name);
+ goto bailout;
+ }
+ printk("test_bus: %s passed test.\n",name);
+ return 0;
+bailout:
+ sdahi(adap);
+ sclhi(adap);
+ return -ENODEV;
+#endif
+ return (0);
+}
+
+/* ----- Utility functions
+ */
+
+
+/* Verify the device we want to talk to on the IIC bus really exists. */
+static inline int try_address(struct i2c_algo_iic_data *adap,
+ unsigned int addr, int retries)
+{
+ int i, ret = -1;
+ short status;
+
+ for (i=0;i<retries;i++) {
+ iic_outw(adap, ITE_I2CSAR, addr);
+ iic_start(adap);
+ if (wait_for_pin(adap, &status) == 0) {
+ if ((status & ITE_I2CHSR_DNE) == 0) {
+ iic_stop(adap);
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+ ret=1;
+ break; /* success! */
+ }
+ }
+ iic_stop(adap);
+ udelay(adap->udelay);
+ }
+ DEB2(if (i) printk("try_address: needed %d retries for 0x%x\n",i,
+ addr));
+ return ret;
+}
+
+
+static int iic_sendbytes(struct i2c_adapter *i2c_adap,const char *buf,
+ int count)
+{
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ int wrcount=0, timeout;
+ short status;
+ int loops, remainder, i, j;
+ union {
+ char byte[2];
+ unsigned short word;
+ } tmp;
+
+ iic_outw(adap, ITE_I2CSSAR, (unsigned short)buf[wrcount++]);
+ count--;
+ if (count == 0)
+ return -EIO;
+
+ loops = count / 32; /* 32-byte FIFO */
+ remainder = count % 32;
+
+ if(loops) {
+ for(i=0; i<loops; i++) {
+
+ iic_outw(adap, ITE_I2CFBCR, 32);
+ for(j=0; j<32/2; j++) {
+ tmp.byte[1] = buf[wrcount++];
+ tmp.byte[0] = buf[wrcount++];
+ iic_outw(adap, ITE_I2CFDR, tmp.word);
+ }
+
+ /* status FIFO overrun */
+ iic_inw(adap, ITE_I2CFSR);
+ iic_inw(adap, ITE_I2CFBCR);
+
+ iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
+
+ /* Wait for transmission to complete */
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+ }
+ }
+ if(remainder) {
+ iic_outw(adap, ITE_I2CFBCR, remainder);
+ for(i=0; i<remainder/2; i++) {
+ tmp.byte[1] = buf[wrcount++];
+ tmp.byte[0] = buf[wrcount++];
+ iic_outw(adap, ITE_I2CFDR, tmp.word);
+ }
+
+ /* status FIFO overrun */
+ iic_inw(adap, ITE_I2CFSR);
+ iic_inw(adap, ITE_I2CFBCR);
+
+ iic_outw(adap, ITE_I2CHCR, ITE_WRITE); /* Issue WRITE command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write timeout.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_sendbytes: %s write error - no ack.\n", i2c_adap->name);
+ return -EREMOTEIO; /* got a better one ?? */
+ }
+#endif
+ }
+ iic_stop(adap);
+ return wrcount;
+}
+
+
+static int iic_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count,
+ int sread)
+{
+ int rdcount=0, i, timeout;
+ short status;
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ int loops, remainder, j;
+ union {
+ char byte[2];
+ unsigned short word;
+ } tmp;
+
+ loops = count / 32; /* 32-byte FIFO */
+ remainder = count % 32;
+
+ if(loops) {
+ for(i=0; i<loops; i++) {
+ iic_outw(adap, ITE_I2CFBCR, 32);
+ if (sread)
+ iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
+ else
+ iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
+ return (-1);
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
+ return (-1);
+ }
+#endif
+
+ timeout = wait_for_fe(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
+ return (-1);
+ }
+
+ for(j=0; j<32/2; j++) {
+ tmp.word = iic_inw(adap, ITE_I2CFDR);
+ buf[rdcount++] = tmp.byte[1];
+ buf[rdcount++] = tmp.byte[0];
+ }
+
+ /* status FIFO underrun */
+ iic_inw(adap, ITE_I2CFSR);
+
+ }
+ }
+
+
+ if(remainder) {
+ remainder=(remainder+1)/2 * 2;
+ iic_outw(adap, ITE_I2CFBCR, remainder);
+ if (sread)
+ iic_outw(adap, ITE_I2CHCR, ITE_SREAD);
+ else
+ iic_outw(adap, ITE_I2CHCR, ITE_READ); /* Issue READ command */
+
+ timeout = wait_for_pin(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read timeout.\n", i2c_adap->name);
+ return (-1);
+ }
+#ifndef STUB_I2C
+ if (status & ITE_I2CHSR_DB) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s read error - no ack.\n", i2c_adap->name);
+ return (-1);
+ }
+#endif
+ timeout = wait_for_fe(adap, &status);
+ if(timeout) {
+ iic_stop(adap);
+ printk("iic_readbytes: %s FIFO is empty\n", i2c_adap->name);
+ return (-1);
+ }
+
+ for(i=0; i<(remainder+1)/2; i++) {
+ tmp.word = iic_inw(adap, ITE_I2CFDR);
+ buf[rdcount++] = tmp.byte[1];
+ buf[rdcount++] = tmp.byte[0];
+ }
+
+ /* status FIFO underrun */
+ iic_inw(adap, ITE_I2CFSR);
+
+ }
+
+ iic_stop(adap);
+ return rdcount;
+}
+
+
+/* This function implements combined transactions. Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+#if 0
+static int iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
+{
+ int i;
+ struct i2c_msg *pmsg;
+ int ret;
+
+ DEB2(printk("Beginning combined transaction\n"));
+
+ for(i=0; i<(num-1); i++) {
+ pmsg = &msgs[i];
+ if(pmsg->flags & I2C_M_RD) {
+ DEB2(printk(" This one is a read\n"));
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
+ }
+ else if(!(pmsg->flags & I2C_M_RD)) {
+ DEB2(printk("This one is a write\n"));
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_COMBINED_XFER);
+ }
+ }
+ /* Last read or write segment needs to be terminated with a stop */
+ pmsg = &msgs[i];
+
+ if(pmsg->flags & I2C_M_RD) {
+ DEB2(printk("Doing the last read\n"));
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+ }
+ else if(!(pmsg->flags & I2C_M_RD)) {
+ DEB2(printk("Doing the last write\n"));
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+ }
+
+ return ret;
+}
+#endif
+
+
+/* Whenever we initiate a transaction, the first byte clocked
+ * onto the bus after the start condition is the address (7 bit) of the
+ * device we want to talk to. This function manipulates the address specified
+ * so that it makes sense to the hardware when written to the IIC peripheral.
+ *
+ * Note: 10 bit addresses are not supported in this driver, although they are
+ * supported by the hardware. This functionality needs to be implemented.
+ */
+static inline int iic_doAddress(struct i2c_algo_iic_data *adap,
+ struct i2c_msg *msg, int retries)
+{
+ unsigned short flags = msg->flags;
+ unsigned int addr;
+ int ret;
+
+/* Ten bit addresses not supported right now */
+ if ( (flags & I2C_M_TEN) ) {
+#if 0
+ addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+ DEB2(printk("addr0: %d\n",addr));
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ iic_outw(adap,msg->addr & 0x7f);
+ if (ret != 1) {
+ printk("iic_doAddress: died at 2nd address code.\n");
+ return -EREMOTEIO;
+ }
+ if ( flags & I2C_M_RD ) {
+ i2c_repstart(adap);
+ addr |= 0x01;
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at extended address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+#endif
+ } else {
+
+ addr = ( msg->addr << 1 );
+
+#if 0
+ if (flags & I2C_M_RD )
+ addr |= 1;
+ if (flags & I2C_M_REV_DIR_ADDR )
+ addr ^= 1;
+#endif
+
+ if (iic_inw(adap, ITE_I2CSAR) != addr) {
+ iic_outw(adap, ITE_I2CSAR, addr);
+ ret = try_address(adap, addr, retries);
+ if (ret!=1) {
+ printk("iic_doAddress: died at address code.\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+
+/* Description: Prepares the controller for a transaction (clearing status
+ * registers, data buffers, etc), and then calls either iic_readbytes or
+ * iic_sendbytes to do the actual transaction.
+ *
+ * still to be done: Before we issue a transaction, we should
+ * verify that the bus is not busy or in some unknown state.
+ */
+static int iic_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct i2c_algo_iic_data *adap = i2c_adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i = 0;
+ int ret, timeout;
+
+ pmsg = &msgs[i];
+
+ if(!pmsg->len) {
+ DEB2(printk("iic_xfer: read/write length is 0\n");)
+ return -EIO;
+ }
+ if(!(pmsg->flags & I2C_M_RD) && (!(pmsg->len)%2) ) {
+ DEB2(printk("iic_xfer: write buffer length is not odd\n");)
+ return -EIO;
+ }
+
+ /* Wait for any pending transfers to complete */
+ timeout = wait_for_bb(adap);
+ if (timeout) {
+ DEB2(printk("iic_xfer: Timeout waiting for host not busy\n");)
+ return -EIO;
+ }
+
+ /* Flush FIFO */
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+
+ /* Load address */
+ ret = iic_doAddress(adap, pmsg, i2c_adap->retries);
+ if (ret)
+ return -EIO;
+
+#if 0
+ /* Combined transaction (read and write) */
+ if(num > 1) {
+ DEB2(printk("iic_xfer: Call combined transaction\n"));
+ ret = iic_combined_transaction(i2c_adap, msgs, num);
+ }
+#endif
+
+ DEB3(printk("iic_xfer: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+ i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+ if(pmsg->flags & I2C_M_RD) /* Read */
+ ret = iic_readbytes(i2c_adap, pmsg->buf, pmsg->len, 0);
+ else { /* Write */
+ udelay(1000);
+ ret = iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len);
+ }
+
+ if (ret != pmsg->len)
+ DEB3(printk("iic_xfer: error or fail on read/write %d bytes.\n",ret));
+ else
+ DEB3(printk("iic_xfer: read/write %d bytes.\n",ret));
+
+ return ret;
+}
+
+
+/* Implements device specific ioctls. Higher level ioctls can
+ * be found in i2c-core.c and are typical of any i2c controller (specifying
+ * slave address, timeouts, etc). These ioctls take advantage of any hardware
+ * features built into the controller for which this algorithm-adapter set
+ * was written. These ioctls allow you to take control of the data and clock
+ * lines and set the either high or low,
+ * similar to a GPIO pin.
+ */
+static int algo_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+
+ struct i2c_algo_iic_data *adap = adapter->algo_data;
+ struct i2c_iic_msg s_msg;
+ char *buf;
+ int ret;
+
+ if (cmd == I2C_SREAD) {
+ if(copy_from_user(&s_msg, (struct i2c_iic_msg *)arg,
+ sizeof(struct i2c_iic_msg)))
+ return -EFAULT;
+ buf = kmalloc(s_msg.len, GFP_KERNEL);
+ if (buf== NULL)
+ return -ENOMEM;
+
+ /* Flush FIFO */
+ iic_outw(adap, ITE_I2CFCR, ITE_I2CFCR_FLUSH);
+
+ /* Load address */
+ iic_outw(adap, ITE_I2CSAR,s_msg.addr<<1);
+ iic_outw(adap, ITE_I2CSSAR,s_msg.waddr & 0xff);
+
+ ret = iic_readbytes(adapter, buf, s_msg.len, 1);
+ if (ret>=0) {
+ if(copy_to_user( s_msg.buf, buf, s_msg.len) )
+ ret = -EFAULT;
+ }
+ kfree(buf);
+ }
+ return 0;
+}
+
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static struct i2c_algorithm iic_algo = {
+ "ITE IIC algorithm",
+ I2C_ALGO_IIC,
+ iic_xfer, /* master_xfer */
+ NULL, /* smbus_xfer */
+ NULL, /* slave_xmit */
+ NULL, /* slave_recv */
+ algo_control, /* ioctl */
+ iic_func, /* functionality */
+};
+
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_iic_add_bus(struct i2c_adapter *adap)
+{
+ int i;
+ short status;
+ struct i2c_algo_iic_data *iic_adap = adap->algo_data;
+
+ if (iic_test) {
+ int ret = test_bus(iic_adap, adap->name);
+ if (ret<0)
+ return -ENODEV;
+ }
+
+ DEB2(printk("i2c-algo-ite: hw routines for %s registered.\n",
+ adap->name));
+
+ /* register new adapter to i2c module... */
+
+ adap->id |= iic_algo.id;
+ adap->algo = &iic_algo;
+
+ adap->timeout = 100; /* default values, should */
+ adap->retries = 3; /* be replaced by defines */
+ adap->flags = 0;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ i2c_add_adapter(adap);
+ iic_init(iic_adap);
+
+ /* scan bus */
+ /* By default scanning the bus is turned off. */
+ if (iic_scan) {
+ printk(KERN_INFO " i2c-algo-ite: scanning bus %s.\n",
+ adap->name);
+ for (i = 0x00; i < 0xff; i+=2) {
+ iic_outw(iic_adap, ITE_I2CSAR, i);
+ iic_start(iic_adap);
+ if ( (wait_for_pin(iic_adap, &status) == 0) &&
+ ((status & ITE_I2CHSR_DNE) == 0) ) {
+ printk(KERN_INFO "\n(%02x)\n",i>>1);
+ } else {
+ printk(KERN_INFO ".");
+ iic_reset(iic_adap);
+ }
+ udelay(iic_adap->udelay);
+ }
+ }
+ return 0;
+}
+
+
+int i2c_iic_del_bus(struct i2c_adapter *adap)
+{
+ int res;
+ if ((res = i2c_del_adapter(adap)) < 0)
+ return res;
+ DEB2(printk("i2c-algo-ite: adapter unregistered: %s\n",adap->name));
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+
+int __init i2c_algo_iic_init (void)
+{
+ printk(KERN_INFO "ITE iic (i2c) algorithm module\n");
+ return 0;
+}
+
+
+void i2c_algo_iic_exit(void)
+{
+ return;
+}
+
+
+EXPORT_SYMBOL(i2c_iic_add_bus);
+EXPORT_SYMBOL(i2c_iic_del_bus);
+
+/* The MODULE_* macros resolve to nothing if MODULES is not defined
+ * when this file is compiled.
+ */
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("ITE iic algorithm");
+
+MODULE_PARM(iic_test, "i");
+MODULE_PARM(iic_scan, "i");
+MODULE_PARM(i2c_debug,"i");
+
+MODULE_PARM_DESC(iic_test, "Test if the I2C bus is available");
+MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
+
+/* This function resolves to init_module (the function invoked when a module
+ * is loaded via insmod) when this file is compiled with MODULES defined.
+ * Otherwise (i.e. if you want this driver statically linked to the kernel),
+ * a pointer to this function is stored in a table and called
+ * during the intialization of the kernel (in do_basic_setup in /init/main.c)
+ *
+ * All this functionality is complements of the macros defined in linux/init.h
+ */
+module_init(i2c_algo_iic_init);
+
+
+/* If MODULES is defined when this file is compiled, then this function will
+ * resolved to cleanup_module.
+ */
+module_exit(i2c_algo_iic_exit);
diff --git a/drivers/i2c/i2c-ite.h b/drivers/i2c/i2c-ite.h
new file mode 100644
index 000000000000..a8ca3c9b546a
--- /dev/null
+++ b/drivers/i2c/i2c-ite.h
@@ -0,0 +1,117 @@
+/*
+ --------------------------------------------------------------------
+ i2c-ite.h: Global defines for the I2C controller on board the
+ ITE MIPS processor.
+ --------------------------------------------------------------------
+ Hai-Pao Fan, MontaVista Software, Inc.
+ hpfan@mvista.com or source@mvista.com
+
+ Copyright 2001 MontaVista Software Inc.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef I2C_ITE_H
+#define I2C_ITE_H 1
+
+#include <asm/it8172/it8172.h>
+
+/* I2C Registers */
+#define ITE_I2CHCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x30
+#define ITE_I2CHSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x34
+#define ITE_I2CSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x38
+#define ITE_I2CSSAR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x3c
+#define ITE_I2CCKCNT IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x48
+#define ITE_I2CSHDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x4c
+#define ITE_I2CRSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x50
+#define ITE_I2CPSUR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x54
+
+#define ITE_I2CFDR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x70
+#define ITE_I2CFBCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x74
+#define ITE_I2CFCR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x78
+#define ITE_I2CFSR IT8172_PCI_IO_BASE + IT_I2C_BASE + 0x7c
+
+
+/* Host Control Register ITE_I2CHCR */
+#define ITE_I2CHCR_HCE 0x01 /* Enable I2C Host Controller */
+#define ITE_I2CHCR_IE 0x02 /* Enable the interrupt after completing
+ the current transaction */
+#define ITE_I2CHCR_CP_W 0x00 /* bit2-4 000 - Write */
+#define ITE_I2CHCR_CP_R 0x08 /* 010 - Current address read */
+#define ITE_I2CHCR_CP_S 0x10 /* 100 - Sequential read */
+#define ITE_I2CHCR_ST 0x20 /* Initiates the I2C host controller to execute
+ the command and send the data programmed in
+ all required registers to I2C bus */
+#define ITE_CMD ITE_I2CHCR_HCE | ITE_I2CHCR_IE | ITE_I2CHCR_ST
+#define ITE_WRITE ITE_CMD | ITE_I2CHCR_CP_W
+#define ITE_READ ITE_CMD | ITE_I2CHCR_CP_R
+#define ITE_SREAD ITE_CMD | ITE_I2CHCR_CP_S
+
+/* Host Status Register ITE_I2CHSR */
+#define ITE_I2CHSR_DB 0x01 /* Device is busy, receives NACK response except
+ in the first and last bytes */
+#define ITE_I2CHSR_DNE 0x02 /* Target address on I2C bus does not exist */
+#define ITE_I2CHSR_TDI 0x04 /* R/W Transaction on I2C bus was completed */
+#define ITE_I2CHSR_HB 0x08 /* Host controller is processing transactions */
+#define ITE_I2CHSR_FER 0x10 /* Error occurs in the FIFO */
+
+/* Slave Address Register ITE_I2CSAR */
+#define ITE_I2CSAR_SA_MASK 0xfe /* Target I2C device address */
+#define ITE_I2CSAR_ASO 0x0100 /* Output 1/0 to I2CAS port when the
+ next slave address is addressed */
+
+/* Slave Sub-address Register ITE_I2CSSAR */
+#define ITE_I2CSSAR_SUBA_MASK 0xff /* Target I2C device sub-address */
+
+/* Clock Counter Register ITE_I2CCKCNT */
+#define ITE_I2CCKCNT_STOP 0x00 /* stop I2C clock */
+#define ITE_I2CCKCNT_HPCC_MASK 0x7f /* SCL high period counter */
+#define ITE_I2CCKCNT_LPCC_MASK 0x7f00 /* SCL low period counter */
+
+/* START Hold Time Register ITE_I2CSHDR */
+/* value is counted based on 16 MHz internal clock */
+#define ITE_I2CSHDR_FM 0x0a /* START condition at fast mode */
+#define ITE_I2CSHDR_SM 0x47 /* START contition at standard mode */
+
+/* (Repeated) START Setup Time Register ITE_I2CRSUR */
+/* value is counted based on 16 MHz internal clock */
+#define ITE_I2CRSUR_FM 0x0a /* repeated START condition at fast mode */
+#define ITE_I2CRSUR_SM 0x50 /* repeated START condition at standard mode */
+
+/* STOP setup Time Register ITE_I2CPSUR */
+
+/* FIFO Data Register ITE_I2CFDR */
+#define ITE_I2CFDR_MASK 0xff
+
+/* FIFO Byte Count Register ITE_I2CFBCR */
+#define ITE_I2CFBCR_MASK 0x3f
+
+/* FIFO Control Register ITE_I2CFCR */
+#define ITE_I2CFCR_FLUSH 0x01 /* Flush FIFO and reset the FIFO point
+ and I2CFSR */
+/* FIFO Status Register ITE_I2CFSR */
+#define ITE_I2CFSR_FO 0x01 /* FIFO is overrun when write */
+#define ITE_I2CFSR_FU 0x02 /* FIFO is underrun when read */
+#define ITE_I2CFSR_FF 0x04 /* FIFO is full when write */
+#define ITE_I2CFSR_FE 0x08 /* FIFO is empty when read */
+
+#endif /* I2C_ITE_H */
diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c
index 3e8f813e532d..0ec403f178d4 100644
--- a/drivers/i2o/i2o_block.c
+++ b/drivers/i2o/i2o_block.c
@@ -1854,16 +1854,14 @@ static struct block_device_operations i2ob_fops =
static struct gendisk i2ob_gendisk =
{
- MAJOR_NR,
- "i2o/hd",
- 4,
- 1<<4,
- i2ob,
- i2ob_sizes,
- MAX_I2OB,
- NULL,
- NULL,
- &i2ob_fops,
+ major: MAJOR_NR,
+ major_name: "i2o/hd",
+ minor_shift: 4,
+ max_p: 1<<4,
+ part: i2ob,
+ sizes: i2ob_sizes,
+ nr_real: MAX_I2OB,
+ fops: &i2ob_fops,
};
diff --git a/drivers/ide/amd7409.c b/drivers/ide/amd7409.c
deleted file mode 100644
index d01a25f266fc..000000000000
--- a/drivers/ide/amd7409.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * linux/drivers/ide/amd7409.c Version 0.05 June 9, 2000
- *
- * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_VIPER_TIMINGS
-
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int amd7409_get_info(char *, char **, off_t, int);
-extern int (*amd7409_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count)
-{
- char *p = buffer;
- u32 bibma = pci_resource_start(bmide_dev, 4);
- u8 c0 = 0, c1 = 0;
-
- /*
- * at that point bibma+0x2 et bibma+0xa are byte registers
- * to investigate:
- */
- c0 = inb_p((unsigned short)bibma + 0x02);
- c1 = inb_p((unsigned short)bibma + 0x0a);
-
- p += sprintf(p, "\n AMD 7409 VIPER Chipset.\n");
- p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
- p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
- p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
- p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
- p += sprintf(p, "PIO\n");
-
- return p-buffer; /* => must be less than 4k! */
-}
-#endif /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte amd7409_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static unsigned int amd7409_swdma_check (struct pci_dev *dev)
-{
- unsigned int class_rev;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
- return ((int) (class_rev >= 7) ? 1 : 0);
-}
-
-static int amd7409_swdma_error(ide_drive_t *drive)
-{
- printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
- return 0;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- *
- */
-static int amd7409_tune_chipset (ide_drive_t *drive, byte speed)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- int err = 0;
- byte unit = (drive->select.b.unit & 0x01);
-#ifdef CONFIG_BLK_DEV_IDEDMA
- unsigned long dma_base = hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- byte drive_pci = 0x00;
- byte drive_pci2 = 0x00;
- byte ultra_timing = 0x00;
- byte dma_pio_timing = 0x00;
- byte pio_timing = 0x00;
-
- switch (drive->dn) {
- case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
- case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
- case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
- case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
- default:
- return -1;
- }
-
- pci_read_config_byte(dev, drive_pci, &ultra_timing);
- pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
- pci_read_config_byte(dev, 0x4c, &pio_timing);
-
-#ifdef DEBUG
- printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
- drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
- ultra_timing &= ~0xC7;
- dma_pio_timing &= ~0xFF;
- pio_timing &= ~(0x03 << drive->dn);
-
-#ifdef DEBUG
- printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
- ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
- switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
- case XFER_UDMA_4:
- ultra_timing |= 0x45;
- dma_pio_timing |= 0x20;
- break;
- case XFER_UDMA_3:
- ultra_timing |= 0x44;
- dma_pio_timing |= 0x20;
- break;
- case XFER_UDMA_2:
- ultra_timing |= 0x40;
- dma_pio_timing |= 0x20;
- break;
- case XFER_UDMA_1:
- ultra_timing |= 0x41;
- dma_pio_timing |= 0x20;
- break;
- case XFER_UDMA_0:
- ultra_timing |= 0x42;
- dma_pio_timing |= 0x20;
- break;
- case XFER_MW_DMA_2:
- dma_pio_timing |= 0x20;
- break;
- case XFER_MW_DMA_1:
- dma_pio_timing |= 0x21;
- break;
- case XFER_MW_DMA_0:
- dma_pio_timing |= 0x77;
- break;
- case XFER_SW_DMA_2:
- if (!amd7409_swdma_check(dev))
- return amd7409_swdma_error(drive);
- dma_pio_timing |= 0x42;
- break;
- case XFER_SW_DMA_1:
- if (!amd7409_swdma_check(dev))
- return amd7409_swdma_error(drive);
- dma_pio_timing |= 0x65;
- break;
- case XFER_SW_DMA_0:
- if (!amd7409_swdma_check(dev))
- return amd7409_swdma_error(drive);
- dma_pio_timing |= 0xA8;
- break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- case XFER_PIO_4:
- dma_pio_timing |= 0x20;
- break;
- case XFER_PIO_3:
- dma_pio_timing |= 0x22;
- break;
- case XFER_PIO_2:
- dma_pio_timing |= 0x42;
- break;
- case XFER_PIO_1:
- dma_pio_timing |= 0x65;
- break;
- case XFER_PIO_0:
- default:
- dma_pio_timing |= 0xA8;
- break;
- }
-
- pio_timing |= (0x03 << drive->dn);
-
- if (!drive->init_speed)
- drive->init_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
- pci_write_config_byte(dev, drive_pci, ultra_timing);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
- pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
- pci_write_config_byte(dev, 0x4c, pio_timing);
-
-#ifdef DEBUG
- printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
- ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (speed > XFER_PIO_4) {
- outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
- } else {
- outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
- }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
- err = ide_config_drive_speed(drive, speed);
- drive->current_speed = speed;
- return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
- unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
- unsigned short xfer_pio = drive->id->eide_pio_modes;
- byte timing, speed, pio;
-
- pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- if (xfer_pio> 4)
- xfer_pio = 0;
-
- if (drive->id->eide_pio_iordy > 0) {
- for (xfer_pio = 5;
- xfer_pio>0 &&
- drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
- xfer_pio--);
- } else {
- xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
- (drive->id->eide_pio_modes & 2) ? 0x04 :
- (drive->id->eide_pio_modes & 1) ? 0x03 :
- (drive->id->tPIO & 2) ? 0x02 :
- (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
- }
-
- timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
- switch(timing) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default:
- speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
- break;
- }
- (void) amd7409_tune_chipset(drive, speed);
- drive->current_speed = speed;
-}
-
-static void amd7409_tune_drive (ide_drive_t *drive, byte pio)
-{
- byte speed;
- switch(pio) {
- case 4: speed = XFER_PIO_4;break;
- case 3: speed = XFER_PIO_3;break;
- case 2: speed = XFER_PIO_2;break;
- case 1: speed = XFER_PIO_1;break;
- default: speed = XFER_PIO_0;break;
- }
- (void) amd7409_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- byte udma_66 = eighty_ninty_three(drive);
- byte udma_100 = 0;
- byte speed = 0x00;
- int rval;
-
- if ((id->dma_ultra & 0x0020) && (udma_66)&& (udma_100)) {
- speed = XFER_UDMA_5;
- } else if ((id->dma_ultra & 0x0010) && (udma_66)) {
- speed = XFER_UDMA_4;
- } else if ((id->dma_ultra & 0x0008) && (udma_66)) {
- speed = XFER_UDMA_3;
- } else if (id->dma_ultra & 0x0004) {
- speed = XFER_UDMA_2;
- } else if (id->dma_ultra & 0x0002) {
- speed = XFER_UDMA_1;
- } else if (id->dma_ultra & 0x0001) {
- speed = XFER_UDMA_0;
- } else if (id->dma_mword & 0x0004) {
- speed = XFER_MW_DMA_2;
- } else if (id->dma_mword & 0x0002) {
- speed = XFER_MW_DMA_1;
- } else if (id->dma_mword & 0x0001) {
- speed = XFER_MW_DMA_0;
- } else {
- return ((int) ide_dma_off_quietly);
- }
-
- (void) amd7409_tune_chipset(drive, speed);
-
- rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
- ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
- ((id->dma_mword >> 8) & 7) ? ide_dma_on :
- ide_dma_off_quietly);
-
- return rval;
-}
-
-
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- ide_dma_action_t dma_func = ide_dma_on;
-
- if (id && (id->capability & 1) && HWIF(drive)->autodma) {
- /* Consult the list of known "bad" drives */
- if (ide_dmaproc(ide_dma_bad_drive, drive)) {
- dma_func = ide_dma_off;
- goto fast_ata_pio;
- }
- dma_func = ide_dma_off_quietly;
- if (id->field_valid & 4) {
- if (id->dma_ultra & 0x002F) {
- /* Force if Capable UltraDMA */
- dma_func = config_chipset_for_dma(drive);
- if ((id->field_valid & 2) &&
- (dma_func != ide_dma_on))
- goto try_dma_modes;
- }
- } else if (id->field_valid & 2) {
-try_dma_modes:
- if ((id->dma_mword & 0x0007) ||
- ((id->dma_1word & 0x007) &&
- (amd7409_swdma_check(HWIF(drive)->pci_dev)))) {
- /* Force if Capable regular DMA modes */
- dma_func = config_chipset_for_dma(drive);
- if (dma_func != ide_dma_on)
- goto no_dma_set;
- }
-
- } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
- if (id->eide_dma_time > 150) {
- goto no_dma_set;
- }
- /* Consult the list of known "good" drives */
- dma_func = config_chipset_for_dma(drive);
- if (dma_func != ide_dma_on)
- goto no_dma_set;
- } else {
- goto fast_ata_pio;
- }
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- dma_func = ide_dma_off_quietly;
-no_dma_set:
-
- config_chipset_for_pio(drive);
- }
- return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * amd7409_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int amd7409_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
- switch (func) {
- case ide_dma_check:
- return config_drive_xfer_rate(drive);
- default:
- break;
- }
- return ide_dmaproc(func, drive); /* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name)
-{
- unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
- if (!amd7409_swdma_check(dev))
- printk("%s: disabling single-word DMA support (revision < C4)\n", name);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
- if (!fixdma_base) {
- /*
- *
- */
- } else {
- /*
- * enable DMA capable bit, and "not" simplex only
- */
- outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
- if (inb(fixdma_base+2) & 0x80)
- printk("%s: simplex device: DMA will fail!!\n", name);
- }
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
- if (!amd7409_proc) {
- amd7409_proc = 1;
- bmide_dev = dev;
- amd7409_display_info = &amd7409_get_info;
- }
-#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
-
- return 0;
-}
-
-unsigned int __init ata66_amd7409 (ide_hwif_t *hwif)
-{
-#ifdef CONFIG_AMD7409_OVERRIDE
- byte ata66 = 1;
-#else
- byte ata66 = 0;
-#endif /* CONFIG_AMD7409_OVERRIDE */
-
-#if 0
- pci_read_config_byte(hwif->pci_dev, 0x48, &ata66);
- return ((ata66 & 0x02) ? 0 : 1);
-#endif
- return ata66;
-}
-
-void __init ide_init_amd7409 (ide_hwif_t *hwif)
-{
- hwif->tuneproc = &amd7409_tune_drive;
- hwif->speedproc = &amd7409_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- hwif->autodma = 0;
- return;
-#else
-
- if (hwif->dma_base) {
- hwif->dmaproc = &amd7409_dmaproc;
- if (!noautodma)
- hwif->autodma = 1;
- } else {
- hwif->autodma = 0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- }
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase)
-{
- ide_setup_dma(hwif, dmabase, 8);
-}
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index ab816436b09c..bdc854f46a3a 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -688,16 +688,13 @@ static int hd_release(struct inode * inode, struct file * file)
extern struct block_device_operations hd_fops;
static struct gendisk hd_gendisk = {
- MAJOR_NR, /* Major number */
- "hd", /* Major name */
- 6, /* Bits to shift to get real from partition */
- 1 << 6, /* Number of partitions per real */
- hd, /* hd struct */
- hd_sizes, /* block sizes */
- 0, /* number */
- NULL, /* internal use, not presently used */
- NULL, /* next */
- &hd_fops, /* file operations */
+ major: MAJOR_NR,
+ major_name: "hd",
+ minor_shift: 6,
+ max_p: 1 << 6,
+ part: hd,
+ sizes: hd_sizes,
+ fops: &hd_fops,
};
static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -842,7 +839,7 @@ int __init hd_init(void)
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
- add_gendisk(&hd_gendisk, MAJOR_NR);
+ add_gendisk(&hd_gendisk);
init_timer(&device_timer);
device_timer.function = hd_times_out;
hd_geninit();
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index c92dbaaf1ed6..3ad4c48e61ce 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -130,10 +130,30 @@ struct drive_list_entry drive_blacklist [] = {
{ "WDC AC23200L" , "21.10N21" },
{ "Compaq CRD-8241B" , "ALL" },
{ "CRD-8400B" , "ALL" },
+ { "CRD-8480B", "ALL" },
+ { "CRD-8480C", "ALL" },
+ { "CRD-8482B", "ALL" },
+ { "CRD-84" , "ALL" },
+ { "SanDisk SDP3B" , "ALL" },
+ { "SanDisk SDP3B-64" , "ALL" },
+ { "SANYO CD-ROM CRD" , "ALL" },
+ { "HITACHI CDR-8" , "ALL" },
+ { "HITACHI CDR-8335" , "ALL" },
+ { "HITACHI CDR-8435" , "ALL" },
+ { "Toshiba CD-ROM XM-6202B" , "ALL" },
+ { "CD-532E-A" , "ALL" },
+ { "E-IDE CD-ROM CR-840", "ALL" },
+ { "CD-ROM Drive/F5A", "ALL" },
+ { "RICOH CD-R/RW MP7083A", "ALL" },
+ { "WPI CDD-820", "ALL" },
+ { "SAMSUNG CD-ROM SC-148C", "ALL" },
+ { "SAMSUNG CD-ROM SC-148F", "ALL" },
+ { "SAMSUNG CD-ROM SC", "ALL" },
{ "SanDisk SDP3B-64" , "ALL" },
{ "SAMSUNG CD-ROM SN-124", "ALL" },
{ "PLEXTOR CD-R PX-W8432T", "ALL" },
{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" },
+ { "_NEC DV5800A", "ALL" },
{ 0 , 0 }
};
diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
index 506ff25f38d7..8f473d078bd7 100644
--- a/drivers/ide/ide-pci.c
+++ b/drivers/ide/ide-pci.c
@@ -38,6 +38,7 @@
#define DEVID_PIIX4U3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9})
#define DEVID_PIIX4U4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8})
#define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561})
+#define DEVID_MR_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1})
#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
#define DEVID_PDC20262 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
@@ -385,6 +386,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
{DEVID_PIIX4U3, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_PIIX4U4, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 },
{DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 },
+ {DEVID_MR_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 },
{DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 },
#ifdef CONFIG_PDC202XX_FORCE
{DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 16 },
@@ -758,6 +760,7 @@ controller_ok:
IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
autodma = 0;
if (autodma)
@@ -767,6 +770,7 @@ controller_ok:
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
+ IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
index c846f7811eb9..a09ba75455a2 100644
--- a/drivers/ide/serverworks.c
+++ b/drivers/ide/serverworks.c
@@ -544,8 +544,33 @@ unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
return 0;
}
+/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem
+ * device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set = secondary IDE channel has 80-pin cable.
+ * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+ * Bit 14 set = primary IDE channel has 80-pin cable.
+ */
+
+static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ return ((1 << (hwif->channel + 14)) &
+ dev->subsystem_device) ? 1 : 0;
+
+ return 0;
+
+}
+
unsigned int __init ata66_svwks (ide_hwif_t *hwif)
{
+ struct pci_dev *dev = hwif->pci_dev;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+ return ata66_svwks_dell (hwif);
+
return 0;
}
diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in
index 8872b4c8a93c..30ccb26c32e8 100644
--- a/drivers/isdn/Config.in
+++ b/drivers/isdn/Config.in
@@ -76,8 +76,11 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
bool ' Am7930' CONFIG_HISAX_AMD7930
fi
fi
+ bool ' HiSax debugging' CONFIG_HISAX_DEBUG
+
dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
+ dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
fi
endmenu
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
index c39f9d5df626..889161b870e7 100644
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -418,7 +418,7 @@ act2000_isa_getid(act2000_card * card)
int
act2000_isa_download(act2000_card * card, act2000_ddef * cb)
{
- int length;
+ unsigned int length;
int ret;
int l;
int c;
@@ -431,9 +431,8 @@ act2000_isa_download(act2000_card * card, act2000_ddef * cb)
if (!act2000_isa_reset(card->port))
return -ENXIO;
act2000_isa_delay(HZ / 2);
- if ((ret = verify_area(VERIFY_READ, (void *) cb, sizeof(cblock))))
- return ret;
- copy_from_user(&cblock, (char *) cb, sizeof(cblock));
+ if(copy_from_user(&cblock, (char *) cb, sizeof(cblock)))
+ return -EFAULT;
length = cblock.length;
p = cblock.buffer;
if ((ret = verify_area(VERIFY_READ, (void *) p, length)))
diff --git a/drivers/isdn/eicon/idi.c b/drivers/isdn/eicon/idi.c
index 1bb57a77924a..62b4342f70d8 100644
--- a/drivers/isdn/eicon/idi.c
+++ b/drivers/isdn/eicon/idi.c
@@ -431,7 +431,9 @@ void DivasOut(ADAPTER * a)
i = this->XCurrent;
X = PTR_X(a,this);
while(i<this->XNum && length<270) {
- clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+ clength = (word)(270-length);
+ if (clength > X[i].PLength-this->XOffset)
+ clength = X[i].PLength-this->XOffset;
a->ram_out_buffer(a,
&ReqOut->XBuffer.P[length],
PTR_P(a,this,&X[i].P[this->XOffset]),
@@ -837,8 +839,9 @@ byte isdn_ind(ADAPTER * a,
this->ROffset = 0;
this->RCurrent++;
}
- clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
- R[this->RCurrent].PLength-this->ROffset);
+ clength = a->ram_inw(a, &RBuffer->length)-offset;
+ if (clength > R[this->RCurrent].PLength-this->ROffset)
+ clength = R[this->RCurrent].PLength-this->ROffset;
if(R[this->RCurrent].P) {
a->ram_in_buffer(a,
&RBuffer->P[offset],
diff --git a/drivers/isdn/eicon/kprintf.c b/drivers/isdn/eicon/kprintf.c
index 9a4598fc6abb..3357bca2666a 100644
--- a/drivers/isdn/eicon/kprintf.c
+++ b/drivers/isdn/eicon/kprintf.c
@@ -30,8 +30,6 @@
#include "eicon.h"
#include "sys.h"
#include <stdarg.h>
-#undef MAX
-#undef MIN
#include "divas.h"
#include "divalog.h"
diff --git a/drivers/isdn/eicon/pc.h b/drivers/isdn/eicon/pc.h
index 0ba821ad2600..1adfe4dac4bc 100644
--- a/drivers/isdn/eicon/pc.h
+++ b/drivers/isdn/eicon/pc.h
@@ -29,12 +29,6 @@
#define byte unsigned char
#define word unsigned short
#define dword unsigned long
-#if !defined(MIN)
-#define MIN(a,b) ((a)>(b) ? (b) : (a))
-#endif
-#if !defined(MAX)
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#endif
/*------------------------------------------------------------------*/
/* buffer definition */
diff --git a/drivers/isdn/eicon/sys.h b/drivers/isdn/eicon/sys.h
index e5141b856b04..3a69dbba063e 100644
--- a/drivers/isdn/eicon/sys.h
+++ b/drivers/isdn/eicon/sys.h
@@ -54,15 +54,6 @@ typedef volatile dword vdword;
#define NULL ((void *) 0)
#endif
-/* MIN and MAX */
-
-#if !defined(MIN)
-#define MIN(a,b) ((a)>(b) ? (b) : (a))
-#endif
-#if !defined(MAX)
-#define MAX(a,b) ((a)>(b) ? (a) : (b))
-#endif
-
/* Return the dimension of an array */
#if !defined(DIM)
@@ -85,6 +76,8 @@ void HwFatalError(void);
/* void HwAssert(char *file, int line, char *condition); */
#include <linux/kernel.h>
+#include <linux/string.h>
+
#define _PRINTK printk
#define _PRINTF DivasPrintf
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 3d79592d565d..9f1a1f657812 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -2,20 +2,21 @@
# The target object and module list name.
-O_TARGET := vmlinux-obj.o
+O_TARGET := vmlinux-obj.o
# Objects that export symbols.
-export-objs := config.o
+export-objs := config.o fsm.o
# Multipart objects.
-list-multi := hisax.o
-hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
- lmgr.o q931.o callc.o fsm.o cert.o
+list-multi := hisax.o hisax_st5481.o
+hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
+ lmgr.o q931.o callc.o fsm.o cert.o
+hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
+ st5481_hdlc.o
# Optional parts of multipart objects.
-
hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o
hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
@@ -27,7 +28,6 @@ hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
-hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
@@ -54,9 +54,10 @@ hisax-objs += $(sort $(hisax-objs-y))
# Each configuration option enables a list of files.
-obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
+obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
-obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
+obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
+obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
@@ -67,3 +68,6 @@ include $(TOPDIR)/Rules.make
hisax.o: $(hisax-objs)
$(LD) -r -o $@ $(hisax-objs)
+
+hisax_st5481.o: $(hisax_st5481-objs)
+ $(LD) -r -o $@ $(hisax_st5481-objs)
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 2f25292320e7..66087a18e119 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 2.51.6.4 2001/06/09 15:14:17 kai Exp $
+/* $Id: callc.c,v 2.51.6.5 2001/08/23 19:44:23 kai Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -20,12 +20,12 @@
#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
#endif /* MODULE */
-const char *lli_revision = "$Revision: 2.51.6.4 $";
+const char *lli_revision = "$Revision: 2.51.6.5 $";
extern struct IsdnCard cards[];
extern int nrcards;
-extern void HiSax_mod_dec_use_count(void);
-extern void HiSax_mod_inc_use_count(void);
+extern void HiSax_mod_dec_use_count(struct IsdnCardState *cs);
+extern void HiSax_mod_inc_use_count(struct IsdnCardState *cs);
static int init_b_st(struct Channel *chanp, int incoming);
static void release_b_st(struct Channel *chanp);
@@ -1584,7 +1584,7 @@ HiSax_command(isdn_ctrl * ic)
}
break;
case (ISDN_CMD_LOCK):
- HiSax_mod_inc_use_count();
+ HiSax_mod_inc_use_count(csta);
#ifdef MODULE
if (csta->channel[0].debug & 0x400)
HiSax_putstatus(csta, " LOCK ", "modcnt %lx",
@@ -1592,7 +1592,7 @@ HiSax_command(isdn_ctrl * ic)
#endif /* MODULE */
break;
case (ISDN_CMD_UNLOCK):
- HiSax_mod_dec_use_count();
+ HiSax_mod_dec_use_count(csta);
#ifdef MODULE
if (csta->channel[0].debug & 0x400)
HiSax_putstatus(csta, " UNLOCK ", "modcnt %lx",
@@ -1624,11 +1624,11 @@ HiSax_command(isdn_ctrl * ic)
break;
case (3):
for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
- HiSax_mod_dec_use_count();
+ HiSax_mod_dec_use_count(NULL);
break;
case (4):
for (i = 0; i < *(unsigned int *) ic->parm.num; i++)
- HiSax_mod_inc_use_count();
+ HiSax_mod_inc_use_count(NULL);
break;
case (5): /* set card in leased mode */
num = *(unsigned int *) ic->parm.num;
@@ -1698,7 +1698,7 @@ HiSax_command(isdn_ctrl * ic)
#ifdef MODULE
case (55):
MOD_USE_COUNT = 0;
- HiSax_mod_inc_use_count();
+ HiSax_mod_inc_use_count(NULL);
break;
#endif /* MODULE */
case (11):
@@ -1810,6 +1810,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
cli();
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
+ nskb->truesize = nskb->len;
if (!ack)
nskb->pkt_type = PACKET_NOACK;
if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I)
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 852ef1a54407..7a2db6d34384 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1,4 +1,4 @@
-/* $Id: config.c,v 2.57.6.16 2001/07/13 09:01:00 kai Exp $
+/* $Id: config.c,v 2.57.6.18 2001/08/27 22:19:05 kai Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -313,7 +313,8 @@ EXPORT_SYMBOL(hfc_init_pcmcia);
#define DEFAULT_PROTO_NAME "UNKNOWN"
#endif
#ifndef DEFAULT_CARD
-#error "HiSax: No cards configured"
+#define DEFAULT_CARD 0
+#define DEFAULT_CFG {0,0,0,0}
#endif
int hisax_init_pcmcia(void *, int *, struct IsdnCard *);
@@ -423,16 +424,6 @@ void __init HiSaxVersion(void)
certification_check(1);
}
-void HiSax_mod_dec_use_count(void)
-{
- MOD_DEC_USE_COUNT;
-}
-
-void HiSax_mod_inc_use_count(void)
-{
- MOD_INC_USE_COUNT;
-}
-
#ifndef MODULE
#define MAX_ARG (HISAX_MAX_CARDS*5)
static int __init HiSax_setup(char *line)
@@ -840,8 +831,9 @@ static void closecard(int cardnr)
if (csta->DC_Close != NULL) {
csta->DC_Close(csta);
}
- csta->cardmsg(csta, CARD_RELEASE, NULL);
- if (csta->dbusytimer.function != NULL)
+ if (csta->cardmsg)
+ csta->cardmsg(csta, CARD_RELEASE, NULL);
+ if (csta->dbusytimer.function != NULL) // FIXME?
del_timer(&csta->dbusytimer);
ll_unload(csta);
}
@@ -1137,6 +1129,9 @@ static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
ret = setup_netjet_u(card);
break;
#endif
+ case ISDN_CTYPE_DYNAMIC:
+ ret = 2;
+ break;
default:
printk(KERN_WARNING
"HiSax: Support for %s Card not selected\n",
@@ -1165,7 +1160,17 @@ static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
init_bcstate(cs, 0);
init_bcstate(cs, 1);
- ret = init_card(cs);
+
+ /* init_card only handles interrupts which are not */
+ /* used here for the loadable driver */
+ switch (card->typ) {
+ case ISDN_CTYPE_DYNAMIC:
+ ret = 0;
+ break;
+ default:
+ ret = init_card(cs);
+ break;
+ }
if (ret) {
closecard(cardnr);
ret = 0;
@@ -1343,6 +1348,8 @@ static int __init HiSax_init(void)
#ifdef MODULE
if (!type[0]) {
/* We 'll register drivers later, but init basic functions */
+ for (i = 0; i < HISAX_MAX_CARDS; i++)
+ cards[i].typ = 0;
return 0;
}
#ifdef CONFIG_HISAX_ELSA
@@ -1572,7 +1579,6 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
{
#ifdef MODULE
int i;
- int nzproto = 0;
nrcards = 0;
/* Initialize all structs, even though we only accept
@@ -1584,14 +1590,12 @@ int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
- nzproto++;
}
}
cards[0].para[0] = pcm_irq;
cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
- nzproto = 1;
if (!HiSax_id)
HiSax_id = HiSaxID;
@@ -1615,7 +1619,6 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
{
#ifdef MODULE
int i;
- int nzproto = 0;
nrcards = 0;
/* Initialize all structs, even though we only accept
@@ -1627,14 +1630,12 @@ int sedl_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
- nzproto++;
}
}
cards[0].para[0] = pcm_irq;
cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_SEDLBAUER_PCMCIA;
- nzproto = 1;
if (!HiSax_id)
HiSax_id = HiSaxID;
@@ -1658,7 +1659,6 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
{
#ifdef MODULE
int i;
- int nzproto = 0;
nrcards = 0;
/* Initialize all structs, even though we only accept
@@ -1670,14 +1670,12 @@ int avm_a1_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
cards[i].typ = type[i];
if (protocol[i]) {
cards[i].protocol = protocol[i];
- nzproto++;
}
}
cards[0].para[0] = pcm_irq;
cards[0].para[1] = (int) pcm_iob;
cards[0].protocol = prot;
cards[0].typ = ISDN_CTYPE_A1_PCMCIA;
- nzproto = 1;
if (!HiSax_id)
HiSax_id = HiSaxID;
@@ -1715,11 +1713,362 @@ int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag,
return ret;
}
+#include "hisax_if.h"
+
+EXPORT_SYMBOL(hisax_register);
+EXPORT_SYMBOL(hisax_unregister);
+
+static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg);
+static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg);
+static void hisax_d_l2l1(struct PStack *st, int pr, void *arg);
+static void hisax_b_l2l1(struct PStack *st, int pr, void *arg);
+static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg);
+static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs);
+static void hisax_bc_close(struct BCState *bcs);
+static void hisax_bh(struct IsdnCardState *cs);
+static void EChannel_proc_rcv(struct hisax_d_if *d_if);
+
+int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
+ char *name, int protocol)
+{
+ int i, retval;
+ char id[20];
+ struct IsdnCardState *cs;
+
+ for (i = 0; i < HISAX_MAX_CARDS; i++) {
+ if (!cards[i].typ)
+ break;
+ }
+
+ if (i >= HISAX_MAX_CARDS)
+ return -EBUSY;
+
+ cards[i].typ = ISDN_CTYPE_DYNAMIC;
+ cards[i].protocol = protocol;
+ sprintf(id, "%s%d", name, i);
+ nrcards++;
+ retval = checkcard(i, id, 0);
+ if (retval == 0) { // yuck
+ cards[i].typ = 0;
+ nrcards--;
+ return retval;
+ }
+ cs = cards[i].cs;
+ hisax_d_if->cs = cs;
+ cs->hw.hisax_d_if = hisax_d_if;
+ cs->cardmsg = hisax_cardmsg;
+ cs->tqueue.routine = (void *) (void *) hisax_bh;
+ cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1;
+ for (i = 0; i < 2; i++) {
+ cs->bcs[i].BC_SetStack = hisax_bc_setstack;
+ cs->bcs[i].BC_Close = hisax_bc_close;
+
+ b_if[i]->ifc.l1l2 = hisax_b_l1l2;
+
+ hisax_d_if->b_if[i] = b_if[i];
+ }
+ hisax_d_if->ifc.l1l2 = hisax_d_l1l2;
+ skb_queue_head_init(&hisax_d_if->erq);
+ clear_bit(0, &hisax_d_if->ph_state);
+
+ return 0;
+}
+
+void hisax_unregister(struct hisax_d_if *hisax_d_if)
+{
+ cards[hisax_d_if->cs->cardnr].typ = 0;
+ HiSax_closecard(hisax_d_if->cs->cardnr);
+ skb_queue_purge(&hisax_d_if->erq);
+}
+
+#include "isdnl1.h"
+
+static void hisax_sched_event(struct IsdnCardState *cs, int event)
+{
+ cs->event |= 1 << event;
+ queue_task(&cs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void hisax_bh(struct IsdnCardState *cs)
+{
+ struct PStack *st;
+ int pr;
+
+ if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+ DChannel_proc_rcv(cs);
+ if (test_and_clear_bit(E_RCVBUFREADY, &cs->event))
+ EChannel_proc_rcv(cs->hw.hisax_d_if);
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ if (test_bit(0, &cs->hw.hisax_d_if->ph_state))
+ pr = PH_ACTIVATE | INDICATION;
+ else
+ pr = PH_DEACTIVATE | INDICATION;
+ for (st = cs->stlist; st; st = st->next)
+ st->l1.l1l2(st, pr, NULL);
+
+ }
+}
+
+static void hisax_b_sched_event(struct BCState *bcs, int event)
+{
+ bcs->event |= 1 << event;
+ queue_task(&bcs->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) d_if;
+ ifc->l2l1(ifc, pr, arg);
+}
+
+static inline void B_L2L1(struct hisax_b_if *b_if, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) b_if;
+ ifc->l2l1(ifc, pr, arg);
+}
+
+static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg)
+{
+ struct hisax_d_if *d_if = (struct hisax_d_if *) ifc;
+ struct IsdnCardState *cs = d_if->cs;
+ struct PStack *st;
+ struct sk_buff *skb;
+
+ switch (pr) {
+ case PH_ACTIVATE | INDICATION:
+ set_bit(0, &d_if->ph_state);
+ hisax_sched_event(cs, D_L1STATECHANGE);
+ break;
+ case PH_DEACTIVATE | INDICATION:
+ clear_bit(0, &d_if->ph_state);
+ hisax_sched_event(cs, D_L1STATECHANGE);
+ break;
+ case PH_DATA | INDICATION:
+ skb_queue_tail(&cs->rq, arg);
+ hisax_sched_event(cs, D_RCVBUFREADY);
+ break;
+ case PH_DATA | CONFIRM:
+ skb = skb_dequeue(&cs->sq);
+ if (skb) {
+ D_L2L1(d_if, PH_DATA | REQUEST, skb);
+ break;
+ }
+ clear_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+ for (st = cs->stlist; st; st = st->next) {
+ if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ break;
+ }
+ }
+ break;
+ case PH_DATA_E | INDICATION:
+ skb_queue_tail(&d_if->erq, arg);
+ hisax_sched_event(cs, E_RCVBUFREADY);
+ break;
+ default:
+ printk("pr %#x\n", pr);
+ break;
+ }
+}
+
+static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
+{
+ struct hisax_b_if *b_if = (struct hisax_b_if *) ifc;
+ struct BCState *bcs = b_if->bcs;
+ struct PStack *st = bcs->st;
+ struct sk_buff *skb;
+
+ // FIXME use isdnl1?
+ switch (pr) {
+ case PH_ACTIVATE | INDICATION:
+ st->l1.l1l2(st, pr, NULL);
+ break;
+ case PH_DEACTIVATE | INDICATION:
+ st->l1.l1l2(st, pr, NULL);
+ bcs->hw.b_if = NULL;
+ break;
+ case PH_DATA | INDICATION:
+ skb_queue_tail(&bcs->rqueue, arg);
+ hisax_b_sched_event(bcs, B_RCVBUFREADY);
+ break;
+ case PH_DATA | CONFIRM:
+ bcs->tx_cnt -= (int) arg;
+ if (bcs->st->lli.l1writewakeup)
+ bcs->st->lli.l1writewakeup(bcs->st, (int) arg);
+ skb = skb_dequeue(&bcs->squeue);
+ if (skb) {
+ B_L2L1(b_if, PH_DATA | REQUEST, skb);
+ break;
+ }
+ clear_bit(BC_FLG_BUSY, &bcs->Flag);
+ if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) {
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ }
+ break;
+ default:
+ printk("hisax_b_l1l2 pr %#x\n", pr);
+ break;
+ }
+}
+
+static void hisax_d_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct IsdnCardState *cs = st->l1.hardware;
+ struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case PH_DATA | REQUEST:
+ case PH_PULL | INDICATION:
+ if (cs->debug & DEB_DLOG_HEX)
+ LogFrame(cs, skb->data, skb->len);
+ if (cs->debug & DEB_DLOG_VERBOSE)
+ dlogframe(cs, skb, 0);
+ Logl2Frame(cs, skb, "PH_DATA_REQ", 0);
+ // FIXME lock?
+ if (!test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ D_L2L1(hisax_d_if, PH_DATA | REQUEST, skb);
+ else
+ skb_queue_tail(&cs->sq, skb);
+ break;
+ case PH_PULL | REQUEST:
+ if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ else
+ set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ default:
+ D_L2L1(hisax_d_if, pr, arg);
+ break;
+ }
+}
+
+static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg)
+{
+ return 0;
+}
+
+static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
+{
+ struct BCState *bcs = st->l1.bcs;
+ struct hisax_b_if *b_if = bcs->hw.b_if;
+
+ switch (pr) {
+ case PH_ACTIVATE | REQUEST:
+ B_L2L1(b_if, pr, (void *) st->l1.mode);
+ break;
+ case PH_DATA | REQUEST:
+ case PH_PULL | INDICATION:
+ // FIXME lock?
+ if (!test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) {
+ B_L2L1(b_if, PH_DATA | REQUEST, arg);
+ } else {
+ skb_queue_tail(&bcs->squeue, arg);
+ }
+ break;
+ case PH_PULL | REQUEST:
+ if (!test_bit(BC_FLG_BUSY, &bcs->Flag))
+ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+ else
+ set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ break;
+ default:
+ B_L2L1(b_if, pr, arg);
+ break;
+ }
+}
+
+static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs)
+{
+ struct IsdnCardState *cs = st->l1.hardware;
+ struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if;
+
+ bcs->channel = st->l1.bc;
+
+ bcs->hw.b_if = hisax_d_if->b_if[st->l1.bc];
+ hisax_d_if->b_if[st->l1.bc]->bcs = bcs;
+
+ st->l1.bcs = bcs;
+ st->l2.l2l1 = hisax_b_l2l1;
+ setstack_manager(st);
+ bcs->st = st;
+ setstack_l1_B(st);
+ skb_queue_head_init(&bcs->rqueue);
+ skb_queue_head_init(&bcs->squeue);
+ return 0;
+}
+
+static void hisax_bc_close(struct BCState *bcs)
+{
+ struct hisax_b_if *b_if = bcs->hw.b_if;
+
+ if (b_if)
+ B_L2L1(b_if, PH_DEACTIVATE | REQUEST, NULL);
+}
+
+static void EChannel_proc_rcv(struct hisax_d_if *d_if)
+{
+ struct IsdnCardState *cs = d_if->cs;
+ u_char *ptr;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&d_if->erq)) != NULL) {
+ if (cs->debug & DEB_DLOG_HEX) {
+ ptr = cs->dlog;
+ if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
+ *ptr++ = 'E';
+ *ptr++ = 'C';
+ *ptr++ = 'H';
+ *ptr++ = 'O';
+ *ptr++ = ':';
+ ptr += QuickHex(ptr, skb->data, skb->len);
+ ptr--;
+ *ptr++ = '\n';
+ *ptr = 0;
+ HiSax_putstatus(cs, NULL, cs->dlog);
+ } else
+ HiSax_putstatus(cs, "LogEcho: ",
+ "warning Frame too big (%d)",
+ skb->len);
+ }
+ dev_kfree_skb_any(skb);
+ }
+}
+
+void HiSax_mod_dec_use_count(struct IsdnCardState *cs)
+{
+ struct module *mod;
+
+ if (cs && cs->cardmsg == hisax_cardmsg) {
+ mod = cs->hw.hisax_d_if->owner;
+ if (mod)
+ __MOD_DEC_USE_COUNT(mod);
+ } else {
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+void HiSax_mod_inc_use_count(struct IsdnCardState *cs)
+{
+ struct module *mod;
+
+ if (cs && cs->cardmsg == hisax_cardmsg) {
+ mod = cs->hw.hisax_d_if->owner;
+ if (mod)
+ // hope we do win the race...
+ try_inc_mod_count(mod);
+ } else {
+ MOD_INC_USE_COUNT;
+ }
+}
+
#include <linux/pci.h>
static struct pci_device_id hisax_pci_tbl[] __initdata = {
#ifdef CONFIG_HISAX_FRITZPCI
- {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
#endif
#ifdef CONFIG_HISAX_DIEHLDIVA
{PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID},
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 53616888bbcd..62f1bf4ac7c7 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -1,4 +1,4 @@
-/* $Id: elsa_ser.c,v 2.10.6.2 2001/06/09 15:14:17 kai Exp $
+/* $Id: elsa_ser.c,v 2.10.6.3 2001/08/17 12:34:26 kai Exp $
*
* stuff for the serial modem on ELSA cards
*
@@ -14,10 +14,6 @@
#define RS_ISR_PASS_LIMIT 256
#define BASE_BAUD ( 1843200 / 16 )
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
//#define SERIAL_DEBUG_OPEN 1
//#define SERIAL_DEBUG_INTR 1
//#define SERIAL_DEBUG_FLOW 1
@@ -257,7 +253,7 @@ inline int
write_modem(struct BCState *bcs) {
int ret=0;
struct IsdnCardState *cs = bcs->cs;
- int count, len, fp, buflen;
+ int count, len, fp;
long flags;
if (!bcs->tx_skb)
@@ -266,12 +262,14 @@ write_modem(struct BCState *bcs) {
return 0;
save_flags(flags);
cli();
- buflen = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
- len = MIN(buflen, bcs->tx_skb->len);
+ len = bcs->tx_skb->len;
+ if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
+ len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF -1);
- count = MIN(len, MAX_MODEM_BUF - fp);
- if (count < len) {
+ count = len;
+ if (count > MAX_MODEM_BUF - fp) {
+ count = MAX_MODEM_BUF - fp;
memcpy(cs->hw.elsa.transbuf + fp, bcs->tx_skb->data, count);
skb_pull(bcs->tx_skb, count);
cs->hw.elsa.transcnt += count;
@@ -472,8 +470,9 @@ modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
}
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
fp &= (MAX_MODEM_BUF -1);
- count = MIN(len, MAX_MODEM_BUF - fp);
- if (count < len) {
+ count = len;
+ if (count > MAX_MODEM_BUF - fp) {
+ count = MAX_MODEM_BUF - fp;
memcpy(cs->hw.elsa.transbuf + fp, msg, count);
cs->hw.elsa.transcnt += count;
msg += count;
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index d1f385ecaf50..423306a057f5 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.14.6.2 2001/05/26 15:19:57 kai Exp $
+/* $Id: fsm.c,v 1.14.6.3 2001/08/23 19:44:23 kai Exp $
*
* Author Karsten Keil (keil@isdn4linux.de)
* based on the teles driver from Jan den Ouden
@@ -15,6 +15,14 @@
#define FSM_TIMER_DEBUG 0
+EXPORT_SYMBOL(FsmNew);
+EXPORT_SYMBOL(FsmFree);
+EXPORT_SYMBOL(FsmEvent);
+EXPORT_SYMBOL(FsmChangeState);
+EXPORT_SYMBOL(FsmInitTimer);
+EXPORT_SYMBOL(FsmDelTimer);
+EXPORT_SYMBOL(FsmRestartTimer);
+
int __init
FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
{
diff --git a/drivers/isdn/hisax/fsm.h b/drivers/isdn/hisax/fsm.h
new file mode 100644
index 000000000000..3a77d1eabdd0
--- /dev/null
+++ b/drivers/isdn/hisax/fsm.h
@@ -0,0 +1,48 @@
+#ifndef __FSM_H__
+#define __FSM_H__
+
+#include <linux/timer.h>
+
+struct FsmInst;
+
+typedef void (* FSMFNPTR)(struct FsmInst *, int, void *);
+
+struct Fsm {
+ FSMFNPTR *jumpmatrix;
+ int state_count, event_count;
+ char **strEvent, **strState;
+};
+
+struct FsmInst {
+ struct Fsm *fsm;
+ int state;
+ int debug;
+ void *userdata;
+ int userint;
+ void (*printdebug) (struct FsmInst *, char *, ...);
+};
+
+struct FsmNode {
+ int state, event;
+ void (*routine) (struct FsmInst *, int, void *);
+};
+
+struct FsmTimer {
+ struct FsmInst *fi;
+ struct timer_list tl;
+ int event;
+ void *arg;
+};
+
+int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
+void FsmFree(struct Fsm *fsm);
+int FsmEvent(struct FsmInst *fi, int event, void *arg);
+void FsmChangeState(struct FsmInst *fi, int newstate);
+void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
+int FsmAddTimer(struct FsmTimer *ft, int millisec, int event,
+ void *arg, int where);
+void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event,
+ void *arg, int where);
+void FsmDelTimer(struct FsmTimer *ft, int where);
+
+#endif
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 344902707b79..38251b34ded9 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1,4 +1,4 @@
-/* $Id: hisax.h,v 2.52.6.7 2001/07/18 16:02:15 kai Exp $
+/* $Id: hisax.h,v 2.52.6.8 2001/08/23 19:44:23 kai Exp $
*
* Basic declarations, defines and prototypes
*
@@ -455,7 +455,6 @@ struct amd7930_hw {
struct tq_struct tq_xmt;
};
-
#define BC_FLG_INIT 1
#define BC_FLG_ACTIV 2
#define BC_FLG_BUSY 3
@@ -512,6 +511,7 @@ struct BCState {
struct tiger_hw tiger;
struct amd7930_hw amd7930;
struct w6692B_hw w6692;
+ struct hisax_b_if *b_if;
} hw;
};
@@ -897,6 +897,7 @@ struct IsdnCardState {
struct bkm_hw ax;
struct gazel_hw gazel;
struct w6692_hw w6692;
+ struct hisax_d_if *hisax_d_if;
} hw;
int myid;
isdn_if iif;
@@ -991,7 +992,8 @@ struct IsdnCardState {
#define ISDN_CTYPE_HFC_SX 37
#define ISDN_CTYPE_NETJET_U 38
#define ISDN_CTYPE_HFC_SP_PCMCIA 39
-#define ISDN_CTYPE_COUNT 39
+#define ISDN_CTYPE_DYNAMIC 40
+#define ISDN_CTYPE_COUNT 40
#ifdef ISDN_CHIP_ISAC
diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
new file mode 100644
index 000000000000..0c94449ac562
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_debug.h
@@ -0,0 +1,80 @@
+/*
+ * Common debugging macros for use with the hisax driver
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/*
+ * How to use:
+ *
+ * Before including this file, you need to
+ * #define __debug_variable my_debug
+ * where my_debug is a variable in your code which
+ * determines the debug bitmask.
+ *
+ * If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing
+ */
+
+#ifndef __HISAX_DEBUG_H__
+#define __HISAX_DEBUG_H__
+
+#ifdef CONFIG_HISAX_DEBUG
+
+#define DBG(level, format, arg...) do { \
+if (level & __debug_variable) \
+printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+} while (0)
+
+#define DBG_PACKET(level,data,count) \
+ if (level & __debug_variable) dump_packet(__FUNCTION__,data,count)
+
+#define DBG_SKB(level,skb) \
+ if ((level & __debug_variable) && skb) dump_packet(__FUNCTION__,skb->data,skb->len)
+
+
+static void __attribute__((unused))
+dump_packet(const char *name,const u_char *data,int pkt_len)
+{
+#define DUMP_HDR_SIZE 20
+#define DUMP_TLR_SIZE 8
+ if (pkt_len) {
+ int i,len1,len2;
+
+ printk(KERN_DEBUG "%s: length=%d,data=",name,pkt_len);
+
+ if (pkt_len > DUMP_HDR_SIZE+ DUMP_TLR_SIZE) {
+ len1 = DUMP_HDR_SIZE;
+ len2 = DUMP_TLR_SIZE;
+ } else {
+ len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
+ len2 = 0;
+ }
+ for (i = 0; i < len1; ++i) {
+ printk ("%.2x", data[i]);
+ }
+ if (len2) {
+ printk ("..");
+ for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
+ printk ("%.2x", data[i]);
+ }
+ }
+ printk ("\n");
+ }
+#undef DUMP_HDR_SIZE
+#undef DUMP_TLR_SIZE
+}
+
+#else
+
+#define DBG(level, format, arg...) do {} while (0)
+#define DBG_PACKET(level,data,count) do {} while (0)
+#define DBG_SKB(level,skb) do {} while (0)
+
+#endif
+
+#endif
diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h
new file mode 100644
index 000000000000..49a856a84ec8
--- /dev/null
+++ b/drivers/isdn/hisax/hisax_if.h
@@ -0,0 +1,54 @@
+#ifndef __HISAX_IF_H__
+#define __HISAX_IF_H__
+
+#include <linux/skbuff.h>
+
+#define REQUEST 0
+#define CONFIRM 1
+#define INDICATION 2
+#define RESPONSE 3
+
+#define PH_ACTIVATE 0x0100
+#define PH_DEACTIVATE 0x0110
+#define PH_DATA 0x0120
+#define PH_PULL 0x0130
+#define PH_DATA_E 0x0140
+
+#define L1_MODE_NULL 0
+#define L1_MODE_TRANS 1
+#define L1_MODE_HDLC 2
+#define L1_MODE_EXTRN 3
+#define L1_MODE_HDLC_56K 4
+#define L1_MODE_MODEM 7
+#define L1_MODE_V32 8
+#define L1_MODE_FAX 9
+
+struct hisax_if {
+ void *priv; // private to driver
+ void (*l1l2)(struct hisax_if *, int pr, void *arg);
+ void (*l2l1)(struct hisax_if *, int pr, void *arg);
+};
+
+struct hisax_b_if {
+ struct hisax_if ifc;
+
+ // private to hisax
+ struct BCState *bcs;
+};
+
+struct hisax_d_if {
+ struct hisax_if ifc;
+
+ // private to hisax
+ struct module *owner;
+ struct IsdnCardState *cs;
+ struct hisax_b_if *b_if[2];
+ struct sk_buff_head erq;
+ long ph_state;
+};
+
+int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
+ char *name, int protocol);
+void hisax_unregister(struct hisax_d_if *hisax_if);
+
+#endif
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 792f9567d679..0a4ba9193048 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.c,v 2.41.6.3 2001/05/26 15:19:57 kai Exp $
+/* $Id: isdnl1.c,v 2.41.6.4 2001/08/23 19:44:23 kai Exp $
*
* isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
* based on the teles driver from Jan den Ouden
@@ -15,7 +15,7 @@
*
*/
-const char *l1_revision = "$Revision: 2.41.6.3 $";
+const char *l1_revision = "$Revision: 2.41.6.4 $";
#define __NO_VERSION__
#include <linux/init.h>
@@ -895,7 +895,8 @@ setstack_HiSax(struct PStack *st, struct IsdnCardState *cs)
setstack_manager(st);
st->l1.stlistp = &(cs->stlist);
st->l2.l2l1 = dch_l2l1;
- cs->setstack_d(st, cs);
+ if (cs->setstack_d)
+ cs->setstack_d(st, cs);
}
void
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
index 435638de1e76..988dfe5751d1 100644
--- a/drivers/isdn/hisax/isdnl1.h
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -1,4 +1,4 @@
-/* $Id: isdnl1.h,v 2.9.6.1 2001/02/16 16:43:27 kai Exp $
+/* $Id: isdnl1.h,v 2.9.6.2 2001/08/23 19:44:23 kai Exp $
*
* Layer 1 defines
*
@@ -14,6 +14,7 @@
#define D_RX_MON1 5
#define D_TX_MON0 6
#define D_TX_MON1 7
+#define E_RCVBUFREADY 8
#define B_RCVBUFREADY 0
#define B_XMTBUFREADY 1
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
new file mode 100644
index 000000000000..333de24cb157
--- /dev/null
+++ b/drivers/isdn/hisax/st5481.h
@@ -0,0 +1,533 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef _ST5481_H_
+#define _ST5481_H_
+
+// USB IDs, the Product Id is in the range 0x4810-0x481F
+
+#define ST_VENDOR_ID 0x0483
+#define ST5481_PRODUCT_ID 0x4810
+#define ST5481_PRODUCT_ID_MASK 0xFFF0
+
+// ST5481 endpoints when using alternative setting 3 (2B+D).
+// To get the endpoint address, OR with 0x80 for IN endpoints.
+
+#define EP_CTRL 0x00U /* Control endpoint */
+#define EP_INT 0x01U /* Interrupt endpoint */
+#define EP_B1_OUT 0x02U /* B1 channel out */
+#define EP_B1_IN 0x03U /* B1 channel in */
+#define EP_B2_OUT 0x04U /* B2 channel out */
+#define EP_B2_IN 0x05U /* B2 channel in */
+#define EP_D_OUT 0x06U /* D channel out */
+#define EP_D_IN 0x07U /* D channel in */
+
+// Number of isochronous packets. With 20 packets we get
+// 50 interrupts/sec for each endpoint.
+
+#define NUM_ISO_PACKETS_D 20
+#define NUM_ISO_PACKETS_B 20
+
+// Size of each isochronous packet.
+// In outgoing direction we need to match ISDN data rates:
+// D: 2 bytes / msec -> 16 kbit / s
+// B: 16 bytes / msec -> 64 kbit / s
+#define SIZE_ISO_PACKETS_D_IN 16
+#define SIZE_ISO_PACKETS_D_OUT 2
+#define SIZE_ISO_PACKETS_B_IN 32
+#define SIZE_ISO_PACKETS_B_OUT 8
+
+// If we overrun/underrun, we send one packet with +/- 2 bytes
+#define B_FLOW_ADJUST 2
+
+// Registers that are written using vendor specific device request
+// on endpoint 0.
+
+#define LBA 0x02 /* S loopback */
+#define SET_DEFAULT 0x06 /* Soft reset */
+#define LBB 0x1D /* S maintenance loopback */
+#define STT 0x1e /* S force transmission signals */
+#define SDA_MIN 0x20 /* SDA-sin minimal value */
+#define SDA_MAX 0x21 /* SDA-sin maximal value */
+#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */
+#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */
+#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */
+#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */
+#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */
+#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */
+#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */
+#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */
+#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */
+#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */
+#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */
+#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */
+#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */
+#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */
+#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */
+#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */
+#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */
+#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */
+#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */
+#define MPMSK 0x4A /* Multi purpose interrupt MASK register */
+#define FFMSK_D 0x4c /* D fifo interrupt MASK register */
+#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */
+#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */
+#define GPIO_DIR 0x52 /* GPIO pins direction registers */
+#define GPIO_OUT 0x53 /* GPIO pins output register */
+#define GPIO_IN 0x54 /* GPIO pins input register */
+#define TXCI 0x56 /* CI command to be transmitted */
+
+
+// Format of the interrupt packet received on endpoint 1:
+//
+// +--------+--------+--------+--------+--------+--------+
+// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT!
+// +--------+--------+--------+--------+--------+--------+
+
+// Offsets in the interrupt packet
+
+#define MPINT 0
+#define FFINT_D 1
+#define FFINT_B1 2
+#define FFINT_B2 3
+#define CCIST 4
+#define GPIO_INT 5
+#define INT_PKT_SIZE 6
+
+// MPINT
+#define LSD_INT 0x80 /* S line activity detected */
+#define RXCI_INT 0x40 /* Indicate primitive arrived */
+#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */
+#define DCOLL_INT 0x10 /* D channel collision */
+#define AMIVN_INT 0x04 /* AMI violation number reached 2 */
+#define INFOI_INT 0x04 /* INFOi changed */
+#define DRXON_INT 0x02 /* Reception channel active */
+#define GPCHG_INT 0x01 /* GPIO pin value changed */
+
+// FFINT_x
+#define IN_OVERRUN 0x80 /* In fifo overrun */
+#define OUT_UNDERRUN 0x40 /* Out fifo underrun */
+#define IN_UP 0x20 /* In fifo thresholdh up-crossed */
+#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */
+#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */
+#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */
+#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */
+#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */
+
+#define ANY_REC_INT (IN_OVERRUN+IN_UP+IN_DOWN+IN_COUNTER_ZEROED)
+#define ANY_XMIT_INT (OUT_UNDERRUN+OUT_UP+OUT_DOWN+OUT_COUNTER_ZEROED)
+
+
+// Level 1 commands that are sent using the TXCI device request
+#define ST5481_CMD_DR 0x0 /* Deactivation Request */
+#define ST5481_CMD_RES 0x1 /* state machine RESet */
+#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */
+#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */
+#define ST5481_CMD_PUP 0x7 /* Power UP */
+#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */
+#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */
+#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */
+#define ST5481_CMD_PDN 0xF /* Power DoWn */
+
+// Turn on/off the LEDs using the GPIO device request.
+// To use the B LEDs, number_of_leds must be set to 4
+#define B1_LED 0x10U
+#define B2_LED 0x20U
+#define GREEN_LED 0x40U
+#define RED_LED 0x80U
+
+// D channel out states
+enum {
+ ST_DOUT_NONE,
+
+ ST_DOUT_SHORT_INIT,
+ ST_DOUT_SHORT_WAIT_DEN,
+
+ ST_DOUT_LONG_INIT,
+ ST_DOUT_LONG_WAIT_DEN,
+ ST_DOUT_NORMAL,
+
+ ST_DOUT_WAIT_FOR_UNDERRUN,
+ ST_DOUT_WAIT_FOR_NOT_BUSY,
+ ST_DOUT_WAIT_FOR_STOP,
+ ST_DOUT_WAIT_FOR_RESET,
+};
+
+#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1)
+
+// D channel out events
+enum {
+ EV_DOUT_START_XMIT,
+ EV_DOUT_COMPLETE,
+ EV_DOUT_DEN,
+ EV_DOUT_RESETED,
+ EV_DOUT_STOPPED,
+ EV_DOUT_COLL,
+ EV_DOUT_UNDERRUN,
+};
+
+#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1)
+
+// ----------------------------------------------------------------------
+
+enum {
+ ST_L1_F3,
+ ST_L1_F4,
+ ST_L1_F6,
+ ST_L1_F7,
+ ST_L1_F8,
+};
+
+#define L1_STATE_COUNT (ST_L1_F8+1)
+
+// The first 16 entries match the Level 1 indications that
+// are found at offset 4 (CCIST) in the interrupt packet
+
+enum {
+ EV_IND_DP, // 0000 Deactivation Pending
+ EV_IND_1, // 0001
+ EV_IND_2, // 0010
+ EV_IND_3, // 0011
+ EV_IND_RSY, // 0100 ReSYnchronizing
+ EV_IND_5, // 0101
+ EV_IND_6, // 0110
+ EV_IND_7, // 0111
+ EV_IND_AP, // 1000 Activation Pending
+ EV_IND_9, // 1001
+ EV_IND_10, // 1010
+ EV_IND_11, // 1011
+ EV_IND_AI8, // 1100 Activation Indication class 8
+ EV_IND_AI10,// 1101 Activation Indication class 10
+ EV_IND_AIL, // 1110 Activation Indication Loopback
+ EV_IND_DI, // 1111 Deactivation Indication
+ EV_PH_ACTIVATE_REQ,
+ EV_PH_DEACTIVATE_REQ,
+ EV_TIMER3,
+};
+
+#define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+#define ERR(format, arg...) \
+printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+#define WARN(format, arg...) \
+printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+#define INFO(format, arg...) \
+printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+#include "st5481_hdlc.h"
+#include "fsm.h"
+#include "hisax_if.h"
+#include <linux/skbuff.h>
+
+/* ======================================================================
+ * FIFO handling
+ */
+
+/* Generic FIFO structure */
+struct fifo {
+ u_char r,w,count,size;
+ spinlock_t lock;
+};
+
+/*
+ * Init an FIFO
+ */
+static inline void fifo_init(struct fifo *fifo, int size)
+{
+ fifo->r = fifo->w = fifo->count = 0;
+ fifo->size = size;
+ spin_lock_init(&fifo->lock);
+}
+
+/*
+ * Add an entry to the FIFO
+ */
+static inline int fifo_add(struct fifo *fifo)
+{
+ unsigned long flags;
+ int index;
+
+ if (!fifo) {
+ return -1;
+ }
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ if (fifo->count == fifo->size) {
+ // FIFO full
+ index = -1;
+ } else {
+ // Return index where to get the next data to add to the FIFO
+ index = fifo->w++ & (fifo->size-1);
+ fifo->count++;
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+ return index;
+}
+
+/*
+ * Remove an entry from the FIFO with the index returned.
+ */
+static inline int fifo_remove(struct fifo *fifo)
+{
+ unsigned long flags;
+ int index;
+
+ if (!fifo) {
+ return -1;
+ }
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ if (!fifo->count) {
+ // FIFO empty
+ index = -1;
+ } else {
+ // Return index where to get the next data from the FIFO
+ index = fifo->r++ & (fifo->size-1);
+ fifo->count--;
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+
+ return index;
+}
+
+/* ======================================================================
+ * control pipe
+ */
+typedef void (*ctrl_complete_t)(void *);
+
+typedef struct ctrl_msg {
+ devrequest dr;
+ ctrl_complete_t complete;
+ void *context;
+} ctrl_msg;
+
+/* FIFO of ctrl messages waiting to be sent */
+#define MAX_EP0_MSG 16
+struct ctrl_msg_fifo {
+ struct fifo f;
+ struct ctrl_msg data[MAX_EP0_MSG];
+};
+
+#define MAX_DFRAME_LEN_L1 300
+#define HSCX_BUFMAX 4096
+
+struct st5481_ctrl {
+ struct ctrl_msg_fifo msg_fifo;
+ unsigned long busy;
+ struct urb *urb;
+};
+
+struct st5481_intr {
+ // struct evt_fifo evt_fifo;
+ struct urb *urb;
+};
+
+struct st5481_d_out {
+ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ unsigned long busy;
+ struct sk_buff *tx_skb;
+ struct FsmInst fsm;
+};
+
+struct st5481_b_out {
+ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ u_char flow_event;
+ u_long busy;
+ struct sk_buff *tx_skb;
+};
+
+struct st5481_in {
+ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ int mode;
+ int bufsize;
+ unsigned int num_packets;
+ unsigned int packet_size;
+ unsigned char ep, counter;
+ unsigned char *rcvbuf;
+ struct st5481_adapter *adapter;
+ struct hisax_if *hisax_if;
+};
+
+int st5481_setup_in(struct st5481_in *in);
+void st5481_release_in(struct st5481_in *in);
+void st5481_in_mode(struct st5481_in *in, int mode);
+
+struct st5481_bcs {
+ struct hisax_b_if b_if;
+ struct st5481_adapter *adapter;
+ struct st5481_in b_in;
+ struct st5481_b_out b_out;
+ int channel;
+ int mode;
+};
+
+struct st5481_adapter {
+ struct list_head list;
+ int number_of_leds;
+ struct usb_device *usb_dev;
+ struct hisax_d_if hisax_d_if;
+
+ struct st5481_ctrl ctrl;
+ struct st5481_intr intr;
+ struct st5481_in d_in;
+ struct st5481_d_out d_out;
+
+ unsigned char leds;
+ unsigned int led_counter;
+
+ unsigned long event;
+
+ struct FsmInst l1m;
+ struct FsmTimer timer;
+
+ struct st5481_bcs bcs[2];
+};
+
+#define TIMER3_VALUE 7000
+
+/* ======================================================================
+ *
+ */
+
+/*
+ * Submit an URB with error reporting. This is a macro so
+ * the __FUNCTION__ returns the caller function name.
+ */
+#define SUBMIT_URB(urb) \
+({ \
+ int status; \
+ if ((status = usb_submit_urb(urb)) < 0) { \
+ WARN("usb_submit_urb failed,status=%d", status); \
+ } \
+ status; \
+})
+
+/*
+ * USB double buffering, return the URB index (0 or 1).
+ */
+static inline int get_buf_nr(struct urb *urbs[], struct urb *urb)
+{
+ return (urbs[0]==urb ? 0 : 1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* B Channel */
+
+int st5481_setup_b(struct st5481_bcs *bcs);
+void st5481_release_b(struct st5481_bcs *bcs);
+void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
+
+/* D Channel */
+
+int st5481_setup_d(struct st5481_adapter *adapter);
+void st5481_release_d(struct st5481_adapter *adapter);
+void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg);
+int st5481_d_init(void);
+void st5481_d_exit(void);
+
+/* USB */
+void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command);
+int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
+ unsigned int pipe, int num_packets,
+ int packet_size, int buf_size,
+ usb_complete_t complete, void *context);
+void st5481_release_isocpipes(struct urb* urb[2]);
+
+int st5481_isoc_flatten(struct urb *urb);
+void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
+ u_char pipe, ctrl_complete_t complete, void *context);
+void st5481_usb_ctrl_msg(struct st5481_adapter *adapter,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ ctrl_complete_t complete, void *context);
+void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
+ u8 request, u16 value,
+ ctrl_complete_t complete, void *context);
+int st5481_setup_usb(struct st5481_adapter *adapter);
+void st5481_release_usb(struct st5481_adapter *adapter);
+void st5481_start(struct st5481_adapter *adapter);
+void st5481_stop(struct st5481_adapter *adapter);
+
+// ----------------------------------------------------------------------
+// debugging macros
+
+#define __debug_variable st5481_debug
+#include "hisax_debug.h"
+
+#ifdef CONFIG_HISAX_DEBUG
+
+extern int st5481_debug;
+
+#define DBG_ISO_PACKET(level,urb) \
+ if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
+
+static void __attribute__((unused))
+dump_iso_packet(const char *name,urb_t *urb)
+{
+ int i,j;
+ int len,ofs;
+ u_char *data;
+
+ printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
+ name,urb->number_of_packets,urb->error_count);
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ if (urb->pipe & USB_DIR_IN) {
+ len = urb->iso_frame_desc[i].actual_length;
+ } else {
+ len = urb->iso_frame_desc[i].length;
+ }
+ ofs = urb->iso_frame_desc[i].offset;
+ printk(KERN_DEBUG "len=%.2d,ofs=%.3d ",len,ofs);
+ if (len) {
+ data = urb->transfer_buffer+ofs;
+ for (j=0; j < len; j++) {
+ printk ("%.2x", data[j]);
+ }
+ }
+ printk("\n");
+ }
+}
+
+static inline const char *ST5481_CMD_string(int evt)
+{
+ static char s[16];
+
+ switch (evt) {
+ case ST5481_CMD_DR: return "DR";
+ case ST5481_CMD_RES: return "RES";
+ case ST5481_CMD_TM1: return "TM1";
+ case ST5481_CMD_TM2: return "TM2";
+ case ST5481_CMD_PUP: return "PUP";
+ case ST5481_CMD_AR8: return "AR8";
+ case ST5481_CMD_AR10: return "AR10";
+ case ST5481_CMD_ARL: return "ARL";
+ case ST5481_CMD_PDN: return "PDN";
+ };
+
+ sprintf(s,"0x%x",evt);
+ return s;
+}
+
+#else
+
+#define DBG_ISO_PACKET(level,urb) do {} while (0)
+
+#endif
+
+
+
+#endif
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
new file mode 100644
index 000000000000..17b2a21f878a
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -0,0 +1,367 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include "st5481.h"
+
+static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
+
+ ifc->l1l2(ifc, pr, arg);
+}
+
+/*
+ * Encode and transmit next frame.
+ */
+static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
+{
+ struct st5481_b_out *b_out = &bcs->b_out;
+ struct st5481_adapter *adapter = bcs->adapter;
+ struct urb *urb;
+ unsigned int packet_size,offset;
+ int len,buf_size,bytes_sent;
+ int i;
+ struct sk_buff *skb;
+
+ if (test_and_set_bit(buf_nr, &b_out->busy)) {
+ DBG(4,"ep %d urb %d busy",(bcs->channel+1)*2,buf_nr);
+ return;
+ }
+ urb = b_out->urb[buf_nr];
+
+ // Adjust isoc buffer size according to flow state
+ if(b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) {
+ buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
+ packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
+ DBG(4,"B%d,adjust flow,add %d bytes",bcs->channel+1,B_FLOW_ADJUST);
+ } else if(b_out->flow_event & OUT_UP){
+ buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
+ packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
+ DBG(4,"B%d,adjust flow,remove %d bytes",bcs->channel+1,B_FLOW_ADJUST);
+ } else {
+ buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT;
+ packet_size = 8;
+ }
+ b_out->flow_event = 0;
+
+ len = 0;
+ while (len < buf_size) {
+ if ((skb = b_out->tx_skb)) {
+ DBG_SKB(0x100, skb);
+ DBG(4,"B%d,len=%d",bcs->channel+1,skb->len);
+
+ if (bcs->mode == L1_MODE_TRANS) {
+ bytes_sent = buf_size - len;
+ if (skb->len < bytes_sent)
+ bytes_sent = skb->len;
+
+ memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
+
+ len += bytes_sent;
+ } else {
+ len += hdlc_encode(&b_out->hdlc_state,
+ skb->data, skb->len, &bytes_sent,
+ urb->transfer_buffer+len, buf_size-len);
+ }
+
+ skb_pull(skb, bytes_sent);
+
+ if (!skb->len) {
+ // Frame sent
+ b_out->tx_skb = NULL;
+ B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+ dev_kfree_skb_any(skb);
+
+/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
+/* st5481B_sched_event(bcs, B_XMTBUFREADY); */
+/* } */
+ }
+ } else {
+ if (bcs->mode == L1_MODE_TRANS) {
+ memset(urb->transfer_buffer+len, 0xff, buf_size-len);
+ len = buf_size;
+ } else {
+ // Send flags
+ len += hdlc_encode(&b_out->hdlc_state,
+ NULL, 0, &bytes_sent,
+ urb->transfer_buffer+len, buf_size-len);
+ }
+ }
+ }
+
+ // Prepare the URB
+ for (i = 0, offset = 0; offset < len; i++) {
+ urb->iso_frame_desc[i].offset = offset;
+ urb->iso_frame_desc[i].length = packet_size;
+ offset += packet_size;
+ packet_size = SIZE_ISO_PACKETS_B_OUT;
+ }
+ urb->transfer_buffer_length = len;
+ urb->number_of_packets = i;
+ urb->dev = adapter->usb_dev;
+
+ DBG_ISO_PACKET(0x200,urb);
+
+ SUBMIT_URB(urb);
+}
+
+/*
+ * Start transfering (flags or data) on the B channel, since
+ * FIFO counters has been set to a non-zero value.
+ */
+static void st5481B_start_xfer(void *context)
+{
+ struct st5481_bcs *bcs = context;
+
+ DBG(4,"B%d",bcs->channel+1);
+
+ // Start transmitting (flags or data) on B channel
+
+ usb_b_out(bcs,0);
+ usb_b_out(bcs,1);
+}
+
+/*
+ * If the adapter has only 2 LEDs, the green
+ * LED will blink with a rate depending
+ * on the number of channels opened.
+ */
+static void led_blink(struct st5481_adapter *adapter)
+{
+ u_char leds = adapter->leds;
+
+ // 50 frames/sec for each channel
+ if (++adapter->led_counter % 50) {
+ return;
+ }
+
+ if (adapter->led_counter % 100) {
+ leds |= GREEN_LED;
+ } else {
+ leds &= ~GREEN_LED;
+ }
+
+ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
+}
+
+static void usb_b_out_complete(struct urb *urb)
+{
+ struct st5481_bcs *bcs = urb->context;
+ struct st5481_b_out *b_out = &bcs->b_out;
+ struct st5481_adapter *adapter = bcs->adapter;
+ int buf_nr;
+
+ buf_nr = get_buf_nr(b_out->urb, urb);
+ test_and_clear_bit(buf_nr, &b_out->busy);
+
+ if (urb->status < 0) {
+ if (urb->status != USB_ST_URB_KILLED) {
+ WARN("urb status %d",urb->status);
+ if (b_out->busy == 0) {
+ st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL);
+ }
+ } else {
+ DBG(1,"urb killed");
+ return; // Give up
+ }
+ }
+
+ usb_b_out(bcs,buf_nr);
+
+ if (adapter->number_of_leds == 2)
+ led_blink(adapter);
+}
+
+/*
+ * Start or stop the transfer on the B channel.
+ */
+static void st5481B_mode(struct st5481_bcs *bcs, int mode)
+{
+ struct st5481_b_out *b_out = &bcs->b_out;
+ struct st5481_adapter *adapter = bcs->adapter;
+
+ DBG(4,"B%d,mode=%d", bcs->channel + 1, mode);
+
+ if (bcs->mode == mode)
+ return;
+
+ bcs->mode = mode;
+
+ // Cancel all USB transfers on this B channel
+ usb_unlink_urb(b_out->urb[0]);
+ usb_unlink_urb(b_out->urb[1]);
+ b_out->busy = 0;
+
+ st5481_in_mode(&bcs->b_in, mode);
+ if (bcs->mode != L1_MODE_NULL) {
+ // Open the B channel
+ if (bcs->mode != L1_MODE_TRANS) {
+ hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+ }
+ st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
+
+ // Enable B channel interrupts
+ st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel*2),
+ OUT_UP+OUT_DOWN+OUT_UNDERRUN, NULL, NULL);
+
+ // Enable B channel FIFOs
+ st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel*2), 32, st5481B_start_xfer, bcs);
+ if (adapter->number_of_leds == 4) {
+ if (bcs->channel == 0) {
+ adapter->leds |= B1_LED;
+ } else {
+ adapter->leds |= B2_LED;
+ }
+ }
+ } else {
+ // Disble B channel interrupts
+ st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel*2), 0, NULL, NULL);
+
+ // Disable B channel FIFOs
+ st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel*2), 0, NULL, NULL);
+
+ if (adapter->number_of_leds == 4) {
+ if (bcs->channel == 0) {
+ adapter->leds &= ~B1_LED;
+ } else {
+ adapter->leds &= ~B2_LED;
+ }
+ } else {
+ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
+ }
+ if (b_out->tx_skb) {
+ dev_kfree_skb_any(b_out->tx_skb);
+ b_out->tx_skb = NULL;
+ }
+
+ }
+}
+
+static int __devinit st5481_setup_b_out(struct st5481_bcs *bcs)
+{
+ struct usb_device *dev = bcs->adapter->usb_dev;
+ struct usb_interface_descriptor *altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ struct st5481_b_out *b_out = &bcs->b_out;
+
+ DBG(4,"");
+
+ altsetting = &(dev->config->interface[0].altsetting[3]);
+
+ // Allocate URBs and buffers for the B channel out
+ endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
+
+ DBG(4,"endpoint address=%02x,packet size=%d",
+ endpoint->bEndpointAddress,endpoint->wMaxPacketSize);
+
+ // Allocate memory for 8000bytes/sec + extra bytes if underrun
+ return st5481_setup_isocpipes(b_out->urb, dev,
+ usb_sndisocpipe(dev, endpoint->bEndpointAddress),
+ NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT,
+ NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST,
+ usb_b_out_complete, bcs);
+}
+
+static void __devexit st5481_release_b_out(struct st5481_bcs *bcs)
+{
+ struct st5481_b_out *b_out = &bcs->b_out;
+
+ DBG(4,"");
+
+ st5481_release_isocpipes(b_out->urb);
+}
+
+int __devinit st5481_setup_b(struct st5481_bcs *bcs)
+{
+ int retval;
+
+ DBG(4,"");
+
+ retval = st5481_setup_b_out(bcs);
+ if (retval)
+ goto err;
+ bcs->b_in.bufsize = HSCX_BUFMAX;
+ bcs->b_in.num_packets = NUM_ISO_PACKETS_B;
+ bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN;
+ bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN;
+ bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER;
+ bcs->b_in.adapter = bcs->adapter;
+ bcs->b_in.hisax_if = &bcs->b_if.ifc;
+ retval = st5481_setup_in(&bcs->b_in);
+ if (retval)
+ goto err_b_out;
+
+
+ return 0;
+
+ err_b_out:
+ st5481_release_b_out(bcs);
+ err:
+ return retval;
+}
+
+/*
+ * Release buffers and URBs for the B channels
+ */
+void __devexit st5481_release_b(struct st5481_bcs *bcs)
+{
+ DBG(4,"");
+
+ st5481_release_in(&bcs->b_in);
+ st5481_release_b_out(bcs);
+}
+
+/*
+ * st5481_b_l2l1 is the entry point for upper layer routines that want to
+ * transmit on the B channel. PH_DATA | REQUEST is a normal packet that
+ * we either start transmitting (if idle) or queue (if busy).
+ * PH_PULL | REQUEST can be called to request a callback message
+ * (PH_PULL | CONFIRM)
+ * once the link is idle. After a "pull" callback, the upper layer
+ * routines can use PH_PULL | INDICATION to send data.
+ */
+void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
+{
+ struct st5481_bcs *bcs = ifc->priv;
+ struct sk_buff *skb = arg;
+ int mode;
+
+ DBG(4, "");
+
+ switch (pr) {
+ case PH_DATA | REQUEST:
+ if (bcs->b_out.tx_skb)
+ BUG();
+
+ bcs->b_out.tx_skb = skb;
+ break;
+ case PH_ACTIVATE | REQUEST:
+ mode = (int) arg;
+ DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
+ st5481B_mode(bcs, mode);
+ B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
+ break;
+ case PH_DEACTIVATE | REQUEST:
+ DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
+ st5481B_mode(bcs, L1_MODE_NULL);
+ B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
+ break;
+ default:
+ WARN("pr %#x\n", pr);
+ }
+}
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
new file mode 100644
index 000000000000..78c4e4961368
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -0,0 +1,774 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include "st5481.h"
+
+static void ph_connect(struct st5481_adapter *adapter);
+static void ph_disconnect(struct st5481_adapter *adapter);
+
+static struct Fsm l1fsm;
+
+static char *strL1State[] =
+{
+ "ST_L1_F3",
+ "ST_L1_F4",
+ "ST_L1_F6",
+ "ST_L1_F7",
+ "ST_L1_F8",
+};
+
+static char *strL1Event[] =
+{
+ "EV_IND_DP",
+ "EV_IND_1",
+ "EV_IND_2",
+ "EV_IND_3",
+ "EV_IND_RSY",
+ "EV_IND_5",
+ "EV_IND_6",
+ "EV_IND_7",
+ "EV_IND_AP",
+ "EV_IND_9",
+ "EV_IND_10",
+ "EV_IND_11",
+ "EV_IND_AI8",
+ "EV_IND_AI10",
+ "EV_IND_AIL",
+ "EV_IND_DI",
+ "EV_PH_ACTIVATE_REQ",
+ "EV_PH_DEACTIVATE_REQ",
+ "EV_TIMER3",
+};
+
+static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg)
+{
+ struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if;
+
+ ifc->l1l2(ifc, pr, arg);
+}
+
+static void
+l1_go_f3(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ if (fi->state == ST_L1_F7)
+ ph_disconnect(adapter);
+
+ FsmChangeState(fi, ST_L1_F3);
+ D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void
+l1_go_f6(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ if (fi->state == ST_L1_F7)
+ ph_disconnect(adapter);
+
+ FsmChangeState(fi, ST_L1_F6);
+}
+
+static void
+l1_go_f7(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ FsmDelTimer(&adapter->timer, 0);
+ ph_connect(adapter);
+ FsmChangeState(fi, ST_L1_F7);
+ D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL);
+}
+
+static void
+l1_go_f8(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ if (fi->state == ST_L1_F7)
+ ph_disconnect(adapter);
+
+ FsmChangeState(fi, ST_L1_F8);
+}
+
+static void
+l1_timer3(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ st5481_ph_command(adapter, ST5481_CMD_DR);
+ FsmChangeState(fi, ST_L1_F3);
+ D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL);
+}
+
+static void
+l1_ignore(struct FsmInst *fi, int event, void *arg)
+{
+}
+
+static void
+l1_activate(struct FsmInst *fi, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fi->userdata;
+
+ st5481_ph_command(adapter, ST5481_CMD_DR);
+ st5481_ph_command(adapter, ST5481_CMD_PUP);
+ FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+ st5481_ph_command(adapter, ST5481_CMD_AR8);
+ FsmChangeState(fi, ST_L1_F4);
+}
+
+static struct FsmNode L1FnList[] __initdata =
+{
+ {ST_L1_F3, EV_IND_DP, l1_ignore},
+ {ST_L1_F3, EV_IND_AP, l1_go_f6},
+ {ST_L1_F3, EV_IND_AI8, l1_go_f7},
+ {ST_L1_F3, EV_IND_AI10, l1_go_f7},
+ {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate},
+
+ {ST_L1_F4, EV_TIMER3, l1_timer3},
+ {ST_L1_F4, EV_IND_DP, l1_go_f3},
+ {ST_L1_F4, EV_IND_AP, l1_go_f6},
+ {ST_L1_F4, EV_IND_AI8, l1_go_f7},
+ {ST_L1_F4, EV_IND_AI10, l1_go_f7},
+
+ {ST_L1_F6, EV_TIMER3, l1_timer3},
+ {ST_L1_F6, EV_IND_DP, l1_go_f3},
+ {ST_L1_F6, EV_IND_AP, l1_ignore},
+ {ST_L1_F6, EV_IND_AI8, l1_go_f7},
+ {ST_L1_F6, EV_IND_AI10, l1_go_f7},
+ {ST_L1_F7, EV_IND_RSY, l1_go_f8},
+
+ {ST_L1_F7, EV_IND_DP, l1_go_f3},
+ {ST_L1_F7, EV_IND_AP, l1_go_f6},
+ {ST_L1_F7, EV_IND_AI8, l1_ignore},
+ {ST_L1_F7, EV_IND_AI10, l1_ignore},
+ {ST_L1_F7, EV_IND_RSY, l1_go_f8},
+
+ {ST_L1_F8, EV_TIMER3, l1_timer3},
+ {ST_L1_F8, EV_IND_DP, l1_go_f3},
+ {ST_L1_F8, EV_IND_AP, l1_go_f6},
+ {ST_L1_F8, EV_IND_AI8, l1_go_f8},
+ {ST_L1_F8, EV_IND_AI10, l1_go_f8},
+ {ST_L1_F8, EV_IND_RSY, l1_ignore},
+};
+
+static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ printk("buf %s\n", buf);
+ DBG(8, "%s", buf);
+ va_end(args);
+}
+
+/* ======================================================================
+ * D-Channel out
+ */
+
+/*
+ D OUT state machine:
+ ====================
+
+ Transmit short frame (< 16 bytes of encoded data):
+
+ L1 FRAME D_OUT_STATE USB D CHANNEL
+ -------- ----------- --- ---------
+
+ FIXME
+
+ -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF]
+ SHORT_WAIT_DEN <> OUT_D_COUNTER=16
+
+ END_OF_SHORT <- DEN_EVENT -> 7Exx
+ xxxx
+ xxxx
+ xxxx
+ xxxx
+ xxxx
+ C1C1
+ 7EFF
+ WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms)
+ IDLE <> Reset pipe
+
+
+
+ Transmit long frame (>= 16 bytes of encoded data):
+
+ L1 FRAME D_OUT_STATE USB D CHANNEL
+ -------- ----------- --- ---------
+
+ -> [xx...xx] IDLE
+ WAIT_FOR_STOP <> OUT_D_COUNTER=0
+ WAIT_FOR_RESET <> Reset pipe
+ STOP
+ INIT_LONG_FRAME -> [7Exx..xx]
+ WAIT_DEN <> OUT_D_COUNTER=16
+ OUT_NORMAL <- DEN_EVENT -> 7Exx
+ END_OF_FRAME_BUSY -> [xxxx] xxxx
+ END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx
+ -> [xxxx] xxxx
+ -> [C1C2] xxxx
+ -> [7EFF] xxxx
+ xxxx
+ xxxx
+ ....
+ xxxx
+ C1C2
+ 7EFF
+ <- D_UNDERRUN <- (> 8ms)
+ WAIT_FOR_STOP <> OUT_D_COUNTER=0
+ WAIT_FOR_RESET <> Reset pipe
+ STOP
+
+*/
+
+static struct Fsm dout_fsm;
+
+static char *strDoutState[] =
+{
+ "ST_DOUT_NONE",
+
+ "ST_DOUT_SHORT_INIT",
+ "ST_DOUT_SHORT_WAIT_DEN",
+
+ "ST_DOUT_LONG_INIT",
+ "ST_DOUT_LONG_WAIT_DEN",
+ "ST_DOUT_NORMAL",
+
+ "ST_DOUT_WAIT_FOR_UNDERRUN",
+ "ST_DOUT_WAIT_FOR_NOT_BUSY",
+ "ST_DOUT_WAIT_FOR_STOP",
+ "ST_DOUT_WAIT_FOR_RESET",
+};
+
+static char *strDoutEvent[] =
+{
+ "EV_DOUT_START_XMIT",
+ "EV_DOUT_COMPLETE",
+ "EV_DOUT_DEN",
+ "EV_DOUT_RESETED",
+ "EV_DOUT_STOPPED",
+ "EV_DOUT_COLL",
+ "EV_DOUT_UNDERRUN",
+};
+
+static void dout_debug(struct FsmInst *fi, char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ DBG(0x2, "%s", buf);
+ va_end(args);
+}
+
+static void dout_stop_event(void *context)
+{
+ struct st5481_adapter *adapter = context;
+
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL);
+}
+
+/*
+ * Start the transfer of a D channel frame.
+ */
+static void usb_d_out(struct st5481_adapter *adapter, int buf_nr)
+{
+ struct st5481_d_out *d_out = &adapter->d_out;
+ struct urb *urb;
+ unsigned int num_packets, packet_offset;
+ int len, buf_size, bytes_sent;
+ struct sk_buff *skb;
+ iso_packet_descriptor_t *desc;
+
+ if (d_out->fsm.state != ST_DOUT_NORMAL)
+ return;
+
+ if (test_and_set_bit(buf_nr, &d_out->busy)) {
+ DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
+ return;
+ }
+ urb = d_out->urb[buf_nr];
+
+ skb = d_out->tx_skb;
+
+ buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
+
+ if (skb) {
+ len = hdlc_encode(&d_out->hdlc_state,
+ skb->data, skb->len, &bytes_sent,
+ urb->transfer_buffer, buf_size);
+ skb_pull(skb,bytes_sent);
+ } else {
+ // Send flags or idle
+ len = hdlc_encode(&d_out->hdlc_state,
+ NULL, 0, &bytes_sent,
+ urb->transfer_buffer, buf_size);
+ }
+
+ if (len < buf_size) {
+ FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
+ }
+ if (skb && !skb->len) {
+ d_out->tx_skb = NULL;
+ D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
+ dev_kfree_skb_any(skb);
+ }
+
+ // Prepare the URB
+ urb->transfer_buffer_length = len;
+ num_packets = 0;
+ packet_offset = 0;
+ while (packet_offset < len) {
+ desc = &urb->iso_frame_desc[num_packets];
+ desc->offset = packet_offset;
+ desc->length = SIZE_ISO_PACKETS_D_OUT;
+ if (len - packet_offset < desc->length)
+ desc->length = len - packet_offset;
+ num_packets++;
+ packet_offset += desc->length;
+ }
+ urb->number_of_packets = num_packets;
+
+ // Prepare the URB
+ urb->dev = adapter->usb_dev;
+ // Need to transmit the next buffer 2ms after the DEN_EVENT
+ urb->transfer_flags = 0;
+ urb->start_frame = usb_get_current_frame_number(adapter->usb_dev)+2;
+
+ DBG_ISO_PACKET(0x20,urb);
+
+ if (usb_submit_urb(urb) < 0) {
+ // There is another URB queued up
+ urb->transfer_flags = USB_ISO_ASAP;
+ SUBMIT_URB(urb);
+ }
+}
+
+static void fifo_reseted(void *context)
+{
+ struct st5481_adapter *adapter = context;
+
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
+}
+
+static void usb_d_out_complete(struct urb *urb)
+{
+ struct st5481_adapter *adapter = urb->context;
+ struct st5481_d_out *d_out = &adapter->d_out;
+ int buf_nr;
+
+ DBG(2, "");
+
+ buf_nr = get_buf_nr(d_out->urb, urb);
+ test_and_clear_bit(buf_nr, &d_out->busy);
+
+ if (urb->status < 0) {
+ if (urb->status != USB_ST_URB_KILLED) {
+ WARN("urb status %d",urb->status);
+ if (d_out->busy == 0) {
+ st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
+ }
+ return;
+ } else {
+ DBG(1,"urb killed");
+ return; // Give up
+ }
+ }
+
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr);
+}
+
+/* ====================================================================== */
+
+static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
+{
+ // FIXME unify?
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+ struct urb *urb;
+ int len, bytes_sent;
+ struct sk_buff *skb;
+ int buf_nr = 0;
+
+ skb = d_out->tx_skb;
+
+ DBG(2,"len=%d",skb->len);
+
+ hdlc_out_init(&d_out->hdlc_state, 1, 0);
+
+ if (test_and_set_bit(buf_nr, &d_out->busy)) {
+ WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
+ return;
+ }
+ urb = d_out->urb[buf_nr];
+
+ DBG_SKB(0x10, skb);
+ len = hdlc_encode(&d_out->hdlc_state,
+ skb->data, skb->len, &bytes_sent,
+ urb->transfer_buffer, 16);
+ skb_pull(skb, bytes_sent);
+
+ if(len < 16)
+ FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT);
+ else
+ FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT);
+
+ if (skb->len == 0) {
+ d_out->tx_skb = NULL;
+ D_L1L2(adapter, PH_DATA | CONFIRM, NULL);
+ dev_kfree_skb_any(skb);
+ }
+
+// Prepare the URB
+ urb->transfer_buffer_length = len;
+
+ urb->iso_frame_desc[0].offset = 0;
+ urb->iso_frame_desc[0].length = len;
+ urb->number_of_packets = 1;
+
+ // Prepare the URB
+ urb->dev = adapter->usb_dev;
+ urb->transfer_flags = USB_ISO_ASAP;
+
+ DBG_ISO_PACKET(0x20,urb);
+ SUBMIT_URB(urb);
+}
+
+static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN);
+ st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
+}
+
+static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN);
+}
+
+static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL);
+ FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN);
+}
+
+static void dout_long_den(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL);
+ usb_d_out(adapter, 0);
+ usb_d_out(adapter, 1);
+}
+
+static void dout_reset(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET);
+ st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter);
+}
+
+static void dout_stop(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP);
+ st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter);
+}
+
+static void dout_underrun(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) {
+ FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY);
+ } else {
+ dout_stop(fsm, event, arg);
+ }
+}
+
+static void dout_check_busy(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy))
+ dout_stop(fsm, event, arg);
+}
+
+static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
+ // FIXME locking
+ if (d_out->tx_skb)
+ FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL);
+}
+
+static void dout_complete(struct FsmInst *fsm, int event, void *arg)
+{
+ struct st5481_adapter *adapter = fsm->userdata;
+ int buf_nr = (int) arg;
+
+ usb_d_out(adapter, buf_nr);
+}
+
+static void dout_ignore(struct FsmInst *fsm, int event, void *arg)
+{
+}
+
+static struct FsmNode DoutFnList[] __initdata =
+{
+ {ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit},
+
+ {ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo},
+
+ {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame},
+ {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
+
+ {ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo},
+
+ {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den},
+ {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun},
+
+ {ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun},
+ {ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete},
+
+ {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun},
+ {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore},
+
+ {ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy},
+
+ {ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset},
+
+ {ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted},
+};
+
+void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
+{
+ struct st5481_adapter *adapter = hisax_d_if->priv;
+ struct sk_buff *skb = arg;
+
+ switch (pr) {
+ case PH_ACTIVATE | REQUEST:
+ FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL);
+ break;
+ case PH_DEACTIVATE | REQUEST:
+ FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL);
+ break;
+ case PH_DATA | REQUEST:
+ DBG(2, "PH_DATA REQUEST len %d", skb->len);
+ if (adapter->d_out.tx_skb)
+ BUG();
+
+ adapter->d_out.tx_skb = skb;
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL);
+ break;
+ default:
+ WARN("pr %#x\n", pr);
+ break;
+ }
+}
+
+/* ======================================================================
+ */
+
+/*
+ * Start receiving on the D channel since entered state F7.
+ */
+static void ph_connect(struct st5481_adapter *adapter)
+{
+ struct st5481_d_out *d_out = &adapter->d_out;
+ struct st5481_in *d_in = &adapter->d_in;
+
+ DBG(8,"");
+
+ FsmChangeState(&d_out->fsm, ST_DOUT_NONE);
+
+ // st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL);
+ st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL);
+ st5481_in_mode(d_in, L1_MODE_HDLC);
+
+#if LOOPBACK
+ // Turn loopback on (data sent on B and D looped back)
+ st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL);
+#endif
+
+ st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL);
+
+ // Turn on the green LED to tell that we are in state F7
+ adapter->leds |= GREEN_LED;
+ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
+}
+
+/*
+ * Stop receiving on the D channel since not in state F7.
+ */
+static void ph_disconnect(struct st5481_adapter *adapter)
+{
+ DBG(8,"");
+
+ st5481_in_mode(&adapter->d_in, L1_MODE_NULL);
+
+ // Turn off the green LED to tell that we left state F7
+ adapter->leds &= ~GREEN_LED;
+ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
+}
+
+static int __devinit st5481_setup_d_out(struct st5481_adapter *adapter)
+{
+ struct usb_device *dev = adapter->usb_dev;
+ struct usb_interface_descriptor *altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ DBG(2,"");
+
+ altsetting = &(dev->config->interface[0].altsetting[3]);
+
+ // Allocate URBs and buffers for the D channel out
+ endpoint = &altsetting->endpoint[EP_D_OUT-1];
+
+ DBG(2,"endpoint address=%02x,packet size=%d",
+ endpoint->bEndpointAddress,endpoint->wMaxPacketSize);
+
+ return st5481_setup_isocpipes(d_out->urb, dev,
+ usb_sndisocpipe(dev, endpoint->bEndpointAddress),
+ NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT,
+ NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT,
+ usb_d_out_complete, adapter);
+}
+
+static void __devexit st5481_release_d_out(struct st5481_adapter *adapter)
+{
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+ DBG(2,"");
+
+ st5481_release_isocpipes(d_out->urb);
+}
+
+int __devinit st5481_setup_d(struct st5481_adapter *adapter)
+{
+ int retval;
+
+ DBG(2,"");
+
+ retval = st5481_setup_d_out(adapter);
+ if (retval)
+ goto err;
+ adapter->d_in.bufsize = MAX_DFRAME_LEN_L1;
+ adapter->d_in.num_packets = NUM_ISO_PACKETS_D;
+ adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN;
+ adapter->d_in.ep = EP_D_IN | USB_DIR_IN;
+ adapter->d_in.counter = IN_D_COUNTER;
+ adapter->d_in.adapter = adapter;
+ adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc;
+ retval = st5481_setup_in(&adapter->d_in);
+ if (retval)
+ goto err_d_out;
+
+ adapter->l1m.fsm = &l1fsm;
+ adapter->l1m.state = ST_L1_F3;
+ adapter->l1m.debug = 1;
+ adapter->l1m.userdata = adapter;
+ adapter->l1m.printdebug = l1m_debug;
+ FsmInitTimer(&adapter->l1m, &adapter->timer);
+
+ adapter->d_out.fsm.fsm = &dout_fsm;
+ adapter->d_out.fsm.state = ST_DOUT_NONE;
+ adapter->d_out.fsm.debug = 1;
+ adapter->d_out.fsm.userdata = adapter;
+ adapter->d_out.fsm.printdebug = dout_debug;
+
+ return 0;
+
+ err_d_out:
+ st5481_release_d_out(adapter);
+ err:
+ return retval;
+}
+
+void __devexit st5481_release_d(struct st5481_adapter *adapter)
+{
+ DBG(2,"");
+
+ st5481_release_in(&adapter->d_in);
+ st5481_release_d_out(adapter);
+}
+
+/* ======================================================================
+ * init / exit
+ */
+
+int __init st5481_d_init(void)
+{
+ int retval;
+
+ l1fsm.state_count = L1_STATE_COUNT;
+ l1fsm.event_count = L1_EVENT_COUNT;
+ l1fsm.strEvent = strL1Event;
+ l1fsm.strState = strL1State;
+ retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
+ if (retval)
+ goto err;
+
+ dout_fsm.state_count = DOUT_STATE_COUNT;
+ dout_fsm.event_count = DOUT_EVENT_COUNT;
+ dout_fsm.strEvent = strDoutEvent;
+ dout_fsm.strState = strDoutState;
+ retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList));
+ if (retval)
+ goto err_l1;
+
+ return 0;
+
+ err_l1:
+ FsmFree(&l1fsm);
+ err:
+ return retval;
+}
+
+// can't be __exit
+void st5481_d_exit(void)
+{
+ FsmFree(&l1fsm);
+ FsmFree(&dout_fsm);
+}
diff --git a/drivers/isdn/hisax/st5481_hdlc.c b/drivers/isdn/hisax/st5481_hdlc.c
new file mode 100644
index 000000000000..2ea5136bed49
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_hdlc.c
@@ -0,0 +1,620 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include "st5481_hdlc.h"
+
+static const unsigned short int crc16_tab[] = {
+ 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
+ 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
+ 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
+ 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
+ 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
+ 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
+ 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
+ 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
+ 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
+ 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
+ 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
+ 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
+ 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
+ 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
+ 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
+ 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
+ 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
+ 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
+ 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
+ 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
+ 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
+ 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
+ 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
+ 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
+ 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
+ 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
+ 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
+ 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
+ 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
+ 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
+ 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
+ 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
+};
+
+
+
+enum {
+ HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
+ HDLC_GET_DATA,HDLC_FAST_FLAG
+};
+
+enum {
+ HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
+ HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
+ HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
+ HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+};
+
+void
+hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56)
+{
+ hdlc->bit_shift = 0;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->data_bits = 0;
+ hdlc->ffbit_shift = 0;
+ hdlc->data_received = 0;
+ hdlc->state = HDLC_GET_DATA;
+ hdlc->do_adapt56 = do_adapt56;
+ hdlc->dchannel = 0;
+ hdlc->crc = 0;
+ hdlc->cbin = 0;
+ hdlc->shift_reg = 0;
+ hdlc->ffvalue = 0;
+ hdlc->dstpos = 0;
+}
+
+void
+hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+{
+ hdlc->bit_shift = 0;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->data_bits = 0;
+ hdlc->ffbit_shift = 0;
+ hdlc->data_received = 0;
+ hdlc->do_closing = 0;
+ hdlc->ffvalue = 0;
+ if (is_d_channel) {
+ hdlc->dchannel = 1;
+ hdlc->state = HDLC_SEND_FIRST_FLAG;
+ } else {
+ hdlc->dchannel = 0;
+ hdlc->state = HDLC_SEND_FAST_FLAG;
+ hdlc->ffvalue = 0x7e;
+ }
+ hdlc->cbin = 0x7e;
+ hdlc->bit_shift = 0;
+ if(do_adapt56){
+ hdlc->do_adapt56 = 1;
+ hdlc->data_bits = 0;
+ hdlc->state = HDLC_SENDFLAG_B0;
+ } else {
+ hdlc->do_adapt56 = 0;
+ hdlc->data_bits = 8;
+ }
+ hdlc->shift_reg = 0;
+}
+
+/*
+ hdlc_decode - decodes HDLC frames from a transparent bit stream.
+
+ The source buffer is scanned for valid HDLC frames looking for
+ flags (01111110) to indicate the start of a frame. If the start of
+ the frame is found, the bit stuffing is removed (0 after 5 1's).
+ When a new flag is found, the complete frame has been received
+ and the CRC is checked.
+ If a valid frame is found, the function returns the frame length
+ excluding the CRC with the bit HDLC_END_OF_FRAME set.
+ If the beginning of a valid frame is found, the function returns
+ the length.
+ If a framing error is found (too many 1s and not a flag) the function
+ returns the length with the bit HDLC_FRAMING_ERROR set.
+ If a CRC error is found the function returns the length with the
+ bit HDLC_CRC_ERROR set.
+ If the frame length exceeds the destination buffer size, the function
+ returns the length with the bit HDLC_LENGTH_ERROR set.
+
+ src - source buffer
+ slen - source buffer length
+ count - number of bytes removed (decoded) from the source buffer
+ dst _ destination buffer
+ dsize - destination buffer size
+ returns - number of decoded bytes in the destination buffer and status
+ flag.
+ */
+int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
+ int slen, int *count, unsigned char *dst, int dsize)
+{
+ int status=0;
+
+ static const unsigned char fast_flag[]={
+ 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+ };
+
+ static const unsigned char fast_flag_value[]={
+ 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+ };
+
+ static const unsigned char fast_abort[]={
+ 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+ };
+
+ *count = slen;
+
+ while(slen > 0){
+ if(hdlc->bit_shift==0){
+ hdlc->cbin = *src++;
+ slen--;
+ hdlc->bit_shift = 8;
+ if(hdlc->do_adapt56){
+ hdlc->bit_shift --;
+ }
+ }
+
+ switch(hdlc->state){
+ case STOPPED:
+ return 0;
+ case HDLC_FAST_IDLE:
+ if(hdlc->cbin == 0xff){
+ hdlc->bit_shift = 0;
+ break;
+ }
+ hdlc->state = HDLC_GET_FLAG_B0;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->bit_shift = 8;
+ break;
+ case HDLC_GET_FLAG_B0:
+ if(!(hdlc->cbin & 0x80)) {
+ hdlc->state = HDLC_GETFLAG_B1A6;
+ hdlc->hdlc_bits1 = 0;
+ } else {
+ if(!hdlc->do_adapt56){
+ if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+ hdlc->state = HDLC_FAST_IDLE;
+ }
+ }
+ hdlc->cbin<<=1;
+ hdlc->bit_shift --;
+ break;
+ case HDLC_GETFLAG_B1A6:
+ if(hdlc->cbin & 0x80){
+ hdlc->hdlc_bits1++;
+ if(hdlc->hdlc_bits1==6){
+ hdlc->state = HDLC_GETFLAG_B7;
+ }
+ } else {
+ hdlc->hdlc_bits1 = 0;
+ }
+ hdlc->cbin<<=1;
+ hdlc->bit_shift --;
+ break;
+ case HDLC_GETFLAG_B7:
+ if(hdlc->cbin & 0x80) {
+ hdlc->state = HDLC_GET_FLAG_B0;
+ } else {
+ hdlc->state = HDLC_GET_DATA;
+ hdlc->crc = 0xffff;
+ hdlc->shift_reg = 0;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->data_bits = 0;
+ hdlc->data_received = 0;
+ }
+ hdlc->cbin<<=1;
+ hdlc->bit_shift --;
+ break;
+ case HDLC_GET_DATA:
+ if(hdlc->cbin & 0x80){
+ hdlc->hdlc_bits1++;
+ switch(hdlc->hdlc_bits1){
+ case 6:
+ break;
+ case 7:
+ if(hdlc->data_received) {
+ // bad frame
+ status = -HDLC_FRAMING_ERROR;
+ }
+ if(!hdlc->do_adapt56){
+ if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
+ hdlc->state = HDLC_FAST_IDLE;
+ hdlc->bit_shift=1;
+ break;
+ }
+ } else {
+ hdlc->state = HDLC_GET_FLAG_B0;
+ }
+ break;
+ default:
+ hdlc->shift_reg>>=1;
+ hdlc->shift_reg |= 0x80;
+ hdlc->data_bits++;
+ break;
+ }
+ } else {
+ switch(hdlc->hdlc_bits1){
+ case 5:
+ break;
+ case 6:
+ if(hdlc->data_received){
+ if (hdlc->dstpos < 2) {
+ status = -HDLC_FRAMING_ERROR;
+ } else if (hdlc->crc != 0xf0b8){
+ // crc error
+ status = -HDLC_CRC_ERROR;
+ } else {
+ // remove CRC
+ hdlc->dstpos -= 2;
+ // good frame
+ status = hdlc->dstpos;
+ }
+ }
+ hdlc->crc = 0xffff;
+ hdlc->shift_reg = 0;
+ hdlc->data_bits = 0;
+ if(!hdlc->do_adapt56){
+ if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
+ hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
+ hdlc->state = HDLC_FAST_FLAG;
+ hdlc->ffbit_shift = hdlc->bit_shift;
+ hdlc->bit_shift = 1;
+ } else {
+ hdlc->state = HDLC_GET_DATA;
+ hdlc->data_received = 0;
+ }
+ } else {
+ hdlc->state = HDLC_GET_DATA;
+ hdlc->data_received = 0;
+ }
+ break;
+ default:
+ hdlc->shift_reg>>=1;
+ hdlc->data_bits++;
+ break;
+ }
+ hdlc->hdlc_bits1 = 0;
+ }
+ if (status) {
+ hdlc->dstpos = 0;
+ *count -= slen;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
+ return status;
+ }
+ if(hdlc->data_bits==8){
+ unsigned cval;
+
+ hdlc->data_bits = 0;
+ hdlc->data_received = 1;
+ cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+ hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+ // good byte received
+ if (dsize--) {
+ dst[hdlc->dstpos++] = hdlc->shift_reg;
+ } else {
+ // frame too long
+ status = -HDLC_LENGTH_ERROR;
+ hdlc->dstpos = 0;
+ }
+ }
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
+ break;
+ case HDLC_FAST_FLAG:
+ if(hdlc->cbin==hdlc->ffvalue){
+ hdlc->bit_shift = 0;
+ break;
+ } else {
+ if(hdlc->cbin == 0xff){
+ hdlc->state = HDLC_FAST_IDLE;
+ hdlc->bit_shift=0;
+ } else if(hdlc->ffbit_shift==8){
+ hdlc->state = HDLC_GETFLAG_B7;
+ break;
+ } else {
+ hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
+ hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
+ if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
+ hdlc->data_bits = hdlc->ffbit_shift-1;
+ hdlc->state = HDLC_GET_DATA;
+ hdlc->data_received = 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ *count -= slen;
+ return 0;
+}
+
+/*
+ hdlc_encode - encodes HDLC frames to a transparent bit stream.
+
+ The bit stream starts with a beginning flag (01111110). After
+ that each byte is added to the bit stream with bit stuffing added
+ (0 after 5 1's).
+ When the last byte has been removed from the source buffer, the
+ CRC (2 bytes is added) and the frame terminates with the ending flag.
+ For the dchannel, the idle character (all 1's) is also added at the end.
+ If this function is called with empty source buffer (slen=0), flags or
+ idle character will be generated.
+
+ src - source buffer
+ slen - source buffer length
+ count - number of bytes removed (encoded) from source buffer
+ dst _ destination buffer
+ dsize - destination buffer size
+ returns - number of encoded bytes in the destination buffer
+*/
+int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src,
+ unsigned short slen, int *count,
+ unsigned char *dst, int dsize)
+{
+ static const unsigned char xfast_flag_value[] = {
+ 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+ };
+
+ int len = 0;
+
+ *count = slen;
+
+ while (dsize > 0) {
+ if(hdlc->bit_shift==0){
+ if(slen && !hdlc->do_closing){
+ hdlc->shift_reg = *src++;
+ slen--;
+ if (slen == 0)
+ hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
+ hdlc->bit_shift = 8;
+ } else {
+ if(hdlc->state == HDLC_SEND_DATA){
+ if(hdlc->data_received){
+ hdlc->state = HDLC_SEND_CRC1;
+ hdlc->crc ^= 0xffff;
+ hdlc->bit_shift = 8;
+ hdlc->shift_reg = hdlc->crc & 0xff;
+ } else if(!hdlc->do_adapt56){
+ hdlc->state = HDLC_SEND_FAST_FLAG;
+ } else {
+ hdlc->state = HDLC_SENDFLAG_B0;
+ }
+ }
+
+ }
+ }
+
+ switch(hdlc->state){
+ case STOPPED:
+ while (dsize--)
+ *dst++ = 0xff;
+
+ return dsize;
+ case HDLC_SEND_FAST_FLAG:
+ hdlc->do_closing = 0;
+ if(slen == 0){
+ *dst++ = hdlc->ffvalue;
+ len++;
+ dsize--;
+ break;
+ }
+ if(hdlc->bit_shift==8){
+ hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+ hdlc->state = HDLC_SEND_DATA;
+ hdlc->crc = 0xffff;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->data_received = 1;
+ }
+ break;
+ case HDLC_SENDFLAG_B0:
+ hdlc->do_closing = 0;
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->state = HDLC_SENDFLAG_B1A6;
+ break;
+ case HDLC_SENDFLAG_B1A6:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ hdlc->cbin++;
+ if(++hdlc->hdlc_bits1 == 6)
+ hdlc->state = HDLC_SENDFLAG_B7;
+ break;
+ case HDLC_SENDFLAG_B7:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(slen == 0){
+ hdlc->state = HDLC_SENDFLAG_B0;
+ break;
+ }
+ if(hdlc->bit_shift==8){
+ hdlc->state = HDLC_SEND_DATA;
+ hdlc->crc = 0xffff;
+ hdlc->hdlc_bits1 = 0;
+ hdlc->data_received = 1;
+ }
+ break;
+ case HDLC_SEND_FIRST_FLAG:
+ hdlc->data_received = 1;
+ if(hdlc->data_bits==8){
+ hdlc->state = HDLC_SEND_DATA;
+ hdlc->crc = 0xffff;
+ hdlc->hdlc_bits1 = 0;
+ break;
+ }
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(hdlc->shift_reg & 0x01)
+ hdlc->cbin++;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ if(hdlc->bit_shift==0){
+ hdlc->state = HDLC_SEND_DATA;
+ hdlc->crc = 0xffff;
+ hdlc->hdlc_bits1 = 0;
+ }
+ break;
+ case HDLC_SEND_DATA:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(hdlc->hdlc_bits1 == 5){
+ hdlc->hdlc_bits1 = 0;
+ break;
+ }
+ if(hdlc->bit_shift==8){
+ unsigned cval;
+
+ cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+ hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+ }
+ if(hdlc->shift_reg & 0x01){
+ hdlc->hdlc_bits1++;
+ hdlc->cbin++;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ } else {
+ hdlc->hdlc_bits1 = 0;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ }
+ break;
+ case HDLC_SEND_CRC1:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(hdlc->hdlc_bits1 == 5){
+ hdlc->hdlc_bits1 = 0;
+ break;
+ }
+ if(hdlc->shift_reg & 0x01){
+ hdlc->hdlc_bits1++;
+ hdlc->cbin++;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ } else {
+ hdlc->hdlc_bits1 = 0;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ }
+ if(hdlc->bit_shift==0){
+ hdlc->shift_reg = (hdlc->crc >> 8);
+ hdlc->state = HDLC_SEND_CRC2;
+ hdlc->bit_shift = 8;
+ }
+ break;
+ case HDLC_SEND_CRC2:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(hdlc->hdlc_bits1 == 5){
+ hdlc->hdlc_bits1 = 0;
+ break;
+ }
+ if(hdlc->shift_reg & 0x01){
+ hdlc->hdlc_bits1++;
+ hdlc->cbin++;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ } else {
+ hdlc->hdlc_bits1 = 0;
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ }
+ if(hdlc->bit_shift==0){
+ hdlc->shift_reg = 0x7e;
+ hdlc->state = HDLC_SEND_CLOSING_FLAG;
+ hdlc->bit_shift = 8;
+ }
+ break;
+ case HDLC_SEND_CLOSING_FLAG:
+ hdlc->cbin <<= 1;
+ hdlc->data_bits++;
+ if(hdlc->hdlc_bits1 == 5){
+ hdlc->hdlc_bits1 = 0;
+ break;
+ }
+ if(hdlc->shift_reg & 0x01){
+ hdlc->cbin++;
+ }
+ hdlc->shift_reg >>= 1;
+ hdlc->bit_shift--;
+ if(hdlc->bit_shift==0){
+ hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
+ if(hdlc->dchannel){
+ hdlc->ffvalue = 0x7e;
+ hdlc->state = HDLC_SEND_IDLE1;
+ hdlc->bit_shift = 8-hdlc->data_bits;
+ if(hdlc->bit_shift==0)
+ hdlc->state = HDLC_SEND_FAST_IDLE;
+ } else {
+ if(!hdlc->do_adapt56){
+ hdlc->state = HDLC_SEND_FAST_FLAG;
+ hdlc->data_received = 0;
+ } else {
+ hdlc->state = HDLC_SENDFLAG_B0;
+ hdlc->data_received = 0;
+ }
+ // Finished with this frame, send flags
+ if (dsize > 1) dsize = 1;
+ }
+ }
+ break;
+ case HDLC_SEND_IDLE1:
+ hdlc->do_closing = 0;
+ hdlc->cbin <<= 1;
+ hdlc->cbin++;
+ hdlc->data_bits++;
+ hdlc->bit_shift--;
+ if(hdlc->bit_shift==0){
+ hdlc->state = HDLC_SEND_FAST_IDLE;
+ hdlc->bit_shift = 0;
+ }
+ break;
+ case HDLC_SEND_FAST_IDLE:
+ hdlc->do_closing = 0;
+ hdlc->cbin = 0xff;
+ hdlc->data_bits = 8;
+ if(hdlc->bit_shift == 8){
+ hdlc->cbin = 0x7e;
+ hdlc->state = HDLC_SEND_FIRST_FLAG;
+ } else {
+ *dst++ = hdlc->cbin;
+ hdlc->bit_shift = hdlc->data_bits = 0;
+ len++;
+ dsize = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ if(hdlc->do_adapt56){
+ if(hdlc->data_bits==7){
+ hdlc->cbin <<= 1;
+ hdlc->cbin++;
+ hdlc->data_bits++;
+ }
+ }
+ if(hdlc->data_bits==8){
+ *dst++ = hdlc->cbin;
+ hdlc->data_bits = 0;
+ len++;
+ dsize--;
+ }
+ }
+ *count -= slen;
+
+ return len;
+}
+
diff --git a/drivers/isdn/hisax/st5481_hdlc.h b/drivers/isdn/hisax/st5481_hdlc.h
new file mode 100644
index 000000000000..495432f0f6ba
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_hdlc.h
@@ -0,0 +1,62 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#ifndef __ST5481_HDLC_H__
+#define __ST5481_HDLC_H__
+
+struct hdlc_vars {
+ int bit_shift;
+ int hdlc_bits1;
+ int data_bits;
+ int ffbit_shift; // encoding only
+ int state;
+ int dstpos;
+
+ int data_received:1; // set if transferring data
+ int dchannel:1; // set if D channel (send idle instead of flags)
+ int do_adapt56:1; // set if 56K adaptation
+ int do_closing:1; // set if in closing phase (need to send CRC + flag
+
+ unsigned short crc;
+
+ unsigned char cbin;
+ unsigned char shift_reg;
+ unsigned char ffvalue;
+
+};
+
+
+/*
+ The return value from hdlc_decode is
+ the frame length, 0 if no complete frame was decoded,
+ or a negative error number
+*/
+
+#define HDLC_FRAMING_ERROR 1
+#define HDLC_CRC_ERROR 2
+#define HDLC_LENGTH_ERROR 3
+
+void
+hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56);
+
+int
+hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
+ unsigned char *dst, int dsize);
+
+void
+hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56);
+
+int
+hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
+ unsigned char *dst,int dsize);
+
+#endif
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
new file mode 100644
index 000000000000..6e299ba936eb
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -0,0 +1,215 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/*
+ * TODO:
+ *
+ * b layer1 delay?
+ * hdlc as module
+ * hotplug / unregister issues
+ * mod_inc/dec_use_count
+ * unify parts of d/b channel usb handling
+ * file header
+ * avoid copy to isoc buffer?
+ * improve usb delay?
+ * merge l1 state machines?
+ * clean up debug
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include "st5481.h"
+
+MODULE_AUTHOR("Frode Isaksen <fisaksen@bewan.com>");
+MODULE_DESCRIPTION("ST5481 USB ISDN modem driver");
+
+static int protocol = 2; /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+static int number_of_leds = 2; /* 2 LEDs on the adpater default */
+MODULE_PARM(number_of_leds, "i");
+
+#ifdef CONFIG_HISAX_DEBUG
+static int debug = 0x1;
+MODULE_PARM(debug, "i");
+int st5481_debug;
+#endif
+
+static LIST_HEAD(adapter_list);
+
+/* ======================================================================
+ * registration/deregistration with the USB layer
+ */
+
+/*
+ * This function will be called when the adapter is plugged
+ * into the USB bus.
+ */
+static void * __devinit probe_st5481(struct usb_device *dev,
+ unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ struct st5481_adapter *adapter;
+ struct hisax_b_if *b_if[2];
+ int retval, i;
+
+ printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct,
+ number_of_leds);
+
+ adapter = kmalloc(sizeof(struct st5481_adapter), GFP_KERNEL);
+ if (!adapter)
+ return NULL;
+
+ memset(adapter, 0, sizeof(struct st5481_adapter));
+
+ adapter->number_of_leds = number_of_leds;
+ adapter->usb_dev = dev;
+
+ SET_MODULE_OWNER(&adapter->hisax_d_if);
+ adapter->hisax_d_if.ifc.priv = adapter;
+ adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1;
+
+ for (i = 0; i < 2; i++) {
+ adapter->bcs[i].adapter = adapter;
+ adapter->bcs[i].channel = i;
+ adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
+ adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1;
+ }
+ list_add(&adapter->list, &adapter_list);
+
+ retval = st5481_setup_usb(adapter);
+ if (retval < 0)
+ goto err;
+
+ retval = st5481_setup_d(adapter);
+ if (retval < 0)
+ goto err_usb;
+
+ retval = st5481_setup_b(&adapter->bcs[0]);
+ if (retval < 0)
+ goto err_d;
+
+ retval = st5481_setup_b(&adapter->bcs[1]);
+ if (retval < 0)
+ goto err_b;
+
+ for (i = 0; i < 2; i++)
+ b_if[i] = &adapter->bcs[i].b_if;
+
+ hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", protocol);
+ st5481_start(adapter);
+
+ return adapter;
+
+ err_b:
+ st5481_release_b(&adapter->bcs[0]);
+ err_d:
+ st5481_release_d(adapter);
+ err_usb:
+ st5481_release_usb(adapter);
+ err:
+ return NULL;
+}
+
+/*
+ * This function will be called when the adapter is removed
+ * from the USB bus.
+ */
+static void __devexit disconnect_st5481(struct usb_device *dev, void *arg)
+{
+ struct st5481_adapter *adapter = arg;
+
+ DBG(1,"");
+
+ list_del(&adapter->list);
+
+ st5481_stop(adapter);
+ st5481_release_b(&adapter->bcs[1]);
+ st5481_release_b(&adapter->bcs[0]);
+ st5481_release_d(adapter);
+ // we would actually better wait for completion of outstanding urbs
+ mdelay(2);
+ st5481_release_usb(adapter);
+
+ hisax_unregister(&adapter->hisax_d_if);
+
+ kfree(adapter);
+}
+
+/*
+ * The last 4 bits in the Product Id is set with 4 pins on the chip.
+ */
+static struct usb_device_id st5481_ids[] = {
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x0) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x1) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x2) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x3) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x4) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x5) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x6) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x7) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x8) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0x9) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xA) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xB) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xC) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xD) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xE) },
+ { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID+0xF) },
+ { }
+};
+MODULE_DEVICE_TABLE (usb, st5481_ids);
+
+static struct usb_driver st5481_usb_driver = {
+ name: "st5481_usb",
+ probe: probe_st5481,
+ disconnect: disconnect_st5481,
+ id_table: st5481_ids,
+};
+
+static int __init st5481_usb_init(void)
+{
+ int retval;
+
+#ifdef CONFIG_HISAX_DEBUG
+ st5481_debug = debug;
+#endif
+
+ printk(KERN_INFO "hiax_st5481: ST5481 USB ISDN driver v0.1.0\n");
+
+ retval = st5481_d_init();
+ if (retval < 0)
+ goto out;
+
+ retval = usb_register(&st5481_usb_driver);
+ if (retval < 0)
+ goto out_d_exit;
+
+ return 0;
+
+ out_d_exit:
+ st5481_d_exit();
+ out:
+ return retval;
+}
+
+static void __exit st5481_usb_exit(void)
+{
+ usb_deregister(&st5481_usb_driver);
+}
+
+module_init(st5481_usb_init);
+module_exit(st5481_usb_exit);
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
new file mode 100644
index 000000000000..9908094c41fc
--- /dev/null
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -0,0 +1,639 @@
+/*
+ * Driver for ST5481 USB ISDN modem
+ *
+ * Author Frode Isaksen
+ * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
+ * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include "st5481.h"
+
+/* ======================================================================
+ * control pipe
+ */
+
+/*
+ * Send the next endpoint 0 request stored in the FIFO.
+ * Called either by the completion or by usb_ctrl_msg.
+ */
+static void usb_next_ctrl_msg(struct urb *urb,
+ struct st5481_adapter *adapter)
+{
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+ int r_index;
+
+ if (test_and_set_bit(0, &ctrl->busy)) {
+ return;
+ }
+
+ if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) {
+ test_and_clear_bit(0,&ctrl->busy);
+ return;
+ }
+ urb->setup_packet =
+ (unsigned char *)&ctrl->msg_fifo.data[r_index];
+
+ DBG(1,"request=0x%02x,value=0x%04x,index=%x",
+ ((struct ctrl_msg *)urb->setup_packet)->dr.request,
+ ((struct ctrl_msg *)urb->setup_packet)->dr.value,
+ ((struct ctrl_msg *)urb->setup_packet)->dr.index);
+
+ // Prepare the URB
+ urb->dev = adapter->usb_dev;
+
+ SUBMIT_URB(urb);
+}
+
+/*
+ * Asynchronous endpoint 0 request (async version of usb_control_msg).
+ * The request will be queued up in a FIFO if the endpoint is busy.
+ */
+void usb_ctrl_msg(struct st5481_adapter *adapter,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ ctrl_complete_t complete, void *context)
+{
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+ int w_index;
+ struct ctrl_msg *ctrl_msg;
+
+ if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) {
+ WARN("control msg FIFO full");
+ return;
+ }
+ ctrl_msg = &ctrl->msg_fifo.data[w_index];
+
+ ctrl_msg->dr.requesttype = requesttype;
+ ctrl_msg->dr.request = request;
+ ctrl_msg->dr.value = cpu_to_le16p(&value);
+ ctrl_msg->dr.index = cpu_to_le16p(&index);
+ ctrl_msg->dr.length = 0;
+ ctrl_msg->complete = complete;
+ ctrl_msg->context = context;
+
+ usb_next_ctrl_msg(ctrl->urb, adapter);
+}
+
+/*
+ * Asynchronous endpoint 0 device request.
+ */
+void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
+ u8 request, u16 value,
+ ctrl_complete_t complete, void *context)
+{
+ usb_ctrl_msg(adapter, request,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, 0, complete, context);
+}
+
+/*
+ * Asynchronous pipe reset (async version of usb_clear_halt).
+ */
+void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
+ u_char pipe,
+ ctrl_complete_t complete, void *context)
+{
+ DBG(1,"pipe=%02x",pipe);
+
+ usb_ctrl_msg(adapter,
+ USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT,
+ 0, pipe, complete, context);
+}
+
+
+/*
+ Physical level functions
+*/
+
+void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
+{
+ DBG(8,"command=%s", ST5481_CMD_string(command));
+
+ st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL);
+}
+
+/*
+ * The request on endpoint 0 has completed.
+ * Call the user provided completion routine and try
+ * to send the next request.
+ */
+static void usb_ctrl_complete(struct urb *urb)
+{
+ struct st5481_adapter *adapter = urb->context;
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+ struct ctrl_msg *ctrl_msg;
+
+ if (urb->status < 0) {
+ if (urb->status != USB_ST_URB_KILLED) {
+ WARN("urb status %d",urb->status);
+ } else {
+ DBG(1,"urb killed");
+ return; // Give up
+ }
+ }
+
+ ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
+
+ if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) {
+ /* Special case handling for pipe reset */
+ le16_to_cpus(&ctrl_msg->dr.index);
+ usb_endpoint_running(adapter->usb_dev,
+ ctrl_msg->dr.index & ~USB_DIR_IN,
+ (ctrl_msg->dr.index & USB_DIR_IN) == 0);
+
+ /* toggle is reset on clear */
+ usb_settoggle(adapter->usb_dev,
+ ctrl_msg->dr.index & ~USB_DIR_IN,
+ (ctrl_msg->dr.index & USB_DIR_IN) == 0,
+ 0);
+
+
+ }
+
+ if (ctrl_msg->complete)
+ ctrl_msg->complete(ctrl_msg->context);
+
+ clear_bit(0, &ctrl->busy);
+
+ // Try to send next control message
+ usb_next_ctrl_msg(urb, adapter);
+ return;
+}
+
+/* ======================================================================
+ * interrupt pipe
+ */
+
+/*
+ * The interrupt endpoint will be called when any
+ * of the 6 registers changes state (depending on masks).
+ * Decode the register values and schedule a private event.
+ * Called at interrupt.
+ */
+static void usb_int_complete(struct urb *urb)
+{
+ u_char *data = urb->transfer_buffer;
+ u_char irqbyte;
+ struct st5481_adapter *adapter = urb->context;
+ int j;
+
+ if (urb->status < 0) {
+ if (urb->status != USB_ST_URB_KILLED) {
+ WARN("urb status %d",urb->status);
+ urb->actual_length = 0;
+ } else {
+ DBG(1,"urb killed");
+ return; // Give up
+ }
+ }
+
+ DBG_PACKET(1, data, INT_PKT_SIZE);
+
+ if (urb->actual_length == 0) {
+ return;
+ }
+
+ irqbyte = data[MPINT];
+ if (irqbyte & DEN_INT)
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL);
+
+ if (irqbyte & DCOLL_INT)
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL);
+
+ irqbyte = data[FFINT_D];
+ if (irqbyte & OUT_UNDERRUN)
+ FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL);
+
+ if (irqbyte & OUT_DOWN)
+;// printk("OUT_DOWN\n");
+
+ irqbyte = data[MPINT];
+ if (irqbyte & RXCI_INT)
+ FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL);
+
+ for (j = 0; j < 2; j++)
+ adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j];
+
+ urb->actual_length = 0;
+}
+
+/* ======================================================================
+ * initialization
+ */
+
+int __devinit st5481_setup_usb(struct st5481_adapter *adapter)
+{
+ struct usb_device *dev = adapter->usb_dev;
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+ struct st5481_intr *intr = &adapter->intr;
+ struct usb_interface_descriptor *altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ int status;
+ urb_t *urb;
+ u_char *buf;
+
+ DBG(1,"");
+
+ if ((status = usb_set_configuration (dev,dev->config[0].bConfigurationValue)) < 0) {
+ WARN("set_configuration failed,status=%d",status);
+ return status;
+ }
+
+
+ altsetting = &(dev->config->interface[0].altsetting[3]);
+
+ // Check if the config is sane
+ if ( altsetting->bNumEndpoints != 7 ) {
+ WARN("expecting 7 got %d endpoints!", altsetting->bNumEndpoints);
+ return -EINVAL;
+ }
+
+ // The descriptor is wrong for some early samples of the ST5481 chip
+ altsetting->endpoint[3].wMaxPacketSize = 32;
+ altsetting->endpoint[4].wMaxPacketSize = 32;
+
+ // Use alternative setting 3 on interface 0 to have 2B+D
+ if ((status = usb_set_interface (dev, 0, 3)) < 0) {
+ WARN("usb_set_interface failed,status=%d",status);
+ return status;
+ }
+
+ // Allocate URB for control endpoint
+ urb = usb_alloc_urb(0);
+ if (!urb) {
+ return -ENOMEM;
+ }
+ ctrl->urb = urb;
+
+ // Fill the control URB
+ FILL_CONTROL_URB (urb, dev,
+ usb_sndctrlpipe(dev, 0),
+ NULL, NULL, 0, usb_ctrl_complete, adapter);
+
+
+ fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data));
+
+ // Allocate URBs and buffers for interrupt endpoint
+ urb = usb_alloc_urb(0);
+ if (!urb) {
+ return -ENOMEM;
+ }
+ intr->urb = urb;
+
+ buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL);
+ if (!buf) {
+ return -ENOMEM;
+ }
+
+ endpoint = &altsetting->endpoint[EP_INT-1];
+
+ // Fill the interrupt URB
+ FILL_INT_URB(urb, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ buf, INT_PKT_SIZE,
+ usb_int_complete, adapter,
+ endpoint->bInterval);
+
+ return 0;
+}
+
+/*
+ * Release buffers and URBs for the interrupt and control
+ * endpoint.
+ */
+void __devexit st5481_release_usb(struct st5481_adapter *adapter)
+{
+ struct st5481_intr *intr = &adapter->intr;
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+
+ DBG(1,"");
+
+ // Stop and free Control and Interrupt URBs
+ usb_unlink_urb(ctrl->urb);
+ if (ctrl->urb->transfer_buffer)
+ kfree(ctrl->urb->transfer_buffer);
+ usb_free_urb(ctrl->urb);
+
+ usb_unlink_urb(intr->urb);
+ if (intr->urb->transfer_buffer)
+ kfree(intr->urb->transfer_buffer);
+ usb_free_urb(intr->urb);
+}
+
+/*
+ * Initialize the adapter.
+ */
+void __devinit st5481_start(struct st5481_adapter *adapter)
+{
+ static const u8 init_cmd_table[]={
+ SET_DEFAULT,0,
+ STT,0,
+ SDA_MIN,0x0d,
+ SDA_MAX,0x29,
+ SDELAY_VALUE,0x14,
+ GPIO_DIR,0x01,
+ GPIO_OUT,RED_LED,
+// FFCTRL_OUT_D,4,
+// FFCTRH_OUT_D,12,
+ FFCTRL_OUT_B1,6,
+ FFCTRH_OUT_B1,20,
+ FFCTRL_OUT_B2,6,
+ FFCTRH_OUT_B2,20,
+ MPMSK,RXCI_INT+DEN_INT+DCOLL_INT,
+ 0
+ };
+ struct st5481_intr *intr = &adapter->intr;
+ int i = 0;
+ u8 request,value;
+
+ DBG(8,"");
+
+ adapter->leds = RED_LED;
+
+ // Start receiving on the interrupt endpoint
+ SUBMIT_URB(intr->urb);
+
+ while ((request = init_cmd_table[i++])) {
+ value = init_cmd_table[i++];
+ st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL);
+ }
+ st5481_ph_command(adapter, ST5481_CMD_PUP);
+}
+
+/*
+ * Reset the adapter to default values.
+ */
+void __devexit st5481_stop(struct st5481_adapter *adapter)
+{
+ DBG(8,"");
+
+ st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL);
+}
+
+/* ======================================================================
+ * isochronous USB helpers
+ */
+
+static void __devinit
+fill_isoc_urb(struct urb *urb, struct usb_device *dev,
+ unsigned int pipe, void *buf, int num_packets,
+ int packet_size, usb_complete_t complete,
+ void *context)
+{
+ int k;
+
+ spin_lock_init(&urb->lock);
+ urb->dev=dev;
+ urb->pipe=pipe;
+ urb->transfer_buffer=buf;
+ urb->number_of_packets = num_packets;
+ urb->transfer_buffer_length=num_packets*packet_size;
+ urb->actual_length = 0;
+ urb->complete=complete;
+ urb->context=context;
+ urb->transfer_flags=USB_ISO_ASAP;
+ for (k = 0; k < num_packets; k++) {
+ urb->iso_frame_desc[k].offset = packet_size * k;
+ urb->iso_frame_desc[k].length = packet_size;
+ urb->iso_frame_desc[k].actual_length = 0;
+ }
+}
+
+int __devinit
+st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
+ unsigned int pipe, int num_packets,
+ int packet_size, int buf_size,
+ usb_complete_t complete, void *context)
+{
+ int j, retval;
+ unsigned char *buf;
+
+ for (j = 0; j < 2; j++) {
+ retval = -ENOMEM;
+ urb[j] = usb_alloc_urb(num_packets);
+ if (!urb[j])
+ goto err;
+
+ // Allocate memory for 2000bytes/sec (16Kb/s)
+ buf = kmalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ goto err;
+
+ // Fill the isochronous URB
+ fill_isoc_urb(urb[j], dev, pipe, buf,
+ num_packets, packet_size, complete,
+ context);
+ }
+ return 0;
+
+ err:
+ for (j = 0; j < 2; j++) {
+ if (urb[j]) {
+ if (urb[j]->transfer_buffer)
+ kfree(urb[j]->transfer_buffer);
+ usb_free_urb(urb[j]);
+ }
+ }
+ return retval;
+}
+
+void __devexit st5481_release_isocpipes(struct urb* urb[2])
+{
+ int j;
+
+ for (j = 0; j < 2; j++) {
+ usb_unlink_urb(urb[j]);
+ if (urb[j]->transfer_buffer)
+ kfree(urb[j]->transfer_buffer);
+ usb_free_urb(urb[j]);
+ }
+}
+
+/*
+ * Decode frames received on the B/D channel.
+ * Note that this function will be called continously
+ * with 64Kbit/s / 16Kbit/s of data and hence it will be
+ * called 50 times per second with 20 ISOC descriptors.
+ * Called at interrupt.
+ */
+static void usb_in_complete(struct urb *urb)
+{
+ struct st5481_in *in = urb->context;
+ unsigned char *ptr;
+ struct sk_buff *skb;
+ int len, count, status;
+
+ if (urb->status < 0) {
+ if (urb->status != USB_ST_URB_KILLED) {
+ WARN("urb status %d",urb->status);
+ } else {
+ DBG(1,"urb killed");
+ return; // Give up
+ }
+ }
+
+ DBG_ISO_PACKET(0x80,urb);
+
+ len = st5481_isoc_flatten(urb);
+ ptr = urb->transfer_buffer;
+ while (len > 0) {
+ if (in->mode == L1_MODE_TRANS) {
+ memcpy(in->rcvbuf, ptr, len);
+ status = len;
+ len = 0;
+ } else {
+ status = hdlc_decode(&in->hdlc_state, ptr, len, &count,
+ in->rcvbuf, in->bufsize);
+ ptr += count;
+ len -= count;
+ }
+
+ if (status > 0) {
+ // Good frame received
+ DBG(4,"count=%d",status);
+ DBG_PACKET(0x400, in->rcvbuf, status);
+ if (!(skb = dev_alloc_skb(status))) {
+ WARN("receive out of memory\n");
+ break;
+ }
+ memcpy(skb_put(skb, status), in->rcvbuf, status);
+ in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb);
+ } else if (status == -HDLC_CRC_ERROR) {
+ INFO("CRC error");
+ } else if (status == -HDLC_FRAMING_ERROR) {
+ INFO("framing error");
+ } else if (status == -HDLC_LENGTH_ERROR) {
+ INFO("length error");
+ }
+ }
+
+ // Prepare URB for next transfer
+ urb->dev = in->adapter->usb_dev;
+ urb->actual_length = 0;
+
+ SUBMIT_URB(urb);
+}
+
+int __devinit st5481_setup_in(struct st5481_in *in)
+{
+ struct usb_device *dev = in->adapter->usb_dev;
+ int retval;
+
+ DBG(4,"");
+
+ in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL);
+ retval = -ENOMEM;
+ if (!in->rcvbuf)
+ goto err;
+
+ retval = st5481_setup_isocpipes(in->urb, dev,
+ usb_rcvisocpipe(dev, in->ep),
+ in->num_packets, in->packet_size,
+ in->num_packets * in->packet_size,
+ usb_in_complete, in);
+ if (retval)
+ goto err_free;
+ return 0;
+
+ err_free:
+ kfree(in->rcvbuf);
+ err:
+ return retval;
+}
+
+void __devexit st5481_release_in(struct st5481_in *in)
+{
+ DBG(2,"");
+
+ st5481_release_isocpipes(in->urb);
+}
+
+/*
+ * Make the transfer_buffer contiguous by
+ * copying from the iso descriptors if necessary.
+ */
+int st5481_isoc_flatten(struct urb *urb)
+{
+ piso_packet_descriptor_t pipd,pend;
+ unsigned char *src,*dst;
+ unsigned int len;
+
+ if (urb->status < 0) {
+ return urb->status;
+ }
+ for (pipd = &urb->iso_frame_desc[0],
+ pend = &urb->iso_frame_desc[urb->number_of_packets],
+ dst = urb->transfer_buffer;
+ pipd < pend;
+ pipd++) {
+
+ if (pipd->status < 0) {
+ return (pipd->status);
+ }
+
+ len = pipd->actual_length;
+ pipd->actual_length = 0;
+ src = urb->transfer_buffer+pipd->offset;
+
+ if (src != dst) {
+ // Need to copy since isoc buffers not full
+ while (len--) {
+ *dst++ = *src++;
+ }
+ } else {
+ // No need to copy, just update destination buffer
+ dst += len;
+ }
+ }
+ // Return size of flattened buffer
+ return (dst - (unsigned char *)urb->transfer_buffer);
+}
+
+static void st5481_start_rcv(void *context)
+{
+ struct st5481_in *in = context;
+ struct st5481_adapter *adapter = in->adapter;
+
+ DBG(4,"");
+
+ in->urb[0]->dev = adapter->usb_dev;
+ SUBMIT_URB(in->urb[0]);
+
+ in->urb[1]->dev = adapter->usb_dev;
+ SUBMIT_URB(in->urb[1]);
+}
+
+void st5481_in_mode(struct st5481_in *in, int mode)
+{
+ if (in->mode == mode)
+ return;
+
+ in->mode = mode;
+
+ usb_unlink_urb(in->urb[0]);
+ usb_unlink_urb(in->urb[1]);
+
+ if (in->mode != L1_MODE_NULL) {
+ if (in->mode != L1_MODE_TRANS)
+ hdlc_rcv_init(&in->hdlc_state,
+ in->mode == L1_MODE_HDLC_56K);
+
+ st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
+ st5481_usb_device_ctrl_msg(in->adapter, in->counter,
+ in->packet_size,
+ NULL, NULL);
+ st5481_start_rcv(in);
+ } else {
+ st5481_usb_device_ctrl_msg(in->adapter, in->counter,
+ 0, NULL, NULL);
+ }
+}
+
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index 5e90a5446a19..e9601e0364cb 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.13 2001/08/13 07:46:15 kai Exp $
+/* $Id: isdn_common.c,v 1.114.6.14 2001/08/17 12:34:25 kai Exp $
* Linux ISDN subsystem, common used functions (linklevel).
*
@@ -51,7 +51,7 @@
isdn_dev *dev;
-static char *isdn_revision = "$Revision: 1.114.6.13 $";
+static char *isdn_revision = "$Revision: 1.114.6.14 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
@@ -792,7 +792,6 @@ isdn_getnum(char **p)
int
isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
{
- int left;
int count;
int count_pull;
int count_put;
@@ -808,10 +807,11 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
else
return 0;
}
- left = MIN(len, dev->drv[di]->rcvcount[channel]);
+ if (len > dev->drv[di]->rcvcount[channel])
+ len = dev->drv[di]->rcvcount[channel];
cp = buf;
count = 0;
- while (left) {
+ while (len) {
if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel])))
break;
#ifdef CONFIG_ISDN_AUDIO
@@ -824,8 +824,8 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
dflag = 0;
count_pull = count_put = 0;
- while ((count_pull < skb->len) && (left > 0)) {
- left--;
+ while ((count_pull < skb->len) && (len > 0)) {
+ len--;
if (dev->drv[di]->DLEflag & DLEmask) {
*cp++ = DLE;
dev->drv[di]->DLEflag &= ~DLEmask;
@@ -846,14 +846,14 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que
#endif
/* No DLE's in buff, so simply copy it */
dflag = 1;
- if ((count_pull = skb->len) > left) {
- count_pull = left;
+ if ((count_pull = skb->len) > len) {
+ count_pull = len;
dflag = 0;
}
count_put = count_pull;
memcpy(cp, skb->data, count_put);
cp += count_put;
- left -= count_put;
+ len -= count_put;
#ifdef CONFIG_ISDN_AUDIO
}
#endif
@@ -1048,12 +1048,15 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
}
interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
}
- if (dev->drv[drvidx]->interface->readstat)
+ if (dev->drv[drvidx]->interface->readstat) {
+ if (count > dev->drv[drvidx]->stavail)
+ count = dev->drv[drvidx]->stavail;
len = dev->drv[drvidx]->interface->
- readstat(buf, MIN(count, dev->drv[drvidx]->stavail),
- 1, drvidx, isdn_minor2chan(minor));
- else
+ readstat(buf, count, 1, drvidx,
+ isdn_minor2chan(minor));
+ } else {
len = 0;
+ }
save_flags(flags);
cli();
if (len)
diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c
index 8fcfdc543dcc..3f77f9c22cca 100644
--- a/drivers/isdn/isdn_net.c
+++ b/drivers/isdn/isdn_net.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.7 2001/07/27 11:15:53 kai Exp $
+/* $Id: isdn_net.c,v 1.140.6.8 2001/08/14 14:04:21 kai Exp $
* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
@@ -190,7 +190,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
-char *isdn_net_revision = "$Revision: 1.140.6.7 $";
+char *isdn_net_revision = "$Revision: 1.140.6.8 $";
/*
* Code for raw-networking over ISDN
@@ -1755,6 +1755,11 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
case CISCO_TYPE_SLARP:
isdn_net_ciscohdlck_slarp_in(lp, skb);
goto out_free;
+ case CISCO_TYPE_CDP:
+ if (lp->cisco_debserint)
+ printk(KERN_DEBUG "%s: Received CDP packet. use "
+ "\"no cdp enable\" on cisco.\n", lp->name);
+ goto out_free;
default:
printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
lp->name, type);
diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h
index 21adcf87be73..7b4a25baeb98 100644
--- a/drivers/isdn/isdn_net.h
+++ b/drivers/isdn/isdn_net.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.h,v 1.19.6.1 2001/04/20 02:41:58 keil Exp $
+/* $Id: isdn_net.h,v 1.19.6.2 2001/08/14 14:04:21 kai Exp $
* header for Linux ISDN subsystem, network related functions (linklevel).
*
@@ -36,6 +36,7 @@
#define CISCO_ADDR_UNICAST 0x0f
#define CISCO_ADDR_BROADCAST 0x8f
#define CISCO_CTRL 0x00
+#define CISCO_TYPE_CDP 0x2000
#define CISCO_TYPE_INET 0x0800
#define CISCO_TYPE_SLARP 0x8035
#define CISCO_SLARP_REPLY 0
diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c
index d0b4baf52e5b..a1e6d1b4180a 100644
--- a/drivers/isdn/isdn_tty.c
+++ b/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94.6.4 2001/07/27 11:15:53 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.7 2001/08/27 22:19:04 kai Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -66,7 +66,7 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.94.6.4 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.7 $";
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -727,9 +727,19 @@ void
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
+ int di, ch;
if (!info)
return;
+
+ di = info->isdn_driver;
+ ch = info->isdn_channel;
+ if (di < 0 || ch < 0)
+ return;
+
+ info->isdn_driver = -1;
+ info->isdn_channel = -1;
+
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
#endif
@@ -770,19 +780,18 @@ isdn_tty_modem_hup(modem_info * info, int local)
isdn_tty_modem_result(RESULT_RUNG, info);
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
info->lsr |= UART_LSR_TEMT;
- if (info->isdn_driver >= 0) {
- if (local) {
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = info->isdn_channel;
- isdn_command(&cmd);
- }
- isdn_all_eaz(info->isdn_driver, info->isdn_channel);
- info->emu.mdmreg[REG_RINGCNT] = 0;
- isdn_free_channel(info->isdn_driver, info->isdn_channel, 0);
+
+ if (local) {
+ cmd.driver = di;
+ cmd.command = ISDN_CMD_HANGUP;
+ cmd.arg = ch;
+ isdn_command(&cmd);
}
- info->isdn_driver = -1;
- info->isdn_channel = -1;
+
+ isdn_all_eaz(di, ch);
+ info->emu.mdmreg[REG_RINGCNT] = 0;
+ isdn_free_channel(di, ch, 0);
+
if (info->drv_index >= 0) {
dev->m_idx[info->drv_index] = -1;
info->drv_index = -1;
@@ -1187,9 +1196,11 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
/* See isdn_tty_senddown() */
atomic_inc(&info->xmit_lock);
while (1) {
- c = MIN(count, info->xmit_size - info->xmit_count);
- if (info->isdn_driver >= 0)
- c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
+ c = count;
+ if (c > info->xmit_size - info->xmit_count)
+ c = info->xmit_size - info->xmit_count;
+ if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
+ c = dev->drv[info->isdn_driver]->maxbufsize;
if (c <= 0)
break;
if ((info->online > 1)
@@ -2709,6 +2720,10 @@ isdn_tty_modem_result(int code, modem_info * info)
if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
+ if (m->mdmreg[REG_CDN] & BIT_CDN) {
+ isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
+ isdn_tty_at_cout(info->emu.cpn, info);
+ }
}
}
isdn_tty_at_cout("\r\n", info);
@@ -2734,6 +2749,10 @@ isdn_tty_modem_result(int code, modem_info * info)
isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout("CALLER NUMBER: ", info);
isdn_tty_at_cout(dev->num[info->drv_index], info);
+ if (m->mdmreg[REG_CDN] & BIT_CDN) {
+ isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
+ isdn_tty_at_cout(info->emu.cpn, info);
+ }
}
break;
case RESULT_NO_CARRIER:
diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h
index 4553cf5687b2..e2ce92c38d18 100644
--- a/drivers/isdn/isdn_tty.h
+++ b/drivers/isdn/isdn_tty.h
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.h,v 1.22 2000/06/21 09:54:29 keil Exp $
+/* $Id: isdn_tty.h,v 1.22.6.1 2001/08/14 14:12:18 kai Exp $
* header for Linux ISDN subsystem, tty related functions (linklevel).
*
@@ -85,7 +85,10 @@
#define REG_CPN 23
#define BIT_CPN 1
+#define REG_CPNFCON 23
#define BIT_CPNFCON 2
+#define REG_CDN 23
+#define BIT_CDN 4
/* defines for result codes */
#define RESULT_OK 0
diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c
index 8899ce5a9a4c..0e6b9a35908f 100644
--- a/drivers/isdn/isdn_ttyfax.c
+++ b/drivers/isdn/isdn_ttyfax.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ttyfax.c,v 1.7 2000/05/11 22:29:21 kai Exp $
+/* $Id: isdn_ttyfax.c,v 1.7.6.1 2001/08/14 14:12:18 kai Exp $
* Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
*
@@ -33,7 +33,7 @@
#include "isdn_ttyfax.h"
-static char *isdn_tty_fax_revision = "$Revision: 1.7 $";
+static char *isdn_tty_fax_revision = "$Revision: 1.7.6.1 $";
#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
@@ -86,7 +86,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
break;
case 2: /* +FCON */
/* Append CPN, if enabled */
- if ((m->mdmreg[REG_CPN] & BIT_CPNFCON) &&
+ if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
(!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
sprintf(rs, "/%s", m->cpn);
isdn_tty_at_cout(rs, info);
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index 5f0f14a76c02..73f4888632f4 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.11.6.4 2001/07/13 09:20:12 kai Exp $
+/* $Id: isdnloop.c,v 1.11.6.5 2001/08/17 12:34:27 kai Exp $
* ISDN low-level module implementing a dummy loop driver.
*
@@ -26,7 +26,7 @@
#include "isdnloop.h"
static char
-*revision = "$Revision: 1.11.6.4 $";
+*revision = "$Revision: 1.11.6.5 $";
static int isdnloop_addcard(char *);
@@ -985,10 +985,12 @@ isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card)
isdn_ctrl cmd;
while (len) {
- int count = MIN(255, len);
+ int count = len;
u_char *p;
u_char msg[0x100];
+ if (count > 255)
+ count = 255;
if (user)
copy_from_user(msg, buf, count);
else
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
index fe8a501104ff..1a59ba57dc87 100644
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.5.6.1 2001/02/10 14:41:23 kai Exp $
+/* $Id: isdnloop.h,v 1.5.6.2 2001/08/17 12:34:27 kai Exp $
* Loopback lowlevel module for testing of linklevel.
*
@@ -128,8 +128,6 @@ MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
/* Utility-Macros */
#define CID (card->interface.id)
-#define MIN(a,b) ((a<b)?a:b)
-#define MAX(a,b) ((a>b)?a:b)
#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
#endif /* isdnloop_h */
diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c
index 7d42369854b9..cb830201c87d 100644
--- a/drivers/md/lvm.c
+++ b/drivers/md/lvm.c
@@ -376,17 +376,13 @@ static int lvm_size[MAX_LV] =
{0,};
static struct gendisk lvm_gendisk =
{
- MAJOR_NR, /* major # */
- LVM_NAME, /* name of major */
- 0, /* number of times minor is shifted
- to get real minor */
- 1, /* maximum partitions per device */
- lvm_hd_struct, /* partition table */
- lvm_size, /* device size in blocks, copied
- to block_size[] */
- MAX_LV, /* number or real devices */
- NULL, /* internal */
- NULL, /* pointer to next gendisk struct (internal) */
+ major: MAJOR_NR,
+ major_name: LVM_NAME,
+ minor_shift: 0,
+ max_p: 1,
+ part: lvm_hd_struct,
+ sizes: lvm_size,
+ nr_real: MAX_LV,
};
/*
diff --git a/drivers/media/video/zr36067.c b/drivers/media/video/zr36067.c
index c8724990abce..1cf403df7fdf 100644
--- a/drivers/media/video/zr36067.c
+++ b/drivers/media/video/zr36067.c
@@ -3734,7 +3734,6 @@ static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd,
zr->window.chromakey = 0;
zr->window.flags = 0; // RJ: Is this intended for interlace on/off ?
zr->window.clips = NULL;
- zr->window.clipcount = vw.clipcount;
/*
* If an overlay is running, we have to switch it off
@@ -3775,7 +3774,8 @@ static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd,
write_overlay_mask(zr, vcp, vw.clipcount);
vfree(vcp);
}
-
+ zr->window.clipcount = vw.clipcount;
+
if (on)
zr36057_overlay(zr, 1);
zr->window_set = 1;
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 8f582fd635f9..ce1bb92fe7b6 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1056,7 +1056,7 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
/* too many inputs? no decoder -> no channels */
- if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
+ if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs || v.channel < 0)
return -EINVAL;
if (v.norm != VIDEO_MODE_PAL &&
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 21b3aa27f5d0..4bec8ae88122 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -1024,11 +1024,6 @@ static struct block_device_operations nftl_fops =
*
****************************************************************************/
-#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
-#define init_nftl init_module
-#define cleanup_nftl cleanup_module
-#endif
-
static struct mtd_notifier nftl_notifier = {
add: NFTL_notify_add,
remove: NFTL_notify_remove
@@ -1045,14 +1040,12 @@ static int __init init_nftl(void)
#endif
if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
- printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
+ printk("unable to register NFTL block device on major %d\n",
+ MAJOR_NR);
return -EBUSY;
} else {
-#if LINUX_VERSION_CODE < 0x20320
- blk_dev[MAJOR_NR].request_fn = nftl_request;
-#else
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
-#endif
+
/* set block size to 1kB each */
for (i = 0; i < 256; i++) {
nftl_blocksizes[i] = 1024;
@@ -1069,20 +1062,12 @@ static int __init init_nftl(void)
static void __exit cleanup_nftl(void)
{
- struct gendisk *gd, **gdp;
-
unregister_mtd_user(&nftl_notifier);
unregister_blkdev(MAJOR_NR, "nftl");
-#if LINUX_VERSION_CODE < 0x20320
- blk_dev[MAJOR_NR].request_fn = 0;
-#else
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-#endif
- /* remove ourself from generic harddisk list
- FIXME: why can't I found this partition on /proc/partition */
- del_gendisk(&nftl_gendisk);:
+ del_gendisk(&nftl_gendisk);
}
module_init(init_nftl);
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index a82d4dcb0f71..e2586618b919 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -1013,6 +1013,8 @@ static struct net_device_stats *cops_get_stats(struct net_device *dev)
#ifdef MODULE
static struct net_device cops0_dev = { init: cops_probe };
+
+MODULE_LICENSE("GPL");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
MODULE_PARM(board_type, "i");
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index acd15efa937e..c5a994577f3d 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -283,6 +283,7 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static struct net_device dev_ipddp;
+MODULE_LICENSE("GPL");
MODULE_PARM(ipddp_mode, "i");
static int __init ipddp_init_module(void)
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6c5560fe6f24..579c3b3cd6ec 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1255,6 +1255,8 @@ __setup("ltpc=", ltpc_setup);
static struct net_device dev_ltpc;
#ifdef MODULE
+
+MODULE_LICENSE("GPL");
MODULE_PARM(debug, "i");
MODULE_PARM(io, "i");
MODULE_PARM(irq, "i");
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 3ebf32ab1771..168b9dd1543f 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -39,7 +39,7 @@
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 0d2ad55b5509..42969a787451 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1111,7 +1111,7 @@ net_open(struct net_device *dev)
(unsigned long)lp->dma_buff,
(unsigned long)virt_to_bus(lp->dma_buff));
}
- if ((unsigned long)virt_to_bus(lp->dma_buff) >= MAX_DMA_ADDRESS ||
+ if ((unsigned long) lp->dma_buff >= MAX_DMA_ADDRESS ||
!dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) {
printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name);
goto release_irq;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 7a86e003c5c1..173e42b4af39 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -1006,7 +1006,7 @@ static void lance_set_multicast_retry(unsigned long _opaque)
lance_set_multicast(dev);
}
-static int __init dec_lance_init(const int type)
+static int __init dec_lance_init(struct net_device *dev, const int type)
{
static unsigned version_printed;
struct net_device *dev;
@@ -1015,7 +1015,6 @@ static int __init dec_lance_init(const int type)
int i, ret;
unsigned long esar_base;
unsigned char *esar;
- struct net_device *dev;
#ifndef CONFIG_TC
system_base = KN01_LANCE_BASE;
@@ -1026,12 +1025,12 @@ static int __init dec_lance_init(const int type)
if (dec_lance_debug && version_printed++ == 0)
printk(version);
- dev = init_etherdev(NULL, sizeof(struct lance_private));
+ dev = init_etherdev(0, sizeof(struct lance_private));
if (!dev)
return -ENOMEM;
/* init_etherdev ensures the data structures used by the LANCE are aligned. */
- lp = dev->priv;
+ lp = (struct lance_private *) dev->priv;
spin_lock_init(&lp->lock);
switch (type) {
@@ -1217,6 +1216,7 @@ err_out:
/* Find all the lance cards on the system and initialize them */
static int __init dec_lance_probe(void)
{
+ struct net_device *dev = NULL;
static int called;
#ifdef MODULE
@@ -1255,7 +1255,7 @@ static int __init dec_lance_probe(void)
}
#endif
- return dec_lance_init(type);
+ return dec_lance_init(dev, type);
}
static void __exit dec_lance_cleanup(void)
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index 542f526a004d..7a6f1385cfe8 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -1292,6 +1292,7 @@ dgrs_found_device(
if (!devN)
goto fail;
memcpy(devN, dev, dev_size);
+ memset(devN->name, 0, sizeof(devN->name));
devN->priv = ((void *)devN) + sizeof(struct net_device);
privN = (DGRS_PRIV *)devN->priv;
/* ... and zero out VM areas */
diff --git a/drivers/net/dmfe.c b/drivers/net/dmfe.c
index 89a2871d38a7..16e1d97b403d 100644
--- a/drivers/net/dmfe.c
+++ b/drivers/net/dmfe.c
@@ -61,7 +61,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
index 948a318e71b8..38f448bf3ea8 100644
--- a/drivers/net/gt96100eth.c
+++ b/drivers/net/gt96100eth.c
@@ -1,7 +1,7 @@
/*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
- * stevel@mvista.com or support@mvista.com
+ * stevel@mvista.com or source@mvista.com
*
* ########################################################################
*
@@ -29,7 +29,6 @@
#endif
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -38,7 +37,7 @@
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
index 2664aa14cdab..dfbc4b13f880 100644
--- a/drivers/net/gt96100eth.h
+++ b/drivers/net/gt96100eth.h
@@ -1,7 +1,7 @@
/*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
- * stevel@mvista.com or support@mvista.com
+ * stevel@mvista.com or source@mvista.com
*
* ########################################################################
*
@@ -27,7 +27,6 @@
#ifndef _GT96100ETH_H
#define _GT96100ETH_H
-#include <linux/config.h>
#include <asm/galileo-boards/gt96100.h>
/* Keep the ring sizes a power of two for efficiency. */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 3b52d93592a2..8036cc4a387e 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -44,7 +44,6 @@
#include <net/irda/irda-usb.h>
-static u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
static int qos_mtt_bits = 0;
static void irda_usb_dump_class_desc(struct irda_class_desc *desc);
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
index 467f51ff63ab..51d0f8d24d60 100644
--- a/drivers/net/irda/toshoboe.c
+++ b/drivers/net/irda/toshoboe.c
@@ -695,7 +695,6 @@ toshoboe_probe (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
{
struct toshoboe_cb *self;
struct net_device *dev;
- struct pm_dev *pmdev;
int i = 0;
int ok = 0;
int err;
@@ -845,11 +844,6 @@ toshoboe_probe (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
}
pci_set_drvdata(pci_dev,self);
-/* pmdev = pm_register (PM_PCI_DEV, PM_PCI_ID(pci_dev), toshoboe_pmproc);
- if (pmdev)
- pmdev->data = self;
- */
-
printk (KERN_WARNING "ToshOboe: Using ");
#ifdef ONETASK
printk ("single");
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 1939f61b3567..3489ffcc82e2 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -47,11 +47,12 @@
/*
* Macros to access SONIC registers
*/
-#define SONIC_READ(reg) \
- *((volatile unsigned int *)base_addr+reg)
+#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg))
-#define SONIC_WRITE(reg,val) \
- *((volatile unsigned int *)base_addr+reg) = val
+#define SONIC_WRITE(reg,val) \
+do { \
+ *((volatile unsigned int *)base_addr+reg) = val; \
+}
/* use 0 for production, 1 for verification, >2 for debug */
@@ -65,8 +66,8 @@ static unsigned int sonic_debug = 1;
* Base address and interrupt of the SONIC controller on JAZZ boards
*/
static struct {
- unsigned int port;
- unsigned int irq;
+ unsigned int port;
+ unsigned int irq;
} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
/*
@@ -76,14 +77,15 @@ static struct {
*/
static unsigned short known_revisions[] =
{
- 0x04, /* Mips Magnum 4000 */
- 0xffff /* end of list */
+ 0x04, /* Mips Magnum 4000 */
+ 0xffff /* end of list */
};
/* Index to functions, as function prototypes. */
extern int sonic_probe(struct net_device *dev);
-static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned int irq);
+static int sonic_probe1(struct net_device *dev, unsigned int base_addr,
+ unsigned int irq);
/*
@@ -92,164 +94,170 @@ static int sonic_probe1(struct net_device *dev, unsigned int base_addr, unsigned
*/
int __init sonic_probe(struct net_device *dev)
{
- unsigned int base_addr = dev ? dev->base_addr : 0;
- int i;
+ unsigned int base_addr = dev ? dev->base_addr : 0;
+ int i;
+
+ /*
+ * Don't probe if we're not running on a Jazz board.
+ */
+ if (mips_machgroup != MACH_GROUP_JAZZ)
+ return -ENODEV;
+ if (base_addr >= KSEG0) /* Check a single specified location. */
+ return sonic_probe1(dev, base_addr, dev->irq);
+ else if (base_addr != 0) /* Don't probe at all. */
+ return -ENXIO;
- /*
- * Don't probe if we're not running on a Jazz board.
- */
- if (mips_machgroup != MACH_GROUP_JAZZ)
+ for (i = 0; sonic_portlist[i].port; i++) {
+ int base_addr = sonic_portlist[i].port;
+ if (check_region(base_addr, 0x100))
+ continue;
+ if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
+ return 0;
+ }
return -ENODEV;
- if (base_addr >= KSEG0) /* Check a single specified location. */
- return sonic_probe1(dev, base_addr, dev->irq);
- else if (base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
-
- for (i = 0; sonic_portlist[i].port; i++) {
- int base_addr = sonic_portlist[i].port;
- if (check_region(base_addr, 0x100))
- continue;
- if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
- return 0;
- }
- return -ENODEV;
}
-static int __init sonic_probe1(struct net_device *dev,
- unsigned int base_addr, unsigned int irq)
+static int __init sonic_probe1(struct net_device *dev, unsigned int base_addr,
+ unsigned int irq)
{
- static unsigned version_printed;
- unsigned int silicon_revision;
- unsigned int val;
- struct sonic_local *lp;
- int i;
-
- /*
- * get the Silicon Revision ID. If this is one of the known
- * one assume that we found a SONIC ethernet controller at
- * the expected location.
- */
- silicon_revision = SONIC_READ(SONIC_SR);
- if (sonic_debug > 1)
- printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
-
- i = 0;
- while ((known_revisions[i] != 0xffff) &&
- (known_revisions[i] != silicon_revision))
- i++;
-
- if (known_revisions[i] == 0xffff) {
- printk("SONIC ethernet controller not found (0x%4x)\n",
- silicon_revision);
- return -ENODEV;
- }
-
- if (!request_region(base_addr, 0x100, dev->name))
- return -EBUSY;
-
- if (sonic_debug && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s found at 0x%08x, ",
- dev->name, "SONIC ethernet", base_addr);
-
- /* Fill in the 'dev' fields. */
- dev->base_addr = base_addr;
- dev->irq = irq;
-
- /*
- * Put the sonic into software reset, then
- * retrieve and print the ethernet address.
- */
- SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
- SONIC_WRITE(SONIC_CEP,0);
- for (i=0; i<3; i++) {
- val = SONIC_READ(SONIC_CAP0-i);
- dev->dev_addr[i*2] = val;
- dev->dev_addr[i*2+1] = val >> 8;
- }
-
- printk("HW Address ");
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i<5)
- printk(":");
- }
-
- printk(" IRQ %d\n", irq);
-
- /* Initialize the device structure. */
- if (dev->priv == NULL) {
+ static unsigned version_printed;
+ unsigned int silicon_revision;
+ unsigned int val;
+ struct sonic_local *lp;
+ int i;
+
/*
- * the memory be located in the same 64kb segment
+ * get the Silicon Revision ID. If this is one of the known
+ * one assume that we found a SONIC ethernet controller at
+ * the expected location.
*/
- lp = NULL;
+ silicon_revision = SONIC_READ(SONIC_SR);
+ if (sonic_debug > 1)
+ printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
+
i = 0;
- do {
- lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
- if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
- /* FIXME, free the memory later */
- kfree (lp);
- lp = NULL;
- }
- } while (lp == NULL && i++ < 20);
-
- if (lp == NULL) {
- printk ("%s: couldn't allocate memory for descriptors\n",
- dev->name);
- return -ENOMEM;
+ while (known_revisions[i] != 0xffff
+ && known_revisions[i] != silicon_revision)
+ i++;
+
+ if (known_revisions[i] == 0xffff) {
+ printk("SONIC ethernet controller not found (0x%4x)\n",
+ silicon_revision);
+ return -ENODEV;
}
-
- memset(lp, 0, sizeof(struct sonic_local));
-
- /* get the virtual dma address */
- lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
- if (lp->cda_laddr == ~0UL) {
- printk ("%s: couldn't get DMA page entry for descriptors\n",
- dev->name);
- return -ENOMEM;
+
+ if (!request_region(base_addr, 0x100, dev->name))
+ return -EBUSY;
+
+ if (sonic_debug && version_printed++ == 0)
+ printk(version);
+
+ printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr);
+
+ /* Fill in the 'dev' fields. */
+ dev->base_addr = base_addr;
+ dev->irq = irq;
+
+ /*
+ * Put the sonic into software reset, then
+ * retrieve and print the ethernet address.
+ */
+ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+ SONIC_WRITE(SONIC_CEP,0);
+ for (i=0; i<3; i++) {
+ val = SONIC_READ(SONIC_CAP0-i);
+ dev->dev_addr[i*2] = val;
+ dev->dev_addr[i*2+1] = val >> 8;
}
- lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
- lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
- lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-
- /* allocate receive buffer area */
- /* FIXME, maybe we should use skbs */
- if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
- printk ("%s: couldn't allocate receive buffers\n",dev->name);
- return -ENOMEM;
+ printk("HW Address ");
+ for (i = 0; i < 6; i++) {
+ printk("%2.2x", dev->dev_addr[i]);
+ if (i<5)
+ printk(":");
}
+
+ printk(" IRQ %d\n", irq);
+
+ /* Initialize the device structure. */
+ if (dev->priv == NULL) {
+ /*
+ * the memory be located in the same 64kb segment
+ */
+ lp = NULL;
+ i = 0;
+ do {
+ lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+ if ((unsigned long) lp >> 16
+ != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
+ /* FIXME, free the memory later */
+ kfree(lp);
+ lp = NULL;
+ }
+ } while (lp == NULL && i++ < 20);
+
+ if (lp == NULL) {
+ printk("%s: couldn't allocate memory for descriptors\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ memset(lp, 0, sizeof(struct sonic_local));
+
+ /* get the virtual dma address */
+ lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
+ if (lp->cda_laddr == ~0UL) {
+ printk("%s: couldn't get DMA page entry for "
+ "descriptors\n", dev->name);
+ return -ENOMEM;
+ }
+
+ lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
+ lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
+ lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
- /* get virtual dma address */
- if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) {
- printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name);
- return -ENOMEM;
+ /* allocate receive buffer area */
+ /* FIXME, maybe we should use skbs */
+ lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL);
+ if (!lp->rba) {
+ printk("%s: couldn't allocate receive buffers\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ /* get virtual dma address */
+ lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),
+ SONIC_NUM_RRS * SONIC_RBSIZE);
+ if (lp->rba_laddr == ~0UL) {
+ printk("%s: couldn't get DMA page entry for receive "
+ "buffers\n",dev->name);
+ return -ENOMEM;
+ }
+
+ /* now convert pointer to KSEG1 pointer */
+ lp->rba = (char *)KSEG1ADDR(lp->rba);
+ flush_cache_all();
+ dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
}
-
- /* now convert pointer to KSEG1 pointer */
- lp->rba = (char *)KSEG1ADDR(lp->rba);
- flush_cache_all();
- dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
- }
-
- lp = (struct sonic_local *)dev->priv;
- dev->open = sonic_open;
- dev->stop = sonic_close;
- dev->hard_start_xmit = sonic_send_packet;
- dev->get_stats = sonic_get_stats;
- dev->set_multicast_list = &sonic_multicast_list;
-
- /*
- * clear tally counter
- */
- SONIC_WRITE(SONIC_CRCT,0xffff);
- SONIC_WRITE(SONIC_FAET,0xffff);
- SONIC_WRITE(SONIC_MPT,0xffff);
-
- /* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
- return 0;
+
+ lp = (struct sonic_local *)dev->priv;
+ dev->open = sonic_open;
+ dev->stop = sonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /*
+ * clear tally counter
+ */
+ SONIC_WRITE(SONIC_CRCT,0xffff);
+ SONIC_WRITE(SONIC_FAET,0xffff);
+ SONIC_WRITE(SONIC_MPT,0xffff);
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+ return 0;
}
/*
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index ccb9748cc463..0255fbeaf4ac 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -7,7 +7,7 @@
Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the Director,
National Security Agency. This software may only be used and
- distributed according to the terms of the GNU Public License
+ distributed according to the terms of the GNU General Public License
as modified by SRC, incorporated herein by reference.
The author may be reached as becker@scyld.com, or C/O
@@ -67,7 +67,7 @@ All other communication is through memory!
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
new file mode 100644
index 000000000000..2eb810c808d7
--- /dev/null
+++ b/drivers/net/ns83820.c
@@ -0,0 +1,1429 @@
+#define VERSION "0.11"
+/* ns83820.c by Benjamin LaHaise <bcrl@redhat.com>
+ *
+ * $Revision: 1.34.2.2 $
+ *
+ * Copyright 2001 Benjamin LaHaise.
+ * Copyright 2001 Red Hat.
+ *
+ * Mmmm, chocolate vanilla mocha...
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * ChangeLog
+ * =========
+ * 20010414 0.1 - created
+ * 20010622 0.2 - basic rx and tx.
+ * 20010711 0.3 - added duplex and link state detection support.
+ * 20010713 0.4 - zero copy, no hangs.
+ * 0.5 - 64 bit dma support (davem will hate me for this)
+ * - disable jumbo frames to avoid tx hangs
+ * - work around tx deadlocks on my 1.02 card via
+ * fiddling with TXCFG
+ * 20010810 0.6 - use pci dma api for ringbuffers, work on ia64
+ * 20010816 0.7 - misc cleanups
+ * 20010826 0.8 - fix critical zero copy bugs
+ * 0.9 - internal experiment
+ * 20010827 0.10 - fix ia64 unaligned access.
+ * 20010906 0.11 - accept all packets with checksum errors as
+ * otherwise fragments get lost
+ - fix >> 32 bugs
+ *
+ * Driver Overview
+ * ===============
+ *
+ * This driver was originally written for the National Semiconductor
+ * 83820 chip, a 10/100/1000 Mbps 64 bit PCI ethernet NIC. Hopefully
+ * this code will turn out to be a) clean, b) correct, and c) fast.
+ * With that in mind, I'm aiming to split the code up as much as
+ * reasonably possible. At present there are X major sections that
+ * break down into a) packet receive, b) packet transmit, c) link
+ * management, d) initialization and configuration. Where possible,
+ * these code paths are designed to run in parallel.
+ *
+ * This driver has been tested and found to work with the following
+ * cards (in no particular order):
+ *
+ * Cameo SOHO-GA2000T SOHO-GA2500T
+ * D-Link DGE-500T
+ * PureData PDP8023Z-TG
+ * SMC SMC9462TX
+ *
+ * Reports of success or failure would be greatly appreciated.
+ */
+//#define dprintk printk
+#define dprintk(x...) do { } while (0)
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/tqueue.h>
+#include <linux/init.h>
+#include <linux/ip.h> /* for iph */
+#include <linux/in.h> /* for IPPROTO_... */
+#include <linux/eeprom.h>
+//#include <linux/skbrefill.h>
+
+/* Dprintk is used for more interesting debug events */
+#undef Dprintk
+#define Dprintk dprintk
+
+#if !defined(GCC_VERSION) || (GCC_VERSION < 2096)
+#define __builtin_expect(x,y) (x)
+#endif
+
+#ifdef CONFIG_HIGHMEM64G
+#define USE_64BIT_ADDR
+#elif defined(__ia64__)
+#define USE_64BIT_ADDR
+#endif
+
+/* Tell davem to fix the pci dma api. Grrr. */
+/* stolen from acenic.c */
+#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_X86)
+#define DMAADDR_OFFSET 0
+#if defined(CONFIG_HIGHMEM64G)
+typedef u64 dmaaddr_high_t;
+#else
+typedef u32 dmaaddr_high_t;
+#endif
+#elif defined(CONFIG_PPC)
+#define DMAADDR_OFFSET PCI_DRAM_OFFSET
+typedef unsigned long dmaaddr_high_t;
+#endif
+
+static inline dmaaddr_high_t
+pci_map_single_high(struct pci_dev *hwdev, struct page *page,
+ int offset, size_t size, int dir)
+{
+ u64 phys;
+ phys = page - mem_map;
+ phys <<= PAGE_SHIFT;
+ phys += offset;
+ phys += DMAADDR_OFFSET;
+ return phys;
+}
+#else
+
+typedef unsigned long dmaaddr_high_t;
+
+static inline dmaaddr_high_t
+pci_map_single_high(struct pci_dev *hwdev, struct page *page,
+ int offset, size_t size, int dir)
+{
+ return pci_map_single(hwdev, page_address(page) + offset, size, dir);
+}
+#endif
+
+/* tunables */
+#define RX_BUF_SIZE 6144 /* 8192 */
+#define NR_RX_DESC 256
+
+#define NR_TX_DESC 256
+
+/* register defines */
+#define CFGCS 0x04
+
+#define CR_TXE 0x00000001
+#define CR_TXD 0x00000002
+#define CR_RXE 0x00000004
+#define CR_RXD 0x00000008
+#define CR_TXR 0x00000010
+#define CR_RXR 0x00000020
+#define CR_SWI 0x00000080
+#define CR_RST 0x00000100
+
+#define PTSCR_EEBIST_EN 0x00000002
+#define PTSCR_EELOAD_EN 0x00000004
+
+#define ISR_TXDESC3 0x40000000
+#define ISR_TXDESC2 0x20000000
+#define ISR_TXDESC1 0x10000000
+#define ISR_TXDESC0 0x08000000
+#define ISR_RXDESC3 0x04000000
+#define ISR_RXDESC2 0x02000000
+#define ISR_RXDESC1 0x01000000
+#define ISR_RXDESC0 0x00800000
+#define ISR_TXRCMP 0x00400000
+#define ISR_RXRCMP 0x00200000
+#define ISR_DPERR 0x00100000
+#define ISR_SSERR 0x00080000
+#define ISR_RMABT 0x00040000
+#define ISR_RTABT 0x00020000
+#define ISR_RXSOVR 0x00010000
+#define ISR_HIBINT 0x00008000
+#define ISR_PHY 0x00004000
+#define ISR_PME 0x00002000
+#define ISR_SWI 0x00001000
+#define ISR_MIB 0x00000800
+#define ISR_TXURN 0x00000400
+#define ISR_TXIDLE 0x00000200
+#define ISR_TXERR 0x00000100
+#define ISR_TXDESC 0x00000080
+#define ISR_TXOK 0x00000040
+#define ISR_RXORN 0x00000020
+#define ISR_RXIDLE 0x00000010
+#define ISR_RXEARLY 0x00000008
+#define ISR_RXERR 0x00000004
+#define ISR_RXDESC 0x00000002
+#define ISR_RXOK 0x00000001
+
+#define TXCFG_CSI 0x80000000
+#define TXCFG_HBI 0x40000000
+#define TXCFG_MLB 0x20000000
+#define TXCFG_ATP 0x10000000
+#define TXCFG_ECRETRY 0x00800000
+#define TXCFG_BRST_DIS 0x00080000
+#define TXCFG_MXDMA1024 0x00000000
+#define TXCFG_MXDMA512 0x00700000
+#define TXCFG_MXDMA256 0x00600000
+#define TXCFG_MXDMA128 0x00500000
+#define TXCFG_MXDMA64 0x00400000
+#define TXCFG_MXDMA32 0x00300000
+#define TXCFG_MXDMA16 0x00200000
+#define TXCFG_MXDMA8 0x00100000
+
+#define CFG_LNKSTS 0x80000000
+#define CFG_SPDSTS 0x60000000
+#define CFG_SPDSTS1 0x40000000
+#define CFG_SPDSTS0 0x20000000
+#define CFG_DUPSTS 0x10000000
+#define CFG_TBI_EN 0x01000000
+#define CFG_MODE_1000 0x00400000
+#define CFG_PINT_CTL 0x001c0000
+#define CFG_PINT_DUPSTS 0x00100000
+#define CFG_PINT_LNKSTS 0x00080000
+#define CFG_PINT_SPDSTS 0x00040000
+#define CFG_TMRTEST 0x00020000
+#define CFG_MRM_DIS 0x00010000
+#define CFG_MWI_DIS 0x00008000
+#define CFG_T64ADDR 0x00004000
+#define CFG_PCI64_DET 0x00002000
+#define CFG_DATA64_EN 0x00001000
+#define CFG_M64ADDR 0x00000800
+#define CFG_PHY_RST 0x00000400
+#define CFG_PHY_DIS 0x00000200
+#define CFG_EXTSTS_EN 0x00000100
+#define CFG_REQALG 0x00000080
+#define CFG_SB 0x00000040
+#define CFG_POW 0x00000020
+#define CFG_EXD 0x00000010
+#define CFG_PESEL 0x00000008
+#define CFG_BROM_DIS 0x00000004
+#define CFG_EXT_125 0x00000002
+#define CFG_BEM 0x00000001
+
+#define EXTSTS_UDPPKT 0x00200000
+#define EXTSTS_TCPPKT 0x00080000
+#define EXTSTS_IPPKT 0x00020000
+
+#define SPDSTS_POLARITY (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS)
+
+#define MIBC_MIBS 0x00000008
+#define MIBC_ACLR 0x00000004
+#define MIBC_FRZ 0x00000002
+#define MIBC_WRN 0x00000001
+
+#define RXCFG_AEP 0x80000000
+#define RXCFG_ARP 0x40000000
+#define RXCFG_STRIPCRC 0x20000000
+#define RXCFG_RX_FD 0x10000000
+#define RXCFG_ALP 0x08000000
+#define RXCFG_AIRL 0x04000000
+#define RXCFG_MXDMA 0x00700000
+#define RXCFG_MXDMA0 0x00100000
+#define RXCFG_MXDMA64 0x00600000
+#define RXCFG_DRTH 0x0000003e
+#define RXCFG_DRTH0 0x00000002
+
+#define RFCR_RFEN 0x80000000
+#define RFCR_AAB 0x40000000
+#define RFCR_AAM 0x20000000
+#define RFCR_AAU 0x10000000
+#define RFCR_APM 0x08000000
+#define RFCR_APAT 0x07800000
+#define RFCR_APAT3 0x04000000
+#define RFCR_APAT2 0x02000000
+#define RFCR_APAT1 0x01000000
+#define RFCR_APAT0 0x00800000
+#define RFCR_AARP 0x00400000
+#define RFCR_MHEN 0x00200000
+#define RFCR_UHEN 0x00100000
+#define RFCR_ULM 0x00080000
+
+#define VRCR_RUDPE 0x00000080
+#define VRCR_RTCPE 0x00000040
+#define VRCR_RIPE 0x00000020
+#define VRCR_IPEN 0x00000010
+#define VRCR_DUTF 0x00000008
+#define VRCR_DVTF 0x00000004
+#define VRCR_VTREN 0x00000002
+#define VRCR_VTDEN 0x00000001
+
+#define VTCR_PPCHK 0x00000008
+#define VTCR_GCHK 0x00000004
+#define VTCR_VPPTI 0x00000002
+#define VTCR_VGTI 0x00000001
+
+#define CR 0x00
+#define CFG 0x04
+#define MEAR 0x08
+#define PTSCR 0x0c
+#define ISR 0x10
+#define IMR 0x14
+#define IER 0x18
+#define IHR 0x1c
+#define TXDP 0x20
+#define TXDP_HI 0x24
+#define TXCFG 0x28
+#define GPIOR 0x2c
+#define RXDP 0x30
+#define RXDP_HI 0x34
+#define RXCFG 0x38
+#define PQCR 0x3c
+#define WCSR 0x40
+#define PCR 0x44
+#define RFCR 0x48
+#define RFDR 0x4c
+
+#define SRR 0x58
+
+#define VRCR 0xbc
+#define VTCR 0xc0
+#define VDR 0xc4
+#define CCSR 0xcc
+
+#define __kick_rx(dev) writel(CR_RXE, dev->base + CR)
+
+#define kick_rx(dev) do { \
+ dprintk("kick_rx: maybe kicking\n"); \
+ if (test_and_clear_bit(0, &dev->rx_info.idle)) { \
+ dprintk("actually kicking\n"); \
+ writel(dev->rx_info.phy_descs + (4 * DESC_SIZE * dev->rx_info.next_rx), dev->base + RXDP); \
+ if (dev->rx_info.next_rx == dev->rx_info.next_empty) \
+ printk(KERN_DEBUG "%s: uh-oh: next_rx == next_empty???\n", dev->net_dev.name);\
+ __kick_rx(dev); \
+ } \
+} while(0)
+
+#ifdef USE_64BIT_ADDR
+typedef u64 hw_addr_t;
+#else
+typedef u32 hw_addr_t;
+#endif
+
+#define HW_ADDR_LEN (sizeof(hw_addr_t))
+
+#define LINK 0
+#define BUFPTR (LINK + HW_ADDR_LEN/4)
+#define CMDSTS (BUFPTR + HW_ADDR_LEN/4)
+#define EXTSTS (CMDSTS + 4/4)
+#define DRV_NEXT (EXTSTS + 4/4)
+
+#define CMDSTS_OWN 0x80000000
+#define CMDSTS_MORE 0x40000000
+#define CMDSTS_INTR 0x20000000
+#define CMDSTS_ERR 0x10000000
+#define CMDSTS_OK 0x08000000
+
+#define CMDSTS_DEST_MASK 0x01800000
+#define CMDSTS_DEST_SELF 0x00800000
+#define CMDSTS_DEST_MULTI 0x01000000
+
+#define DESC_SIZE 8 /* Should be cache line sized */
+
+struct rx_info {
+ spinlock_t lock;
+ int up;
+ long idle;
+
+ struct sk_buff *skbs[NR_RX_DESC];
+
+ unsigned next_rx, next_empty;
+
+ u32 *descs;
+ dma_addr_t phy_descs;
+};
+
+
+struct ns83820 {
+ struct net_device net_dev;
+ u8 *base;
+
+ struct pci_dev *pci_dev;
+ struct ns83820 *next_dev;
+
+ struct rx_info rx_info;
+
+ unsigned ihr;
+ struct tq_struct tq_refill;
+
+ /* protects everything below. irqsave when using. */
+ spinlock_t misc_lock;
+
+ u32 CFG_cache;
+
+ u32 MEAR_cache;
+ u32 IMR_cache;
+ struct eeprom ee;
+
+
+ spinlock_t tx_lock;
+
+ long tx_idle;
+ u32 tx_done_idx;
+ u32 tx_idx;
+ volatile u32 tx_free_idx; /* idx of free desc chain */
+ u32 tx_intr_idx;
+
+ struct sk_buff *tx_skbs[NR_TX_DESC];
+
+ char pad[16] __attribute__((aligned(16)));
+ u32 *tx_descs;
+ dma_addr_t tx_phy_descs;
+};
+
+//free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC
+#define start_tx_okay(dev) \
+ (((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > NR_TX_DESC/2)
+
+static struct ns83820 *ns83820_chain;
+
+
+/* Packet Receiver
+ *
+ * The hardware supports linked lists of receive descriptors for
+ * which ownership is transfered back and forth by means of an
+ * ownership bit. While the hardware does support the use of a
+ * ring for receive descriptors, we only make use of a chain in
+ * an attempt to reduce bus traffic under heavy load scenarios.
+ * This will also make bugs a bit more obvious. The current code
+ * only makes use of a single rx chain; I hope to implement
+ * priority based rx for version 1.0. Goal: even under overload
+ * conditions, still route realtime traffic with as low jitter as
+ * possible.
+ */
+#ifdef USE_64BIT_ADDR
+static inline void build_rx_desc64(struct ns83820 *dev, u32 *desc, u64 link, u64 buf, u32 cmdsts, u32 extsts)
+{
+ desc[0] = link;
+ desc[1] = link >> 32;
+ desc[2] = buf;
+ desc[3] = buf >> 32;
+ desc[5] = extsts;
+ mb();
+ desc[4] = cmdsts;
+}
+
+#define build_rx_desc build_rx_desc64
+#else
+
+static inline void build_rx_desc32(struct ns83820 *dev, u32 *desc, u32 link, u32 buf, u32 cmdsts, u32 extsts)
+{
+ desc[0] = link;
+ desc[1] = buf;
+ desc[3] = extsts;
+ mb();
+ desc[2] = cmdsts;
+}
+
+#define build_rx_desc build_rx_desc32
+#endif
+
+#define nr_rx_empty(dev) ((NR_RX_DESC-2 + dev->rx_info.next_rx - dev->rx_info.next_empty) % NR_RX_DESC)
+static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
+{
+ unsigned next_empty;
+ u32 cmdsts;
+ u32 *sg;
+ hw_addr_t buf;
+
+ next_empty = dev->rx_info.next_empty;
+
+ /* don't overrun last rx marker */
+ if (nr_rx_empty(dev) <= 2) {
+ kfree_skb(skb);
+ return 1;
+ }
+
+#if 0
+ dprintk("next_empty[%d] nr_used[%d] next_rx[%d]\n",
+ dev->rx_info.next_empty,
+ dev->rx_info.nr_used,
+ dev->rx_info.next_rx
+ );
+#endif
+
+ sg = dev->rx_info.descs + (next_empty * DESC_SIZE);
+ if (dev->rx_info.skbs[next_empty])
+ BUG();
+ dev->rx_info.skbs[next_empty] = skb;
+
+ dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC;
+ cmdsts = RX_BUF_SIZE | CMDSTS_INTR;
+ buf = pci_map_single(dev->pci_dev, skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
+ /* update link of previous rx */
+ if (next_empty != dev->rx_info.next_rx)
+ dev->rx_info.descs[((NR_RX_DESC + next_empty - 1) % NR_RX_DESC) * DESC_SIZE] = dev->rx_info.phy_descs + (next_empty * DESC_SIZE * 4);
+
+ return 0;
+}
+
+static int rx_refill(struct ns83820 *dev, int gfp)
+{
+ unsigned i;
+ long flags = 0;
+
+ dprintk("rx_refill(%p)\n", dev);
+ if (gfp == GFP_ATOMIC)
+ spin_lock_irqsave(&dev->rx_info.lock, flags);
+ for (i=0; i<NR_RX_DESC; i++) {
+ struct sk_buff *skb;
+ long res;
+ skb = __dev_alloc_skb(RX_BUF_SIZE+16, gfp);
+ if (!skb)
+ break;
+
+ res = (long)skb->tail & 0xf;
+ res = 0x10 - res;
+ res &= 0xf;
+ skb_reserve(skb, res);
+
+ skb->dev = &dev->net_dev;
+ if (gfp != GFP_ATOMIC)
+ spin_lock_irqsave(&dev->rx_info.lock, flags);
+ res = ns83820_add_rx_skb(dev, skb);
+ if (gfp != GFP_ATOMIC)
+ spin_unlock_irqrestore(&dev->rx_info.lock, flags);
+ if (res) {
+ i = 1;
+ break;
+ }
+ }
+ if (gfp == GFP_ATOMIC)
+ spin_unlock_irqrestore(&dev->rx_info.lock, flags);
+
+ return i ? 0 : -ENOMEM;
+}
+
+/* REFILL */
+static inline void queue_refill(void *_dev)
+{
+ struct ns83820 *dev = _dev;
+
+ rx_refill(dev, GFP_KERNEL);
+ if (dev->rx_info.up)
+ kick_rx(dev);
+}
+
+static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
+{
+ build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0);
+}
+
+static void phy_intr(struct ns83820 *dev)
+{
+ static char *speeds[] = { "10", "100", "1000", "1000(?)" };
+ u32 cfg, new_cfg;
+
+ new_cfg = dev->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+
+ if (cfg & CFG_SPDSTS1)
+ new_cfg |= CFG_MODE_1000 | CFG_SB;
+ else
+ new_cfg &= ~CFG_MODE_1000 | CFG_SB;
+
+ if ((cfg & CFG_LNKSTS) && ((new_cfg ^ dev->CFG_cache) & CFG_MODE_1000)) {
+ writel(new_cfg, dev->base + CFG);
+ dev->CFG_cache = new_cfg;
+ }
+
+ dev->CFG_cache &= ~CFG_SPDSTS;
+ dev->CFG_cache |= cfg & CFG_SPDSTS;
+
+ if (cfg & CFG_LNKSTS) {
+ netif_start_queue(&dev->net_dev);
+ netif_wake_queue(&dev->net_dev);
+ } else {
+ netif_stop_queue(&dev->net_dev);
+ }
+
+ if (cfg & CFG_LNKSTS)
+ printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n",
+ dev->net_dev.name,
+ speeds[((cfg / CFG_SPDSTS0) & 3)],
+ (cfg & CFG_DUPSTS) ? "full" : "half");
+ else
+ printk(KERN_INFO "%s: link now down.\n", dev->net_dev.name);
+}
+
+static int ns83820_setup_rx(struct ns83820 *dev)
+{
+ unsigned i;
+ int ret;
+
+ dprintk("ns83820_setup_rx(%p)\n", dev);
+
+ dev->rx_info.idle = 1;
+ dev->rx_info.next_rx = 0;
+ dev->rx_info.next_empty = 0;
+
+ for (i=0; i<NR_RX_DESC; i++)
+ clear_rx_desc(dev, i);
+
+ writel(0, dev->base + RXDP_HI);
+ writel(dev->rx_info.phy_descs, dev->base + RXDP);
+
+ ret = rx_refill(dev, GFP_KERNEL);
+ if (!ret) {
+ dprintk("starting receiver\n");
+ /* prevent the interrupt handler from stomping on us */
+ spin_lock_irq(&dev->rx_info.lock);
+
+ writel(0x0001, dev->base + CCSR);
+ writel(0, dev->base + RFCR);
+ writel(0x7fc00000, dev->base + RFCR);
+ writel(0xffc00000, dev->base + RFCR);
+
+ dev->rx_info.up = 1;
+
+ phy_intr(dev);
+
+ /* Okay, let it rip */
+ spin_lock(&dev->misc_lock);
+ dev->IMR_cache |= ISR_PHY;
+ dev->IMR_cache |= ISR_RXRCMP;
+ //dev->IMR_cache |= ISR_RXERR;
+ //dev->IMR_cache |= ISR_RXOK;
+ dev->IMR_cache |= ISR_RXORN;
+ dev->IMR_cache |= ISR_RXSOVR;
+ dev->IMR_cache |= ISR_RXDESC;
+ dev->IMR_cache |= ISR_RXIDLE;
+ dev->IMR_cache |= ISR_TXDESC;
+ //dev->IMR_cache |= ISR_TXIDLE;
+
+ writel(dev->IMR_cache, dev->base + IMR);
+ writel(1, dev->base + IER);
+ spin_unlock(&dev->misc_lock);
+
+ kick_rx(dev);
+
+ spin_unlock_irq(&dev->rx_info.lock);
+ }
+ return ret;
+}
+
+static void ns83820_cleanup_rx(struct ns83820 *dev)
+{
+ unsigned i;
+ long flags;
+
+ dprintk("ns83820_cleanup_rx(%p)\n", dev);
+
+ /* disable receive interrupts */
+ spin_lock_irqsave(&dev->misc_lock, flags);
+ dev->IMR_cache &= ~(ISR_RXOK | ISR_RXDESC | ISR_RXERR | ISR_RXEARLY | ISR_RXIDLE);
+ writel(dev->IMR_cache, dev->base + IMR);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
+
+ /* synchronize with the interrupt handler and kill it */
+ dev->rx_info.up = 0;
+ synchronize_irq();
+
+ /* touch the pci bus... */
+ readl(dev->base + IMR);
+
+ /* assumes the transmitter is already disabled and reset */
+ writel(0, dev->base + RXDP_HI);
+ writel(0, dev->base + RXDP);
+
+ for (i=0; i<NR_RX_DESC; i++) {
+ struct sk_buff *skb = dev->rx_info.skbs[i];
+ dev->rx_info.skbs[i] = NULL;
+ clear_rx_desc(dev, i);
+ if (skb)
+ kfree_skb(skb);
+ }
+}
+
+/* rx_irq
+ *
+ */
+static void FASTCALL(rx_irq(struct ns83820 *dev));
+static void rx_irq(struct ns83820 *dev)
+{
+ struct rx_info *info = &dev->rx_info;
+ unsigned next_rx;
+ u32 cmdsts, *desc;
+ long flags;
+ int nr = 0;
+
+ dprintk("rx_irq(%p)\n", dev);
+ dprintk("rxdp: %08x, descs: %08lx next_rx[%d]: %p next_empty[%d]: %p\n",
+ readl(dev->base + RXDP),
+ (dev->rx_info.phy_descs),
+ dev->rx_info.next_rx,
+ (dev->rx_info.descs + (DESC_SIZE * dev->rx_info.next_rx)),
+ dev->rx_info.next_empty,
+ (dev->rx_info.descs + (DESC_SIZE * dev->rx_info.next_empty))
+ );
+
+ spin_lock_irqsave(&info->lock, flags);
+ if (!info->up)
+ goto out;
+
+ dprintk("walking descs\n");
+ next_rx = info->next_rx;
+ desc = info->descs + (DESC_SIZE * next_rx);
+ while ((CMDSTS_OWN & (cmdsts = desc[CMDSTS])) &&
+ (cmdsts != CMDSTS_OWN)) {
+ struct sk_buff *skb;
+ u32 extsts = desc[EXTSTS];
+ dmaaddr_high_t bufptr = *(hw_addr_t *)(desc + BUFPTR);
+
+ dprintk("cmdsts: %08x\n", cmdsts);
+ dprintk("link: %08x\n", desc[LINK]);
+ dprintk("extsts: %08x\n", desc[EXTSTS]);
+
+ skb = info->skbs[next_rx];
+ info->skbs[next_rx] = NULL;
+ info->next_rx = (next_rx + 1) % NR_RX_DESC;
+
+ barrier();
+ clear_rx_desc(dev, next_rx);
+
+ pci_unmap_single(dev->pci_dev, bufptr,
+ RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (CMDSTS_OK & cmdsts) {
+#ifndef __i386__
+ struct sk_buff *tmp;
+#endif
+ int len = cmdsts & 0xffff;
+ if (!skb)
+ BUG();
+ skb_put(skb, len);
+#ifndef __i386__ /* I hate the network stack sometimes */
+ tmp = __dev_alloc_skb(RX_BUF_SIZE+16, GFP_ATOMIC);
+ if (!tmp)
+ goto done;
+ tmp->dev = &dev->net_dev;
+ skb_reserve(tmp, 2);
+ memcpy(skb_put(tmp, len), skb->data, len);
+ kfree_skb(skb);
+ skb = tmp;
+#endif
+ if ((extsts & 0x002a0000) && !(extsts & 0x00540000)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ skb->protocol = eth_type_trans(skb, &dev->net_dev);
+ switch (netif_rx(skb)) {
+ case NET_RX_SUCCESS:
+ dev->ihr = 3;
+ break;
+ case NET_RX_CN_LOW:
+ dev->ihr = 3;
+ break;
+ case NET_RX_CN_MOD:
+ dev->ihr = dev->ihr + 1;
+ break;
+ case NET_RX_CN_HIGH:
+ dev->ihr += dev->ihr/2 + 1;
+ break;
+ case NET_RX_DROP:
+ dev->ihr = 255;
+ break;
+ }
+ if (dev->ihr > 255)
+ dev->ihr = 255;
+#ifndef __i386__
+ done:;
+#endif
+ } else {
+ static int err;
+ if (err++ < 20) {
+ Dprintk("error packet: cmdsts: %08x extsts: %08x\n", cmdsts, extsts);
+ }
+ kfree_skb(skb);
+ }
+
+ nr++;
+ next_rx = info->next_rx;
+ desc = info->descs + (DESC_SIZE * next_rx);
+ }
+ info->next_rx = next_rx;
+
+out:
+ if (0 && !nr) {
+ Dprintk("dazed: cmdsts_f: %08x\n", cmdsts);
+ }
+
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+/* Packet Transmit code
+ */
+static inline void kick_tx(struct ns83820 *dev)
+{
+ dprintk("kick_tx(%p): tx_idle=%ld, tx_idx=%d free_idx=%d\n",
+ dev, dev->tx_idle, dev->tx_idx, dev->tx_free_idx);
+ writel(CR_TXE, dev->base + CR);
+}
+
+/* no spinlock needed on the transmit irq path as the interrupt handler is serialized */
+static void do_tx_done(struct ns83820 *dev)
+{
+ u32 cmdsts, tx_done_idx, *desc;
+
+ dprintk("do_tx_done(%p)\n", dev);
+ tx_done_idx = dev->tx_done_idx;
+ desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+
+ dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+ tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+ while ((tx_done_idx != dev->tx_free_idx) &&
+ !(CMDSTS_OWN & (cmdsts = desc[CMDSTS])) ) {
+ struct sk_buff *skb;
+
+ dprintk("tx_done_idx=%d free_idx=%d cmdsts=%08x\n",
+ tx_done_idx, dev->tx_free_idx, desc[CMDSTS]);
+ skb = dev->tx_skbs[tx_done_idx];
+ dev->tx_skbs[tx_done_idx] = NULL;
+ dprintk("done(%p)\n", skb);
+ if (skb) {
+ pci_unmap_single(dev->pci_dev,
+ *(hw_addr_t *)(desc + BUFPTR),
+ skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+ }
+
+ tx_done_idx = (tx_done_idx + 1) % NR_TX_DESC;
+ dev->tx_done_idx = tx_done_idx;
+ desc[CMDSTS] = 0;
+ barrier();
+ desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
+ }
+
+ /* Allow network stack to resume queueing packets after we've
+ * finished transmitting at least 1/4 of the packets in the queue.
+ */
+ if (netif_queue_stopped(&dev->net_dev) && start_tx_okay(dev)) {
+ dprintk("start_queue(%p)\n", dev);
+ netif_start_queue(&dev->net_dev);
+ netif_wake_queue(&dev->net_dev);
+ }
+}
+
+static void ns83820_cleanup_tx(struct ns83820 *dev)
+{
+ unsigned i;
+
+ for (i=0; i<NR_TX_DESC; i++) {
+ struct sk_buff *skb = dev->tx_skbs[i];
+ dev->tx_skbs[i] = NULL;
+ if (skb)
+ dev_kfree_skb(skb);
+ }
+
+ memset(dev->tx_descs, 0, NR_TX_DESC * DESC_SIZE * 4);
+ set_bit(0, &dev->tx_idle);
+}
+
+/* transmit routine. This code relies on the network layer serializing
+ * its calls in, but will run happily in parallel with the interrupt
+ * handler. This code currently has provisions for fragmenting tx buffers
+ * while trying to track down a bug in either the zero copy code or
+ * the tx fifo (hence the MAX_FRAG_LEN).
+ */
+#define MAX_FRAG_LEN 8192 /* disabled for now */
+static int ns83820_hard_start_xmit(struct sk_buff *skb, struct net_device *_dev)
+{
+ struct ns83820 *dev = (struct ns83820 *)_dev;
+ u32 free_idx, cmdsts, extsts;
+ int nr_free, nr_frags;
+ unsigned tx_done_idx;
+ dmaaddr_high_t buf;
+ unsigned len;
+ skb_frag_t *frag;
+ int stopped = 0;
+ int do_intr = 0;
+ volatile u32 *first_desc;
+
+ dprintk("ns83820_hard_start_xmit\n");
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+again:
+ if (__builtin_expect(dev->CFG_cache & CFG_LNKSTS, 0)) {
+ netif_stop_queue(&dev->net_dev);
+ if (__builtin_expect(dev->CFG_cache & CFG_LNKSTS, 0))
+ return 1;
+ netif_start_queue(&dev->net_dev);
+ }
+
+ free_idx = dev->tx_free_idx;
+ tx_done_idx = dev->tx_done_idx;
+ nr_free = (tx_done_idx + NR_TX_DESC-2 - free_idx) % NR_TX_DESC;
+ nr_free -= 1;
+ if ((nr_free <= nr_frags) || (nr_free <= 8192 / MAX_FRAG_LEN)) {
+ dprintk("stop_queue - not enough(%p)\n", dev);
+ netif_stop_queue(&dev->net_dev);
+
+ /* Check again: we may have raced with a tx done irq */
+ if (dev->tx_done_idx != tx_done_idx) {
+ dprintk("restart queue(%p)\n", dev);
+ netif_start_queue(&dev->net_dev);
+ goto again;
+ }
+ return 1;
+ }
+
+ if (free_idx == dev->tx_intr_idx) {
+ do_intr = 1;
+ dev->tx_intr_idx = (dev->tx_intr_idx + NR_TX_DESC/2) % NR_TX_DESC;
+ }
+
+ nr_free -= nr_frags;
+ if (nr_free < 1) {
+ dprintk("stop_queue - last entry(%p)\n", dev);
+ netif_stop_queue(&dev->net_dev);
+ stopped = 1;
+ }
+
+ frag = skb_shinfo(skb)->frags;
+ if (!nr_frags)
+ frag = 0;
+ extsts = 0;
+ if (skb->ip_summed == CHECKSUM_HW) {
+ extsts |= EXTSTS_IPPKT;
+ if (IPPROTO_TCP == skb->nh.iph->protocol)
+ extsts |= EXTSTS_TCPPKT;
+ else if (IPPROTO_UDP == skb->nh.iph->protocol)
+ extsts |= EXTSTS_UDPPKT;
+ }
+
+ len = skb->len;
+ if (nr_frags)
+ len -= skb->data_len;
+ buf = pci_map_single(dev->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+
+ first_desc = dev->tx_descs + (free_idx * DESC_SIZE);
+
+ for (;;) {
+ volatile u32 *desc = dev->tx_descs + (free_idx * DESC_SIZE);
+ u32 residue = 0;
+#if 0
+ if (len > MAX_FRAG_LEN) {
+ residue = len;
+ /* align the start address of the next fragment */
+ len = MAX_FRAG_LEN;
+ residue -= len;
+ }
+#endif
+
+ dprintk("frag[%3u]: %4u @ 0x%x%08Lx\n", free_idx, len,
+ (unsigned long long)buf);
+ free_idx = (free_idx + 1) % NR_TX_DESC;
+ desc[LINK] = dev->tx_phy_descs + (free_idx * DESC_SIZE * 4);
+ *(hw_addr_t *)(desc + BUFPTR) = buf;
+ desc[EXTSTS] = extsts;
+
+ cmdsts = ((nr_frags|residue) ? CMDSTS_MORE : do_intr ? CMDSTS_INTR : 0);
+ cmdsts |= (desc == first_desc) ? 0 : CMDSTS_OWN;
+ cmdsts |= len;
+ desc[CMDSTS] = cmdsts;
+
+ if (residue) {
+ buf += len;
+ len = residue;
+ continue;
+ }
+
+ if (!nr_frags)
+ break;
+
+ buf = pci_map_single_high(dev->pci_dev, frag->page, 0,
+ frag->size, PCI_DMA_TODEVICE);
+ dprintk("frag: buf=%08Lx page=%08lx\n",
+ (long long)buf, (long)(frag->page - mem_map));
+ len = frag->size;
+ frag++;
+ nr_frags--;
+ }
+ dprintk("done pkt\n");
+ dev->tx_skbs[free_idx] = skb;
+ first_desc[CMDSTS] |= CMDSTS_OWN;
+ dev->tx_free_idx = free_idx;
+ kick_tx(dev);
+
+ /* Check again: we may have raced with a tx done irq */
+ if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))
+ netif_start_queue(&dev->net_dev);
+
+ return 0;
+}
+
+static void ns83820_irq(int foo, void *data, struct pt_regs *regs)
+{
+ struct ns83820 *dev = data;
+ int count = 0;
+ u32 isr;
+ dprintk("ns83820_irq(%p)\n", dev);
+
+ dev->ihr = 0;
+
+ while (count++ < 32 && (isr = readl(dev->base + ISR))) {
+ dprintk("irq: %08x\n", isr);
+
+ if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
+ Dprintk("odd isr? 0x%08x\n", isr);
+
+ if ((ISR_RXEARLY | ISR_RXIDLE | ISR_RXORN | ISR_RXDESC | ISR_RXOK | ISR_RXERR) & isr) {
+ if (ISR_RXIDLE & isr) {
+ dev->rx_info.idle = 1;
+ Dprintk("oh dear, we are idle\n");
+ }
+
+ if ((ISR_RXDESC) & isr) {
+ rx_irq(dev);
+ writel(4, dev->base + IHR);
+ }
+
+ if (nr_rx_empty(dev) >= NR_RX_DESC/4) {
+ if (dev->rx_info.up) {
+ rx_refill(dev, GFP_ATOMIC);
+ kick_rx(dev);
+ }
+ }
+
+ if (dev->rx_info.up && nr_rx_empty(dev) > NR_RX_DESC*3/4)
+ schedule_task(&dev->tq_refill);
+ else
+ kick_rx(dev);
+ if (dev->rx_info.idle)
+ Dprintk("BAD\n");
+ }
+
+ if (ISR_RXSOVR & isr)
+ Dprintk("overrun\n");
+ if (ISR_RXORN & isr)
+ Dprintk("overrun\n");
+
+ if ((ISR_RXRCMP & isr) && dev->rx_info.up)
+ writel(CR_RXE, dev->base + CR);
+
+ if (ISR_TXIDLE & isr) {
+ u32 txdp;
+ txdp = readl(dev->base + TXDP);
+ dprintk("txdp: %08x\n", txdp);
+ txdp -= dev->tx_phy_descs;
+ dev->tx_idx = txdp / (DESC_SIZE * 4);
+ if (dev->tx_idx >= NR_TX_DESC) {
+ printk(KERN_ALERT "%s: BUG -- txdp out of range\n", dev->net_dev.name);
+ dev->tx_idx = 0;
+ }
+ if (dev->tx_idx != dev->tx_free_idx)
+ writel(CR_TXE, dev->base + CR);
+ //kick_tx(dev);
+ else
+ dev->tx_idle = 1;
+ mb();
+ if (dev->tx_idx != dev->tx_free_idx)
+ kick_tx(dev);
+ }
+
+ /* Defer tx ring processing until more than a minimum amount of
+ * work has accumulated
+ */
+ if ((ISR_TXDESC | ISR_TXIDLE) & isr)
+ do_tx_done(dev);
+
+ if (ISR_PHY & isr)
+ phy_intr(dev);
+ }
+
+#if 0 /* Still working on the interrupt mitigation strategy */
+ if (dev->ihr)
+ writel(dev->ihr, dev->base + IHR);
+#endif
+}
+
+static void ns83820_do_reset(struct ns83820 *dev, u32 which)
+{
+ Dprintk("resetting chip...\n");
+ writel(which, dev->base + CR);
+ do {
+ schedule();
+ } while (readl(dev->base + CR) & which);
+ Dprintk("okay!\n");
+}
+
+static int ns83820_stop(struct net_device *_dev)
+{
+ struct ns83820 *dev = (struct ns83820 *)_dev;
+
+ /* FIXME: protect against interrupt handler? */
+
+ /* disable interrupts */
+ writel(0, dev->base + IMR);
+ writel(0, dev->base + IER);
+ readl(dev->base + IER);
+
+ dev->rx_info.up = 0;
+ synchronize_irq();
+
+ ns83820_do_reset(dev, CR_RST);
+
+ synchronize_irq();
+
+ dev->IMR_cache &= ~(ISR_TXURN | ISR_TXIDLE | ISR_TXERR | ISR_TXDESC | ISR_TXOK);
+ ns83820_cleanup_rx(dev);
+ ns83820_cleanup_tx(dev);
+
+ return 0;
+}
+
+static int ns83820_open(struct net_device *_dev)
+{
+ struct ns83820 *dev = (struct ns83820 *)_dev;
+ unsigned i;
+ u32 desc;
+ int ret;
+
+ dprintk("ns83820_open\n");
+
+ writel(0, dev->base + PQCR);
+
+ ret = ns83820_setup_rx(dev);
+ if (ret)
+ goto failed;
+
+ memset(dev->tx_descs, 0, 4 * NR_TX_DESC * DESC_SIZE);
+ for (i=0; i<NR_TX_DESC; i++) {
+ *(hw_addr_t *)(dev->tx_descs + (i * DESC_SIZE) + LINK)
+ = dev->tx_phy_descs
+ + ((i+1) % NR_TX_DESC) * DESC_SIZE * 4;
+ }
+
+ dev->tx_idx = 0;
+ dev->tx_done_idx = 0;
+ desc = dev->tx_phy_descs;
+ writel(0, dev->base + TXDP_HI);
+ writel(desc, dev->base + TXDP);
+
+//printk("IMR: %08x / %08x\n", readl(dev->base + IMR), dev->IMR_cache);
+
+ set_bit(0, &dev->tx_idle);
+ netif_start_queue(&dev->net_dev); /* FIXME: wait for phy to come up */
+
+ return 0;
+
+failed:
+ ns83820_stop(_dev);
+ return ret;
+}
+
+#if 0 /* FIXME: implement this! */
+static void ns83820_tx_timeout(struct net_device *_dev)
+{
+ struct ns83820 *dev = (struct ns83820 *)_dev;
+
+ printk("ns83820_tx_timeout\n");
+}
+#endif
+
+static void ns83820_getmac(struct ns83820 *dev, u8 *mac)
+{
+ unsigned i;
+ for (i=0; i<3; i++) {
+ u32 data;
+#if 0 /* I've left this in as an example of how to use eeprom.h */
+ data = eeprom_readw(&dev->ee, 0xa + 2 - i);
+#else
+ writel(i*2, dev->base + RFCR);
+ data = readl(dev->base + RFDR);
+#endif
+ *mac++ = data;
+ *mac++ = data >> 8;
+ }
+}
+
+static int ns83820_change_mtu(struct net_device *_dev, int new_mtu)
+{
+ if (new_mtu > RX_BUF_SIZE)
+ return -EINVAL;
+ _dev->mtu = new_mtu;
+ return 0;
+}
+
+static int ns83820_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+{
+ struct ns83820 *dev;
+ long addr;
+ int err;
+
+ dev = (struct ns83820 *)alloc_etherdev((sizeof *dev) - (sizeof dev->net_dev));
+ err = -ENOMEM;
+ if (!dev)
+ goto out;
+
+ spin_lock_init(&dev->rx_info.lock);
+ spin_lock_init(&dev->tx_lock);
+ spin_lock_init(&dev->misc_lock);
+ dev->pci_dev = pci_dev;
+
+ dev->ee.cache = &dev->MEAR_cache;
+ dev->ee.lock = &dev->misc_lock;
+ dev->net_dev.owner = THIS_MODULE;
+
+ PREPARE_TQUEUE(&dev->tq_refill, queue_refill, dev);
+
+ err = pci_enable_device(pci_dev);
+ if (err) {
+ printk(KERN_INFO "ns83820: pci_enable_dev: %d\n", err);
+ goto out_free;
+ }
+
+ pci_set_master(pci_dev);
+ addr = pci_resource_start(pci_dev, 1);
+ dev->base = ioremap_nocache(addr, PAGE_SIZE);
+ dev->tx_descs = pci_alloc_consistent(pci_dev,
+ 4 * DESC_SIZE * NR_TX_DESC, &dev->tx_phy_descs);
+ dev->rx_info.descs = pci_alloc_consistent(pci_dev,
+ 4 * DESC_SIZE * NR_RX_DESC, &dev->rx_info.phy_descs);
+ err = -ENOMEM;
+ if (!dev->base || !dev->tx_descs || !dev->rx_info.descs)
+ goto out_disable;
+
+ dprintk("%p: %08lx %p: %08lx\n", dev->tx_descs, dev->tx_phy_descs,
+ dev->rx_info.descs, dev->rx_info.phy_descs);
+ /* disable interrupts */
+ writel(0, dev->base + IMR);
+ writel(0, dev->base + IER);
+ readl(dev->base + IER);
+
+ dev->IMR_cache = 0;
+
+ setup_ee_mem_bitbanger(&dev->ee, (long)dev->base + MEAR, 3, 2, 1, 0,
+ 0);
+
+ err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
+ dev->net_dev.name, dev);
+ if (err) {
+ printk(KERN_INFO "ns83820: unable to register irq %d\n",
+ pci_dev->irq);
+ goto out_unmap;
+ }
+
+ dev->net_dev.open = ns83820_open;
+ dev->net_dev.stop = ns83820_stop;
+ dev->net_dev.hard_start_xmit = ns83820_hard_start_xmit;
+ dev->net_dev.change_mtu = ns83820_change_mtu;
+ //FIXME: dev->net_dev.tx_timeout = ns83820_tx_timeout;
+
+ lock_kernel();
+ dev->next_dev = ns83820_chain;
+ ns83820_chain = dev;
+ unlock_kernel();
+
+ ns83820_do_reset(dev, CR_RST);
+
+ dprintk("start bist\n");
+ writel(PTSCR_EEBIST_EN, dev->base + PTSCR);
+ do {
+ schedule();
+ } while (readl(dev->base + PTSCR) & PTSCR_EEBIST_EN);
+ dprintk("done bist\n");
+
+ dprintk("start eeload\n");
+ writel(PTSCR_EELOAD_EN, dev->base + PTSCR);
+ do {
+ schedule();
+ } while (readl(dev->base + PTSCR) & PTSCR_EELOAD_EN);
+ dprintk("done eeload\n");
+
+ /* I love config registers */
+ dev->CFG_cache = readl(dev->base + CFG);
+
+ if ((dev->CFG_cache & CFG_PCI64_DET)) {
+ printk("%s: enabling 64 bit PCI.\n", dev->net_dev.name);
+ dev->CFG_cache |= CFG_T64ADDR | CFG_DATA64_EN;
+ } else {
+ printk("%s: disabling 64 bit PCI.\n", dev->net_dev.name);
+ dev->CFG_cache &= ~(CFG_T64ADDR | CFG_DATA64_EN);
+ }
+ dev->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS |
+ CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
+ CFG_M64ADDR);
+ dev->CFG_cache |= CFG_PINT_DUPSTS | CFG_PINT_LNKSTS | CFG_PINT_SPDSTS |
+ CFG_EXTSTS_EN | CFG_EXD | CFG_PESEL;
+ dev->CFG_cache |= CFG_REQALG;
+ dev->CFG_cache |= CFG_POW;
+#ifdef USE_64BIT_ADDR
+ dev->CFG_cache |= CFG_M64ADDR;
+ printk("using 64 bit addressing\n");
+#endif
+#ifdef __LITTLE_ENDIAN
+ dev->CFG_cache &= ~CFG_BEM;
+#elif defined(__BIG_ENDIAN)
+ dev->CFG_cache |= CFG_BEM;
+#else
+#error This driver only works for big or little endian!!!
+#endif
+
+ writel(dev->CFG_cache, dev->base + CFG);
+ dprintk("CFG: %08x\n", dev->CFG_cache);
+
+ if (readl(dev->base + SRR))
+ writel(readl(dev->base+0x20c) | 0xfe00, dev->base + 0x20c);
+
+ /* Note! The DMA burst size interacts with packet
+ * transmission, such that the largest packet that
+ * can be transmitted is 8192 - FLTH - burst size.
+ * If only the transmit fifo was larger...
+ */
+ writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA1024
+ | ((1600 / 32) * 0x100),
+ dev->base + TXCFG);
+
+ /* Flush the interrupt holdoff timer */
+ writel(0x000, dev->base + IHR);
+ writel(0x100, dev->base + IHR);
+
+ /* Set Rx to full duplex, don't accept runt, errored, long or length
+ * range errored packets. Set MXDMA to 7 => 512 word burst
+ */
+ writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
+ | RXCFG_ALP
+ | RXCFG_MXDMA | 0, dev->base + RXCFG);
+
+ /* Disable priority queueing */
+ writel(0, dev->base + PQCR);
+
+ /* Enable IP checksum validation and detetion of VLAN headers.
+ * Note: do not set the reject options as at least the 0x102
+ * revision of the chip does not properly accept IP fragments
+ * at least for UDP.
+ */
+ writel(VRCR_IPEN | VRCR_VTDEN, dev->base + VRCR);
+
+ /* Enable per-packet TCP/UDP/IP checksumming */
+ writel(VTCR_PPCHK, dev->base + VTCR);
+
+ /* Disable Pause frames */
+ writel(0, dev->base + PCR);
+
+ /* Disable Wake On Lan */
+ writel(0, dev->base + WCSR);
+
+ ns83820_getmac(dev, dev->net_dev.dev_addr);
+
+ /* Yes, we support dumb IP checksum on transmit */
+ dev->net_dev.features |= NETIF_F_SG;
+ dev->net_dev.features |= NETIF_F_IP_CSUM;
+#if defined(USE_64BIT_ADDR) || defined(CONFIG_HIGHMEM4G)
+ dev->net_dev.features |= NETIF_F_HIGHDMA;
+#endif
+
+ register_netdev(&dev->net_dev);
+
+ printk(KERN_INFO "%s: ns83820.c v" VERSION ": DP83820 %02x:%02x:%02x:%02x:%02x:%02x pciaddr=0x%08lx irq=%d rev 0x%x\n",
+ dev->net_dev.name,
+ dev->net_dev.dev_addr[0], dev->net_dev.dev_addr[1],
+ dev->net_dev.dev_addr[2], dev->net_dev.dev_addr[3],
+ dev->net_dev.dev_addr[4], dev->net_dev.dev_addr[5],
+ addr, pci_dev->irq,
+ (unsigned)readl(dev->base + SRR)
+ );
+
+ return 0;
+
+out_unmap:
+ iounmap(dev->base);
+out_disable:
+ pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_TX_DESC, dev->tx_descs, dev->tx_phy_descs);
+ pci_free_consistent(pci_dev, 4 * DESC_SIZE * NR_RX_DESC, dev->rx_info.descs, dev->rx_info.phy_descs);
+ pci_disable_device(pci_dev);
+out_free:
+ kfree(dev);
+out:
+ return err;
+}
+
+static struct pci_device_id pci_device_id[] __devinitdata = {
+ { 0x100b, 0x0022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ { 0, },
+};
+
+static struct pci_driver driver = {
+ name: "ns83820",
+ id_table: pci_device_id,
+ probe: ns83820_probe,
+#if 0 /* FIXME: implement */
+ remove: ,
+ suspend: ,
+ resume: ,
+#endif
+};
+
+
+static int __init ns83820_init(void)
+{
+ printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/100 driver.\n");
+ return pci_module_init(&driver);
+}
+
+static void ns83820_exit(void)
+{
+ struct ns83820 *dev;
+
+ for (dev = ns83820_chain; dev; ) {
+ struct ns83820 *next = dev->next_dev;
+
+ writel(0, dev->base + IMR); /* paranoia */
+ writel(0, dev->base + IER);
+ readl(dev->base + IER);
+
+ unregister_netdev(&dev->net_dev);
+ free_irq(dev->pci_dev->irq, dev);
+ iounmap(dev->base);
+ pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_TX_DESC,
+ dev->tx_descs, dev->tx_phy_descs);
+ pci_free_consistent(dev->pci_dev, 4 * DESC_SIZE * NR_RX_DESC,
+ dev->rx_info.descs, dev->rx_info.phy_descs);
+ pci_disable_device(dev->pci_dev);
+ kfree(dev);
+ dev = next;
+ }
+ pci_unregister_driver(&driver);
+ ns83820_chain = NULL;
+}
+
+MODULE_AUTHOR("Benjamin LaHaise <bcrl@redhat.com>");
+MODULE_DESCRIPTION("National Semiconductor DP83820 10/100/1000 driver");
+MODULE_DEVICE_TABLE(pci, pci_device_id);
+module_init(ns83820_init);
+module_exit(ns83820_exit);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index fb21b3c663d8..37d965573a5f 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -179,6 +179,7 @@ static int full_duplex[MAX_UNITS];
* v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
* v1.26 Converted to pci_alloc_consistent, Jamey Hicks / George France
* <jamey@crl.dec.com>
+ * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
*/
@@ -471,7 +472,7 @@ static int __init pcnet32_probe_vlbus(int cards_found)
-static int __init
+static int __devinit
pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int card_idx;
@@ -506,10 +507,11 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
* pdev will be NULL when called from pcnet32_probe_vlbus.
*/
-static int __init
+static int __devinit
pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
{
struct pcnet32_private *lp;
+ struct resource *res;
dma_addr_t lp_dma_addr;
int i,media,fdx = 0, mii = 0, fset = 0;
#ifdef DO_DXSUFLO
@@ -643,7 +645,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
}
if( memcmp( promaddr, dev->dev_addr, 6) )
{
- printk(" warning PROM address does not match CSR address");
+ printk(" warning PROM address does not match CSR address\n");
#if defined(__i386__)
printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
memcpy(dev->dev_addr, promaddr, 6);
@@ -682,11 +684,15 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
}
dev->base_addr = ioaddr;
- request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
+ res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
+ if (res == NULL)
+ return -EBUSY;
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
- if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL)
+ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+ release_resource(res);
return -ENOMEM;
+ }
memset(lp, 0, sizeof(*lp));
lp->dma_addr = lp_dma_addr;
@@ -715,6 +721,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
if (a == NULL) {
printk(KERN_ERR "pcnet32: No access methods\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ release_resource(res);
return -ENODEV;
}
lp->a = *a;
@@ -762,6 +769,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car
else {
printk(", failed to detect IRQ line.\n");
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ release_resource(res);
return -ENODEV;
}
}
@@ -1579,6 +1587,8 @@ static void __exit pcnet32_cleanup_module(void)
next_dev = lp->next;
unregister_netdev(pcnet32_dev);
release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
+ if (lp->pci_dev != NULL)
+ pci_unregister_driver(&pcnet32_driver);
pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
kfree(pcnet32_dev);
pcnet32_dev = next_dev;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 9f1896bcc369..fd1a5d852472 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -636,7 +636,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
break;
- if (uprog.len > 0) {
+ if (uprog.len > 0 && uprog.len < 65536) {
err = -ENOMEM;
len = uprog.len * sizeof(struct sock_filter);
code = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index f5680e2cd2aa..a65b3b097c2b 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -600,7 +600,7 @@ static u16 sis900_default_phy(struct net_device * net_dev)
/**
* sis900_set_capability: - set the media capability of network adapter.
* @net_dev : the net device to probe for
- * @mii_phy : default PHY
+ * @phy : default PHY
*
* Set the media capability of network adapter according to
* mii status register. It's necessary before auto-negotiate.
@@ -1190,6 +1190,7 @@ static void sis900_check_mode (struct net_device *net_dev, struct mii_phy *mii_p
/**
* sis900_set_mode: - Set the media mode of mac register.
+ * @ioaddr: the address of the device
* @speed : the transmit speed to be determined
* @duplex: the duplex mode to be determined
*
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
index 49974a7c030e..7a7c953b7b16 100644
--- a/drivers/net/sk98lin/h/skdrv1st.h
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -113,7 +113,7 @@ typedef struct s_AC SK_AC;
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 8df9e438c560..a55fa1d36e6b 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1503,6 +1503,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
#ifdef CONFIG_TULIP_MWI
if (!force_csr0 && (tp->flags & HAS_PCI_MWI))
tulip_mwi_config (pdev, dev);
+#else
+ /* MWI is broken for DC21143 rev 65... */
+ if (chip_idx == DC21143 && chip_rev == 65)
+ tp->csr0 &= ~MWI;
#endif
/* Stop the chip's Tx and Rx processes. */
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 67c168b4a65c..23812dcbc2b8 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -1830,3 +1830,4 @@ fst_cleanup_module(void)
module_init ( fst_init );
module_exit ( fst_cleanup_module );
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index af385d12a288..f43e33a9ab0d 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -400,7 +400,6 @@ static void sv11_shutdown(struct sv11_device *dev)
static int io=0x200;
static int irq=9;
-#ifdef LINUX_21
MODULE_PARM(io,"i");
MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card");
MODULE_PARM(dma,"i");
@@ -408,9 +407,9 @@ MODULE_PARM_DESC(dma, "Set this to 1 to use DMA1/DMA3 for TX/RX");
MODULE_PARM(irq,"i");
MODULE_PARM_DESC(irq, "The interrupt line setting for the Comtrol Hostess SV11 card");
-MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_AUTHOR("Alan Cox");
+MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11");
-#endif
static struct sv11_device *sv11_unit;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 3b3bd1707ac8..157ec0df84bd 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -11,7 +11,7 @@
* at http://www.granch.com (English) or http://www.granch.ru (Russian)
*
* This software may be used and distributed according to the terms
- * of the GNU Public License.
+ * of the GNU General Public License.
*
*
* 5.0.1 Jun 22 2001
@@ -1474,6 +1474,8 @@ MODULE_PARM( mac, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
MODULE_PARM( skip_pci_probe, "i" );
+MODULE_LICENSE("GPL");
+
int
init_module( void )
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 906067d6f230..8bc2e120a1fd 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -9,6 +9,7 @@
* 2 of the License, or (at your option) any later version.
*
* (c) Copyright 1999 Building Number Three Ltd
+ * (c) Copyright 2001 Alan Cox.
*
*/
@@ -455,7 +456,8 @@ MODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card");
MODULE_PARM(slow,"i");
MODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012");
-MODULE_AUTHOR("Bulding Number Three Ltd");
+MODULE_AUTHOR("Alan Cox");
+MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Modular driver for the SeaLevel 4021");
#endif
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 940de522a7b8..abc551f57656 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -1739,7 +1739,7 @@ EXPORT_SYMBOL(z8530_get_stats);
/*
* Module support
*/
-static const char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n";
+static char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n";
static int __init z85230_init_driver(void)
{
@@ -1752,3 +1752,7 @@ static void __exit z85230_cleanup_driver(void)
{
}
module_exit(z85230_cleanup_driver);
+
+MODULE_AUTHOR("Red Hat Inc.");
+MODULE_DESCRIPTION("Z85x30 synchronous driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 4d5a4186add3..c1f49dfd32a4 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -25,8 +25,11 @@ endif
#
obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
+obj-$(CONFIG_PARISC) += setup-bus.o
obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
obj-$(CONFIG_ALL_PPC) += setup-bus.o
+obj-$(CONFIG_DDB5476) += setup-bus.o
+obj-$(CONFIG_SGI_IP27) += setup-irq.o
ifndef CONFIG_X86
obj-y += syscall.o
diff --git a/drivers/scsi/53c700-mem.c b/drivers/scsi/53c700-mem.c
new file mode 100644
index 000000000000..4a8dd939e799
--- /dev/null
+++ b/drivers/scsi/53c700-mem.c
@@ -0,0 +1,1842 @@
+/* WARNING: GENERATED FILE (from 53c700.c), DO NOT MODIFY */
+#define MEM_MAPPED
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR (or Symbios) 53c700 and 53c700-66 Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/* Notes:
+ *
+ * This driver is designed exclusively for these chips (virtually the
+ * earliest of the scripts engine chips). They need their own drivers
+ * because they are missing so many of the scripts and snazzy register
+ * features of their elder brothers (the 710, 720 and 770).
+ *
+ * The 700 is the lowliest of the line, it can only do async SCSI.
+ * The 700-66 can at least do synchronous SCSI up to 10MHz.
+ *
+ * The 700 chip has no host bus interface logic of its own. However,
+ * it is usually mapped to a location with well defined register
+ * offsets. Therefore, if you can determine the base address and the
+ * irq your board incorporating this chip uses, you can probably use
+ * this driver to run it (although you'll probably have to write a
+ * minimal wrapper for the purpose---see the NCR_D700 driver for
+ * details about how to do this).
+ *
+ *
+ * TODO List:
+ *
+ * 1. Better statistics in the proc fs
+ *
+ * 2. Implement message queue (queues SCSI messages like commands) and make
+ * the abort and device reset functions use them.
+ * */
+
+/* CHANGELOG
+ *
+ * Version 2.3
+ *
+ * More endianness/cache coherency changes.
+ *
+ * Better bad device handling (handles devices lying about tag
+ * queueing support and devices which fail to provide sense data on
+ * contingent allegiance conditions)
+ *
+ * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
+ * debugging this driver on the parisc architecture and suggesting
+ * many improvements and bug fixes.
+ *
+ * Thanks also go to Linuxcare Inc. for providing several PARISC
+ * machines for me to debug the driver on.
+ *
+ * Version 2.2
+ *
+ * Made the driver mem or io mapped; added endian invariance; added
+ * dma cache flushing operations for architectures which need it;
+ * added support for more varied clocking speeds.
+ *
+ * Version 2.1
+ *
+ * Initial modularisation from the D700. See NCR_D700.c for the rest of
+ * the changelog.
+ * */
+#define NCR_700_VERSION "2.3"
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+#include <linux/blk.h>
+#include <linux/module.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#include "53c700.h"
+
+#ifdef NCR_700_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("53c700 and 53c700-66 Driver");
+MODULE_LICENSE("GPL");
+
+/* This is the script */
+#include "53c700_d.h"
+
+
+STATIC int NCR_700_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+STATIC int NCR_700_abort(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_proc_directory_info(char *, char **, off_t, int, int, int);
+STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
+STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
+
+static char *NCR_700_phase[] = {
+ "",
+ "after selection",
+ "before command phase",
+ "after command phase",
+ "after status phase",
+ "after data in phase",
+ "after data out phase",
+ "during data phase",
+};
+
+static char *NCR_700_condition[] = {
+ "",
+ "NOT MSG_OUT",
+ "UNEXPECTED PHASE",
+ "NOT MSG_IN",
+ "UNEXPECTED MSG",
+ "MSG_IN",
+ "SDTR_MSG RECEIVED",
+ "REJECT_MSG RECEIVED",
+ "DISCONNECT_MSG RECEIVED",
+ "MSG_OUT",
+ "DATA_IN",
+
+};
+
+static char *NCR_700_fatal_messages[] = {
+ "unexpected message after reselection",
+ "still MSG_OUT after message injection",
+ "not MSG_IN after selection",
+ "Illegal message length received",
+};
+
+static char *NCR_700_SBCL_bits[] = {
+ "IO ",
+ "CD ",
+ "MSG ",
+ "ATN ",
+ "SEL ",
+ "BSY ",
+ "ACK ",
+ "REQ ",
+};
+
+static char *NCR_700_SBCL_to_phase[] = {
+ "DATA_OUT",
+ "DATA_IN",
+ "CMD_OUT",
+ "STATE",
+ "ILLEGAL PHASE",
+ "ILLEGAL PHASE",
+ "MSG OUT",
+ "MSG IN",
+};
+
+static __u8 NCR_700_SDTR_msg[] = {
+ 0x01, /* Extended message */
+ 0x03, /* Extended message Length */
+ 0x01, /* SDTR Extended message */
+ NCR_700_MIN_PERIOD,
+ NCR_700_MAX_OFFSET
+};
+
+struct Scsi_Host * __init
+NCR_700_detect(Scsi_Host_Template *tpnt,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ __u32 *script = kmalloc(sizeof(SCRIPT), GFP_KERNEL);
+ __u32 pScript;
+ struct Scsi_Host *host;
+ static int banner = 0;
+ int j;
+
+ /* Fill in the missing routines from the host template */
+ tpnt->queuecommand = NCR_700_queuecommand;
+ tpnt->eh_abort_handler = NCR_700_abort;
+ tpnt->eh_device_reset_handler = NCR_700_dev_reset;
+ tpnt->eh_bus_reset_handler = NCR_700_bus_reset;
+ tpnt->eh_host_reset_handler = NCR_700_host_reset;
+ tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST;
+ tpnt->sg_tablesize = NCR_700_SG_SEGMENTS;
+ tpnt->cmd_per_lun = NCR_700_MAX_TAGS;
+ tpnt->use_clustering = DISABLE_CLUSTERING;
+ tpnt->use_new_eh_code = 1;
+ tpnt->proc_info = NCR_700_proc_directory_info;
+
+ if(tpnt->name == NULL)
+ tpnt->name = "53c700";
+ if(tpnt->proc_name == NULL)
+ tpnt->proc_name = "53c700";
+
+
+ if((host = scsi_register(tpnt, 4)) == NULL)
+ return NULL;
+ if(script == NULL) {
+ printk(KERN_ERR "53c700: Failed to allocate script, detatching\n");
+ scsi_unregister(host);
+ return NULL;
+ }
+
+ hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST, GFP_KERNEL);
+ if(hostdata->slots == NULL) {
+ printk(KERN_ERR "53c700: Failed to allocate command slots, detatching\n");
+ scsi_unregister(host);
+ return NULL;
+ }
+ memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST);
+ for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
+ if(j == 0)
+ hostdata->free_list = &hostdata->slots[j];
+ else
+ hostdata->slots[j-1].ITL_forw = &hostdata->slots[j];
+ hostdata->slots[j].state = NCR_700_SLOT_FREE;
+ }
+ host->hostdata[0] = (__u32)hostdata;
+ for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) {
+ script[j] = bS_to_host(SCRIPT[j]);
+ }
+ /* bus physical address of script */
+ pScript = virt_to_bus(script);
+ /* adjust all labels to be bus physical */
+ for(j = 0; j < PATCHES; j++) {
+ script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
+ }
+ /* now patch up fixed addresses */
+ script_patch_32(script, MessageLocation,
+ virt_to_bus(&hostdata->msgout[0]));
+ script_patch_32(script, StatusAddress,
+ virt_to_bus(&hostdata->status));
+ script_patch_32(script, ReceiveMsgAddress,
+ virt_to_bus(&hostdata->msgin[0]));
+
+ hostdata->script = script;
+ hostdata->pScript = pScript;
+ hostdata->state = NCR_700_HOST_FREE;
+ spin_lock_init(&hostdata->lock);
+ hostdata->cmd = NULL;
+ host->max_id = 7;
+ host->max_lun = NCR_700_MAX_LUNS;
+ host->unique_id = hostdata->base;
+ host->base = hostdata->base;
+ host->hostdata[0] = (unsigned long)hostdata;
+ /* kick the chip */
+ NCR_700_writeb(0xff, host, CTEST9_REG);
+ hostdata->rev = (NCR_700_readb(host, CTEST7_REG)<<4) & 0x0f;
+ hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0);
+ if(banner == 0) {
+ printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n");
+ banner = 1;
+ }
+ printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
+ hostdata->fast ? "53c700-66" : "53c700",
+ hostdata->rev, hostdata->differential ?
+ "(Differential)" : "");
+ /* reset the chip */
+ NCR_700_chip_reset(host);
+ NCR_700_writeb(ASYNC_OPERATION , host, SXFER_REG);
+
+ return host;
+}
+
+int
+NCR_700_release(struct Scsi_Host *host)
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ kfree(hostdata->script);
+ return 1;
+}
+
+static inline __u8
+NCR_700_identify(int can_disconnect, __u8 lun)
+{
+ return IDENTIFY_BASE |
+ ((can_disconnect) ? 0x40 : 0) |
+ (lun & NCR_700_LUN_MASK);
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip. If you
+ * really want to know what this function is doing, it's almost a
+ * direct transcription of the algorithm described in the 53c710
+ * guide, except that the DBC and DFIFO registers are only 6 bits
+ * wide.
+ *
+ * Inputs : host - SCSI host */
+static inline int
+NCR_700_data_residual (struct Scsi_Host *host) {
+ int count, synchronous;
+ unsigned int ddir;
+
+ count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
+ (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
+
+ synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
+
+ /* get the data direction */
+ ddir = NCR_700_readb(host, CTEST0_REG) & 0x01;
+
+ if (ddir) {
+ /* Receive */
+ if (synchronous)
+ count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4;
+ else
+ if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL)
+ ++count;
+ } else {
+ /* Send */
+ __u8 sstat = NCR_700_readb(host, SSTAT1_REG);
+ if (sstat & SODL_REG_FULL)
+ ++count;
+ if (synchronous && (sstat & SODR_REG_FULL))
+ ++count;
+ }
+ return count;
+}
+
+/* print out the SCSI wires and corresponding phase from the SBCL register
+ * in the chip */
+static inline char *
+sbcl_to_string(__u8 sbcl)
+{
+ int i;
+ static char ret[256];
+
+ ret[0]='\0';
+ for(i=0; i<8; i++) {
+ if((1<<i) & sbcl)
+ strcat(ret, NCR_700_SBCL_bits[i]);
+ }
+ strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]);
+ return ret;
+}
+
+static inline __u8
+bitmap_to_number(__u8 bitmap)
+{
+ __u8 i;
+
+ for(i=0; i<8 && !(bitmap &(1<<i)); i++)
+ ;
+ return i;
+}
+
+/* Pull a slot off the free list */
+STATIC struct NCR_700_command_slot *
+find_empty_slot(struct NCR_700_Host_Parameters *hostdata)
+{
+ struct NCR_700_command_slot *slot = hostdata->free_list;
+
+ if(slot == NULL) {
+ /* sanity check */
+ if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST)
+ printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST);
+ return NULL;
+ }
+
+ if(slot->state != NCR_700_SLOT_FREE)
+ /* should panic! */
+ printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n");
+
+
+ hostdata->free_list = slot->ITL_forw;
+ slot->ITL_forw = NULL;
+
+
+ /* NOTE: set the state to busy here, not queued, since this
+ * indicates the slot is in use and cannot be run by the IRQ
+ * finish routine. If we cannot queue the command when it
+ * is properly build, we then change to NCR_700_SLOT_QUEUED */
+ slot->state = NCR_700_SLOT_BUSY;
+ hostdata->command_slot_count++;
+
+ return slot;
+}
+
+STATIC void
+free_slot(struct NCR_700_command_slot *slot,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ int hash;
+ struct NCR_700_command_slot **forw, **back;
+
+
+ if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
+ printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
+ }
+ if(slot->state == NCR_700_SLOT_FREE) {
+ printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
+ }
+ /* remove from queues */
+ if(slot->tag != NCR_700_NO_TAG) {
+ hash = hash_ITLQ(slot->cmnd->target, slot->cmnd->lun,
+ slot->tag);
+ if(slot->ITLQ_forw == NULL)
+ back = &hostdata->ITLQ_Hash_back[hash];
+ else
+ back = &slot->ITLQ_forw->ITLQ_back;
+
+ if(slot->ITLQ_back == NULL)
+ forw = &hostdata->ITLQ_Hash_forw[hash];
+ else
+ forw = &slot->ITLQ_back->ITLQ_forw;
+
+ *forw = slot->ITLQ_forw;
+ *back = slot->ITLQ_back;
+ }
+ hash = hash_ITL(slot->cmnd->target, slot->cmnd->lun);
+ if(slot->ITL_forw == NULL)
+ back = &hostdata->ITL_Hash_back[hash];
+ else
+ back = &slot->ITL_forw->ITL_back;
+
+ if(slot->ITL_back == NULL)
+ forw = &hostdata->ITL_Hash_forw[hash];
+ else
+ forw = &slot->ITL_back->ITL_forw;
+
+ *forw = slot->ITL_forw;
+ *back = slot->ITL_back;
+
+ slot->resume_offset = 0;
+ slot->cmnd = NULL;
+ slot->state = NCR_700_SLOT_FREE;
+ slot->ITL_forw = hostdata->free_list;
+ hostdata->free_list = slot;
+ hostdata->command_slot_count--;
+}
+
+
+/* This routine really does very little. The command is indexed on
+ the ITL and (if tagged) the ITLQ lists in _queuecommand */
+STATIC void
+save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp)
+{
+ /* Its just possible that this gets executed twice */
+ if(SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ slot->resume_offset = dsp;
+ }
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+}
+
+/* Most likely nexus is the oldest in each case */
+STATIC inline struct NCR_700_command_slot *
+find_ITL_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun)
+{
+ int hash = hash_ITL(pun, lun);
+ struct NCR_700_command_slot *slot = hostdata->ITL_Hash_back[hash];
+ while(slot != NULL && !(slot->cmnd->target == pun &&
+ slot->cmnd->lun == lun))
+ slot = slot->ITL_back;
+ return slot;
+}
+
+STATIC inline struct NCR_700_command_slot *
+find_ITLQ_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun,
+ __u8 lun, __u8 tag)
+{
+ int hash = hash_ITLQ(pun, lun, tag);
+ struct NCR_700_command_slot *slot = hostdata->ITLQ_Hash_back[hash];
+
+ while(slot != NULL && !(slot->cmnd->target == pun
+ && slot->cmnd->lun == lun && slot->tag == tag))
+ slot = slot->ITLQ_back;
+
+#ifdef NCR_700_TAG_DEBUG
+ if(slot != NULL) {
+ struct NCR_700_command_slot *n = slot->ITLQ_back;
+ while(n != NULL && n->cmnd->target != pun
+ && n->cmnd->lun != lun && n->tag != tag)
+ n = n->ITLQ_back;
+
+ if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun
+ && n->tag == tag) {
+ printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n",
+ tag);
+ }
+ }
+#endif
+ return slot;
+}
+
+
+
+/* This translates the SDTR message offset and period to a value
+ * which can be loaded into the SXFER_REG.
+ *
+ * NOTE: According to SCSI-2, the true transfer period (in ns) is
+ * actually four times this period value */
+STATIC inline __u8
+NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
+ __u8 offset, __u8 period)
+{
+ int XFERP;
+
+ if(period*4 < NCR_700_MIN_PERIOD) {
+ printk(KERN_WARNING "53c700: Period %dns is less than SCSI-2 minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD);
+ period = NCR_700_MIN_PERIOD/4;
+ }
+ XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
+ if(offset > NCR_700_MAX_OFFSET) {
+ printk(KERN_WARNING "53c700: Offset %d exceeds maximum, setting to %d\n",
+ offset, NCR_700_MAX_OFFSET);
+ offset = NCR_700_MAX_OFFSET;
+ }
+ if(XFERP < NCR_700_MIN_XFERP) {
+ printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
+ XFERP, NCR_700_MIN_XFERP);
+ XFERP = NCR_700_MIN_XFERP;
+ }
+ return (offset & 0x0f) | (XFERP & 0x07)<<4;
+}
+
+
+STATIC inline void
+NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, int result)
+{
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+
+ if(SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {
+#ifdef NCR_700_DEBUG
+ printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is",
+ SCp, SCp->cmnd[7], result);
+ print_sense("53c700", SCp);
+#endif
+ if(result == 0)
+ result = SCp->cmnd[7];
+ }
+
+ free_slot(slot, hostdata);
+
+ SCp->host_scribble = NULL;
+ SCp->result = result;
+ SCp->scsi_done(SCp);
+ if(NCR_700_get_depth(SCp->device) == 0 ||
+ NCR_700_get_depth(SCp->device) > NCR_700_MAX_TAGS)
+ printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n",
+ NCR_700_get_depth(SCp->device));
+ NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
+ } else {
+ printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n");
+ }
+}
+
+
+STATIC void
+NCR_700_internal_bus_reset(struct Scsi_Host *host)
+{
+ /* Bus reset */
+ NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG);
+ udelay(50);
+ NCR_700_writeb(0, host, SCNTL1_REG);
+
+}
+
+STATIC void
+NCR_700_chip_setup(struct Scsi_Host *host)
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ NCR_700_writeb(1 << host->this_id, host, SCID_REG);
+ NCR_700_writeb(0, host, SBCL_REG);
+ NCR_700_writeb(0, host, SXFER_REG);
+
+ NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT
+ | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG);
+
+ NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG);
+ NCR_700_writeb(BURST_LENGTH_8, host, DMODE_REG);
+ NCR_700_writeb(FULL_ARBITRATION | PARITY | AUTO_ATN, host, SCNTL0_REG);
+ NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION|GENERATE_RECEIVE_PARITY,
+ host, CTEST8_REG);
+ NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG);
+ if(hostdata->clock > 75) {
+ printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock);
+ /* do the best we can, but the async clock will be out
+ * of spec: sync divider 2, async divider 3 */
+ DEBUG(("53c700: sync 2 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock/2;
+ } else if(hostdata->clock > 50 && hostdata->clock <= 75) {
+ /* sync divider 1.5, async divider 3 */
+ DEBUG(("53c700: sync 1.5 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock*2;
+ hostdata->sync_clock /= 3;
+
+ } else if(hostdata->clock > 37 && hostdata->clock <= 50) {
+ /* sync divider 1, async divider 2 */
+ DEBUG(("53c700: sync 1 async 2\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_2_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else if(hostdata->clock > 25 && hostdata->clock <=37) {
+ /* sync divider 1, async divider 1.5 */
+ DEBUG(("53c700: sync 1 async 1.5\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_5, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else {
+ DEBUG(("53c700: sync 1 async 1\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_0, host, DCNTL_REG);
+ /* sync divider 1, async divider 1 */
+ }
+}
+
+STATIC void
+NCR_700_chip_reset(struct Scsi_Host *host)
+{
+ /* Chip reset */
+ NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
+ udelay(100);
+
+ NCR_700_writeb(0, host, DCNTL_REG);
+
+ mdelay(1000);
+
+ NCR_700_chip_setup(host);
+}
+
+/* The heart of the message processing engine is that the instruction
+ * immediately after the INT is the normal case (and so must be CLEAR
+ * ACK). If we want to do something else, we call that routine in
+ * scripts and set temp to be the normal case + 8 (skipping the CLEAR
+ * ACK) so that the routine returns correctly to resume its activity
+ * */
+STATIC __u32
+process_extended_message(struct Scsi_Host *host,
+ struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+ __u32 resume_offset = dsp, temp = dsp + 8;
+ __u8 pun = 0xff, lun = 0xff;
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ switch(hostdata->msgin[2]) {
+ case A_SDTR_MSG:
+ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+ __u8 period = hostdata->msgin[3];
+ __u8 offset = hostdata->msgin[4];
+ __u8 sxfer;
+
+ if(offset != 0 && period != 0)
+ sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period);
+ else
+ sxfer = 0;
+
+ if(sxfer != NCR_700_get_SXFER(SCp->device)) {
+ printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
+ host->host_no, pun, lun,
+ offset, period*4);
+
+ NCR_700_set_SXFER(SCp->device, sxfer);
+ }
+
+
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+
+ NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+ host, SXFER_REG);
+
+ } else {
+ /* SDTR message out of the blue, reject it */
+ printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n",
+ host->host_no);
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+ }
+ break;
+
+ case A_WDTR_MSG:
+ printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
+ host->host_no, pun, lun);
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+ break;
+
+ default:
+ printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ print_msg(hostdata->msgin);
+ printk("\n");
+ /* just reject it */
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+ }
+ NCR_700_writel(temp, host, TEMP_REG);
+ return resume_offset;
+}
+
+STATIC __u32
+process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+ /* work out where to return to */
+ __u32 temp = dsp + 8, resume_offset = dsp;
+ __u8 pun = 0xff, lun = 0xff;
+
+ dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+#ifdef NCR_700_DEBUG
+ printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ print_msg(hostdata->msgin);
+ printk("\n");
+#endif
+
+ switch(hostdata->msgin[0]) {
+
+ case A_EXTENDED_MSG:
+ return process_extended_message(host, hostdata, SCp,
+ dsp, dsps);
+
+ case A_REJECT_MSG:
+ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+ /* Rejected our sync negotiation attempt */
+ NCR_700_set_SXFER(SCp->device, 0);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
+ /* rejected our first simple tag message */
+ printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ hostdata->tag_negotiated &= ~(1<<SCp->target);
+ } else {
+ printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ /* however, just ignore it */
+ }
+ break;
+
+ case A_PARITY_ERROR_MSG:
+ printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no,
+ pun, lun);
+ NCR_700_internal_bus_reset(host);
+ break;
+ case A_SIMPLE_TAG_MSG:
+ printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no,
+ pun, lun, hostdata->msgin[1],
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ /* just ignore it */
+ break;
+ default:
+ printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+
+ print_msg(hostdata->msgin);
+ printk("\n");
+ /* just reject it */
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+ break;
+ }
+ NCR_700_writel(temp, host, TEMP_REG);
+ return resume_offset;
+}
+
+STATIC __u32
+process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
+ struct Scsi_Host *host,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ __u32 resume_offset = 0;
+ __u8 pun = 0xff, lun=0xff;
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
+ dma_cache_inv((unsigned long)hostdata->status, sizeof(hostdata->status));
+ DEBUG((" COMMAND COMPLETE, status=%02x\n",
+ hostdata->status));
+ /* OK, if TCQ still on, we know it works */
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* check for contingent allegiance contitions */
+ if(status_byte(hostdata->status) == CHECK_CONDITION ||
+ status_byte(hostdata->status) == COMMAND_TERMINATED) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ if(SCp->cmnd[0] == REQUEST_SENSE) {
+ /* OOPS: bad device, returning another
+ * contingent allegiance condition */
+ printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun);
+ NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+ } else {
+
+ DEBUG((" cmd %p has status %d, requesting sense\n",
+ SCp, hostdata->status));
+ /* we can destroy the command here because the
+ * contingent allegiance condition will cause a
+ * retry which will re-copy the command from the
+ * saved data_cmnd */
+ SCp->cmnd[0] = REQUEST_SENSE;
+ SCp->cmnd[1] = (SCp->lun & 0x7) << 5;
+ SCp->cmnd[2] = 0;
+ SCp->cmnd[3] = 0;
+ SCp->cmnd[4] = sizeof(SCp->sense_buffer);
+ SCp->cmnd[5] = 0;
+ SCp->cmd_len = 6;
+ /* Here's a quiet hack: the REQUEST_SENSE command is
+ * six bytes, so store a flag indicating that this
+ * was an internal sense request and the original
+ * status at the end of the command */
+ SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
+ SCp->cmnd[7] = hostdata->status;
+ slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
+ slot->SG[0].pAddr = bS_to_host(virt_to_bus(SCp->sense_buffer));
+ slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
+ slot->SG[1].pAddr = 0;
+ slot->resume_offset = hostdata->pScript;
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2);
+ dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer));
+
+ /* queue the command for reissue */
+ slot->state = NCR_700_SLOT_QUEUED;
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+ }
+ } else {
+ if(status_byte(hostdata->status) == GOOD &&
+ SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
+ /* Piggy back the tag queueing support
+ * on this command */
+ if(((char *)SCp->request_buffer)[7] & 0x02) {
+ printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun);
+ hostdata->tag_negotiated |= (1<<SCp->target);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ } else {
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ hostdata->tag_negotiated &= ~(1<<SCp->target);
+ }
+ }
+ NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+ }
+ } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) {
+ __u8 i = (dsps & 0xf00) >> 8;
+
+ printk(KERN_ERR "scsi%d: (%d:%d), UNEXPECTED PHASE %s (%s)\n",
+ host->host_no, pun, lun,
+ NCR_700_phase[i],
+ sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+ printk(KERN_ERR " len = %d, cmd =", SCp->cmd_len);
+ print_command(SCp->cmnd);
+
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff000) == A_FATAL) {
+ int i = (dsps & 0xfff);
+
+ printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n",
+ host->host_no, pun, lun, NCR_700_fatal_messages[i]);
+ if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) {
+ printk(KERN_ERR " msg begins %02x %02x\n",
+ hostdata->msgin[0], hostdata->msgin[1]);
+ }
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff0f0) == A_DISCONNECT) {
+#ifdef NCR_700_DEBUG
+ __u8 i = (dsps & 0xf00) >> 8;
+
+ printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n",
+ host->host_no, pun, lun,
+ i, NCR_700_phase[i]);
+#endif
+ save_for_reselection(hostdata, SCp, dsp);
+
+ } else if(dsps == A_RESELECTION_IDENTIFIED) {
+ __u8 lun;
+ struct NCR_700_command_slot *slot;
+ __u8 reselection_id = hostdata->reselection_id;
+
+ dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ lun = hostdata->msgin[0] & 0x1f;
+
+ hostdata->reselection_id = 0xff;
+ DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
+ host->host_no, reselection_id, lun));
+ /* clear the reselection indicator */
+ if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
+ slot = find_ITLQ_Nexus(hostdata, reselection_id,
+ lun, hostdata->msgin[2]);
+ } else {
+ slot = find_ITL_Nexus(hostdata, reselection_id, lun);
+ }
+ retry:
+ if(slot == NULL) {
+ struct NCR_700_command_slot *s = find_ITL_Nexus(hostdata, reselection_id, lun);
+ printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
+ host->host_no, reselection_id, lun,
+ hostdata->msgin[0], hostdata->msgin[1],
+ hostdata->msgin[2]);
+ printk(KERN_ERR " OUTSTANDING TAGS:");
+ while(s != NULL) {
+ if(s->cmnd->target == reselection_id &&
+ s->cmnd->lun == lun) {
+ printk("%d ", s->tag);
+ if(s->tag == hostdata->msgin[2]) {
+ printk(" ***FOUND*** \n");
+ slot = s;
+ goto retry;
+ }
+
+ }
+ s = s->ITL_back;
+ }
+ printk("\n");
+ } else {
+ if(hostdata->state != NCR_700_HOST_BUSY)
+ printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
+ host->host_no);
+ resume_offset = slot->resume_offset;
+ hostdata->cmd = slot->cmnd;
+
+ /* re-patch for this command */
+ script_patch_32_abs(hostdata->script, CommandAddress,
+ virt_to_bus(slot->cmnd->cmnd));
+ script_patch_16(hostdata->script,
+ CommandCount, slot->cmnd->cmd_len);
+ script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+ virt_to_bus(&slot->SG[0].ins));
+
+ /* Note: setting SXFER only works if we're
+ * still in the MESSAGE phase, so it is vital
+ * that ACK is still asserted when we process
+ * the reselection message. The resume offset
+ * should therefore always clear ACK */
+ NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
+ host, SXFER_REG);
+
+ }
+ } else if(dsps == A_RESELECTED_DURING_SELECTION) {
+
+ /* This section is full of debugging code because I've
+ * never managed to reach it. I think what happens is
+ * that, because the 700 runs with selection
+ * interrupts enabled the whole time that we take a
+ * selection interrupt before we manage to get to the
+ * reselected script interrupt */
+
+ __u8 reselection_id = NCR_700_readb(host, SFBR_REG);
+ struct NCR_700_command_slot *slot;
+
+ /* Take out our own ID */
+ reselection_id &= ~(1<<host->this_id);
+
+ printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%p[%04x] state=%d, count=%d\n",
+ host->host_no, reselection_id, lun, (void *)dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
+
+ {
+ /* FIXME: DEBUGGING CODE */
+ __u32 SG = (__u32)bus_to_virt(hostdata->script[A_SGScriptStartAddress_used[0]]);
+ int i;
+
+ for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ if(SG >= (__u32)(&hostdata->slots[i].SG[0])
+ && SG <= (__u32)(&hostdata->slots[i].SG[NCR_700_SG_SEGMENTS]))
+ break;
+ }
+ printk(KERN_INFO "IDENTIFIED SG segment as being %p in slot %p, cmd %p, slot->resume_offset=%p\n", (void *)SG, &hostdata->slots[i], hostdata->slots[i].cmnd, (void *)hostdata->slots[i].resume_offset);
+ SCp = hostdata->slots[i].cmnd;
+ }
+
+ if(SCp != NULL) {
+ slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+ /* change slot from busy to queued to redo command */
+ slot->state = NCR_700_SLOT_QUEUED;
+ }
+ hostdata->cmd = NULL;
+
+ if(reselection_id == 0) {
+ if(hostdata->reselection_id == 0xff) {
+ printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no);
+ return 0;
+ } else {
+ printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n",
+ host->host_no);
+ reselection_id = hostdata->reselection_id;
+ }
+ } else {
+
+ /* convert to real ID */
+ reselection_id = bitmap_to_number(reselection_id);
+ }
+ hostdata->reselection_id = reselection_id;
+ hostdata->msgin[1] = 0;
+ dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+ if(hostdata->tag_negotiated & (1<<reselection_id)) {
+ resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+ } else {
+ resume_offset = hostdata->pScript + Ent_GetReselectionData;
+ }
+ } else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) {
+ /* we've just disconnected from the bus, do nothing since
+ * a return here will re-run the queued command slot
+ * that may have been interrupted by the initial selection */
+ DEBUG((" SELECTION COMPLETED\n"));
+ } else if((dsps & 0xfffff0f0) == A_MSG_IN) {
+ resume_offset = process_message(host, hostdata, SCp,
+ dsp, dsps);
+ } else if((dsps & 0xfffff000) == 0) {
+ __u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8;
+ printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n",
+ host->host_no, pun, lun, NCR_700_condition[i],
+ NCR_700_phase[j], dsp - hostdata->pScript);
+ if(SCp != NULL) {
+ print_command(SCp->cmnd);
+
+ if(SCp->use_sg) {
+ for(i = 0; i < SCp->use_sg + 1; i++) {
+ printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
+ }
+ }
+ }
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
+ printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %p[%04x], continuing\n",
+ host->host_no, pun, lun, dsps & 0xfff, (void *)dsp, dsp - hostdata->pScript);
+ resume_offset = dsp;
+ } else {
+ printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n",
+ host->host_no, pun, lun, dsps, dsp - hostdata->pScript);
+ NCR_700_internal_bus_reset(host);
+ }
+ return resume_offset;
+}
+
+/* We run the 53c700 with selection interrupts always enabled. This
+ * means that the chip may be selected as soon as the bus frees. On a
+ * busy bus, this can be before the scripts engine finishes its
+ * processing. Therefore, part of the selection processing has to be
+ * to find out what the scripts engine is doing and complete the
+ * function if necessary (i.e. process the pending disconnect or save
+ * the interrupted initial selection */
+STATIC inline __u32
+process_selection(struct Scsi_Host *host, __u32 dsp)
+{
+ __u8 id = 0; /* Squash compiler warning */
+ int count = 0;
+ __u32 resume_offset = 0;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ Scsi_Cmnd *SCp = hostdata->cmd;
+ __u8 sbcl;
+
+ for(count = 0; count < 5; count++) {
+ id = NCR_700_readb(host, SFBR_REG);
+
+ /* Take out our own ID */
+ id &= ~(1<<host->this_id);
+ if(id != 0)
+ break;
+ udelay(5);
+ }
+ sbcl = NCR_700_readb(host, SBCL_REG);
+ if((sbcl & SBCL_IO) == 0) {
+ /* mark as having been selected rather than reselected */
+ id = 0xff;
+ } else {
+ /* convert to real ID */
+ hostdata->reselection_id = id = bitmap_to_number(id);
+ DEBUG(("scsi%d: Reselected by %d\n",
+ host->host_no, id));
+ }
+ if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset));
+
+ switch(dsp - hostdata->pScript) {
+ case Ent_Disconnect1:
+ case Ent_Disconnect2:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript);
+ break;
+ case Ent_Disconnect3:
+ case Ent_Disconnect4:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript);
+ break;
+ case Ent_Disconnect5:
+ case Ent_Disconnect6:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript);
+ break;
+ case Ent_Disconnect7:
+ case Ent_Disconnect8:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript);
+ break;
+ case Ent_Finish1:
+ case Ent_Finish2:
+ process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata);
+ break;
+
+ default:
+ slot->state = NCR_700_SLOT_QUEUED;
+ break;
+ }
+ }
+ hostdata->state = NCR_700_HOST_BUSY;
+ hostdata->cmd = NULL;
+ hostdata->msgin[1] = 0;
+ dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ if(id == 0xff) {
+ /* Selected as target, Ignore */
+ resume_offset = hostdata->pScript + Ent_SelectedAsTarget;
+ } else if(hostdata->tag_negotiated & (1<<id)) {
+ resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+ } else {
+ resume_offset = hostdata->pScript + Ent_GetReselectionData;
+ }
+ return resume_offset;
+}
+
+
+STATIC int
+NCR_700_start_command(Scsi_Cmnd *SCp)
+{
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+ unsigned long flags;
+ __u16 count = 1; /* for IDENTIFY message */
+
+ save_flags(flags);
+ cli();
+ if(hostdata->state != NCR_700_HOST_FREE) {
+ /* keep this inside the lock to close the race window where
+ * the running command finishes on another CPU while we don't
+ * change the state to queued on this one */
+ slot->state = NCR_700_SLOT_QUEUED;
+ restore_flags(flags);
+
+ DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n",
+ SCp->host->host_no, slot->cmnd, slot));
+ return 0;
+ }
+ hostdata->state = NCR_700_HOST_BUSY;
+ hostdata->cmd = SCp;
+ slot->state = NCR_700_SLOT_BUSY;
+ /* keep interrupts disabled until we have the command correctly
+ * set up so we cannot take a selection interrupt */
+
+ hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE,
+ SCp->lun);
+ /* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
+ * if the negotiated transfer parameters still hold, so
+ * always renegotiate them */
+ if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE) {
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ }
+
+ /* REQUEST_SENSE is asking for contingent I_T_L status. If a
+ * contingent allegiance condition exists, the device will
+ * refuse all tags, so send the request sense as untagged */
+ if((hostdata->tag_negotiated & (1<<SCp->target))
+ && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
+ hostdata->msgout[count++] = A_SIMPLE_TAG_MSG;
+ hostdata->msgout[count++] = slot->tag;
+ }
+
+ if(hostdata->fast &&
+ NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
+ memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
+ sizeof(NCR_700_SDTR_msg));
+ count += sizeof(NCR_700_SDTR_msg);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ }
+
+ dma_cache_wback((unsigned long)hostdata->msgout, count);
+
+ script_patch_16(hostdata->script, MessageCount, count);
+
+
+ script_patch_ID(hostdata->script,
+ Device_ID, 1<<SCp->target);
+
+ script_patch_32_abs(hostdata->script, CommandAddress,
+ virt_to_bus(SCp->cmnd));
+ script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
+ /* finally plumb the beginning of the SG list into the script
+ * */
+ script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+ virt_to_bus(&slot->SG[0].ins));
+ NCR_700_writeb(CLR_FIFO, SCp->host, DFIFO_REG);
+
+ /* set the synchronous period/offset */
+ if(slot->resume_offset == 0)
+ slot->resume_offset = hostdata->pScript;
+ NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+ SCp->host, SXFER_REG);
+ /* allow interrupts here so that if we're selected we can take
+ * a selection interrupt. The script start may not be
+ * effective in this case, but the selection interrupt will
+ * save our command in that case */
+ NCR_700_writel(slot->temp, SCp->host, TEMP_REG);
+ NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG);
+ restore_flags(flags);
+
+ return 1;
+}
+
+void
+NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ __u8 istat;
+ __u32 resume_offset = 0;
+ __u8 pun = 0xff, lun = 0xff;
+ unsigned long flags;
+
+ /* Unfortunately, we have to take the io_request_lock here
+ * rather than the host lock hostdata->lock because we're
+ * looking to exclude queuecommand from messing with the
+ * registers while we're processing the interrupt. Since
+ * queuecommand is called holding io_request_lock, and we have
+ * to take io_request_lock before we call the command
+ * scsi_done, we would get a deadlock if we took
+ * hostdata->lock here and in queuecommand (because the order
+ * of locking in queuecommand: 1) io_request_lock then 2)
+ * hostdata->lock would be the reverse of taking it in this
+ * routine */
+ spin_lock_irqsave(&io_request_lock, flags);
+ if((istat = NCR_700_readb(host, ISTAT_REG))
+ & (SCSI_INT_PENDING | DMA_INT_PENDING)) {
+ __u32 dsps;
+ __u8 sstat0 = 0, dstat = 0;
+ __u32 dsp;
+ Scsi_Cmnd *SCp = hostdata->cmd;
+ enum NCR_700_Host_State state;
+
+ state = hostdata->state;
+ SCp = hostdata->cmd;
+
+ if(istat & SCSI_INT_PENDING) {
+ udelay(10);
+
+ sstat0 = NCR_700_readb(host, SSTAT0_REG);
+ }
+
+ if(istat & DMA_INT_PENDING) {
+ udelay(10);
+
+ dstat = NCR_700_readb(host, DSTAT_REG);
+ }
+
+ dsps = NCR_700_readl(host, DSPS_REG);
+ dsp = NCR_700_readl(host, DSP_REG);
+
+ DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n",
+ host->host_no, istat, sstat0, dstat,
+ (dsp - (__u32)virt_to_bus(hostdata->script))/4,
+ dsp, dsps));
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ if(sstat0 & SCSI_RESET_DETECTED) {
+ Scsi_Device *SDp;
+ int i;
+
+ hostdata->state = NCR_700_HOST_BUSY;
+
+ printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %p[%04x]\n",
+ host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, (void *)dsp, dsp - hostdata->pScript);
+
+ /* clear all the negotiated parameters */
+ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next)
+ SDp->hostdata = 0;
+
+ /* clear all the slots and their pending commands */
+ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ Scsi_Cmnd *SCp;
+ struct NCR_700_command_slot *slot =
+ &hostdata->slots[i];
+
+ if(slot->state == NCR_700_SLOT_FREE)
+ continue;
+
+ SCp = slot->cmnd;
+ printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n",
+ slot, SCp);
+ free_slot(slot, hostdata);
+ SCp->host_scribble = NULL;
+ NCR_700_set_depth(SCp->device, 0);
+ /* NOTE: deadlock potential here: we
+ * rely on mid-layer guarantees that
+ * scsi_done won't try to issue the
+ * command again otherwise we'll
+ * deadlock on the
+ * hostdata->state_lock */
+ SCp->result = DID_RESET << 16;
+ SCp->scsi_done(SCp);
+ }
+ mdelay(25);
+ NCR_700_chip_setup(host);
+
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+ goto out_unlock;
+ } else if(sstat0 & SELECTION_TIMEOUT) {
+ DEBUG(("scsi%d: (%d:%d) selection timeout\n",
+ host->host_no, pun, lun));
+ NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16);
+ } else if(sstat0 & PHASE_MISMATCH) {
+ struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL :
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ if(dsp == Ent_SendMessage + 8 + hostdata->pScript) {
+ /* It wants to reply to some part of
+ * our message */
+#ifdef NCR_700_DEBUG
+ __u32 temp = NCR_700_readl(host, TEMP_REG);
+ int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host));
+ printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+#endif
+ resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
+ } else if(dsp >= virt_to_bus(&slot->SG[0].ins) &&
+ dsp <= virt_to_bus(&slot->SG[NCR_700_SG_SEGMENTS].ins)) {
+ int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
+ int SGcount = (dsp - virt_to_bus(&slot->SG[0].ins))/sizeof(struct NCR_700_SG_List);
+ int residual = NCR_700_data_residual(host);
+ int i;
+#ifdef NCR_700_DEBUG
+ printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
+ host->host_no, pun, lun,
+ SGcount, data_transfer);
+ print_command(SCp->cmnd);
+ if(residual) {
+ printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n",
+ host->host_no, pun, lun,
+ SGcount, data_transfer, residual);
+ }
+#endif
+ data_transfer += residual;
+
+ if(data_transfer != 0) {
+ int count;
+ __u32 pAddr;
+
+ SGcount--;
+
+ count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff);
+ DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer));
+ slot->SG[SGcount].ins &= bS_to_host(0xff000000);
+ slot->SG[SGcount].ins |= bS_to_host(data_transfer);
+ pAddr = bS_to_cpu(slot->SG[SGcount].pAddr);
+ pAddr += (count - data_transfer);
+ slot->SG[SGcount].pAddr = bS_to_host(pAddr);
+ }
+ /* set the executed moves to nops */
+ for(i=0; i<SGcount; i++) {
+ slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
+ slot->SG[i].pAddr = 0;
+ }
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ /* and pretend we disconnected after
+ * the command phase */
+ resume_offset = hostdata->pScript + Ent_MsgInDuringData;
+ } else {
+ __u8 sbcl = NCR_700_readb(host, SBCL_REG);
+ printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n",
+ host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl));
+ NCR_700_internal_bus_reset(host);
+ }
+
+ } else if(sstat0 & SCSI_GROSS_ERROR) {
+ printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n",
+ host->host_no, pun, lun);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ } else if(dstat & SCRIPT_INT_RECEIVED) {
+ DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n",
+ host->host_no, pun, lun));
+ resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata);
+ } else if(dstat & (ILGL_INST_DETECTED)) {
+ printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%p[0x%x]!!!\n"
+ " Please email James.Bottomley@HansenPartnership.com with the details\n",
+ host->host_no, pun, lun,
+ (void *)dsp, dsp - hostdata->pScript);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) {
+ printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n",
+ host->host_no, pun, lun, dstat);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ }
+
+
+ /* NOTE: selection interrupt processing MUST occur
+ * after script interrupt processing to correctly cope
+ * with the case where we process a disconnect and
+ * then get reselected before we process the
+ * disconnection */
+ if(sstat0 & SELECTED) {
+ /* FIXME: It currently takes at least FOUR
+ * interrupts to complete a command that
+ * disconnects: one for the disconnect, one
+ * for the reselection, one to get the
+ * reselection data and one to complete the
+ * command. If we guess the reselected
+ * command here and prepare it, we only need
+ * to get a reselection data interrupt if we
+ * guessed wrongly. Since the interrupt
+ * overhead is much greater than the command
+ * setup, this would be an efficient
+ * optimisation particularly as we probably
+ * only have one outstanding command on a
+ * target most of the time */
+
+ resume_offset = process_selection(host, dsp);
+
+ }
+
+ }
+
+ if(resume_offset) {
+ if(hostdata->state != NCR_700_HOST_BUSY) {
+ printk(KERN_ERR "scsi%d: Driver error: resume at %p [%04x] with non busy host!\n",
+ host->host_no, (void *)resume_offset, resume_offset - hostdata->pScript);
+ hostdata->state = NCR_700_HOST_BUSY;
+ }
+
+ DEBUG(("Attempting to resume at %x\n", resume_offset));
+ NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
+ NCR_700_writel(resume_offset, host, DSP_REG);
+ }
+ /* There is probably a technical no-no about this: If we're a
+ * shared interrupt and we got this interrupt because the
+ * other device needs servicing not us, we're still going to
+ * check our queued commands here---of course, there shouldn't
+ * be any outstanding.... */
+ if(hostdata->state == NCR_700_HOST_FREE) {
+ int i;
+
+ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ /* fairness: always run the queue from the last
+ * position we left off */
+ int j = (i + hostdata->saved_slot_position)
+ % NCR_700_COMMAND_SLOTS_PER_HOST;
+
+ if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED)
+ continue;
+ if(NCR_700_start_command(hostdata->slots[j].cmnd)) {
+ DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n",
+ host->host_no, &hostdata->slots[j],
+ hostdata->slots[j].cmnd));
+ hostdata->saved_slot_position = j + 1;
+ }
+
+ break;
+ }
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/* FIXME: Need to put some proc information in and plumb it
+ * into the scsi proc system */
+STATIC int
+NCR_700_proc_directory_info(char *proc_buf, char **startp,
+ off_t offset, int bytes_available,
+ int host_no, int write)
+{
+ static char buf[4096]; /* 1 page should be sufficient */
+ int len = 0;
+ struct Scsi_Host *host = scsi_hostlist;
+ struct NCR_700_Host_Parameters *hostdata;
+ Scsi_Device *SDp;
+
+ while(host != NULL && host->host_no != host_no)
+ host = host->next;
+
+ if(host == NULL)
+ return 0;
+
+ if(write) {
+ /* FIXME: Clear internal statistics here */
+ return 0;
+ }
+ hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ len += sprintf(&buf[len], "Total commands outstanding: %d\n", hostdata->command_slot_count);
+ len += sprintf(&buf[len],"\
+Target Depth Active Next Tag\n\
+====== ===== ====== ========\n");
+ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) {
+ len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag);
+ }
+ if((len -= offset) <= 0)
+ return 0;
+ if(len > bytes_available)
+ len = bytes_available;
+ memcpy(proc_buf, buf + offset, len);
+ return len;
+}
+
+STATIC int
+NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+ __u32 move_ins;
+ struct NCR_700_command_slot *slot;
+ int hash;
+
+ if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
+ /* We're over our allocation, this should never happen
+ * since we report the max allocation to the mid layer */
+ printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no);
+ return 1;
+ }
+ if(NCR_700_get_depth(SCp->device) != 0 && !(hostdata->tag_negotiated & (1<<SCp->target))) {
+ DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n",
+ SCp->host->host_no, SCp->target, SCp->lun,
+ NCR_700_get_depth(SCp->device)));
+ return 1;
+ }
+ if(NCR_700_get_depth(SCp->device) >= NCR_700_MAX_TAGS) {
+ DEBUG((KERN_ERR "scsi%d (%d:%d) has max tag depth %d\n",
+ SCp->host->host_no, SCp->target, SCp->lun,
+ NCR_700_get_depth(SCp->device)));
+ return 1;
+ }
+ NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1);
+
+ /* begin the command here */
+ /* no need to check for NULL, test for command_slot_cound above
+ * ensures a slot is free */
+ slot = find_empty_slot(hostdata);
+
+ slot->cmnd = SCp;
+
+ SCp->scsi_done = done;
+ SCp->host_scribble = (unsigned char *)slot;
+ SCp->SCp.ptr = NULL;
+ SCp->SCp.buffer = NULL;
+
+#ifdef NCR_700_DEBUG
+ printk("53c700: scsi%d, command ", SCp->host->host_no);
+ print_command(SCp->cmnd);
+#endif
+
+ if(hostdata->tag_negotiated &(1<<SCp->target)) {
+
+ struct NCR_700_command_slot *old =
+ find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
+#ifdef NCR_700_TAG_DEBUG
+ struct NCR_700_command_slot *found;
+#endif
+
+ if(old != NULL && old->tag == SCp->device->current_tag) {
+ printk(KERN_WARNING "scsi%d (%d:%d) Tag clock back to current, queueing\n", SCp->host->host_no, SCp->target, SCp->lun);
+ return 1;
+ }
+ slot->tag = SCp->device->current_tag++;
+#ifdef NCR_700_TAG_DEBUG
+ while((found = find_ITLQ_Nexus(hostdata, SCp->target, SCp->lun, slot->tag)) != NULL) {
+ printk("\n\n**ERROR** already using tag %d, but oldest is %d\n", slot->tag, (old == NULL) ? -1 : old->tag);
+ printk(" FOUND = %p, tag = %d, pun = %d, lun = %d\n",
+ found, found->tag, found->cmnd->target, found->cmnd->lun);
+ slot->tag = SCp->device->current_tag++;
+ printk(" Tag list is: ");
+ while(old != NULL) {
+ if(old->cmnd->target == SCp->target &&
+ old->cmnd->lun == SCp->lun)
+ printk("%d ", old->tag);
+ old = old->ITL_back;
+ }
+ printk("\n\n");
+ }
+#endif
+ hash = hash_ITLQ(SCp->target, SCp->lun, slot->tag);
+ /* link into the ITLQ hash queues */
+ slot->ITLQ_forw = hostdata->ITLQ_Hash_forw[hash];
+ hostdata->ITLQ_Hash_forw[hash] = slot;
+#ifdef NCR_700_TAG_DEBUG
+ if(slot->ITLQ_forw != NULL && slot->ITLQ_forw->ITLQ_back != NULL) {
+ printk(KERN_ERR "scsi%d (%d:%d) ITLQ_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun);
+ }
+#endif
+ if(slot->ITLQ_forw != NULL)
+ slot->ITLQ_forw->ITLQ_back = slot;
+ else
+ hostdata->ITLQ_Hash_back[hash] = slot;
+ slot->ITLQ_back = NULL;
+ } else {
+ slot->tag = NCR_700_NO_TAG;
+ }
+ /* link into the ITL hash queues */
+ hash = hash_ITL(SCp->target, SCp->lun);
+ slot->ITL_forw = hostdata->ITL_Hash_forw[hash];
+ hostdata->ITL_Hash_forw[hash] = slot;
+#ifdef NCR_700_TAG_DEBUG
+ if(slot->ITL_forw != NULL && slot->ITL_forw->ITL_back != NULL) {
+ printk(KERN_ERR "scsi%d (%d:%d) ITL_back is not NULL!!!!\n",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ }
+#endif
+ if(slot->ITL_forw != NULL)
+ slot->ITL_forw->ITL_back = slot;
+ else
+ hostdata->ITL_Hash_back[hash] = slot;
+ slot->ITL_back = NULL;
+
+
+ /* This is f****g ridiculous; every low level HBA driver has
+ * to determine the direction of the commands, why isn't this
+ * done inside the scsi_lib !!??? */
+ switch (SCp->cmnd[0]) {
+ case REQUEST_SENSE:
+ /* clear the internal sense magic */
+ SCp->cmnd[6] = 0;
+ /* fall through */
+ case INQUIRY:
+ case MODE_SENSE:
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_CAPACITY:
+ case READ_BLOCK_LIMITS:
+ case READ_TOC:
+ move_ins = SCRIPT_MOVE_DATA_IN;
+ break;
+ case MODE_SELECT:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ move_ins = SCRIPT_MOVE_DATA_OUT;
+ break;
+ case TEST_UNIT_READY:
+ case ALLOW_MEDIUM_REMOVAL:
+ case START_STOP:
+ move_ins = 0;
+ break;
+ default:
+ /* OK, get it from the command */
+ switch(SCp->sc_data_direction) {
+ case SCSI_DATA_UNKNOWN:
+ default:
+ printk(KERN_ERR "53c700: Unknown command for data direction ");
+ print_command(SCp->cmnd);
+
+ move_ins = 0;
+ break;
+ case SCSI_DATA_NONE:
+ move_ins = 0;
+ break;
+ case SCSI_DATA_READ:
+ move_ins = SCRIPT_MOVE_DATA_IN;
+ break;
+ case SCSI_DATA_WRITE:
+ move_ins = SCRIPT_MOVE_DATA_OUT;
+ break;
+ }
+ }
+
+ /* now build the scatter gather list */
+ if(move_ins != 0) {
+ int i;
+
+ for(i = 0; i < (SCp->use_sg ? SCp->use_sg : 1); i++) {
+ void *vPtr;
+ __u32 count;
+
+ if(SCp->use_sg) {
+ vPtr = (((struct scatterlist *)SCp->buffer)[i].address);
+ count = ((struct scatterlist *)SCp->buffer)[i].length;
+ } else {
+ vPtr = SCp->request_buffer;
+ count = SCp->request_bufflen;
+ }
+ slot->SG[i].ins = bS_to_host(move_ins | count);
+ DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
+ i, count, slot->SG[i].ins,
+ virt_to_bus(vPtr)));
+ dma_cache_wback_inv((unsigned long)vPtr, count);
+ slot->SG[i].pAddr = bS_to_host(virt_to_bus(vPtr));
+ }
+ slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
+ slot->SG[i].pAddr = 0;
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ DEBUG((" SETTING %08lx to %x\n",
+ virt_to_bus(&slot->SG[i].ins),
+ slot->SG[i].ins));
+ }
+ slot->resume_offset = 0;
+ NCR_700_start_command(SCp);
+ return 0;
+}
+
+STATIC int
+NCR_700_abort(Scsi_Cmnd * SCp)
+{
+ struct NCR_700_command_slot *slot;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ slot = find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
+ while(slot != NULL && slot->cmnd != SCp)
+ slot = slot->ITL_back;
+
+ if(slot == NULL)
+ /* no outstanding command to abort */
+ return SUCCESS;
+ if(SCp->cmnd[0] == TEST_UNIT_READY) {
+ /* FIXME: This is because of a problem in the new
+ * error handler. When it is in error recovery, it
+ * will send a TUR to a device it thinks may still be
+ * showing a problem. If the TUR isn't responded to,
+ * it will abort it and mark the device off line.
+ * Unfortunately, it does no other error recovery, so
+ * this would leave us with an outstanding command
+ * occupying a slot. Rather than allow this to
+ * happen, we issue a bus reset to force all
+ * outstanding commands to terminate here. */
+ NCR_700_internal_bus_reset(SCp->host);
+ /* still drop through and return failed */
+ }
+ return FAILED;
+
+}
+
+STATIC int
+NCR_700_bus_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun, SCp);
+ print_command(SCp->cmnd);
+ NCR_700_internal_bus_reset(SCp->host);
+ return SUCCESS;
+}
+
+STATIC int
+NCR_700_dev_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ return FAILED;
+}
+
+STATIC int
+NCR_700_host_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants HOST reset\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ NCR_700_internal_bus_reset(SCp->host);
+ NCR_700_chip_reset(SCp->host);
+ return SUCCESS;
+}
+
+EXPORT_SYMBOL(NCR_700_detect);
+EXPORT_SYMBOL(NCR_700_release);
+EXPORT_SYMBOL(NCR_700_intr);
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
new file mode 100644
index 000000000000..ea77fd0d541d
--- /dev/null
+++ b/drivers/scsi/53c700.c
@@ -0,0 +1,1840 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR (or Symbios) 53c700 and 53c700-66 Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/* Notes:
+ *
+ * This driver is designed exclusively for these chips (virtually the
+ * earliest of the scripts engine chips). They need their own drivers
+ * because they are missing so many of the scripts and snazzy register
+ * features of their elder brothers (the 710, 720 and 770).
+ *
+ * The 700 is the lowliest of the line, it can only do async SCSI.
+ * The 700-66 can at least do synchronous SCSI up to 10MHz.
+ *
+ * The 700 chip has no host bus interface logic of its own. However,
+ * it is usually mapped to a location with well defined register
+ * offsets. Therefore, if you can determine the base address and the
+ * irq your board incorporating this chip uses, you can probably use
+ * this driver to run it (although you'll probably have to write a
+ * minimal wrapper for the purpose---see the NCR_D700 driver for
+ * details about how to do this).
+ *
+ *
+ * TODO List:
+ *
+ * 1. Better statistics in the proc fs
+ *
+ * 2. Implement message queue (queues SCSI messages like commands) and make
+ * the abort and device reset functions use them.
+ * */
+
+/* CHANGELOG
+ *
+ * Version 2.3
+ *
+ * More endianness/cache coherency changes.
+ *
+ * Better bad device handling (handles devices lying about tag
+ * queueing support and devices which fail to provide sense data on
+ * contingent allegiance conditions)
+ *
+ * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
+ * debugging this driver on the parisc architecture and suggesting
+ * many improvements and bug fixes.
+ *
+ * Thanks also go to Linuxcare Inc. for providing several PARISC
+ * machines for me to debug the driver on.
+ *
+ * Version 2.2
+ *
+ * Made the driver mem or io mapped; added endian invariance; added
+ * dma cache flushing operations for architectures which need it;
+ * added support for more varied clocking speeds.
+ *
+ * Version 2.1
+ *
+ * Initial modularisation from the D700. See NCR_D700.c for the rest of
+ * the changelog.
+ * */
+#define NCR_700_VERSION "2.3"
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+#include <linux/blk.h>
+#include <linux/module.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#include "53c700.h"
+
+#ifdef NCR_700_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("53c700 and 53c700-66 Driver");
+MODULE_LICENSE("GPL");
+
+/* This is the script */
+#include "53c700_d.h"
+
+
+STATIC int NCR_700_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+STATIC int NCR_700_abort(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_proc_directory_info(char *, char **, off_t, int, int, int);
+STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
+STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
+
+static char *NCR_700_phase[] = {
+ "",
+ "after selection",
+ "before command phase",
+ "after command phase",
+ "after status phase",
+ "after data in phase",
+ "after data out phase",
+ "during data phase",
+};
+
+static char *NCR_700_condition[] = {
+ "",
+ "NOT MSG_OUT",
+ "UNEXPECTED PHASE",
+ "NOT MSG_IN",
+ "UNEXPECTED MSG",
+ "MSG_IN",
+ "SDTR_MSG RECEIVED",
+ "REJECT_MSG RECEIVED",
+ "DISCONNECT_MSG RECEIVED",
+ "MSG_OUT",
+ "DATA_IN",
+
+};
+
+static char *NCR_700_fatal_messages[] = {
+ "unexpected message after reselection",
+ "still MSG_OUT after message injection",
+ "not MSG_IN after selection",
+ "Illegal message length received",
+};
+
+static char *NCR_700_SBCL_bits[] = {
+ "IO ",
+ "CD ",
+ "MSG ",
+ "ATN ",
+ "SEL ",
+ "BSY ",
+ "ACK ",
+ "REQ ",
+};
+
+static char *NCR_700_SBCL_to_phase[] = {
+ "DATA_OUT",
+ "DATA_IN",
+ "CMD_OUT",
+ "STATE",
+ "ILLEGAL PHASE",
+ "ILLEGAL PHASE",
+ "MSG OUT",
+ "MSG IN",
+};
+
+static __u8 NCR_700_SDTR_msg[] = {
+ 0x01, /* Extended message */
+ 0x03, /* Extended message Length */
+ 0x01, /* SDTR Extended message */
+ NCR_700_MIN_PERIOD,
+ NCR_700_MAX_OFFSET
+};
+
+struct Scsi_Host * __init
+NCR_700_detect(Scsi_Host_Template *tpnt,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ __u32 *script = kmalloc(sizeof(SCRIPT), GFP_KERNEL);
+ __u32 pScript;
+ struct Scsi_Host *host;
+ static int banner = 0;
+ int j;
+
+ /* Fill in the missing routines from the host template */
+ tpnt->queuecommand = NCR_700_queuecommand;
+ tpnt->eh_abort_handler = NCR_700_abort;
+ tpnt->eh_device_reset_handler = NCR_700_dev_reset;
+ tpnt->eh_bus_reset_handler = NCR_700_bus_reset;
+ tpnt->eh_host_reset_handler = NCR_700_host_reset;
+ tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST;
+ tpnt->sg_tablesize = NCR_700_SG_SEGMENTS;
+ tpnt->cmd_per_lun = NCR_700_MAX_TAGS;
+ tpnt->use_clustering = DISABLE_CLUSTERING;
+ tpnt->use_new_eh_code = 1;
+ tpnt->proc_info = NCR_700_proc_directory_info;
+
+ if(tpnt->name == NULL)
+ tpnt->name = "53c700";
+ if(tpnt->proc_name == NULL)
+ tpnt->proc_name = "53c700";
+
+
+ if((host = scsi_register(tpnt, 4)) == NULL)
+ return NULL;
+ if(script == NULL) {
+ printk(KERN_ERR "53c700: Failed to allocate script, detatching\n");
+ scsi_unregister(host);
+ return NULL;
+ }
+
+ hostdata->slots = kmalloc(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST, GFP_KERNEL);
+ if(hostdata->slots == NULL) {
+ printk(KERN_ERR "53c700: Failed to allocate command slots, detatching\n");
+ scsi_unregister(host);
+ return NULL;
+ }
+ memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST);
+ for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
+ if(j == 0)
+ hostdata->free_list = &hostdata->slots[j];
+ else
+ hostdata->slots[j-1].ITL_forw = &hostdata->slots[j];
+ hostdata->slots[j].state = NCR_700_SLOT_FREE;
+ }
+ host->hostdata[0] = (__u32)hostdata;
+ for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) {
+ script[j] = bS_to_host(SCRIPT[j]);
+ }
+ /* bus physical address of script */
+ pScript = virt_to_bus(script);
+ /* adjust all labels to be bus physical */
+ for(j = 0; j < PATCHES; j++) {
+ script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
+ }
+ /* now patch up fixed addresses */
+ script_patch_32(script, MessageLocation,
+ virt_to_bus(&hostdata->msgout[0]));
+ script_patch_32(script, StatusAddress,
+ virt_to_bus(&hostdata->status));
+ script_patch_32(script, ReceiveMsgAddress,
+ virt_to_bus(&hostdata->msgin[0]));
+
+ hostdata->script = script;
+ hostdata->pScript = pScript;
+ hostdata->state = NCR_700_HOST_FREE;
+ spin_lock_init(&hostdata->lock);
+ hostdata->cmd = NULL;
+ host->max_id = 7;
+ host->max_lun = NCR_700_MAX_LUNS;
+ host->unique_id = hostdata->base;
+ host->base = hostdata->base;
+ host->hostdata[0] = (unsigned long)hostdata;
+ /* kick the chip */
+ NCR_700_writeb(0xff, host, CTEST9_REG);
+ hostdata->rev = (NCR_700_readb(host, CTEST7_REG)<<4) & 0x0f;
+ hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0);
+ if(banner == 0) {
+ printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n");
+ banner = 1;
+ }
+ printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
+ hostdata->fast ? "53c700-66" : "53c700",
+ hostdata->rev, hostdata->differential ?
+ "(Differential)" : "");
+ /* reset the chip */
+ NCR_700_chip_reset(host);
+ NCR_700_writeb(ASYNC_OPERATION , host, SXFER_REG);
+
+ return host;
+}
+
+int
+NCR_700_release(struct Scsi_Host *host)
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ kfree(hostdata->script);
+ return 1;
+}
+
+static inline __u8
+NCR_700_identify(int can_disconnect, __u8 lun)
+{
+ return IDENTIFY_BASE |
+ ((can_disconnect) ? 0x40 : 0) |
+ (lun & NCR_700_LUN_MASK);
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip. If you
+ * really want to know what this function is doing, it's almost a
+ * direct transcription of the algorithm described in the 53c710
+ * guide, except that the DBC and DFIFO registers are only 6 bits
+ * wide.
+ *
+ * Inputs : host - SCSI host */
+static inline int
+NCR_700_data_residual (struct Scsi_Host *host) {
+ int count, synchronous;
+ unsigned int ddir;
+
+ count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
+ (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
+
+ synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
+
+ /* get the data direction */
+ ddir = NCR_700_readb(host, CTEST0_REG) & 0x01;
+
+ if (ddir) {
+ /* Receive */
+ if (synchronous)
+ count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4;
+ else
+ if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL)
+ ++count;
+ } else {
+ /* Send */
+ __u8 sstat = NCR_700_readb(host, SSTAT1_REG);
+ if (sstat & SODL_REG_FULL)
+ ++count;
+ if (synchronous && (sstat & SODR_REG_FULL))
+ ++count;
+ }
+ return count;
+}
+
+/* print out the SCSI wires and corresponding phase from the SBCL register
+ * in the chip */
+static inline char *
+sbcl_to_string(__u8 sbcl)
+{
+ int i;
+ static char ret[256];
+
+ ret[0]='\0';
+ for(i=0; i<8; i++) {
+ if((1<<i) & sbcl)
+ strcat(ret, NCR_700_SBCL_bits[i]);
+ }
+ strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]);
+ return ret;
+}
+
+static inline __u8
+bitmap_to_number(__u8 bitmap)
+{
+ __u8 i;
+
+ for(i=0; i<8 && !(bitmap &(1<<i)); i++)
+ ;
+ return i;
+}
+
+/* Pull a slot off the free list */
+STATIC struct NCR_700_command_slot *
+find_empty_slot(struct NCR_700_Host_Parameters *hostdata)
+{
+ struct NCR_700_command_slot *slot = hostdata->free_list;
+
+ if(slot == NULL) {
+ /* sanity check */
+ if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST)
+ printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST);
+ return NULL;
+ }
+
+ if(slot->state != NCR_700_SLOT_FREE)
+ /* should panic! */
+ printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n");
+
+
+ hostdata->free_list = slot->ITL_forw;
+ slot->ITL_forw = NULL;
+
+
+ /* NOTE: set the state to busy here, not queued, since this
+ * indicates the slot is in use and cannot be run by the IRQ
+ * finish routine. If we cannot queue the command when it
+ * is properly build, we then change to NCR_700_SLOT_QUEUED */
+ slot->state = NCR_700_SLOT_BUSY;
+ hostdata->command_slot_count++;
+
+ return slot;
+}
+
+STATIC void
+free_slot(struct NCR_700_command_slot *slot,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ int hash;
+ struct NCR_700_command_slot **forw, **back;
+
+
+ if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
+ printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
+ }
+ if(slot->state == NCR_700_SLOT_FREE) {
+ printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
+ }
+ /* remove from queues */
+ if(slot->tag != NCR_700_NO_TAG) {
+ hash = hash_ITLQ(slot->cmnd->target, slot->cmnd->lun,
+ slot->tag);
+ if(slot->ITLQ_forw == NULL)
+ back = &hostdata->ITLQ_Hash_back[hash];
+ else
+ back = &slot->ITLQ_forw->ITLQ_back;
+
+ if(slot->ITLQ_back == NULL)
+ forw = &hostdata->ITLQ_Hash_forw[hash];
+ else
+ forw = &slot->ITLQ_back->ITLQ_forw;
+
+ *forw = slot->ITLQ_forw;
+ *back = slot->ITLQ_back;
+ }
+ hash = hash_ITL(slot->cmnd->target, slot->cmnd->lun);
+ if(slot->ITL_forw == NULL)
+ back = &hostdata->ITL_Hash_back[hash];
+ else
+ back = &slot->ITL_forw->ITL_back;
+
+ if(slot->ITL_back == NULL)
+ forw = &hostdata->ITL_Hash_forw[hash];
+ else
+ forw = &slot->ITL_back->ITL_forw;
+
+ *forw = slot->ITL_forw;
+ *back = slot->ITL_back;
+
+ slot->resume_offset = 0;
+ slot->cmnd = NULL;
+ slot->state = NCR_700_SLOT_FREE;
+ slot->ITL_forw = hostdata->free_list;
+ hostdata->free_list = slot;
+ hostdata->command_slot_count--;
+}
+
+
+/* This routine really does very little. The command is indexed on
+ the ITL and (if tagged) the ITLQ lists in _queuecommand */
+STATIC void
+save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp)
+{
+ /* Its just possible that this gets executed twice */
+ if(SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ slot->resume_offset = dsp;
+ }
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+}
+
+/* Most likely nexus is the oldest in each case */
+STATIC inline struct NCR_700_command_slot *
+find_ITL_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun, __u8 lun)
+{
+ int hash = hash_ITL(pun, lun);
+ struct NCR_700_command_slot *slot = hostdata->ITL_Hash_back[hash];
+ while(slot != NULL && !(slot->cmnd->target == pun &&
+ slot->cmnd->lun == lun))
+ slot = slot->ITL_back;
+ return slot;
+}
+
+STATIC inline struct NCR_700_command_slot *
+find_ITLQ_Nexus(struct NCR_700_Host_Parameters *hostdata, __u8 pun,
+ __u8 lun, __u8 tag)
+{
+ int hash = hash_ITLQ(pun, lun, tag);
+ struct NCR_700_command_slot *slot = hostdata->ITLQ_Hash_back[hash];
+
+ while(slot != NULL && !(slot->cmnd->target == pun
+ && slot->cmnd->lun == lun && slot->tag == tag))
+ slot = slot->ITLQ_back;
+
+#ifdef NCR_700_TAG_DEBUG
+ if(slot != NULL) {
+ struct NCR_700_command_slot *n = slot->ITLQ_back;
+ while(n != NULL && n->cmnd->target != pun
+ && n->cmnd->lun != lun && n->tag != tag)
+ n = n->ITLQ_back;
+
+ if(n != NULL && n->cmnd->target == pun && n->cmnd->lun == lun
+ && n->tag == tag) {
+ printk(KERN_WARNING "53c700: WARNING: DUPLICATE tag %d\n",
+ tag);
+ }
+ }
+#endif
+ return slot;
+}
+
+
+
+/* This translates the SDTR message offset and period to a value
+ * which can be loaded into the SXFER_REG.
+ *
+ * NOTE: According to SCSI-2, the true transfer period (in ns) is
+ * actually four times this period value */
+STATIC inline __u8
+NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
+ __u8 offset, __u8 period)
+{
+ int XFERP;
+
+ if(period*4 < NCR_700_MIN_PERIOD) {
+ printk(KERN_WARNING "53c700: Period %dns is less than SCSI-2 minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD);
+ period = NCR_700_MIN_PERIOD/4;
+ }
+ XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
+ if(offset > NCR_700_MAX_OFFSET) {
+ printk(KERN_WARNING "53c700: Offset %d exceeds maximum, setting to %d\n",
+ offset, NCR_700_MAX_OFFSET);
+ offset = NCR_700_MAX_OFFSET;
+ }
+ if(XFERP < NCR_700_MIN_XFERP) {
+ printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
+ XFERP, NCR_700_MIN_XFERP);
+ XFERP = NCR_700_MIN_XFERP;
+ }
+ return (offset & 0x0f) | (XFERP & 0x07)<<4;
+}
+
+
+STATIC inline void
+NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, int result)
+{
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+
+ if(SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {
+#ifdef NCR_700_DEBUG
+ printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is",
+ SCp, SCp->cmnd[7], result);
+ print_sense("53c700", SCp);
+#endif
+ if(result == 0)
+ result = SCp->cmnd[7];
+ }
+
+ free_slot(slot, hostdata);
+
+ SCp->host_scribble = NULL;
+ SCp->result = result;
+ SCp->scsi_done(SCp);
+ if(NCR_700_get_depth(SCp->device) == 0 ||
+ NCR_700_get_depth(SCp->device) > NCR_700_MAX_TAGS)
+ printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n",
+ NCR_700_get_depth(SCp->device));
+ NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
+ } else {
+ printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n");
+ }
+}
+
+
+STATIC void
+NCR_700_internal_bus_reset(struct Scsi_Host *host)
+{
+ /* Bus reset */
+ NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG);
+ udelay(50);
+ NCR_700_writeb(0, host, SCNTL1_REG);
+
+}
+
+STATIC void
+NCR_700_chip_setup(struct Scsi_Host *host)
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ NCR_700_writeb(1 << host->this_id, host, SCID_REG);
+ NCR_700_writeb(0, host, SBCL_REG);
+ NCR_700_writeb(0, host, SXFER_REG);
+
+ NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT
+ | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG);
+
+ NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG);
+ NCR_700_writeb(BURST_LENGTH_8, host, DMODE_REG);
+ NCR_700_writeb(FULL_ARBITRATION | PARITY | AUTO_ATN, host, SCNTL0_REG);
+ NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION|GENERATE_RECEIVE_PARITY,
+ host, CTEST8_REG);
+ NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG);
+ if(hostdata->clock > 75) {
+ printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock);
+ /* do the best we can, but the async clock will be out
+ * of spec: sync divider 2, async divider 3 */
+ DEBUG(("53c700: sync 2 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock/2;
+ } else if(hostdata->clock > 50 && hostdata->clock <= 75) {
+ /* sync divider 1.5, async divider 3 */
+ DEBUG(("53c700: sync 1.5 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock*2;
+ hostdata->sync_clock /= 3;
+
+ } else if(hostdata->clock > 37 && hostdata->clock <= 50) {
+ /* sync divider 1, async divider 2 */
+ DEBUG(("53c700: sync 1 async 2\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_2_0, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else if(hostdata->clock > 25 && hostdata->clock <=37) {
+ /* sync divider 1, async divider 1.5 */
+ DEBUG(("53c700: sync 1 async 1.5\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_5, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else {
+ DEBUG(("53c700: sync 1 async 1\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_0, host, DCNTL_REG);
+ /* sync divider 1, async divider 1 */
+ }
+}
+
+STATIC void
+NCR_700_chip_reset(struct Scsi_Host *host)
+{
+ /* Chip reset */
+ NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
+ udelay(100);
+
+ NCR_700_writeb(0, host, DCNTL_REG);
+
+ mdelay(1000);
+
+ NCR_700_chip_setup(host);
+}
+
+/* The heart of the message processing engine is that the instruction
+ * immediately after the INT is the normal case (and so must be CLEAR
+ * ACK). If we want to do something else, we call that routine in
+ * scripts and set temp to be the normal case + 8 (skipping the CLEAR
+ * ACK) so that the routine returns correctly to resume its activity
+ * */
+STATIC __u32
+process_extended_message(struct Scsi_Host *host,
+ struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+ __u32 resume_offset = dsp, temp = dsp + 8;
+ __u8 pun = 0xff, lun = 0xff;
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ switch(hostdata->msgin[2]) {
+ case A_SDTR_MSG:
+ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+ __u8 period = hostdata->msgin[3];
+ __u8 offset = hostdata->msgin[4];
+ __u8 sxfer;
+
+ if(offset != 0 && period != 0)
+ sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period);
+ else
+ sxfer = 0;
+
+ if(sxfer != NCR_700_get_SXFER(SCp->device)) {
+ printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
+ host->host_no, pun, lun,
+ offset, period*4);
+
+ NCR_700_set_SXFER(SCp->device, sxfer);
+ }
+
+
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+
+ NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+ host, SXFER_REG);
+
+ } else {
+ /* SDTR message out of the blue, reject it */
+ printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n",
+ host->host_no);
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+ }
+ break;
+
+ case A_WDTR_MSG:
+ printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
+ host->host_no, pun, lun);
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+ break;
+
+ default:
+ printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ print_msg(hostdata->msgin);
+ printk("\n");
+ /* just reject it */
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+ }
+ NCR_700_writel(temp, host, TEMP_REG);
+ return resume_offset;
+}
+
+STATIC __u32
+process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata,
+ Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+ /* work out where to return to */
+ __u32 temp = dsp + 8, resume_offset = dsp;
+ __u8 pun = 0xff, lun = 0xff;
+
+ dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+#ifdef NCR_700_DEBUG
+ printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ print_msg(hostdata->msgin);
+ printk("\n");
+#endif
+
+ switch(hostdata->msgin[0]) {
+
+ case A_EXTENDED_MSG:
+ return process_extended_message(host, hostdata, SCp,
+ dsp, dsps);
+
+ case A_REJECT_MSG:
+ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+ /* Rejected our sync negotiation attempt */
+ NCR_700_set_SXFER(SCp->device, 0);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
+ /* rejected our first simple tag message */
+ printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ hostdata->tag_negotiated &= ~(1<<SCp->target);
+ } else {
+ printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ /* however, just ignore it */
+ }
+ break;
+
+ case A_PARITY_ERROR_MSG:
+ printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no,
+ pun, lun);
+ NCR_700_internal_bus_reset(host);
+ break;
+ case A_SIMPLE_TAG_MSG:
+ printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no,
+ pun, lun, hostdata->msgin[1],
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+ /* just ignore it */
+ break;
+ default:
+ printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+ host->host_no, pun, lun,
+ NCR_700_phase[(dsps & 0xf00) >> 8]);
+
+ print_msg(hostdata->msgin);
+ printk("\n");
+ /* just reject it */
+ hostdata->msgout[0] = A_REJECT_MSG;
+ dma_cache_wback((unsigned long)hostdata->msgout, sizeof(hostdata->msgout));
+ script_patch_16(hostdata->script, MessageCount, 1);
+ /* SendMsgOut returns, so set up the return
+ * address */
+ resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+ break;
+ }
+ NCR_700_writel(temp, host, TEMP_REG);
+ return resume_offset;
+}
+
+STATIC __u32
+process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
+ struct Scsi_Host *host,
+ struct NCR_700_Host_Parameters *hostdata)
+{
+ __u32 resume_offset = 0;
+ __u8 pun = 0xff, lun=0xff;
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
+ dma_cache_inv((unsigned long)hostdata->status, sizeof(hostdata->status));
+ DEBUG((" COMMAND COMPLETE, status=%02x\n",
+ hostdata->status));
+ /* OK, if TCQ still on, we know it works */
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* check for contingent allegiance contitions */
+ if(status_byte(hostdata->status) == CHECK_CONDITION ||
+ status_byte(hostdata->status) == COMMAND_TERMINATED) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ if(SCp->cmnd[0] == REQUEST_SENSE) {
+ /* OOPS: bad device, returning another
+ * contingent allegiance condition */
+ printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun);
+ NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+ } else {
+
+ DEBUG((" cmd %p has status %d, requesting sense\n",
+ SCp, hostdata->status));
+ /* we can destroy the command here because the
+ * contingent allegiance condition will cause a
+ * retry which will re-copy the command from the
+ * saved data_cmnd */
+ SCp->cmnd[0] = REQUEST_SENSE;
+ SCp->cmnd[1] = (SCp->lun & 0x7) << 5;
+ SCp->cmnd[2] = 0;
+ SCp->cmnd[3] = 0;
+ SCp->cmnd[4] = sizeof(SCp->sense_buffer);
+ SCp->cmnd[5] = 0;
+ SCp->cmd_len = 6;
+ /* Here's a quiet hack: the REQUEST_SENSE command is
+ * six bytes, so store a flag indicating that this
+ * was an internal sense request and the original
+ * status at the end of the command */
+ SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
+ SCp->cmnd[7] = hostdata->status;
+ slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
+ slot->SG[0].pAddr = bS_to_host(virt_to_bus(SCp->sense_buffer));
+ slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
+ slot->SG[1].pAddr = 0;
+ slot->resume_offset = hostdata->pScript;
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG[0])*2);
+ dma_cache_inv((unsigned long)SCp->sense_buffer, sizeof(SCp->sense_buffer));
+
+ /* queue the command for reissue */
+ slot->state = NCR_700_SLOT_QUEUED;
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+ }
+ } else {
+ if(status_byte(hostdata->status) == GOOD &&
+ SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
+ /* Piggy back the tag queueing support
+ * on this command */
+ if(((char *)SCp->request_buffer)[7] & 0x02) {
+ printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun);
+ hostdata->tag_negotiated |= (1<<SCp->target);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ } else {
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ hostdata->tag_negotiated &= ~(1<<SCp->target);
+ }
+ }
+ NCR_700_scsi_done(hostdata, SCp, hostdata->status);
+ }
+ } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) {
+ __u8 i = (dsps & 0xf00) >> 8;
+
+ printk(KERN_ERR "scsi%d: (%d:%d), UNEXPECTED PHASE %s (%s)\n",
+ host->host_no, pun, lun,
+ NCR_700_phase[i],
+ sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+ printk(KERN_ERR " len = %d, cmd =", SCp->cmd_len);
+ print_command(SCp->cmnd);
+
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff000) == A_FATAL) {
+ int i = (dsps & 0xfff);
+
+ printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n",
+ host->host_no, pun, lun, NCR_700_fatal_messages[i]);
+ if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) {
+ printk(KERN_ERR " msg begins %02x %02x\n",
+ hostdata->msgin[0], hostdata->msgin[1]);
+ }
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff0f0) == A_DISCONNECT) {
+#ifdef NCR_700_DEBUG
+ __u8 i = (dsps & 0xf00) >> 8;
+
+ printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n",
+ host->host_no, pun, lun,
+ i, NCR_700_phase[i]);
+#endif
+ save_for_reselection(hostdata, SCp, dsp);
+
+ } else if(dsps == A_RESELECTION_IDENTIFIED) {
+ __u8 lun;
+ struct NCR_700_command_slot *slot;
+ __u8 reselection_id = hostdata->reselection_id;
+
+ dma_cache_inv((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ lun = hostdata->msgin[0] & 0x1f;
+
+ hostdata->reselection_id = 0xff;
+ DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
+ host->host_no, reselection_id, lun));
+ /* clear the reselection indicator */
+ if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
+ slot = find_ITLQ_Nexus(hostdata, reselection_id,
+ lun, hostdata->msgin[2]);
+ } else {
+ slot = find_ITL_Nexus(hostdata, reselection_id, lun);
+ }
+ retry:
+ if(slot == NULL) {
+ struct NCR_700_command_slot *s = find_ITL_Nexus(hostdata, reselection_id, lun);
+ printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
+ host->host_no, reselection_id, lun,
+ hostdata->msgin[0], hostdata->msgin[1],
+ hostdata->msgin[2]);
+ printk(KERN_ERR " OUTSTANDING TAGS:");
+ while(s != NULL) {
+ if(s->cmnd->target == reselection_id &&
+ s->cmnd->lun == lun) {
+ printk("%d ", s->tag);
+ if(s->tag == hostdata->msgin[2]) {
+ printk(" ***FOUND*** \n");
+ slot = s;
+ goto retry;
+ }
+
+ }
+ s = s->ITL_back;
+ }
+ printk("\n");
+ } else {
+ if(hostdata->state != NCR_700_HOST_BUSY)
+ printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
+ host->host_no);
+ resume_offset = slot->resume_offset;
+ hostdata->cmd = slot->cmnd;
+
+ /* re-patch for this command */
+ script_patch_32_abs(hostdata->script, CommandAddress,
+ virt_to_bus(slot->cmnd->cmnd));
+ script_patch_16(hostdata->script,
+ CommandCount, slot->cmnd->cmd_len);
+ script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+ virt_to_bus(&slot->SG[0].ins));
+
+ /* Note: setting SXFER only works if we're
+ * still in the MESSAGE phase, so it is vital
+ * that ACK is still asserted when we process
+ * the reselection message. The resume offset
+ * should therefore always clear ACK */
+ NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
+ host, SXFER_REG);
+
+ }
+ } else if(dsps == A_RESELECTED_DURING_SELECTION) {
+
+ /* This section is full of debugging code because I've
+ * never managed to reach it. I think what happens is
+ * that, because the 700 runs with selection
+ * interrupts enabled the whole time that we take a
+ * selection interrupt before we manage to get to the
+ * reselected script interrupt */
+
+ __u8 reselection_id = NCR_700_readb(host, SFBR_REG);
+ struct NCR_700_command_slot *slot;
+
+ /* Take out our own ID */
+ reselection_id &= ~(1<<host->this_id);
+
+ printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%p[%04x] state=%d, count=%d\n",
+ host->host_no, reselection_id, lun, (void *)dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
+
+ {
+ /* FIXME: DEBUGGING CODE */
+ __u32 SG = (__u32)bus_to_virt(hostdata->script[A_SGScriptStartAddress_used[0]]);
+ int i;
+
+ for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ if(SG >= (__u32)(&hostdata->slots[i].SG[0])
+ && SG <= (__u32)(&hostdata->slots[i].SG[NCR_700_SG_SEGMENTS]))
+ break;
+ }
+ printk(KERN_INFO "IDENTIFIED SG segment as being %p in slot %p, cmd %p, slot->resume_offset=%p\n", (void *)SG, &hostdata->slots[i], hostdata->slots[i].cmnd, (void *)hostdata->slots[i].resume_offset);
+ SCp = hostdata->slots[i].cmnd;
+ }
+
+ if(SCp != NULL) {
+ slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+ /* change slot from busy to queued to redo command */
+ slot->state = NCR_700_SLOT_QUEUED;
+ }
+ hostdata->cmd = NULL;
+
+ if(reselection_id == 0) {
+ if(hostdata->reselection_id == 0xff) {
+ printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no);
+ return 0;
+ } else {
+ printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n",
+ host->host_no);
+ reselection_id = hostdata->reselection_id;
+ }
+ } else {
+
+ /* convert to real ID */
+ reselection_id = bitmap_to_number(reselection_id);
+ }
+ hostdata->reselection_id = reselection_id;
+ hostdata->msgin[1] = 0;
+ dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+ if(hostdata->tag_negotiated & (1<<reselection_id)) {
+ resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+ } else {
+ resume_offset = hostdata->pScript + Ent_GetReselectionData;
+ }
+ } else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) {
+ /* we've just disconnected from the bus, do nothing since
+ * a return here will re-run the queued command slot
+ * that may have been interrupted by the initial selection */
+ DEBUG((" SELECTION COMPLETED\n"));
+ } else if((dsps & 0xfffff0f0) == A_MSG_IN) {
+ resume_offset = process_message(host, hostdata, SCp,
+ dsp, dsps);
+ } else if((dsps & 0xfffff000) == 0) {
+ __u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8;
+ printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n",
+ host->host_no, pun, lun, NCR_700_condition[i],
+ NCR_700_phase[j], dsp - hostdata->pScript);
+ if(SCp != NULL) {
+ print_command(SCp->cmnd);
+
+ if(SCp->use_sg) {
+ for(i = 0; i < SCp->use_sg + 1; i++) {
+ printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
+ }
+ }
+ }
+ NCR_700_internal_bus_reset(host);
+ } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
+ printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %p[%04x], continuing\n",
+ host->host_no, pun, lun, dsps & 0xfff, (void *)dsp, dsp - hostdata->pScript);
+ resume_offset = dsp;
+ } else {
+ printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n",
+ host->host_no, pun, lun, dsps, dsp - hostdata->pScript);
+ NCR_700_internal_bus_reset(host);
+ }
+ return resume_offset;
+}
+
+/* We run the 53c700 with selection interrupts always enabled. This
+ * means that the chip may be selected as soon as the bus frees. On a
+ * busy bus, this can be before the scripts engine finishes its
+ * processing. Therefore, part of the selection processing has to be
+ * to find out what the scripts engine is doing and complete the
+ * function if necessary (i.e. process the pending disconnect or save
+ * the interrupted initial selection */
+STATIC inline __u32
+process_selection(struct Scsi_Host *host, __u32 dsp)
+{
+ __u8 id = 0; /* Squash compiler warning */
+ int count = 0;
+ __u32 resume_offset = 0;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ Scsi_Cmnd *SCp = hostdata->cmd;
+ __u8 sbcl;
+
+ for(count = 0; count < 5; count++) {
+ id = NCR_700_readb(host, SFBR_REG);
+
+ /* Take out our own ID */
+ id &= ~(1<<host->this_id);
+ if(id != 0)
+ break;
+ udelay(5);
+ }
+ sbcl = NCR_700_readb(host, SBCL_REG);
+ if((sbcl & SBCL_IO) == 0) {
+ /* mark as having been selected rather than reselected */
+ id = 0xff;
+ } else {
+ /* convert to real ID */
+ hostdata->reselection_id = id = bitmap_to_number(id);
+ DEBUG(("scsi%d: Reselected by %d\n",
+ host->host_no, id));
+ }
+ if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) {
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset));
+
+ switch(dsp - hostdata->pScript) {
+ case Ent_Disconnect1:
+ case Ent_Disconnect2:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript);
+ break;
+ case Ent_Disconnect3:
+ case Ent_Disconnect4:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript);
+ break;
+ case Ent_Disconnect5:
+ case Ent_Disconnect6:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript);
+ break;
+ case Ent_Disconnect7:
+ case Ent_Disconnect8:
+ save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript);
+ break;
+ case Ent_Finish1:
+ case Ent_Finish2:
+ process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata);
+ break;
+
+ default:
+ slot->state = NCR_700_SLOT_QUEUED;
+ break;
+ }
+ }
+ hostdata->state = NCR_700_HOST_BUSY;
+ hostdata->cmd = NULL;
+ hostdata->msgin[1] = 0;
+ dma_cache_wback((unsigned long)hostdata->msgin, sizeof(hostdata->msgin));
+
+ if(id == 0xff) {
+ /* Selected as target, Ignore */
+ resume_offset = hostdata->pScript + Ent_SelectedAsTarget;
+ } else if(hostdata->tag_negotiated & (1<<id)) {
+ resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+ } else {
+ resume_offset = hostdata->pScript + Ent_GetReselectionData;
+ }
+ return resume_offset;
+}
+
+
+STATIC int
+NCR_700_start_command(Scsi_Cmnd *SCp)
+{
+ struct NCR_700_command_slot *slot =
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+ unsigned long flags;
+ __u16 count = 1; /* for IDENTIFY message */
+
+ save_flags(flags);
+ cli();
+ if(hostdata->state != NCR_700_HOST_FREE) {
+ /* keep this inside the lock to close the race window where
+ * the running command finishes on another CPU while we don't
+ * change the state to queued on this one */
+ slot->state = NCR_700_SLOT_QUEUED;
+ restore_flags(flags);
+
+ DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n",
+ SCp->host->host_no, slot->cmnd, slot));
+ return 0;
+ }
+ hostdata->state = NCR_700_HOST_BUSY;
+ hostdata->cmd = SCp;
+ slot->state = NCR_700_SLOT_BUSY;
+ /* keep interrupts disabled until we have the command correctly
+ * set up so we cannot take a selection interrupt */
+
+ hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE,
+ SCp->lun);
+ /* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
+ * if the negotiated transfer parameters still hold, so
+ * always renegotiate them */
+ if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE) {
+ NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+ }
+
+ /* REQUEST_SENSE is asking for contingent I_T_L status. If a
+ * contingent allegiance condition exists, the device will
+ * refuse all tags, so send the request sense as untagged */
+ if((hostdata->tag_negotiated & (1<<SCp->target))
+ && (slot->tag != NCR_700_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
+ hostdata->msgout[count++] = A_SIMPLE_TAG_MSG;
+ hostdata->msgout[count++] = slot->tag;
+ }
+
+ if(hostdata->fast &&
+ NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
+ memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
+ sizeof(NCR_700_SDTR_msg));
+ count += sizeof(NCR_700_SDTR_msg);
+ NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ }
+
+ dma_cache_wback((unsigned long)hostdata->msgout, count);
+
+ script_patch_16(hostdata->script, MessageCount, count);
+
+
+ script_patch_ID(hostdata->script,
+ Device_ID, 1<<SCp->target);
+
+ script_patch_32_abs(hostdata->script, CommandAddress,
+ virt_to_bus(SCp->cmnd));
+ script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
+ /* finally plumb the beginning of the SG list into the script
+ * */
+ script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+ virt_to_bus(&slot->SG[0].ins));
+ NCR_700_writeb(CLR_FIFO, SCp->host, DFIFO_REG);
+
+ /* set the synchronous period/offset */
+ if(slot->resume_offset == 0)
+ slot->resume_offset = hostdata->pScript;
+ NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+ SCp->host, SXFER_REG);
+ /* allow interrupts here so that if we're selected we can take
+ * a selection interrupt. The script start may not be
+ * effective in this case, but the selection interrupt will
+ * save our command in that case */
+ NCR_700_writel(slot->temp, SCp->host, TEMP_REG);
+ NCR_700_writel(slot->resume_offset, SCp->host, DSP_REG);
+ restore_flags(flags);
+
+ return 1;
+}
+
+void
+NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ __u8 istat;
+ __u32 resume_offset = 0;
+ __u8 pun = 0xff, lun = 0xff;
+ unsigned long flags;
+
+ /* Unfortunately, we have to take the io_request_lock here
+ * rather than the host lock hostdata->lock because we're
+ * looking to exclude queuecommand from messing with the
+ * registers while we're processing the interrupt. Since
+ * queuecommand is called holding io_request_lock, and we have
+ * to take io_request_lock before we call the command
+ * scsi_done, we would get a deadlock if we took
+ * hostdata->lock here and in queuecommand (because the order
+ * of locking in queuecommand: 1) io_request_lock then 2)
+ * hostdata->lock would be the reverse of taking it in this
+ * routine */
+ spin_lock_irqsave(&io_request_lock, flags);
+ if((istat = NCR_700_readb(host, ISTAT_REG))
+ & (SCSI_INT_PENDING | DMA_INT_PENDING)) {
+ __u32 dsps;
+ __u8 sstat0 = 0, dstat = 0;
+ __u32 dsp;
+ Scsi_Cmnd *SCp = hostdata->cmd;
+ enum NCR_700_Host_State state;
+
+ state = hostdata->state;
+ SCp = hostdata->cmd;
+
+ if(istat & SCSI_INT_PENDING) {
+ udelay(10);
+
+ sstat0 = NCR_700_readb(host, SSTAT0_REG);
+ }
+
+ if(istat & DMA_INT_PENDING) {
+ udelay(10);
+
+ dstat = NCR_700_readb(host, DSTAT_REG);
+ }
+
+ dsps = NCR_700_readl(host, DSPS_REG);
+ dsp = NCR_700_readl(host, DSP_REG);
+
+ DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n",
+ host->host_no, istat, sstat0, dstat,
+ (dsp - (__u32)virt_to_bus(hostdata->script))/4,
+ dsp, dsps));
+
+ if(SCp != NULL) {
+ pun = SCp->target;
+ lun = SCp->lun;
+ }
+
+ if(sstat0 & SCSI_RESET_DETECTED) {
+ Scsi_Device *SDp;
+ int i;
+
+ hostdata->state = NCR_700_HOST_BUSY;
+
+ printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %p[%04x]\n",
+ host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, (void *)dsp, dsp - hostdata->pScript);
+
+ /* clear all the negotiated parameters */
+ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next)
+ SDp->hostdata = 0;
+
+ /* clear all the slots and their pending commands */
+ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ Scsi_Cmnd *SCp;
+ struct NCR_700_command_slot *slot =
+ &hostdata->slots[i];
+
+ if(slot->state == NCR_700_SLOT_FREE)
+ continue;
+
+ SCp = slot->cmnd;
+ printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n",
+ slot, SCp);
+ free_slot(slot, hostdata);
+ SCp->host_scribble = NULL;
+ NCR_700_set_depth(SCp->device, 0);
+ /* NOTE: deadlock potential here: we
+ * rely on mid-layer guarantees that
+ * scsi_done won't try to issue the
+ * command again otherwise we'll
+ * deadlock on the
+ * hostdata->state_lock */
+ SCp->result = DID_RESET << 16;
+ SCp->scsi_done(SCp);
+ }
+ mdelay(25);
+ NCR_700_chip_setup(host);
+
+ hostdata->state = NCR_700_HOST_FREE;
+ hostdata->cmd = NULL;
+ goto out_unlock;
+ } else if(sstat0 & SELECTION_TIMEOUT) {
+ DEBUG(("scsi%d: (%d:%d) selection timeout\n",
+ host->host_no, pun, lun));
+ NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16);
+ } else if(sstat0 & PHASE_MISMATCH) {
+ struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL :
+ (struct NCR_700_command_slot *)SCp->host_scribble;
+
+ if(dsp == Ent_SendMessage + 8 + hostdata->pScript) {
+ /* It wants to reply to some part of
+ * our message */
+#ifdef NCR_700_DEBUG
+ __u32 temp = NCR_700_readl(host, TEMP_REG);
+ int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host));
+ printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+#endif
+ resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
+ } else if(dsp >= virt_to_bus(&slot->SG[0].ins) &&
+ dsp <= virt_to_bus(&slot->SG[NCR_700_SG_SEGMENTS].ins)) {
+ int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
+ int SGcount = (dsp - virt_to_bus(&slot->SG[0].ins))/sizeof(struct NCR_700_SG_List);
+ int residual = NCR_700_data_residual(host);
+ int i;
+#ifdef NCR_700_DEBUG
+ printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
+ host->host_no, pun, lun,
+ SGcount, data_transfer);
+ print_command(SCp->cmnd);
+ if(residual) {
+ printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n",
+ host->host_no, pun, lun,
+ SGcount, data_transfer, residual);
+ }
+#endif
+ data_transfer += residual;
+
+ if(data_transfer != 0) {
+ int count;
+ __u32 pAddr;
+
+ SGcount--;
+
+ count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff);
+ DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer));
+ slot->SG[SGcount].ins &= bS_to_host(0xff000000);
+ slot->SG[SGcount].ins |= bS_to_host(data_transfer);
+ pAddr = bS_to_cpu(slot->SG[SGcount].pAddr);
+ pAddr += (count - data_transfer);
+ slot->SG[SGcount].pAddr = bS_to_host(pAddr);
+ }
+ /* set the executed moves to nops */
+ for(i=0; i<SGcount; i++) {
+ slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
+ slot->SG[i].pAddr = 0;
+ }
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ /* and pretend we disconnected after
+ * the command phase */
+ resume_offset = hostdata->pScript + Ent_MsgInDuringData;
+ } else {
+ __u8 sbcl = NCR_700_readb(host, SBCL_REG);
+ printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n",
+ host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl));
+ NCR_700_internal_bus_reset(host);
+ }
+
+ } else if(sstat0 & SCSI_GROSS_ERROR) {
+ printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n",
+ host->host_no, pun, lun);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ } else if(dstat & SCRIPT_INT_RECEIVED) {
+ DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n",
+ host->host_no, pun, lun));
+ resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata);
+ } else if(dstat & (ILGL_INST_DETECTED)) {
+ printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%p[0x%x]!!!\n"
+ " Please email James.Bottomley@HansenPartnership.com with the details\n",
+ host->host_no, pun, lun,
+ (void *)dsp, dsp - hostdata->pScript);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) {
+ printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n",
+ host->host_no, pun, lun, dstat);
+ NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+ }
+
+
+ /* NOTE: selection interrupt processing MUST occur
+ * after script interrupt processing to correctly cope
+ * with the case where we process a disconnect and
+ * then get reselected before we process the
+ * disconnection */
+ if(sstat0 & SELECTED) {
+ /* FIXME: It currently takes at least FOUR
+ * interrupts to complete a command that
+ * disconnects: one for the disconnect, one
+ * for the reselection, one to get the
+ * reselection data and one to complete the
+ * command. If we guess the reselected
+ * command here and prepare it, we only need
+ * to get a reselection data interrupt if we
+ * guessed wrongly. Since the interrupt
+ * overhead is much greater than the command
+ * setup, this would be an efficient
+ * optimisation particularly as we probably
+ * only have one outstanding command on a
+ * target most of the time */
+
+ resume_offset = process_selection(host, dsp);
+
+ }
+
+ }
+
+ if(resume_offset) {
+ if(hostdata->state != NCR_700_HOST_BUSY) {
+ printk(KERN_ERR "scsi%d: Driver error: resume at %p [%04x] with non busy host!\n",
+ host->host_no, (void *)resume_offset, resume_offset - hostdata->pScript);
+ hostdata->state = NCR_700_HOST_BUSY;
+ }
+
+ DEBUG(("Attempting to resume at %x\n", resume_offset));
+ NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
+ NCR_700_writel(resume_offset, host, DSP_REG);
+ }
+ /* There is probably a technical no-no about this: If we're a
+ * shared interrupt and we got this interrupt because the
+ * other device needs servicing not us, we're still going to
+ * check our queued commands here---of course, there shouldn't
+ * be any outstanding.... */
+ if(hostdata->state == NCR_700_HOST_FREE) {
+ int i;
+
+ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+ /* fairness: always run the queue from the last
+ * position we left off */
+ int j = (i + hostdata->saved_slot_position)
+ % NCR_700_COMMAND_SLOTS_PER_HOST;
+
+ if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED)
+ continue;
+ if(NCR_700_start_command(hostdata->slots[j].cmnd)) {
+ DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n",
+ host->host_no, &hostdata->slots[j],
+ hostdata->slots[j].cmnd));
+ hostdata->saved_slot_position = j + 1;
+ }
+
+ break;
+ }
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/* FIXME: Need to put some proc information in and plumb it
+ * into the scsi proc system */
+STATIC int
+NCR_700_proc_directory_info(char *proc_buf, char **startp,
+ off_t offset, int bytes_available,
+ int host_no, int write)
+{
+ static char buf[4096]; /* 1 page should be sufficient */
+ int len = 0;
+ struct Scsi_Host *host = scsi_hostlist;
+ struct NCR_700_Host_Parameters *hostdata;
+ Scsi_Device *SDp;
+
+ while(host != NULL && host->host_no != host_no)
+ host = host->next;
+
+ if(host == NULL)
+ return 0;
+
+ if(write) {
+ /* FIXME: Clear internal statistics here */
+ return 0;
+ }
+ hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+ len += sprintf(&buf[len], "Total commands outstanding: %d\n", hostdata->command_slot_count);
+ len += sprintf(&buf[len],"\
+Target Depth Active Next Tag\n\
+====== ===== ====== ========\n");
+ for(SDp = host->host_queue; SDp != NULL; SDp = SDp->next) {
+ len += sprintf(&buf[len]," %2d:%2d %4d %4d %4d\n", SDp->id, SDp->lun, SDp->queue_depth, NCR_700_get_depth(SDp), SDp->current_tag);
+ }
+ if((len -= offset) <= 0)
+ return 0;
+ if(len > bytes_available)
+ len = bytes_available;
+ memcpy(proc_buf, buf + offset, len);
+ return len;
+}
+
+STATIC int
+NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
+{
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+ __u32 move_ins;
+ struct NCR_700_command_slot *slot;
+ int hash;
+
+ if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
+ /* We're over our allocation, this should never happen
+ * since we report the max allocation to the mid layer */
+ printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->host->host_no);
+ return 1;
+ }
+ if(NCR_700_get_depth(SCp->device) != 0 && !(hostdata->tag_negotiated & (1<<SCp->target))) {
+ DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n",
+ SCp->host->host_no, SCp->target, SCp->lun,
+ NCR_700_get_depth(SCp->device)));
+ return 1;
+ }
+ if(NCR_700_get_depth(SCp->device) >= NCR_700_MAX_TAGS) {
+ DEBUG((KERN_ERR "scsi%d (%d:%d) has max tag depth %d\n",
+ SCp->host->host_no, SCp->target, SCp->lun,
+ NCR_700_get_depth(SCp->device)));
+ return 1;
+ }
+ NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1);
+
+ /* begin the command here */
+ /* no need to check for NULL, test for command_slot_cound above
+ * ensures a slot is free */
+ slot = find_empty_slot(hostdata);
+
+ slot->cmnd = SCp;
+
+ SCp->scsi_done = done;
+ SCp->host_scribble = (unsigned char *)slot;
+ SCp->SCp.ptr = NULL;
+ SCp->SCp.buffer = NULL;
+
+#ifdef NCR_700_DEBUG
+ printk("53c700: scsi%d, command ", SCp->host->host_no);
+ print_command(SCp->cmnd);
+#endif
+
+ if(hostdata->tag_negotiated &(1<<SCp->target)) {
+
+ struct NCR_700_command_slot *old =
+ find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
+#ifdef NCR_700_TAG_DEBUG
+ struct NCR_700_command_slot *found;
+#endif
+
+ if(old != NULL && old->tag == SCp->device->current_tag) {
+ printk(KERN_WARNING "scsi%d (%d:%d) Tag clock back to current, queueing\n", SCp->host->host_no, SCp->target, SCp->lun);
+ return 1;
+ }
+ slot->tag = SCp->device->current_tag++;
+#ifdef NCR_700_TAG_DEBUG
+ while((found = find_ITLQ_Nexus(hostdata, SCp->target, SCp->lun, slot->tag)) != NULL) {
+ printk("\n\n**ERROR** already using tag %d, but oldest is %d\n", slot->tag, (old == NULL) ? -1 : old->tag);
+ printk(" FOUND = %p, tag = %d, pun = %d, lun = %d\n",
+ found, found->tag, found->cmnd->target, found->cmnd->lun);
+ slot->tag = SCp->device->current_tag++;
+ printk(" Tag list is: ");
+ while(old != NULL) {
+ if(old->cmnd->target == SCp->target &&
+ old->cmnd->lun == SCp->lun)
+ printk("%d ", old->tag);
+ old = old->ITL_back;
+ }
+ printk("\n\n");
+ }
+#endif
+ hash = hash_ITLQ(SCp->target, SCp->lun, slot->tag);
+ /* link into the ITLQ hash queues */
+ slot->ITLQ_forw = hostdata->ITLQ_Hash_forw[hash];
+ hostdata->ITLQ_Hash_forw[hash] = slot;
+#ifdef NCR_700_TAG_DEBUG
+ if(slot->ITLQ_forw != NULL && slot->ITLQ_forw->ITLQ_back != NULL) {
+ printk(KERN_ERR "scsi%d (%d:%d) ITLQ_back is not NULL!!!!\n", SCp->host->host_no, SCp->target, SCp->lun);
+ }
+#endif
+ if(slot->ITLQ_forw != NULL)
+ slot->ITLQ_forw->ITLQ_back = slot;
+ else
+ hostdata->ITLQ_Hash_back[hash] = slot;
+ slot->ITLQ_back = NULL;
+ } else {
+ slot->tag = NCR_700_NO_TAG;
+ }
+ /* link into the ITL hash queues */
+ hash = hash_ITL(SCp->target, SCp->lun);
+ slot->ITL_forw = hostdata->ITL_Hash_forw[hash];
+ hostdata->ITL_Hash_forw[hash] = slot;
+#ifdef NCR_700_TAG_DEBUG
+ if(slot->ITL_forw != NULL && slot->ITL_forw->ITL_back != NULL) {
+ printk(KERN_ERR "scsi%d (%d:%d) ITL_back is not NULL!!!!\n",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ }
+#endif
+ if(slot->ITL_forw != NULL)
+ slot->ITL_forw->ITL_back = slot;
+ else
+ hostdata->ITL_Hash_back[hash] = slot;
+ slot->ITL_back = NULL;
+
+
+ /* This is f****g ridiculous; every low level HBA driver has
+ * to determine the direction of the commands, why isn't this
+ * done inside the scsi_lib !!??? */
+ switch (SCp->cmnd[0]) {
+ case REQUEST_SENSE:
+ /* clear the internal sense magic */
+ SCp->cmnd[6] = 0;
+ /* fall through */
+ case INQUIRY:
+ case MODE_SENSE:
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ case READ_CAPACITY:
+ case READ_BLOCK_LIMITS:
+ case READ_TOC:
+ move_ins = SCRIPT_MOVE_DATA_IN;
+ break;
+ case MODE_SELECT:
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ move_ins = SCRIPT_MOVE_DATA_OUT;
+ break;
+ case TEST_UNIT_READY:
+ case ALLOW_MEDIUM_REMOVAL:
+ case START_STOP:
+ move_ins = 0;
+ break;
+ default:
+ /* OK, get it from the command */
+ switch(SCp->sc_data_direction) {
+ case SCSI_DATA_UNKNOWN:
+ default:
+ printk(KERN_ERR "53c700: Unknown command for data direction ");
+ print_command(SCp->cmnd);
+
+ move_ins = 0;
+ break;
+ case SCSI_DATA_NONE:
+ move_ins = 0;
+ break;
+ case SCSI_DATA_READ:
+ move_ins = SCRIPT_MOVE_DATA_IN;
+ break;
+ case SCSI_DATA_WRITE:
+ move_ins = SCRIPT_MOVE_DATA_OUT;
+ break;
+ }
+ }
+
+ /* now build the scatter gather list */
+ if(move_ins != 0) {
+ int i;
+
+ for(i = 0; i < (SCp->use_sg ? SCp->use_sg : 1); i++) {
+ void *vPtr;
+ __u32 count;
+
+ if(SCp->use_sg) {
+ vPtr = (((struct scatterlist *)SCp->buffer)[i].address);
+ count = ((struct scatterlist *)SCp->buffer)[i].length;
+ } else {
+ vPtr = SCp->request_buffer;
+ count = SCp->request_bufflen;
+ }
+ slot->SG[i].ins = bS_to_host(move_ins | count);
+ DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
+ i, count, slot->SG[i].ins,
+ virt_to_bus(vPtr)));
+ dma_cache_wback_inv((unsigned long)vPtr, count);
+ slot->SG[i].pAddr = bS_to_host(virt_to_bus(vPtr));
+ }
+ slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
+ slot->SG[i].pAddr = 0;
+ dma_cache_wback((unsigned long)slot->SG, sizeof(slot->SG));
+ DEBUG((" SETTING %08lx to %x\n",
+ virt_to_bus(&slot->SG[i].ins),
+ slot->SG[i].ins));
+ }
+ slot->resume_offset = 0;
+ NCR_700_start_command(SCp);
+ return 0;
+}
+
+STATIC int
+NCR_700_abort(Scsi_Cmnd * SCp)
+{
+ struct NCR_700_command_slot *slot;
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SCp->host->hostdata[0];
+
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ slot = find_ITL_Nexus(hostdata, SCp->target, SCp->lun);
+ while(slot != NULL && slot->cmnd != SCp)
+ slot = slot->ITL_back;
+
+ if(slot == NULL)
+ /* no outstanding command to abort */
+ return SUCCESS;
+ if(SCp->cmnd[0] == TEST_UNIT_READY) {
+ /* FIXME: This is because of a problem in the new
+ * error handler. When it is in error recovery, it
+ * will send a TUR to a device it thinks may still be
+ * showing a problem. If the TUR isn't responded to,
+ * it will abort it and mark the device off line.
+ * Unfortunately, it does no other error recovery, so
+ * this would leave us with an outstanding command
+ * occupying a slot. Rather than allow this to
+ * happen, we issue a bus reset to force all
+ * outstanding commands to terminate here. */
+ NCR_700_internal_bus_reset(SCp->host);
+ /* still drop through and return failed */
+ }
+ return FAILED;
+
+}
+
+STATIC int
+NCR_700_bus_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun, SCp);
+ print_command(SCp->cmnd);
+ NCR_700_internal_bus_reset(SCp->host);
+ return SUCCESS;
+}
+
+STATIC int
+NCR_700_dev_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ return FAILED;
+}
+
+STATIC int
+NCR_700_host_reset(Scsi_Cmnd * SCp)
+{
+ printk(KERN_INFO "scsi%d (%d:%d) New error handler wants HOST reset\n\t",
+ SCp->host->host_no, SCp->target, SCp->lun);
+ print_command(SCp->cmnd);
+
+ NCR_700_internal_bus_reset(SCp->host);
+ NCR_700_chip_reset(SCp->host);
+ return SUCCESS;
+}
+
+EXPORT_SYMBOL(NCR_700_detect);
+EXPORT_SYMBOL(NCR_700_release);
+EXPORT_SYMBOL(NCR_700_intr);
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
new file mode 100644
index 000000000000..456b78b43328
--- /dev/null
+++ b/drivers/scsi/53c700.h
@@ -0,0 +1,534 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* Driver for 53c700 and 53c700-66 chips from NCR and Symbios
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+ */
+
+#ifndef _53C700_H
+#define _53C700_H
+
+/* Turn on for general debugging---too verbose for normal use */
+#undef NCR_700_DEBUG
+/* Debug the tag queues, checking hash queue allocation and deallocation
+ * and search for duplicate tags */
+#undef NCR_700_TAG_DEBUG
+
+#ifdef NCR_700_DEBUG
+#define DEBUG(x) printk x
+#else
+#define DEBUG(x)
+#endif
+
+/* The number of available command slots */
+#define NCR_700_COMMAND_SLOTS_PER_HOST 64
+/* The maximum number of Scatter Gathers we allow */
+#define NCR_700_SG_SEGMENTS 32
+/* The maximum number of luns (make this of the form 2^n) */
+#define NCR_700_MAX_LUNS 32
+#define NCR_700_LUN_MASK (NCR_700_MAX_LUNS - 1)
+/* Alter this with care: too many tags won't give the elevator a chance to
+ * work; too few will cause the device to operate less efficiently */
+#define NCR_700_MAX_TAGS 16
+/* magic byte identifying an internally generated REQUEST_SENSE command */
+#define NCR_700_INTERNAL_SENSE_MAGIC 0x42
+
+/* WARNING: Leave this in for now: the dependency preprocessor doesn't
+ * pick up file specific flags, so must define here if they are not
+ * set */
+#if !defined(IO_MAPPED) && !defined(MEM_MAPPED)
+#define IO_MAPPED
+#endif
+
+
+struct NCR_700_Host_Parameters;
+
+/* These are the externally used routines */
+struct Scsi_Host *NCR_700_detect(Scsi_Host_Template *, struct NCR_700_Host_Parameters *);
+int NCR_700_release(struct Scsi_Host *host);
+void NCR_700_intr(int, void *, struct pt_regs *);
+
+
+enum NCR_700_Host_State {
+ NCR_700_HOST_BUSY,
+ NCR_700_HOST_FREE,
+};
+
+struct NCR_700_SG_List {
+ /* The following is a script fragment to move the buffer onto the
+ * bus and then link the next fragment or return */
+ #define SCRIPT_MOVE_DATA_IN 0x09000000
+ #define SCRIPT_MOVE_DATA_OUT 0x08000000
+ __u32 ins;
+ __u32 pAddr;
+ #define SCRIPT_NOP 0x80000000
+ #define SCRIPT_RETURN 0x90080000
+};
+
+/* We use device->hostdata to store negotiated parameters. This is
+ * supposed to be a pointer to a device private area, but we cannot
+ * really use it as such since it will never be freed, so just use the
+ * 32 bits to cram the information. The SYNC negotiation sequence looks
+ * like:
+ *
+ * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the
+ * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION
+ * If we get an SDTR reply, work out the SXFER parameters, squirrel
+ * them away here, clear DEV_BEGIN_SYNC_NEGOTIATION and set
+ * DEV_NEGOTIATED_SYNC. If we get a REJECT msg, squirrel
+ *
+ *
+ * 0:7 SXFER_REG negotiated value for this device
+ * 8:15 Current queue depth
+ * 16 negotiated SYNC flag
+ * 17 begin SYNC negotiation flag
+ * 18 device supports tag queueing */
+#define NCR_700_DEV_NEGOTIATED_SYNC (1<<16)
+#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17)
+#define NCR_700_DEV_BEGIN_TAG_QUEUEING (1<<18)
+
+static inline void
+NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer)
+{
+ ((__u32)SDp->hostdata) &= 0xffffff00;
+ ((__u32)SDp->hostdata) |= sxfer & 0xff;
+}
+static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp)
+{
+ return (((__u32)SDp->hostdata) & 0xff);
+}
+static inline void
+NCR_700_set_depth(Scsi_Device *SDp, __u8 depth)
+{
+ ((__u32)SDp->hostdata) &= 0xffff00ff;
+ ((__u32)SDp->hostdata) |= (0xff00 & (depth << 8));
+}
+static inline __u8
+NCR_700_get_depth(Scsi_Device *SDp)
+{
+ return ((((__u32)SDp->hostdata) & 0xff00)>>8);
+}
+static inline int
+NCR_700_is_flag_set(Scsi_Device *SDp, __u32 flag)
+{
+ return (((__u32)SDp->hostdata) & flag) == flag;
+}
+static inline int
+NCR_700_is_flag_clear(Scsi_Device *SDp, __u32 flag)
+{
+ return (((__u32)SDp->hostdata) & flag) == 0;
+}
+static inline void
+NCR_700_set_flag(Scsi_Device *SDp, __u32 flag)
+{
+ ((__u32)SDp->hostdata) |= (flag & 0xffff0000);
+}
+static inline void
+NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
+{
+ ((__u32)SDp->hostdata) &= ~(flag & 0xffff0000);
+}
+
+/* These represent the Nexus hashing functions. A Nexus in SCSI terms
+ * just means the identification of an outstanding command, by ITL
+ * (Initiator Target Lun) or ITLQ (Initiator Target Lun Tag). I'm not
+ * very keen on XOR based hashes, so these are based on number theory
+ * instead. All you need to do is to fix your hash bucket size and
+ * then choose reasonable strides which are coprime with the chosen
+ * bucket size
+ *
+ * Note: this mathematical hash can be made very efficient, if the
+ * compiler is good at optimising: Choose the number of buckets to be
+ * 2^n and the modulo becomes a logical and with (2^n-1).
+ * Additionally, if you chose the coprimes of the form 2^n-2^n the
+ * multiplication can be done by a shift and an addition. */
+#define MAX_ITL_HASH_BUCKETS 16
+#define ITL_HASH_PRIME 7
+
+#define MAX_ITLQ_HASH_BUCKETS 64
+#define ITLQ_PUN_PRIME 7
+#define ITLQ_LUN_PRIME 3
+
+static inline int
+hash_ITL(__u8 pun, __u8 lun)
+{
+ return (pun*ITL_HASH_PRIME + lun) % MAX_ITL_HASH_BUCKETS;
+}
+
+static inline int
+hash_ITLQ(__u8 pun, __u8 lun, __u8 tag)
+{
+ return (pun*ITLQ_PUN_PRIME + lun*ITLQ_LUN_PRIME + tag) % MAX_ITLQ_HASH_BUCKETS;
+}
+
+struct NCR_700_command_slot {
+ #define NCR_700_SLOT_MASK 0xFC
+ #define NCR_700_SLOT_MAGIC 0xb8
+ #define NCR_700_SLOT_FREE (0|NCR_700_SLOT_MAGIC) /* slot may be used */
+ #define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */
+ #define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */
+ __u8 state;
+ #define NCR_700_NO_TAG 0xdead
+ __u16 tag;
+ struct NCR_700_SG_List SG[NCR_700_SG_SEGMENTS+1];
+ __u32 resume_offset;
+ Scsi_Cmnd *cmnd;
+ __u32 temp;
+ /* Doubly linked ITL/ITLQ list kept in strict time order
+ * (latest at the back) */
+ struct NCR_700_command_slot *ITL_forw;
+ struct NCR_700_command_slot *ITL_back;
+ struct NCR_700_command_slot *ITLQ_forw;
+ struct NCR_700_command_slot *ITLQ_back;
+};
+
+struct NCR_700_Host_Parameters {
+ /* These must be filled in by the calling driver */
+ int clock; /* board clock speed in MHz */
+ __u32 base; /* the base for the port (copied to host) */
+ __u8 differential:1; /* if we are differential */
+#ifdef __hppa__
+ /* This option is for HP only. Set it if your chip is wired for
+ * little endian on this platform (which is big endian) */
+ __u8 force_le_on_be:1;
+#endif
+
+ /* NOTHING BELOW HERE NEEDS ALTERING */
+ __u8 fast:1; /* if we can alter the SCSI bus clock
+ speed (so can negiotiate sync) */
+
+ int sync_clock; /* The speed of the SYNC core */
+
+ __u32 *script; /* pointer to script location */
+ __u32 pScript; /* physical mem addr of script */
+
+ /* This will be the host lock. Unfortunately, we can't use it
+ * at the moment because of the necessity of holding the
+ * io_request_lock */
+ spinlock_t lock;
+ enum NCR_700_Host_State state; /* protected by state lock */
+ Scsi_Cmnd *cmd;
+
+ __u8 msgout[8];
+ __u8 tag_negotiated;
+ __u8 status;
+ __u8 msgin[8];
+ struct NCR_700_command_slot *slots;
+ int saved_slot_position;
+ int command_slot_count; /* protected by state lock */
+ __u8 rev;
+ __u8 reselection_id;
+ /* flags for the host */
+
+ /* ITL list. ALL outstanding commands are hashed here in strict
+ * order, latest at the back */
+ struct NCR_700_command_slot *ITL_Hash_forw[MAX_ITL_HASH_BUCKETS];
+ struct NCR_700_command_slot *ITL_Hash_back[MAX_ITL_HASH_BUCKETS];
+
+ /* Only tagged outstanding commands are hashed here (also latest
+ * at the back) */
+ struct NCR_700_command_slot *ITLQ_Hash_forw[MAX_ITLQ_HASH_BUCKETS];
+ struct NCR_700_command_slot *ITLQ_Hash_back[MAX_ITLQ_HASH_BUCKETS];
+
+ /* Free list, singly linked by ITL_forw elements */
+ struct NCR_700_command_slot *free_list;
+};
+
+/*
+ * 53C700 Register Interface - the offset from the Selected base
+ * I/O address */
+#ifdef __hppa__
+#define bE (hostdata->force_le_on_be ? 0 : 3)
+#define bSWAP (hostdata->force_le_on_be)
+#elif defined(__BIG_ENDIAN)
+#define bE 3
+#define bSWAP 0
+#elif defined(__LITTLE_ENDIAN)
+#define bE 0
+#define bSWAP 0
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?"
+#endif
+#define bS_to_cpu(x) (bSWAP ? le32_to_cpu(x) : (x))
+#define bS_to_host(x) (bSWAP ? cpu_to_le32(x) : (x))
+
+/* NOTE: These registers are in the LE register space only, the required byte
+ * swapping is done by the NCR_700_{read|write}[b] functions */
+#define SCNTL0_REG 0x00
+#define FULL_ARBITRATION 0xc0
+#define PARITY 0x08
+#define ENABLE_PARITY 0x04
+#define AUTO_ATN 0x02
+#define SCNTL1_REG 0x01
+#define SLOW_BUS 0x80
+#define ENABLE_SELECT 0x20
+#define ASSERT_RST 0x08
+#define ASSERT_EVEN_PARITY 0x04
+#define SDID_REG 0x02
+#define SIEN_REG 0x03
+#define PHASE_MM_INT 0x80
+#define FUNC_COMP_INT 0x40
+#define SEL_TIMEOUT_INT 0x20
+#define SELECT_INT 0x10
+#define GROSS_ERR_INT 0x08
+#define UX_DISC_INT 0x04
+#define RST_INT 0x02
+#define PAR_ERR_INT 0x01
+#define SCID_REG 0x04
+#define SXFER_REG 0x05
+#define ASYNC_OPERATION 0x00
+#define SODL_REG 0x06
+#define SOCL_REG 0x07
+#define SFBR_REG 0x08
+#define SIDL_REG 0x09
+#define SBDL_REG 0x0A
+#define SBCL_REG 0x0B
+/* read bits */
+#define SBCL_IO 0x01
+/*write bits */
+#define SYNC_DIV_AS_ASYNC 0x00
+#define SYNC_DIV_1_0 0x01
+#define SYNC_DIV_1_5 0x02
+#define SYNC_DIV_2_0 0x03
+#define DSTAT_REG 0x0C
+#define ILGL_INST_DETECTED 0x01
+#define WATCH_DOG_INTERRUPT 0x02
+#define SCRIPT_INT_RECEIVED 0x04
+#define ABORTED 0x10
+#define SSTAT0_REG 0x0D
+#define PARITY_ERROR 0x01
+#define SCSI_RESET_DETECTED 0x02
+#define UNEXPECTED_DISCONNECT 0x04
+#define SCSI_GROSS_ERROR 0x08
+#define SELECTED 0x10
+#define SELECTION_TIMEOUT 0x20
+#define FUNCTION_COMPLETE 0x40
+#define PHASE_MISMATCH 0x80
+#define SSTAT1_REG 0x0E
+#define SIDL_REG_FULL 0x80
+#define SODR_REG_FULL 0x40
+#define SODL_REG_FULL 0x20
+#define SSTAT2_REG 0x0F
+#define CTEST0_REG 0x14
+#define CTEST1_REG 0x15
+#define CTEST2_REG 0x16
+#define CTEST3_REG 0x17
+#define CTEST4_REG 0x18
+#define DISABLE_FIFO 0x00
+#define SLBE 0x10
+#define SFWR 0x08
+#define BYTE_LANE0 0x04
+#define BYTE_LANE1 0x05
+#define BYTE_LANE2 0x06
+#define BYTE_LANE3 0x07
+#define SCSI_ZMODE 0x20
+#define ZMODE 0x40
+#define CTEST5_REG 0x19
+#define MASTER_CONTROL 0x10
+#define DMA_DIRECTION 0x08
+#define CTEST7_REG 0x1B
+#define DFP 0x08
+#define EVP 0x04
+#define DIFF 0x01
+#define CTEST6_REG 0x1A
+#define TEMP_REG 0x1C
+#define DFIFO_REG 0x20
+#define FLUSH_DMA_FIFO 0x80
+#define CLR_FIFO 0x40
+#define ISTAT_REG 0x21
+#define ABORT_OPERATION 0x80
+#define DMA_INT_PENDING 0x01
+#define SCSI_INT_PENDING 0x02
+#define CONNECTED 0x08
+#define CTEST8_REG 0x22
+#define LAST_DIS_ENBL 0x01
+#define SHORTEN_FILTERING 0x04
+#define ENABLE_ACTIVE_NEGATION 0x10
+#define GENERATE_RECEIVE_PARITY 0x20
+#define CTEST9_REG 0x23
+#define DBC_REG 0x24
+#define DCMD_REG 0x27
+#define DNAD_REG 0x28
+#define DIEN_REG 0x39
+#define ABORT_INT 0x10
+#define INT_INST_INT 0x04
+#define WD_INT 0x02
+#define ILGL_INST_INT 0x01
+#define DCNTL_REG 0x3B
+#define SOFTWARE_RESET 0x01
+#define SCRPTS_16BITS 0x20
+#define ASYNC_DIV_2_0 0x00
+#define ASYNC_DIV_1_5 0x01
+#define ASYNC_DIV_1_0 0x02
+#define ASYNC_DIV_3_0 0x03
+#define DMODE_REG 0x34
+#define BURST_LENGTH_1 0x00
+#define BURST_LENGTH_2 0x40
+#define BURST_LENGTH_4 0x80
+#define BURST_LENGTH_8 0xC0
+#define BW16 32
+#define MODE_286 16
+#define IO_XFER 8
+#define FIXED_ADDR 4
+
+#define DSP_REG 0x2C
+#define DSPS_REG 0x30
+
+/* Parameters to begin SDTR negotiations. Empirically, I find that
+ * the 53c700-66 cannot handle an offset >8, so don't change this */
+#define NCR_700_MAX_OFFSET 8
+#define NCR_700_MIN_XFERP 1
+#define NCR_700_MIN_PERIOD 25 /* for SDTR message, 100ns */
+
+#define script_patch_32(script, symbol, value) \
+{ \
+ int i; \
+ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+ __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \
+ (script)[A_##symbol##_used[i]] = bS_to_host(val); \
+ dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \
+ DEBUG((" script, patching %s at %d to 0x%lx\n", \
+ #symbol, A_##symbol##_used[i], (value))); \
+ } \
+}
+
+#define script_patch_32_abs(script, symbol, value) \
+{ \
+ int i; \
+ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+ (script)[A_##symbol##_used[i]] = bS_to_host(value); \
+ dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \
+ DEBUG((" script, patching %s at %d to 0x%lx\n", \
+ #symbol, A_##symbol##_used[i], (value))); \
+ } \
+}
+
+/* Used for patching the SCSI ID in the SELECT instruction */
+#define script_patch_ID(script, symbol, value) \
+{ \
+ int i; \
+ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+ __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \
+ val &= 0xff00ffff; \
+ val |= ((value) & 0xff) << 16; \
+ (script)[A_##symbol##_used[i]] = bS_to_host(val); \
+ dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \
+ DEBUG((" script, patching ID field %s at %d to 0x%x\n", \
+ #symbol, A_##symbol##_used[i], val)); \
+ } \
+}
+
+#define script_patch_16(script, symbol, value) \
+{ \
+ int i; \
+ for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+ __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \
+ val &= 0xffff0000; \
+ val |= ((value) & 0xffff); \
+ (script)[A_##symbol##_used[i]] = bS_to_host(val); \
+ dma_cache_wback((unsigned long)&(script)[A_##symbol##_used[i]], 4); \
+ DEBUG((" script, patching ID field %s at %d to 0x%x\n", \
+ #symbol, A_##symbol##_used[i], val)); \
+ } \
+}
+
+#endif
+
+#ifdef MEM_MAPPED
+static inline __u8
+NCR_700_readb(struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ return readb(host->base + (reg^bE));
+}
+
+static inline __u32
+NCR_700_readl(struct Scsi_Host *host, __u32 reg)
+{
+ __u32 value = readl(host->base + reg);
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+#if 1
+ /* sanity check the register */
+ if((reg & 0x3) != 0)
+ BUG();
+#endif
+
+ return bS_to_cpu(value);
+}
+
+static inline void
+NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ writeb(value, host->base + (reg^bE));
+}
+
+static inline void
+NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+ /* sanity check the register */
+ if((reg & 0x3) != 0)
+ BUG();
+#endif
+
+ writel(bS_to_host(value), host->base + reg);
+}
+#elif defined(IO_MAPPED)
+static inline __u8
+NCR_700_readb(struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ return inb(host->base + (reg^bE));
+}
+
+static inline __u32
+NCR_700_readl(struct Scsi_Host *host, __u32 reg)
+{
+ __u32 value = inl(host->base + reg);
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+ /* sanity check the register */
+ if((reg & 0x3) != 0)
+ BUG();
+#endif
+
+ return bS_to_cpu(value);
+}
+
+static inline void
+NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ outb(value, host->base + (reg^bE));
+}
+
+static inline void
+NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+{
+ const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+ = (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+ /* sanity check the register */
+ if((reg & 0x3) != 0)
+ BUG();
+#endif
+
+ outl(bS_to_host(value), host->base + reg);
+}
+#endif
diff --git a/drivers/scsi/53c700.scr b/drivers/scsi/53c700.scr
new file mode 100644
index 000000000000..30d22a34dbea
--- /dev/null
+++ b/drivers/scsi/53c700.scr
@@ -0,0 +1,404 @@
+; Script for the NCR (or symbios) 53c700 and 53c700-66 chip
+;
+; Copyright (C) 2001 James.Bottomley@HansenPartnership.com
+;;-----------------------------------------------------------------------------
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;
+;;-----------------------------------------------------------------------------
+;
+; This script is designed to be modified for the particular command in
+; operation. The particular variables pertaining to the commands are:
+;
+ABSOLUTE Device_ID = 0 ; ID of target for command
+ABSOLUTE MessageCount = 0 ; Number of bytes in message
+ABSOLUTE MessageLocation = 0 ; Addr of message
+ABSOLUTE CommandCount = 0 ; Number of bytes in command
+ABSOLUTE CommandAddress = 0 ; Addr of Command
+ABSOLUTE StatusAddress = 0 ; Addr to receive status return
+ABSOLUTE ReceiveMsgAddress = 0 ; Addr to receive msg
+;
+; This is the magic component for handling scatter-gather. Each of the
+; SG components is preceeded by a script fragment which moves the
+; necessary amount of data and jumps to the next SG segment. The final
+; SG segment jumps back to . However, this address is the first SG script
+; segment.
+;
+ABSOLUTE SGScriptStartAddress = 0
+
+; The following represent status interrupts we use 3 hex digits for
+; this: 0xPRS where
+
+; P:
+ABSOLUTE AFTER_SELECTION = 0x100
+ABSOLUTE BEFORE_CMD = 0x200
+ABSOLUTE AFTER_CMD = 0x300
+ABSOLUTE AFTER_STATUS = 0x400
+ABSOLUTE AFTER_DATA_IN = 0x500
+ABSOLUTE AFTER_DATA_OUT = 0x600
+ABSOLUTE DURING_DATA_IN = 0x700
+
+; R:
+ABSOLUTE NOT_MSG_OUT = 0x10
+ABSOLUTE UNEXPECTED_PHASE = 0x20
+ABSOLUTE NOT_MSG_IN = 0x30
+ABSOLUTE UNEXPECTED_MSG = 0x40
+ABSOLUTE MSG_IN = 0x50
+ABSOLUTE SDTR_MSG_R = 0x60
+ABSOLUTE REJECT_MSG_R = 0x70
+ABSOLUTE DISCONNECT = 0x80
+ABSOLUTE MSG_OUT = 0x90
+ABSOLUTE WDTR_MSG_R = 0xA0
+
+; S:
+ABSOLUTE GOOD_STATUS = 0x1
+
+; Combinations, since the script assembler can't process |
+ABSOLUTE NOT_MSG_OUT_AFTER_SELECTION = 0x110
+ABSOLUTE UNEXPECTED_PHASE_BEFORE_CMD = 0x220
+ABSOLUTE UNEXPECTED_PHASE_AFTER_CMD = 0x320
+ABSOLUTE NOT_MSG_IN_AFTER_STATUS = 0x430
+ABSOLUTE GOOD_STATUS_AFTER_STATUS = 0x401
+ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_IN = 0x520
+ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_OUT = 0x620
+ABSOLUTE UNEXPECTED_MSG_BEFORE_CMD = 0x240
+ABSOLUTE MSG_IN_BEFORE_CMD = 0x250
+ABSOLUTE MSG_IN_AFTER_CMD = 0x350
+ABSOLUTE SDTR_MSG_BEFORE_CMD = 0x260
+ABSOLUTE REJECT_MSG_BEFORE_CMD = 0x270
+ABSOLUTE DISCONNECT_AFTER_CMD = 0x380
+ABSOLUTE SDTR_MSG_AFTER_CMD = 0x360
+ABSOLUTE WDTR_MSG_AFTER_CMD = 0x3A0
+ABSOLUTE DISCONNECT_AFTER_DATA = 0x580
+ABSOLUTE MSG_IN_AFTER_DATA_IN = 0x550
+ABSOLUTE MSG_IN_AFTER_DATA_OUT = 0x650
+ABSOLUTE MSG_OUT_AFTER_DATA_IN = 0x590
+ABSOLUTE DATA_IN_AFTER_DATA_IN = 0x5a0
+ABSOLUTE MSG_IN_DURING_DATA_IN = 0x750
+ABSOLUTE DISCONNECT_DURING_DATA = 0x780
+
+;
+; Other interrupt conditions
+;
+ABSOLUTE RESELECTED_DURING_SELECTION = 0x1000
+ABSOLUTE COMPLETED_SELECTION_AS_TARGET = 0x1001
+ABSOLUTE RESELECTION_IDENTIFIED = 0x1003
+;
+; Fatal interrupt conditions. If you add to this, also add to the
+; array of corresponding messages
+;
+ABSOLUTE FATAL = 0x2000
+ABSOLUTE FATAL_UNEXPECTED_RESELECTION_MSG = 0x2000
+ABSOLUTE FATAL_SEND_MSG = 0x2001
+ABSOLUTE FATAL_NOT_MSG_IN_AFTER_SELECTION = 0x2002
+ABSOLUTE FATAL_ILLEGAL_MSG_LENGTH = 0x2003
+
+ABSOLUTE DEBUG_INTERRUPT = 0x3000
+ABSOLUTE DEBUG_INTERRUPT1 = 0x3001
+ABSOLUTE DEBUG_INTERRUPT2 = 0x3002
+ABSOLUTE DEBUG_INTERRUPT3 = 0x3003
+ABSOLUTE DEBUG_INTERRUPT4 = 0x3004
+ABSOLUTE DEBUG_INTERRUPT5 = 0x3005
+ABSOLUTE DEBUG_INTERRUPT6 = 0x3006
+
+
+;
+; SCSI Messages we interpret in the script
+;
+ABSOLUTE EXTENDED_MSG = 0x01
+ABSOLUTE SDTR_MSG = 0x01
+ABSOLUTE SAVE_DATA_PTRS_MSG = 0x02
+ABSOLUTE RESTORE_DATA_PTRS_MSG = 0x03
+ABSOLUTE WDTR_MSG = 0x03
+ABSOLUTE DISCONNECT_MSG = 0x04
+ABSOLUTE REJECT_MSG = 0x07
+ABSOLUTE PARITY_ERROR_MSG = 0x09
+ABSOLUTE SIMPLE_TAG_MSG = 0x20
+ABSOLUTE IDENTIFY_MSG = 0x80
+ABSOLUTE IDENTIFY_MSG_MASK = 0x7F
+ABSOLUTE TWO_BYTE_MSG = 0x20
+ABSOLUTE TWO_BYTE_MSG_MASK = 0x0F
+
+; This is where the script begins
+
+ENTRY StartUp
+
+StartUp:
+ SELECT ATN Device_ID, Reselect
+ JUMP Finish, WHEN STATUS
+ JUMP SendIdentifyMsg, IF MSG_OUT
+ INT NOT_MSG_OUT_AFTER_SELECTION
+
+Reselect:
+ WAIT RESELECT SelectedAsTarget
+ INT RESELECTED_DURING_SELECTION, WHEN MSG_IN
+ INT FATAL_NOT_MSG_IN_AFTER_SELECTION
+
+ ENTRY GetReselectionData
+GetReselectionData:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ INT RESELECTION_IDENTIFIED
+
+ ENTRY GetReselectionWithTag
+GetReselectionWithTag:
+ MOVE 3, ReceiveMsgAddress, WHEN MSG_IN
+ INT RESELECTION_IDENTIFIED
+
+ ENTRY SelectedAsTarget
+SelectedAsTarget:
+; Basically tell the selecting device that there's nothing here
+ SET TARGET
+ DISCONNECT
+ CLEAR TARGET
+ INT COMPLETED_SELECTION_AS_TARGET
+;
+; These are the messaging entries
+;
+; Send a message. Message count should be correctly patched
+ ENTRY SendMessage
+SendMessage:
+ MOVE MessageCount, MessageLocation, WHEN MSG_OUT
+ResumeSendMessage:
+ RETURN, WHEN NOT MSG_OUT
+ INT FATAL_SEND_MSG
+
+ ENTRY SendMessagePhaseMismatch
+SendMessagePhaseMismatch:
+ CLEAR ACK
+ JUMP ResumeSendMessage
+;
+; Receive a message. Need to identify the message to
+; receive it correctly
+ ENTRY ReceiveMessage
+ReceiveMessage:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+;
+; Use this entry if we've just tried to look at the first byte
+; of the message and want to process it further
+ProcessReceiveMessage:
+ JUMP ReceiveExtendedMessage, IF EXTENDED_MSG
+ RETURN, IF NOT TWO_BYTE_MSG, AND MASK TWO_BYTE_MSG_MASK
+ CLEAR ACK
+ MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN
+ RETURN
+ReceiveExtendedMessage:
+ CLEAR ACK
+ MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN
+ JUMP Receive1Byte, IF 0x01
+ JUMP Receive2Byte, IF 0x02
+ JUMP Receive3Byte, IF 0x03
+ JUMP Receive4Byte, IF 0x04
+ JUMP Receive5Byte, IF 0x05
+ INT FATAL_ILLEGAL_MSG_LENGTH
+Receive1Byte:
+ CLEAR ACK
+ MOVE 1, ReceiveMsgAddress + 2, WHEN MSG_IN
+ RETURN
+Receive2Byte:
+ CLEAR ACK
+ MOVE 2, ReceiveMsgAddress + 2, WHEN MSG_IN
+ RETURN
+Receive3Byte:
+ CLEAR ACK
+ MOVE 3, ReceiveMsgAddress + 2, WHEN MSG_IN
+ RETURN
+Receive4Byte:
+ CLEAR ACK
+ MOVE 4, ReceiveMsgAddress + 2, WHEN MSG_IN
+ RETURN
+Receive5Byte:
+ CLEAR ACK
+ MOVE 5, ReceiveMsgAddress + 2, WHEN MSG_IN
+ RETURN
+;
+; Come here from the message processor to ignore the message
+;
+ ENTRY IgnoreMessage
+IgnoreMessage:
+ CLEAR ACK
+ RETURN
+;
+; Come here to send a reply to a message
+;
+ ENTRY SendMessageWithATN
+SendMessageWithATN:
+ SET ATN
+ CLEAR ACK
+ JUMP SendMessage
+
+SendIdentifyMsg:
+ CALL SendMessage
+ JUMP SendCommand
+
+IgnoreMsgBeforeCommand:
+ CLEAR ACK
+ ENTRY SendCommand
+SendCommand:
+ JUMP Finish, WHEN STATUS
+ JUMP MsgInBeforeCommand, IF MSG_IN
+ INT UNEXPECTED_PHASE_BEFORE_CMD, IF NOT CMD
+ MOVE CommandCount, CommandAddress, WHEN CMD
+ResumeSendCommand:
+ JUMP Finish, WHEN STATUS
+ JUMP MsgInAfterCmd, IF MSG_IN
+ JUMP DataIn, IF DATA_IN
+ JUMP DataOut, IF DATA_OUT
+ INT UNEXPECTED_PHASE_AFTER_CMD
+
+IgnoreMsgDuringData:
+ CLEAR ACK
+ ; fall through to MsgInDuringData
+
+Entry MsgInDuringData
+MsgInDuringData:
+;
+; Could be we have nothing more to transfer
+;
+ JUMP Finish, WHEN STATUS
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ JUMP DisconnectDuringDataIn, IF DISCONNECT_MSG
+ JUMP IgnoreMsgDuringData, IF SAVE_DATA_PTRS_MSG
+ JUMP IgnoreMsgDuringData, IF RESTORE_DATA_PTRS_MSG
+ INT MSG_IN_DURING_DATA_IN
+
+MsgInAfterCmd:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ JUMP DisconnectAfterCmd, IF DISCONNECT_MSG
+ JUMP IgnoreMsgInAfterCmd, IF SAVE_DATA_PTRS_MSG
+ JUMP IgnoreMsgInAfterCmd, IF RESTORE_DATA_PTRS_MSG
+ CALL ProcessReceiveMessage
+ INT MSG_IN_AFTER_CMD
+ CLEAR ACK
+ JUMP ResumeSendCommand
+
+IgnoreMsgInAfterCmd:
+ CLEAR ACK
+ JUMP ResumeSendCommand
+
+DisconnectAfterCmd:
+ CLEAR ACK
+ WAIT DISCONNECT
+ ENTRY Disconnect1
+Disconnect1:
+ INT DISCONNECT_AFTER_CMD
+ ENTRY Disconnect2
+Disconnect2:
+; We return here after a reselection
+ CLEAR ACK
+ JUMP ResumeSendCommand
+
+MsgInBeforeCommand:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ JUMP IgnoreMsgBeforeCommand, IF SAVE_DATA_PTRS_MSG
+ JUMP IgnoreMsgBeforeCommand, IF RESTORE_DATA_PTRS_MSG
+ CALL ProcessReceiveMessage
+ INT MSG_IN_BEFORE_CMD
+ CLEAR ACK
+ JUMP SendCommand
+
+DataIn:
+ CALL SGScriptStartAddress
+ResumeDataIn:
+ JUMP Finish, WHEN STATUS
+ JUMP MsgInAfterDataIn, IF MSG_IN
+ JUMP DataInAfterDataIn, if DATA_IN
+ INT MSG_OUT_AFTER_DATA_IN, if MSG_OUT
+ INT UNEXPECTED_PHASE_AFTER_DATA_IN
+
+DataInAfterDataIn:
+ INT DATA_IN_AFTER_DATA_IN
+ JUMP ResumeDataIn
+
+DataOut:
+ CALL SGScriptStartAddress
+ResumeDataOut:
+ JUMP Finish, WHEN STATUS
+ JUMP MsgInAfterDataOut, IF MSG_IN
+ INT UNEXPECTED_PHASE_AFTER_DATA_OUT
+
+MsgInAfterDataIn:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ JUMP DisconnectAfterDataIn, IF DISCONNECT_MSG
+ JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+ JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+ CALL ProcessReceiveMessage
+ INT MSG_IN_AFTER_DATA_IN
+ CLEAR ACK
+ JUMP ResumeDataIn
+
+DisconnectDuringDataIn:
+ CLEAR ACK
+ WAIT DISCONNECT
+ ENTRY Disconnect3
+Disconnect3:
+ INT DISCONNECT_DURING_DATA
+ ENTRY Disconnect4
+Disconnect4:
+; we return here after a reselection
+ CLEAR ACK
+ JUMP ResumeSendCommand
+
+
+DisconnectAfterDataIn:
+ CLEAR ACK
+ WAIT DISCONNECT
+ ENTRY Disconnect5
+Disconnect5:
+ INT DISCONNECT_AFTER_DATA
+ ENTRY Disconnect6
+Disconnect6:
+; we return here after a reselection
+ CLEAR ACK
+ JUMP ResumeDataIn
+
+MsgInAfterDataOut:
+ MOVE 1, ReceiveMsgAddress, WHEN MSG_IN
+ JUMP DisconnectAfterDataOut, if DISCONNECT_MSG
+ JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+ JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+ CALL ProcessReceiveMessage
+ INT MSG_IN_AFTER_DATA_OUT
+ CLEAR ACK
+ JUMP ResumeDataOut
+
+IgnoreMsgAfterData:
+ CLEAR ACK
+; Data in and out do the same thing on resume, so pick one
+ JUMP ResumeDataIn
+
+DisconnectAfterDataOut:
+ CLEAR ACK
+ WAIT DISCONNECT
+ ENTRY Disconnect7
+Disconnect7:
+ INT DISCONNECT_AFTER_DATA
+ ENTRY Disconnect8
+Disconnect8:
+; we return here after a reselection
+ CLEAR ACK
+ JUMP ResumeDataOut
+
+Finish:
+ MOVE 1, StatusAddress, WHEN STATUS
+ INT NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN
+ CALL ReceiveMessage
+ CLEAR ACK
+ WAIT DISCONNECT
+ ENTRY Finish1
+Finish1:
+ INT GOOD_STATUS_AFTER_STATUS
+ ENTRY Finish2
+Finish2:
+
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index d77f242d81ae..68560498e442 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -33,7 +33,7 @@ mainmenu_option next_comment
comment 'SCSI low-level drivers'
if [ "$CONFIG_SGI_IP22" = "y" ]; then
- dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI
+ dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SGIWD93_SCSI $CONFIG_SCSI
fi
if [ "$CONFIG_DECSTATION" = "y" ]; then
if [ "$CONFIG_TC" = "y" ]; then
@@ -59,6 +59,7 @@ if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS
fi
fi
+dep_tristate 'Adaptec I2O RAID support ' CONFIG_SCSI_DPT_I2O $CONFIG_SCSI
dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI $CONFIG_PCI
@@ -85,7 +86,7 @@ dep_tristate 'Future Domain 16xx SCSI/AHA-2920A support' CONFIG_SCSI_FUTURE_DOMA
if [ "$CONFIG_MCA" = "y" ]; then
dep_tristate 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS $CONFIG_SCSI
fi
-dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
+dep_tristate 'Intel/ICP (former GDT SCSI Disk Array) RAID Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
bool ' Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400
@@ -114,6 +115,10 @@ if [ "$CONFIG_PARPORT" != "n" ]; then
fi
fi
dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
+dep_tristate 'NCR Dual 700 MCA SCSI support' CONFIG_SCSI_NCR_D700 $CONFIG_SCSI $CONFIG_MCA
+if [ "$CONFIG_PARISC" = "y" ]; then
+ dep_tristate 'HP LASI SCSI support for 53c700' CONFIG_SCSI_LASI70 $CONFIG_SCSI
+fi
dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI
if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then
bool ' always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync
@@ -151,6 +156,9 @@ dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
dep_tristate 'Qlogic ISP FC SCSI support' CONFIG_SCSI_QLOGIC_FC $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_QLOGIC_FC" != "n" ]; then
+ bool ' Include loadable firmware in driver' CONFIG_SCSI_QLOGIC_FC_FIRMWARE
+ fi
dep_tristate 'Qlogic QLA 1280 SCSI support' CONFIG_SCSI_QLOGIC_1280 $CONFIG_SCSI
fi
if [ "$CONFIG_X86" = "y" ]; then
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index fff2cf8d263d..7fe4fe985dc7 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -31,7 +31,7 @@ else
endif
endif
-export-objs := scsi_syms.o
+export-objs := scsi_syms.o 53c700.o 53c700-mem.o
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
@@ -47,6 +47,7 @@ obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o
+obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o
obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o
obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o
obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o
@@ -65,6 +66,7 @@ obj-$(CONFIG_SCSI_PCI2000) += pci2000.o
obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o
obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
+obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
@@ -80,6 +82,7 @@ obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
obj-$(CONFIG_SCSI_IN2000) += in2000.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o
+obj-$(CONFIG_SCSI_NCR_D700) += NCR_D700.o 53c700.o
obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o
obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o
obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o
@@ -121,6 +124,8 @@ obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o
obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
obj-$(CONFIG_SCSI_FCAL) += fcal.o
+obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o
+obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700-mem.o
ifeq ($(CONFIG_ARCH_ACORN),y)
mod-subdirs += ../acorn/scsi
@@ -193,3 +198,22 @@ sim710_d.h: sim710.scr script_asm.pl
sim710_u.h: sim710_d.h
sim710.o : sim710_d.h
+
+53c700_d.h: 53c700.scr script_asm.pl
+ $(PERL) -s script_asm.pl -ncr7x0_family < 53c700.scr
+ rm -f scriptu.h
+ mv script.h 53c700_d.h
+
+53c700.o: 53c700_d.h
+
+53c700-mem.o: 53c700_d.h
+
+53c700-mem.c: 53c700.c
+ echo "/* WARNING: GENERATED FILE (from $<), DO NOT MODIFY */" > $@
+ echo "#define MEM_MAPPED" >> $@
+ cat $< >> $@
+
+cpqfc.o: cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o cpqfcTSworker.o \
+ cpqfcTStrigger.o
+ $(LD) -r -o cpqfc.o cpqfcTSinit.o cpqfcTScontrol.o \
+ cpqfcTSi2c.o cpqfcTSworker.o cpqfcTStrigger.o
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
new file mode 100644
index 000000000000..80a6c1d52f1e
--- /dev/null
+++ b/drivers/scsi/NCR_D700.c
@@ -0,0 +1,326 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Dual 700 MCA SCSI Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/* Notes:
+ *
+ * Most of the work is done in the chip specific module, 53c700.o
+ *
+ * TODO List:
+ *
+ * 1. Extract the SCSI ID from the voyager CMOS table (necessary to
+ * support multi-host environments.
+ *
+ * */
+
+
+/* CHANGELOG
+ *
+ * Version 2.1
+ *
+ * Modularise the driver into a Board piece (this file) and a chip
+ * piece 53c700.[ch] and 53c700.scr, added module options. You can
+ * now specify the scsi id by the parameters
+ *
+ * NCR_D700=slot:<n> [siop:<n>] id:<n> ....
+ *
+ * They need to be comma separated if compiled into the kernel
+ *
+ * Version 2.0
+ *
+ * Initial implementation of TCQ (Tag Command Queueing). TCQ is full
+ * featured and uses the clock algorithm to keep track of outstanding
+ * tags and guard against individual tag starvation. Also fixed a bug
+ * in all of the 1.x versions where the D700_data_residue() function
+ * was returning results off by 32 bytes (and thus causing the same 32
+ * bytes to be written twice corrupting the data block). It turns out
+ * the 53c700 only has a 6 bit DBC and DFIFO registers not 7 bit ones
+ * like the 53c710 (The 710 is the only data manual still available,
+ * which I'd been using to program the 700).
+ *
+ * Version 1.2
+ *
+ * Much improved message handling engine
+ *
+ * Version 1.1
+ *
+ * Add code to handle selection reasonably correctly. By the time we
+ * get the selection interrupt, we've already responded, but drop off the
+ * bus and hope the selector will go away.
+ *
+ * Version 1.0:
+ *
+ * Initial release. Fully functional except for procfs and tag
+ * command queueing. Has only been tested on cards with 53c700-66
+ * chips and only single ended. Features are
+ *
+ * 1. Synchronous data transfers to offset 8 (limit of 700-66) and
+ * 100ns (10MHz) limit of SCSI-2
+ *
+ * 2. Disconnection and reselection
+ *
+ * Testing:
+ *
+ * I've only really tested this with the 700-66 chip, but have done
+ * soak tests in multi-device environments to verify that
+ * disconnections and reselections are being processed correctly.
+ * */
+
+#define NCR_D700_VERSION "2.1"
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+#include <linux/blk.h>
+#include <linux/module.h>
+
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#include "53c700.h"
+#include "NCR_D700.h"
+
+#ifndef CONFIG_MCA
+#error "NCR_D700 driver only compiles for MCA"
+#endif
+
+#ifdef NCR_D700_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+char *NCR_D700; /* command line from insmod */
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(NCR_D700, "s");
+
+static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+ { [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+static int __init
+param_setup(char *string)
+{
+ char *pos = string, *next;
+ int slot = -1, siop = -1;
+
+ while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
+ int val = (int)simple_strtoul(++next, NULL, 0);
+
+ if(!strncmp(pos, "slot:", 5))
+ slot = val;
+ else if(!strncmp(pos, "siop:", 5))
+ siop = val;
+ else if(!strncmp(pos, "id:", 3)) {
+ if(slot == -1) {
+ printk(KERN_WARNING "NCR D700: Must specify slot for id parameter\n");
+ } else if(slot > MCA_MAX_SLOT_NR) {
+ printk(KERN_WARNING "NCR D700: Illegal slot %d for id %d\n", slot, val);
+ } else {
+ if(siop != 0 && siop != 1) {
+ id_array[slot*2] = val;
+ id_array[slot*2 + 1] =val;
+ } else {
+ id_array[slot*2 + siop] = val;
+ }
+ }
+ }
+ if((pos = strchr(pos, ARG_SEP)) != NULL)
+ pos++;
+ }
+ return 1;
+}
+
+#ifndef MODULE
+__setup("NCR_D700=", param_setup);
+#endif
+
+/* Detect a D700 card. Note, because of the set up---the chips are
+ * essentially connectecd to the MCA bus independently, it is easier
+ * to set them up as two separate host adapters, rather than one
+ * adapter with two channels */
+STATIC int __init
+D700_detect(Scsi_Host_Template *tpnt)
+{
+ int slot = 0;
+ int found = 0;
+ int differential;
+ int banner = 1;
+
+ if(!MCA_bus)
+ return 0;
+
+#ifdef MODULE
+ if(NCR_D700)
+ param_setup(NCR_D700);
+#endif
+
+ for(slot = 0; (slot = mca_find_adapter(NCR_D700_MCA_ID, slot)) != MCA_NOTFOUND; slot++) {
+ int irq, i;
+ int pos3j, pos3k, pos3a, pos3b, pos4;
+ __u32 base_addr, offset_addr;
+ struct Scsi_Host *host = NULL;
+
+ /* enable board interrupt */
+ pos4 = mca_read_pos(slot, 4);
+ pos4 |= 0x4;
+ mca_write_pos(slot, 4, pos4);
+
+ mca_write_pos(slot, 6, 9);
+ pos3j = mca_read_pos(slot, 3);
+ mca_write_pos(slot, 6, 10);
+ pos3k = mca_read_pos(slot, 3);
+ mca_write_pos(slot, 6, 0);
+ pos3a = mca_read_pos(slot, 3);
+ mca_write_pos(slot, 6, 1);
+ pos3b = mca_read_pos(slot, 3);
+
+ base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
+ offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
+
+ irq = (pos4 & 0x3) + 11;
+ if(irq >= 13)
+ irq++;
+ if(banner) {
+ printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
+ "NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
+ "NCR D700:\n");
+ banner = 0;
+ }
+ printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr);
+
+ tpnt->proc_name = "NCR_D700";
+
+ /*outb(BOARD_RESET, base_addr);*/
+
+ /* clear any pending interrupts */
+ (void)inb(base_addr + 0x08);
+ /* get modctl, used later for setting diff bits */
+ switch(differential = (inb(base_addr + 0x08) >> 6)) {
+ case 0x00:
+ /* only SIOP1 differential */
+ differential = 0x02;
+ break;
+ case 0x01:
+ /* Both SIOPs differential */
+ differential = 0x03;
+ break;
+ case 0x03:
+ /* No SIOPs differential */
+ differential = 0x00;
+ break;
+ default:
+ printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
+ differential);
+ differential = 0x00;
+ break;
+ }
+
+ /* plumb in both 700 chips */
+ for(i=0; i<2; i++) {
+ __u32 region = offset_addr | (0x80 * i);
+ struct NCR_700_Host_Parameters *hostdata =
+ kmalloc(sizeof(struct NCR_700_Host_Parameters),
+ GFP_KERNEL);
+ if(hostdata == NULL) {
+ printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
+ continue;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+ if(request_region(region, 64, "NCR_D700") == NULL) {
+ printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
+ kfree(hostdata);
+ continue;
+ }
+
+ /* Fill in the three required pieces of hostdata */
+ hostdata->base = region;
+ hostdata->differential = (((1<<i) & differential) != 0);
+ hostdata->clock = NCR_D700_CLOCK_MHZ;
+ /* and register the chip */
+ if((host = NCR_700_detect(tpnt, hostdata)) == NULL) {
+ kfree(hostdata);
+ release_region(host->base, 64);
+ continue;
+ }
+ host->irq = irq;
+ /* FIXME: Read this from SUS */
+ host->this_id = id_array[slot * 2 + i];
+ printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
+ i, host->this_id);
+ if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
+ printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
+ scsi_unregister(host);
+ NCR_700_release(host);
+ continue;
+ }
+ found++;
+ }
+ }
+
+ return found;
+}
+
+
+STATIC int
+D700_release(struct Scsi_Host *host)
+{
+ struct D700_Host_Parameters *hostdata =
+ (struct D700_Host_Parameters *)host->hostdata[0];
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ release_region(host->base, 64);
+ return 1;
+}
+
+
+static Scsi_Host_Template driver_template = NCR_D700_SCSI;
+
+#include "scsi_module.c"
+
diff --git a/drivers/scsi/NCR_D700.h b/drivers/scsi/NCR_D700.h
new file mode 100644
index 000000000000..cd9e4829b3a9
--- /dev/null
+++ b/drivers/scsi/NCR_D700.h
@@ -0,0 +1,45 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Dual 700 MCA SCSI Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+ */
+
+#ifndef _NCR_D700_H
+#define _NCR_D700_H
+
+/* Don't turn on debugging messages */
+#undef NCR_D700_DEBUG
+
+/* The MCA identifier */
+#define NCR_D700_MCA_ID 0x0092
+
+static int D700_detect(Scsi_Host_Template *);
+static int D700_release(struct Scsi_Host *host);
+
+
+/* Host template. Note the name and proc_name are optional, all the
+ * remaining parameters shown below must be filled in. The 53c700
+ * routine NCR_700_detect will fill in all of the missing routines */
+#define NCR_D700_SCSI { \
+ name: "NCR Dual 700 MCA", \
+ proc_name: "NCR_D700", \
+ detect: D700_detect, \
+ release: D700_release, \
+ this_id: 7, \
+}
+
+
+/* Defines for the Board registers */
+#define BOARD_RESET 0x80 /* board level reset */
+#define ADD_PARENB 0x04 /* Address Parity Enabled */
+#define DAT_PARENB 0x01 /* Data Parity Enabled */
+#define SFBK_ENB 0x10 /* SFDBK Interrupt Enabled */
+#define LED0GREEN 0x20 /* Led 0 (red 0; green 1) */
+#define LED1GREEN 0x40 /* Led 1 (red 0; green 1) */
+#define LED0RED 0xDF /* Led 0 (red 0; green 1) */
+#define LED1RED 0xBF /* Led 1 (red 0; green 1) */
+
+#define NCR_D700_CLOCK_MHZ 50
+
+#endif
diff --git a/drivers/scsi/README.53c700 b/drivers/scsi/README.53c700
new file mode 100644
index 000000000000..20f895946cd7
--- /dev/null
+++ b/drivers/scsi/README.53c700
@@ -0,0 +1,17 @@
+This driver supports the 53c700 and 53c700-66 chips only. It is full
+featured and does sync (-66 only), disconnects and tag command
+queueing.
+
+Since the 53c700 must be interfaced to a bus, you need to wrapper the
+card detector around this driver. For an example, see the
+NCR_D700.[ch] files.
+
+The comments in the 53c700.[ch] files tell you which parts you need to
+fill in to get the driver working.
+
+The driver is currently I/O mapped only, but it should be easy enough
+to memory map (just make the port reads #defines with MEM_MAPPED for
+memory mapping or nothing for I/O mapping, specify an extra rule for
+53c700-mem.o with the -DMEM_MAPPED flag and make your driver use it,
+that way the make rules will generate the correct version).
+
diff --git a/drivers/scsi/README.dpti b/drivers/scsi/README.dpti
new file mode 100644
index 000000000000..daaab2c057f9
--- /dev/null
+++ b/drivers/scsi/README.dpti
@@ -0,0 +1,83 @@
+ /* TERMS AND CONDITIONS OF USE
+ *
+ * Redistribution and use in source form, with or without modification, are
+ * permitted provided that redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following disclaimer.
+ *
+ * This software is provided `as is' by Adaptec and
+ * any express or implied warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose,
+ * are disclaimed. In no event shall Adaptec be
+ * liable for any direct, indirect, incidental, special, exemplary or
+ * consequential damages (including, but not limited to, procurement of
+ * substitute goods or services; loss of use, data, or profits; or business
+ * interruptions) however caused and on any theory of liability, whether in
+ * contract, strict liability, or tort (including negligence or otherwise)
+ * arising in any way out of the use of this driver software, even if advised
+ * of the possibility of such damage.
+ *
+ ****************************************************************
+ * This driver supports the Adaptec I2O RAID and DPT SmartRAID V I2O boards.
+ *
+ * CREDITS:
+ * The original linux driver was ported to Linux by Karen White while at
+ * Dell Computer. It was ported from Bob Pasteur's (of DPT) original
+ * non-Linux driver. Mark Salyzyn and Bob Pasteur consulted on the original
+ * driver.
+ *
+ * 2.0 version of the driver by Deanna Bonds and Mark Salyzyn.
+ *
+ * HISTORY:
+ * The driver was originally ported to linux version 2.0.34
+ *
+ * V2.0 Rewrite of driver. Re-architectured based on i2o subsystem.
+ * This was the first full GPL version since the last version used
+ * i2osig headers which were not GPL. Developer Testing version.
+ * V2.1 Internal testing
+ * V2.2 First released version
+ *
+ * V2.3
+ * Changes:
+ * Added Raptor Support
+ * Fixed bug causing system to hang under extreme load with
+ * management utilities running (removed GFP_DMA from kmalloc flags)
+ *
+ *
+ * V2.4 First version ready to be submitted to be embedded in the kernel
+ * Changes:
+ * Implemented suggestions from Alan Cox
+ * Added calculation of resid for sg layer
+ * Better error handling
+ * Added checking underflow condtions
+ * Added DATAPROTECT checking
+ * Changed error return codes
+ * Fixed pointer bug in bus reset routine
+ * Enabled hba reset from ioctls (allows a FW flash to reboot and use the new
+ * FW without having to reboot)
+ * Changed proc output
+ *
+ * TODO:
+ * Add 64 bit Scatter Gather when compiled on 64 bit architectures
+ * Add sparse lun scanning
+ * Add code that checks if a device that had been taken offline is
+ * now online (at the FW level) when test unit ready or inquiry
+ * command from scsi-core
+ * Add proc read interface
+ * busrescan command
+ * rescan command
+ * Add code to rescan routine that notifies scsi-core about new devices
+ * Add support for C-PCI (hotplug stuff)
+ * Add ioctl passthru error recovery
+ *
+ * NOTES:
+ * The DPT card optimizes the order of processing commands. Consequently,
+ * a command may take up to 6 minutes to complete after it has been sent
+ * to the board.
+ *
+ * The files dpti_ioctl.h dptsig.h osd_defs.h osd_util.h sys_info.h are part of the
+ * interface files for Adaptecs managment routines. These define the structures used
+ * in the ioctls. They are written to be portable. They are hard to read, but I need
+ * to use them 'as is' or I can miss changes in the interface.
+ *
+ */
+
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index 9a51418d7442..1106dab4ff2d 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -9,6 +9,14 @@
* Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*
* jazz_esp is based on David S. Miller's ESP driver and cyber_esp
+ *
+ * 20000819 - Small PMAZ-AA fixes by Florian Lohoff <flo@rfc822.org>
+ * Be warned the PMAZ-AA works currently as a single card.
+ * Dont try to put multiple cards in one machine - They are
+ * both detected but it may crash under high load garbling your
+ * data.
+ * 20001005 - Initialization fixes for 2.4.0-test9
+ * Florian Lohoff <flo@rfc822.org>
*/
#include <linux/kernel.h>
@@ -45,8 +53,6 @@
* starting point. #define this an be prepared for tons
* of warnings and errors :)
*/
-#undef PMAZ_A
-
static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
static void dma_drain(struct NCR_ESP *esp);
static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp);
@@ -62,7 +68,6 @@ static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp);
static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp);
static void dma_advance_sg(Scsi_Cmnd * sp);
-#ifdef PMAZ_A
static void pmaz_dma_drain(struct NCR_ESP *esp);
static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
@@ -70,10 +75,6 @@ static void pmaz_dma_ints_off(struct NCR_ESP *esp);
static void pmaz_dma_ints_on(struct NCR_ESP *esp);
static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp);
-static void pmaz_dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp);
-
-volatile int *scsi_pmaz_dma_ptr_tc;
-#endif
#define TC_ESP_RAM_SIZE 0x20000
#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1))
@@ -83,9 +84,6 @@ volatile int *scsi_pmaz_dma_ptr_tc;
#define TC_ESP_DMAR_WRITE 0x80000000
#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK)
-volatile unsigned char *scsi_pmaz_dma_ptrs_tc[ESP_NCMD];
-unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD];
-unsigned char scsi_cur_buff = 1; /* Leave space for command buffer */
__u32 esp_virt_buffer;
int scsi_current_length;
@@ -105,20 +103,21 @@ volatile unsigned long *scsi_sdr1;
static void scsi_dma_int(int, void *, struct pt_regs *);
+static Scsi_Host_Template driver_template = SCSI_DEC_ESP;
+
+#include "scsi_module.c"
+
/***************************************************************** Detection */
int dec_esp_detect(Scsi_Host_Template * tpnt)
{
struct NCR_ESP *esp;
struct ConfigDev *esp_dev;
-#ifdef PMAZ_A
- int slot, i;
+ int slot;
unsigned long mem_start;
- volatile unsigned char *buffer;
-#endif
if (IOASIC) {
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp_dev = 0;
+ esp = esp_allocate(tpnt, (void *) esp_dev);
scsi_dma_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_P);
scsi_next_ptr = (unsigned long *) (system_base + IOCTL + SCSI_DMA_BP);
@@ -127,86 +126,89 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
scsi_sdr0 = (unsigned long *) (system_base + IOCTL + SCSI_SDR0);
scsi_sdr1 = (unsigned long *) (system_base + IOCTL + SCSI_SDR1);
- /* Do command transfer with programmed I/O */
- esp->do_pio_cmds = 1;
+ /* Do command transfer with programmed I/O */
+ esp->do_pio_cmds = 1;
- /* Required functions */
- esp->dma_bytes_sent = &dma_bytes_sent;
- esp->dma_can_transfer = &dma_can_transfer;
- esp->dma_dump_state = &dma_dump_state;
- esp->dma_init_read = &dma_init_read;
- esp->dma_init_write = &dma_init_write;
- esp->dma_ints_off = &dma_ints_off;
- esp->dma_ints_on = &dma_ints_on;
- esp->dma_irq_p = &dma_irq_p;
- esp->dma_ports_p = &dma_ports_p;
- esp->dma_setup = &dma_setup;
-
- /* Optional functions */
- esp->dma_barrier = 0;
+ /* Required functions */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &dma_init_read;
+ esp->dma_init_write = &dma_init_write;
+ esp->dma_ints_off = &dma_ints_off;
+ esp->dma_ints_on = &dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &dma_setup;
+
+ /* Optional functions */
+ esp->dma_barrier = 0;
esp->dma_drain = &dma_drain;
- esp->dma_invalidate = 0;
- esp->dma_irq_entry = 0;
- esp->dma_irq_exit = 0;
- esp->dma_poll = 0;
- esp->dma_reset = 0;
- esp->dma_led_off = 0;
- esp->dma_led_on = 0;
-
- /* virtual DMA functions */
- esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
- esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ /* virtual DMA functions */
+ esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
esp->dma_mmu_release_scsi_one = 0;
esp->dma_mmu_release_scsi_sgl = 0;
- esp->dma_advance_sg = &dma_advance_sg;
+ esp->dma_advance_sg = &dma_advance_sg;
- /* SCSI chip speed */
+ /* SCSI chip speed */
esp->cfreq = 25000000;
- /*
- * we don't give the address of DMA channel, but the number
- * of DMA channel, so we can use the jazz DMA functions
- *
- */
- esp->dregs = JAZZ_SCSI_DMA;
+ /*
+ * we don't give the address of DMA channel, but the number
+ * of DMA channel, so we can use the jazz DMA functions
+ *
+ */
+ esp->dregs = JAZZ_SCSI_DMA;
- /* ESP register base */
+ /* ESP register base */
esp->eregs = (struct ESP_regs *) (system_base + SCSI);
- /* Set the command buffer */
+ /* Set the command buffer */
esp->esp_command = (volatile unsigned char *) cmd_buffer;
- /* get virtual dma address for command buffer */
+ /* get virtual dma address for command buffer */
esp->esp_command_dvma = (__u32) KSEG1ADDR((volatile unsigned char *) cmd_buffer);
esp->irq = SCSI_INT;
+
+ esp->scsi_id = 7;
+
+ /* Check for differential SCSI-bus */
+ esp->diff = 0;
+
+ esp_initialize(esp);
+
if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
"NCR 53C94 SCSI", NULL))
goto err_dealloc;
if (request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT,
"JUNKIO SCSI DMA", NULL))
goto err_free_irq;
-
-
- esp->scsi_id = 7;
-
- /* Check for differential SCSI-bus */
- esp->diff = 0;
-
- esp_initialize(esp);
-
+
}
-#ifdef PMAZ_A
if (TURBOCHANNEL) {
- while ((slot = search_tc_card("PMAZ_AA")) >= 0) {
+ while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
claim_tc_card(slot);
- mem_start = get_tc_base_addr(slot);
esp_dev = 0;
esp = esp_allocate(tpnt, (void *) esp_dev);
+ mem_start = get_tc_base_addr(slot);
+
+ /* Store base addr into esp struct */
+ esp->slot = mem_start;
+
esp->dregs = 0;
esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG);
esp->do_pio_cmds = 1;
@@ -217,16 +219,6 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
/* get virtual dma address for command buffer */
esp->esp_command_dvma = (__u32) KSEG0ADDR((volatile unsigned char *) pmaz_cmd_buffer);
- buffer = (volatile unsigned char *) (mem_start + DEC_SCSI_SRAM);
-
- scsi_pmaz_dma_ptr_tc = (volatile int *) (mem_start + DEC_SCSI_DMAREG);
-
- for (i = 0; i < ESP_NCMD; i++) {
- scsi_pmaz_dma_ptrs_tc[i] = (volatile unsigned char *) (buffer + ESP_TGT_DMA_SIZE * i);
- }
-
- scsi_pmaz_dma_buff_used[0] = 1;
-
esp->cfreq = get_tc_speed();
esp->irq = get_tc_irq_nr(slot);
@@ -260,18 +252,17 @@ int dec_esp_detect(Scsi_Host_Template * tpnt)
esp->dma_mmu_release_scsi_sgl = 0;
esp->dma_advance_sg = 0;
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
- "PMAZ_AA", NULL)) {
- esp_deallocate(esp);
- release_tc_card(slot);
- continue;
- }
+ if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ "PMAZ_AA", NULL)) {
+ esp_deallocate(esp);
+ release_tc_card(slot);
+ continue;
+ }
esp->scsi_id = 7;
esp->diff = 0;
esp_initialize(esp);
}
}
-#endif
if(nesps) {
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
@@ -476,30 +467,35 @@ static void dma_advance_sg(Scsi_Cmnd * sp)
sp->SCp.ptr = (char *) ((unsigned long) sp->SCp.buffer->dvma_address);
}
-#ifdef PMAZ_A
-
static void pmaz_dma_drain(struct NCR_ESP *esp)
{
memcpy((void *) (KSEG0ADDR(esp_virt_buffer)),
- (void *) scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], scsi_current_length);
+ (void *) ( esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE),
+ scsi_current_length);
}
static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
{
+ volatile int *dmareg = (volatile int *) (esp->slot + DEC_SCSI_DMAREG);
if (length > ESP_TGT_DMA_SIZE)
length = ESP_TGT_DMA_SIZE;
- *scsi_pmaz_dma_ptr_tc = TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]);
+ *dmareg = TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE);
+
esp_virt_buffer = vaddress;
scsi_current_length = length;
}
static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
{
- memcpy((void *)scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], KSEG0ADDR((void *) vaddress), length);
+ volatile int *dmareg = (volatile int *) ( esp->slot + DEC_SCSI_DMAREG );
+
+ memcpy((void *) (esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE),
+ KSEG0ADDR((void *) vaddress), length);
- *scsi_pmaz_dma_ptr_tc = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]);
+ *dmareg = TC_ESP_DMAR_WRITE |
+ TC_ESP_DMA_ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE);
}
@@ -524,18 +520,9 @@ static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write
}
}
-static void pmaz_dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
-{
- int x;
- for (x = 1; x < 6; x++)
- if (sp->SCp.have_data_in == PHYSADDR(scsi_pmaz_dma_ptrs_tc[x]))
- scsi_pmaz_dma_buff_used[x] = 0;
-}
-
static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp)
{
sp->SCp.have_data_in = (int) sp->SCp.ptr =
(char *) KSEG0ADDR((sp->request_buffer));
}
-#endif
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index ddf8c957caca..1ee77dba489e 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1081,6 +1081,9 @@ static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u3
{
struct adpt_device* d;
+ if(chan < 0 || chan >= MAX_CHANNEL)
+ return NULL;
+
if( pHba->channel[chan].device == NULL){
printk(KERN_DEBUG"Adaptec I2O RAID: Trying to find device before they are allocated\n");
return NULL;
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
new file mode 100644
index 000000000000..0bd3a64e24ec
--- /dev/null
+++ b/drivers/scsi/lasi700.c
@@ -0,0 +1,188 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* PARISC LASI driver for the 53c700 chip
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/*
+ * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
+ * debugging this driver on the parisc architecture and suggesting
+ * many improvements and bug fixes.
+ *
+ * Thanks also go to Linuxcare Inc. for providing several PARISC
+ * machines for me to debug the driver on.
+ */
+
+#ifndef __hppa__
+#error "lasi700 only compiles on hppa architecture"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/blk.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/delay.h>
+#include <asm/gsc.h>
+
+#include <linux/module.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#include "lasi700.h"
+#include "53c700.h"
+
+#ifdef MODULE
+
+char *lasi700; /* command line from insmod */
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("lasi700 SCSI Driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(lasi700, "s");
+
+#endif
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+static unsigned long __initdata opt_base;
+static int __initdata opt_irq;
+
+static int __init
+param_setup(char *string)
+{
+ char *pos = string, *next;
+
+ while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
+ int val = (int)simple_strtoul(++next, NULL, 0);
+
+ if(!strncmp(pos, "addr:", 5))
+ opt_base = val;
+ else if(!strncmp(pos, "irq:", 4))
+ opt_irq = val;
+
+ if((pos = strchr(pos, ARG_SEP)) != NULL)
+ pos++;
+ }
+ return 1;
+}
+
+#ifndef MODULE
+__setup("lasi700=", param_setup);
+#endif
+
+static Scsi_Host_Template __initdata *host_tpnt = NULL;
+static int __initdata host_count = 0;
+static struct parisc_device_id lasi700_scsi_tbl[] = {
+ LASI700_ID_TABLE,
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(parisc, lasi700_scsi_tbl);
+
+static struct parisc_driver lasi700_driver = LASI700_DRIVER;
+
+static int __init
+lasi700_detect(Scsi_Host_Template *tpnt)
+{
+ host_tpnt = tpnt;
+
+#ifdef MODULE
+ if(lasi700)
+ param_setup(lasi700);
+#endif
+
+ register_parisc_driver(&lasi700_driver);
+
+ return (host_count != 0);
+}
+
+static int __init
+lasi700_driver_callback(struct parisc_device *dev)
+{
+ unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET;
+ int irq = busdevice_alloc_irq(dev);
+ struct Scsi_Host *host;
+ struct NCR_700_Host_Parameters *hostdata =
+ kmalloc(sizeof(struct NCR_700_Host_Parameters),
+ GFP_KERNEL);
+ if(hostdata == NULL) {
+ printk(KERN_ERR "lasi700: Failed to allocate host data\n");
+ return 1;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+ if(request_mem_region(base, 64, "lasi700") == NULL) {
+ printk(KERN_ERR "lasi700: Failed to claim memory region\n");
+ kfree(hostdata);
+ return 1;
+ }
+ hostdata->base = base;
+ hostdata->differential = 0;
+ hostdata->clock = LASI700_CLOCK;
+ hostdata->force_le_on_be = 1;
+ if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) {
+ kfree(hostdata);
+ release_mem_region(host->base, 64);
+ return 1;
+ }
+ host->irq = irq;
+ if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) {
+ printk(KERN_ERR "lasi700: irq problem, detatching\n");
+ scsi_unregister(host);
+ NCR_700_release(host);
+ return 1;
+ }
+ host_count++;
+ return 0;
+}
+
+static int
+lasi700_release(struct Scsi_Host *host)
+{
+ struct D700_Host_Parameters *hostdata =
+ (struct D700_Host_Parameters *)host->hostdata[0];
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ release_mem_region(host->base, 64);
+ return 1;
+}
+
+static Scsi_Host_Template driver_template = LASI700_SCSI;
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/lasi700.h b/drivers/scsi/lasi700.h
new file mode 100644
index 000000000000..2c2cee9cdd83
--- /dev/null
+++ b/drivers/scsi/lasi700.h
@@ -0,0 +1,57 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* PARISC LASI driver for the 53c700 chip
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+#ifndef _LASI700_H
+#define _LASI700_H
+
+static int lasi700_detect(Scsi_Host_Template *);
+static int lasi700_driver_callback(struct parisc_device *dev);
+static int lasi700_release(struct Scsi_Host *host);
+
+
+#define LASI700_SCSI { \
+ name: "LASI SCSI 53c700", \
+ proc_name: "lasi700", \
+ detect: lasi700_detect, \
+ release: lasi700_release, \
+ this_id: 7, \
+}
+
+#define LASI700_ID_TABLE { \
+ hw_type: HPHW_FIO, \
+ sversion: 0x071, \
+ hversion: HVERSION_ANY_ID, \
+ hversion_rev: HVERSION_REV_ANY_ID, \
+}
+
+#define LASI700_DRIVER { \
+ name: "Lasi SCSI", \
+ id_table: lasi700_scsi_tbl, \
+ probe: lasi700_driver_callback,\
+}
+
+#define LASI700_CLOCK 25
+#define LASI_SCSI_CORE_OFFSET 0x100
+
+#endif
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index eb21e36e61ba..802f1f625878 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -3138,16 +3138,18 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
* First argument (major) to register_chrdev implies a dynamic major
* number allocation.
*/
- major = register_chrdev (0, "megadev", &megadev_fops);
+ if (count) {
+ major = register_chrdev (0, "megadev", &megadev_fops);
- /*
- * Register the Shutdown Notification hook in kernel
- */
- if (register_reboot_notifier (&mega_notifier)) {
- printk ("MegaRAID Shutdown routine not registered!!\n");
- }
+ /*
+ * Register the Shutdown Notification hook in kernel
+ */
+ if (register_reboot_notifier (&mega_notifier)) {
+ printk ("MegaRAID Shutdown routine not registered!!\n");
+ }
- init_MUTEX (&mimd_entry_mtx);
+ init_MUTEX (&mimd_entry_mtx);
+ }
return count;
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 0d9343e7fd60..91a1e0258d81 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -421,6 +421,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
static unsigned char generic_sense[6] =
{REQUEST_SENSE, 0, 0, 0, 255, 0};
unsigned char scsi_result0[256], *scsi_result = NULL;
+ int saved_result;
ASSERT_LOCK(&io_request_lock, 0);
@@ -446,6 +447,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
memset((void *) scsi_result, 0, 256);
+ saved_result = SCpnt->result;
SCpnt->request_buffer = scsi_result;
SCpnt->request_bufflen = 256;
SCpnt->use_sg = 0;
@@ -470,6 +472,7 @@ STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
*/
memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
sizeof(SCpnt->data_cmnd));
+ SCpnt->result = saved_result;
SCpnt->request_buffer = SCpnt->buffer;
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->use_sg = SCpnt->old_use_sg;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d8c61f5537f5..bea96170a4df 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -563,16 +563,11 @@ static struct block_device_operations sd_fops =
static struct gendisk sd_gendisk =
{
- SCSI_DISK0_MAJOR, /* Major number */
- "sd", /* Major name */
- 4, /* Bits to shift to get real from partition */
- 1 << 4, /* Number of partitions per real */
- NULL, /* hd struct */
- NULL, /* block sizes */
- 0, /* number */
- NULL, /* internal */
- NULL, /* next */
- &sd_fops, /* file operations */
+ major: SCSI_DISK0_MAJOR,
+ major_name: "sd",
+ minor_shift: 4,
+ max_p: 1 << 4,
+ fops: &sd_fops,
};
static struct gendisk *sd_gendisks = &sd_gendisk;
@@ -1021,7 +1016,7 @@ static int sd_init_onedisk(int i)
cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ?
((rscsi_disks[i].device->lun << 5) & 0xe0) : 0;
cmd[2] = 0x3f; /* Get all pages */
- cmd[4] = 255; /* But we only want the 8 byte header */
+ cmd[4] = 255; /* Ask for 255 bytes, even tho we want just the first 8 */
SRpnt->sr_cmd_len = 0;
SRpnt->sr_sense_buffer[0] = 0;
SRpnt->sr_sense_buffer[2] = 0;
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 50a7bb34d06e..a7b441d38447 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -281,18 +281,30 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
sgiwd93_host->irq = SGI_WD93_0_IRQ;
buf = (uchar *) get_free_page(GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_WARNING "sgiwd93: Could not allocate memory for host0 buffer.\n");
+ scsi_unregister(sgiwd93_host);
+ return 0;
+ }
init_hpc_chain(buf);
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
/* HPC_SCSI_REG0 | 0x03 | KSEG1 */
- wd33c93_init(sgiwd93_host, (wd33c93_regs *) 0xbfbc0003,
+ wd33c93_init(sgiwd93_host, (wd33c93_regs *) KSEG1ADDR (0x1fbc0003),
dma_setup, dma_stop, WD33C93_FS_16_20);
hdata = (struct WD33C93_hostdata *)sgiwd93_host->hostdata;
hdata->no_sync = 0;
hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
- dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
- request_irq(SGI_WD93_0_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host);
+ if (request_irq(SGI_WD93_0_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host)) {
+ printk(KERN_WARNING "sgiwd93: Could not register IRQ %d (for host 0).\n", SGI_WD93_0_IRQ);
+#ifdef MODULE
+ wd33c93_release();
+#endif
+ free_page((unsigned long)buf);
+ scsi_unregister(sgiwd93_host);
+ return 0;
+ }
/* set up second controller on the Indigo2 */
if(!sgi_guiness) {
sgiwd93_host1 = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata));
@@ -302,10 +314,16 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
sgiwd93_host1->irq = SGI_WD93_1_IRQ;
buf = (uchar *) get_free_page(GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_WARNING "sgiwd93: Could not allocate memory for host1 buffer.\n");
+ scsi_unregister(sgiwd93_host1);
+ called = 1;
+ return 1; /* We registered host0 so return success*/
+ }
init_hpc_chain(buf);
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
/* HPC_SCSI_REG1 | 0x03 | KSEG1 */
- wd33c93_init(sgiwd93_host1, (wd33c93_regs *) 0xbfbc8003,
+ wd33c93_init(sgiwd93_host1, (wd33c93_regs *) KSEG1ADDR (0x1fbc8003),
dma_setup, dma_stop, WD33C93_FS_16_20);
hdata1 = (struct WD33C93_hostdata *)sgiwd93_host1->hostdata;
@@ -313,7 +331,15 @@ int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
hdata1->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf));
dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
- request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1);
+ if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) {
+ printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ);
+#ifdef MODULE
+ wd33c93_release();
+#endif
+ free_page((unsigned long)buf);
+ scsi_unregister(sgiwd93_host1);
+ /* Fall through since host0 registered OK */
+ }
}
}
diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c
index dac53001ccc3..3139a8c448ad 100644
--- a/drivers/sound/i810_audio.c
+++ b/drivers/sound/i810_audio.c
@@ -106,6 +106,7 @@
static int ftsodell=0;
static int strict_clocking=0;
static unsigned int clocking=48000;
+static int spdif_locked=0;
//#define DEBUG
//#define DEBUG2
@@ -118,6 +119,11 @@ static unsigned int clocking=48000;
#define I810_FMT_STEREO 2
#define I810_FMT_MASK 3
+#define SPDIF_ON 0x0004
+#define SURR_ON 0x0010
+#define CENTER_LFE_ON 0x0020
+#define VOL_MUTED 0x8000
+
/* the 810's array of pointers to data buffers */
struct sg_item {
@@ -325,6 +331,8 @@ struct i810_card {
struct i810_state *states[NR_HW_CH];
u16 ac97_features;
+ u16 ac97_status;
+ u16 channels;
/* hardware resources */
unsigned long iobase;
@@ -401,11 +409,164 @@ static void i810_free_pcm_channel(struct i810_card *card, int channel)
card->channel[channel].used=0;
}
+static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate )
+{
+ unsigned long id = 0L;
+
+ id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16);
+ id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
+#ifdef DEBUG
+ printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id);
+#endif
+ switch ( id ) {
+ case 0x41445361: /* AD1886 */
+ if (rate == 48000) {
+ return 1;
+ }
+ break;
+ default: /* all other codecs, until we know otherwiae */
+ if (rate == 48000 || rate == 44100 || rate == 32000) {
+ return 1;
+ }
+ break;
+ }
+ return (0);
+}
+
+/* i810_set_spdif_output
+ *
+ * Configure the S/PDIF output transmitter. When we turn on
+ * S/PDIF, we turn off the analog output. This may not be
+ * the right thing to do.
+ *
+ * Assumptions:
+ * The DSP sample rate must already be set to a supported
+ * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
+ */
+static void i810_set_spdif_output(struct i810_state *state, int slots, int rate)
+{
+ int vol;
+ int aud_reg;
+ struct ac97_codec *codec = state->card->ac97_codec[0];
+
+ if(!(state->card->ac97_features & 4)) {
+#ifdef DEBUG
+ printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
+#endif
+ state->card->ac97_status &= ~SPDIF_ON;
+ } else {
+ if ( slots == -1 ) { /* Turn off S/PDIF */
+ aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
+ i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+
+ /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
+ if ( !(state->card->ac97_status & VOL_MUTED) ) {
+ aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+ i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
+ }
+ state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
+ return;
+ }
+
+ vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO);
+ state->card->ac97_status = vol & VOL_MUTED;
+
+ /* Set S/PDIF transmitter sample rate */
+ aud_reg = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
+ switch ( rate ) {
+ case 32000:
+ aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
+ break;
+ case 44100:
+ aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
+ break;
+ case 48000:
+ aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
+ break;
+ default:
+#ifdef DEBUG
+ printk(KERN_WARNING "i810_audio: %d sample rate not supported by S/PDIF.\n", rate);
+#endif
+ /* turn off S/PDIF */
+ aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
+ i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+ state->card->ac97_status &= ~SPDIF_ON;
+ return;
+ }
+
+ i810_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
+
+ aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
+ aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_VRA | AC97_EA_SPDIF;
+ i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+ state->card->ac97_status |= SPDIF_ON;
+
+ /* Check to make sure the configuration is valid */
+ aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
+ if ( ! (aud_reg & 0x0400) ) {
+#ifdef DEBUG
+ printk(KERN_WARNING "i810_audio: S/PDIF transmitter configuration not valid (0x%04x).\n", aud_reg);
+#endif
+
+ /* turn off S/PDIF */
+ i810_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
+ state->card->ac97_status &= ~SPDIF_ON;
+ return;
+ }
+ /* Mute the analog output */
+ /* Should this only mute the PCM volume??? */
+ i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED));
+ }
+}
+
+/* i810_set_dac_channels
+ *
+ * Configure the codec's multi-channel DACs
+ *
+ * The logic is backwards. Setting the bit to 1 turns off the DAC.
+ *
+ * What about the ICH? We currently configure it using the
+ * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
+ * does that imply that we want the ICH set to support
+ * these channels?
+ *
+ * TODO:
+ * vailidate that the codec really supports these DACs
+ * before turning them on.
+ */
+static void i810_set_dac_channels(struct i810_state *state, int channel)
+{
+ int aud_reg;
+ struct ac97_codec *codec = state->card->ac97_codec[0];
+
+ aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
+ aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
+ state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
+
+ switch ( channel ) {
+ case 2: /* always enabled */
+ break;
+ case 4:
+ aud_reg &= ~AC97_EA_PRJ;
+ state->card->ac97_status |= SURR_ON;
+ break;
+ case 6:
+ aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
+ state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
+ break;
+ default:
+ break;
+ }
+ i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
+
+}
+
+
/* set playback sample rate */
static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u32 dacp, new_rate;
+ u32 new_rate;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
@@ -445,7 +606,7 @@ static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int ra
static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
{
struct dmabuf *dmabuf = &state->dmabuf;
- u32 dacp, new_rate;
+ u32 new_rate;
struct ac97_codec *codec=state->card->ac97_codec[0];
if(!(state->card->ac97_features&0x0001))
@@ -1359,7 +1520,9 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
- int val, mapped, ret;
+ unsigned int i_glob_cnt;
+ int val = 0, mapped, ret;
+ struct ac97_codec *codec = state->card->ac97_codec[0];
mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
((file->f_mode & FMODE_READ) && dmabuf->mapped);
@@ -1412,11 +1575,31 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_WRITE) {
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- i810_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
+ if ( (state->card->ac97_status & SPDIF_ON) ) { /* S/PDIF Enabled */
+ /* AD1886 only supports 48000, need to check that */
+ if ( i810_valid_spdif_rate ( codec, val ) ) {
+ /* Set DAC rate */
+ i810_set_spdif_output ( state, -1, 0 );
+ stop_dac(state);
+ dmabuf->ready = 0;
+ spin_lock_irqsave(&state->card->lock, flags);
+ i810_set_dac_rate(state, val);
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ /* Set S/PDIF transmitter rate. */
+ i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val );
+ if ( ! (state->card->ac97_status & SPDIF_ON) ) {
+ val = dmabuf->rate;
+ }
+ } else { /* Not a valid rate for S/PDIF, ignore it */
+ val = dmabuf->rate;
+ }
+ } else {
+ stop_dac(state);
+ dmabuf->ready = 0;
+ spin_lock_irqsave(&state->card->lock, flags);
+ i810_set_dac_rate(state, val);
+ spin_unlock_irqrestore(&state->card->lock, flags);
+ }
}
if (file->f_mode & FMODE_READ) {
stop_adc(state);
@@ -1467,7 +1650,18 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
#ifdef DEBUG
printk("SNDCTL_DSP_SETFMT\n");
#endif
- return put_user(AFMT_S16_LE, (int *)arg);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch ( val ) {
+ case AFMT_S16_LE:
+ break;
+ case AFMT_QUERY:
+ default:
+ val = AFMT_S16_LE;
+ break;
+ }
+ return put_user(val, (int *)arg);
case SNDCTL_DSP_CHANNELS:
#ifdef DEBUG
@@ -1477,14 +1671,61 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EFAULT;
if (val > 0) {
- if (dmabuf->enable & DAC_RUNNING) {
+ if (dmabuf->enable & DAC_RUNNING) {
stop_dac(state);
}
if (dmabuf->enable & ADC_RUNNING) {
stop_adc(state);
}
+ } else {
+ return put_user(state->card->channels, (int *)arg);
}
- return put_user(2, (int *)arg);
+
+ /* ICH and ICH0 only support 2 channels */
+ if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 )
+ return put_user(2, (int *)arg);
+
+ /* Multi-channel support was added with ICH2. Bits in */
+ /* Global Status and Global Control register are now */
+ /* used to indicate this. */
+
+ i_glob_cnt = inl(state->card->iobase + GLOB_CNT);
+
+ /* Current # of channels enabled */
+ if ( i_glob_cnt & 0x0100000 )
+ ret = 4;
+ else if ( i_glob_cnt & 0x0200000 )
+ ret = 6;
+ else
+ ret = 2;
+
+ switch ( val ) {
+ case 2: /* 2 channels is always supported */
+ outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff));
+ /* Do we need to change mixer settings???? */
+ break;
+ case 4: /* Supported on some chipsets, better check first */
+ if ( state->card->channels >= 4 ) {
+ outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000));
+ /* Do we need to change mixer settings??? */
+ } else {
+ val = ret;
+ }
+ break;
+ case 6: /* Supported on some chipsets, better check first */
+ if ( state->card->channels >= 6 ) {
+ outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000));
+ /* Do we need to change mixer settings??? */
+ } else {
+ val = ret;
+ }
+ break;
+ default: /* nothing else is ever supported by the chipset */
+ val = ret;
+ break;
+ }
+
+ return put_user(val, (int *)arg);
case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
/* we update the swptr to the end of the last sg segment then return */
@@ -1731,6 +1972,148 @@ static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
#endif
return put_user(AFMT_S16_LE, (int *)arg);
+ case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
+#ifdef DEBUG
+ printk("SNDCTL_DSP_SETSPDIF\n");
+#endif
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ /* Check to make sure the codec supports S/PDIF transmitter */
+
+ if((state->card->ac97_features & 4)) {
+ /* mask out the transmitter speed bits so the user can't set them */
+ val &= ~0x3000;
+
+ /* Add the current transmitter speed bits to the passed value */
+ ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
+ val |= (ret & 0x3000);
+
+ i810_ac97_set(codec, AC97_SPDIF_CONTROL, val);
+ if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) {
+ printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
+ return -EFAULT;
+ }
+ }
+#ifdef DEBUG
+ else
+ printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
+#endif
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
+#ifdef DEBUG
+ printk("SNDCTL_DSP_GETSPDIF\n");
+#endif
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ /* Check to make sure the codec supports S/PDIF transmitter */
+
+ if(!(state->card->ac97_features & 4)) {
+#ifdef DEBUG
+ printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n");
+#endif
+ val = 0;
+ } else {
+ val = i810_ac97_get(codec, AC97_SPDIF_CONTROL);
+ }
+ //return put_user((val & 0xcfff), (int *)arg);
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETCHANNELMASK:
+#ifdef DEBUG
+ printk("SNDCTL_DSP_GETCHANNELMASK\n");
+#endif
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ /* Based on AC'97 DAC support, not ICH hardware */
+ val = DSP_BIND_FRONT;
+ if ( state->card->ac97_features & 0x0004 )
+ val |= DSP_BIND_SPDIF;
+
+ if ( state->card->ac97_features & 0x0080 )
+ val |= DSP_BIND_SURR;
+ if ( state->card->ac97_features & 0x0140 )
+ val |= DSP_BIND_CENTER_LFE;
+
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_BIND_CHANNEL:
+#ifdef DEBUG
+ printk("SNDCTL_DSP_BIND_CHANNEL\n");
+#endif
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if ( val == DSP_BIND_QUERY ) {
+ val = DSP_BIND_FRONT; /* Always report this as being enabled */
+ if ( state->card->ac97_status & SPDIF_ON )
+ val |= DSP_BIND_SPDIF;
+ else {
+ if ( state->card->ac97_status & SURR_ON )
+ val |= DSP_BIND_SURR;
+ if ( state->card->ac97_status & CENTER_LFE_ON )
+ val |= DSP_BIND_CENTER_LFE;
+ }
+ } else { /* Not a query, set it */
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ if ( dmabuf->enable == DAC_RUNNING ) {
+ stop_dac(state);
+ }
+ if ( val & DSP_BIND_SPDIF ) { /* Turn on SPDIF */
+ /* Ok, this should probably define what slots
+ * to use. For now, we'll only set it to the
+ * defaults:
+ *
+ * non multichannel codec maps to slots 3&4
+ * 2 channel codec maps to slots 7&8
+ * 4 channel codec maps to slots 6&9
+ * 6 channel codec maps to slots 10&11
+ *
+ * there should be some way for the app to
+ * select the slot assignment.
+ */
+
+ i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate );
+ if ( !(state->card->ac97_status & SPDIF_ON) )
+ val &= ~DSP_BIND_SPDIF;
+ } else {
+ int mask;
+ int channels;
+
+ /* Turn off S/PDIF if it was on */
+ if ( state->card->ac97_status & SPDIF_ON )
+ i810_set_spdif_output ( state, -1, 0 );
+
+ mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE);
+ switch (mask) {
+ case DSP_BIND_FRONT:
+ channels = 2;
+ break;
+ case DSP_BIND_FRONT|DSP_BIND_SURR:
+ channels = 4;
+ break;
+ case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
+ channels = 6;
+ break;
+ default:
+ val = DSP_BIND_FRONT;
+ channels = 2;
+ break;
+ }
+ i810_set_dac_channels ( state, channels );
+
+ /* check that they really got turned on */
+ if ( !state->card->ac97_status & SURR_ON )
+ val &= ~DSP_BIND_SURR;
+ if ( !state->card->ac97_status & CENTER_LFE_ON )
+ val &= ~DSP_BIND_CENTER_LFE;
+ }
+ }
+ return put_user(val, (int *)arg);
+
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
@@ -1796,7 +2179,15 @@ found_virt:
card->states[i] = NULL;;
return -EBUSY;
}
- i810_set_dac_rate(state, 8000);
+ /* Initialize to 8kHz? What if we don't support 8kHz? */
+ /* Let's change this to check for S/PDIF stuff */
+
+ if ( spdif_locked ) {
+ i810_set_dac_rate(state, spdif_locked);
+ i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
+ } else {
+ i810_set_dac_rate(state, 8000);
+ }
dmabuf->trigger |= PCM_ENABLE_OUTPUT;
}
@@ -1866,20 +2257,23 @@ static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
{
struct i810_card *card = dev->private_data;
int count = 100;
+ u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
while(count-- && (inb(card->iobase + CAS) & 1))
udelay(1);
- return inw(card->ac97base + (reg&0x7f));
+
+ return inw(card->ac97base + reg_set);
}
static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
{
struct i810_card *card = dev->private_data;
int count = 100;
+ u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
while(count-- && (inb(card->iobase + CAS) & 1))
udelay(1);
- outw(data, card->ac97base + (reg&0x7f));
+ outw(data, card->ac97base + reg_set);
}
@@ -1920,7 +2314,7 @@ static /*const*/ struct file_operations i810_mixer_fops = {
static int __init i810_ac97_init(struct i810_card *card)
{
int num_ac97 = 0;
- int ready_2nd = 0;
+ int total_channels = 0;
struct ac97_codec *codec;
u16 eid;
int i=0;
@@ -1952,10 +2346,38 @@ static int __init i810_ac97_init(struct i810_card *card)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/5);
+
+ /* Number of channels supported */
+ /* What about the codec? Just because the ICH supports */
+ /* multiple channels doesn't mean the codec does. */
+ /* we'll have to modify this in the codec section below */
+ /* to reflect what the codec has. */
+ /* ICH and ICH0 only support 2 channels so don't bother */
+ /* to check.... */
+
+ card->channels = 2;
+ reg = inl(card->iobase + GLOB_STA);
+ if ( reg & 0x0200000 )
+ card->channels = 6;
+ else if ( reg & 0x0100000 )
+ card->channels = 4;
+ printk("i810_audio: Audio Controller supports %d channels.\n", card->channels);
inw(card->ac97base);
for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+
+ /* The ICH programmer's reference says you should */
+ /* check the ready status before probing. So we chk */
+ /* What do we do if it's not ready? Wait and try */
+ /* again, or abort? */
+ reg = inl(card->iobase + GLOB_STA);
+ if (!(reg & (0x100 << num_ac97))) {
+ if(num_ac97 == 0)
+ printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
+ break; /* I think this works, if not ready stop */
+ }
+
if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(codec, 0, sizeof(struct ac97_codec));
@@ -1983,6 +2405,9 @@ static int __init i810_ac97_init(struct i810_card *card)
schedule_timeout(HZ/20);
}
+ /* Store state information about S/PDIF transmitter */
+ card->ac97_status = 0;
+
/* Don't attempt to get eid until powerup is complete */
eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
@@ -2014,6 +2439,63 @@ static int __init i810_ac97_init(struct i810_card *card)
}
}
+ /* Determine how many channels the codec(s) support */
+ /* - The primary codec always supports 2 */
+ /* - If the codec supports AMAP, surround DACs will */
+ /* automaticlly get assigned to slots. */
+ /* * Check for surround DACs and increment if */
+ /* found. */
+ /* - Else check if the codec is revision 2.2 */
+ /* * If surround DACs exist, assign them to slots */
+ /* and increment channel count. */
+
+ /* All of this only applies to ICH2 and above. ICH */
+ /* and ICH0 only support 2 channels. ICH2 will only */
+ /* support multiple codecs in a "split audio" config. */
+ /* as described above. */
+
+ /* TODO: Remove all the debugging messages! */
+
+ if((eid & 0xc000) == 0) /* primary codec */
+ total_channels += 2;
+
+ if(eid & 0x200) { /* GOOD, AMAP support */
+ if (eid & 0x0080) /* L/R Surround channels */
+ total_channels += 2;
+ if (eid & 0x0140) /* LFE and Center channels */
+ total_channels += 2;
+ printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", num_ac97, total_channels);
+ } else if (eid & 0x0400) { /* this only works on 2.2 compliant codecs */
+ eid &= 0xffcf;
+ if((eid & 0xc000) != 0) {
+ switch ( total_channels ) {
+ case 2:
+ /* Set dsa1, dsa0 to 01 */
+ eid |= 0x0010;
+ break;
+ case 4:
+ /* Set dsa1, dsa0 to 10 */
+ eid |= 0x0020;
+ break;
+ case 6:
+ /* Set dsa1, dsa0 to 11 */
+ eid |= 0x0030;
+ break;
+ }
+ total_channels += 2;
+ }
+ i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
+ eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
+ printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", num_ac97, eid);
+ if (eid & 0x0080) /* L/R Surround channels */
+ total_channels += 2;
+ if (eid & 0x0140) /* LFE and Center channels */
+ total_channels += 2;
+ printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", num_ac97, total_channels);
+ } else {
+ printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", num_ac97, total_channels);
+ }
+
if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
printk(KERN_ERR "i810_audio: couldn't register mixer!\n");
kfree(codec);
@@ -2021,11 +2503,11 @@ static int __init i810_ac97_init(struct i810_card *card)
}
card->ac97_codec[num_ac97] = codec;
-
- /* if there is no secondary codec at all, don't probe any more */
- if (!ready_2nd)
- return num_ac97+1;
}
+
+ /* pick the minimum of channels supported by ICHx or codec(s) */
+ card->channels = (card->channels > total_channels)?total_channels:card->channels;
+
return num_ac97;
}
@@ -2221,6 +2703,7 @@ MODULE_DESCRIPTION("Intel 810 audio support");
MODULE_PARM(ftsodell, "i");
MODULE_PARM(clocking, "i");
MODULE_PARM(strict_clocking, "i");
+MODULE_PARM(spdif_locked, "i");
#define I810_MODULE_NAME "intel810_audio"
@@ -2250,6 +2733,15 @@ static int __init i810_init_module (void)
if(clocking == 48000) {
i810_configure_clocking();
}
+ if(spdif_locked > 0 ) {
+ if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) {
+ printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked);
+ } else {
+ printk("i810_audio: S/PDIF can only be locked to 32000, 441000, or 48000Hz.\n");
+ spdif_locked = 0;
+ }
+ }
+
return 0;
}
diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c
index 7f2b0d347809..51c5cf29e6f5 100644
--- a/drivers/sound/opl3sa2.c
+++ b/drivers/sound/opl3sa2.c
@@ -810,7 +810,7 @@ static void __exit unload_opl3sa2(struct address_info* hw_config, int card)
struct isapnp_device_id isapnp_opl3sa2_list[] __initdata = {
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021),
- NULL },
+ 0 },
{0}
};
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index e0bfdc9541d7..83e7cd921f19 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -145,7 +145,7 @@ static void __sound_remove_unit(struct sound_unit **list, int unit)
* This lock guards the sound loader list.
*/
-spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
/*
* Allocate the controlling structure and add it to the sound driver
diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c
index cf8f040ee493..1ea4615e0173 100644
--- a/drivers/sound/via82cxxx_audio.c
+++ b/drivers/sound/via82cxxx_audio.c
@@ -858,6 +858,7 @@ static void via_chan_pcm_fmt (struct via_channel *chan, int reset)
/**
* via_chan_clear - Stop DMA channel operation, and reset pointers
+ * @card: the chip to accessed
* @chan: Channel to be cleared
*
* Call via_chan_stop to halt DMA operations, and then resets
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index f118838131d0..e5d934b5861c 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -6693,7 +6693,10 @@ static int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd,
retval = ixj_init_filter_raw(j, &jfr);
break;
case IXJCTL_GET_FILTER_HIST:
- retval = j->filter_hist[arg];
+ if(arg<0||arg>3)
+ retval = -EINVAL;
+ else
+ retval = j->filter_hist[arg];
break;
case IXJCTL_INIT_TONE:
copy_from_user(&ti, (char *) arg, sizeof(ti));
diff --git a/drivers/video/radeon.h b/drivers/video/radeon.h
index 447fdb08b777..7e56c8a5a9a4 100644
--- a/drivers/video/radeon.h
+++ b/drivers/video/radeon.h
@@ -7,6 +7,7 @@
#define PCI_DEVICE_ID_RADEON_QE 0x5145
#define PCI_DEVICE_ID_RADEON_QF 0x5146
#define PCI_DEVICE_ID_RADEON_QG 0x5147
+#define PCI_DEVICE_ID_RADEON_VE 0x5159
#define RADEON_REGSIZE 0x4000
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
index d7c091559c8e..764c439c61c5 100644
--- a/drivers/video/radeonfb.c
+++ b/drivers/video/radeonfb.c
@@ -12,13 +12,14 @@
* 2001-07-05 fixed scrolling issues, engine initialization,
* and minor mode tweaking, 0.0.9
*
+ * 2001-09-07 Radeon VE support
*
* Special thanks to ATI DevRel team for their hardware donations.
*
*/
-#define RADEON_VERSION "0.0.9"
+#define RADEON_VERSION "0.0.10"
#include <linux/config.h>
@@ -62,7 +63,8 @@ enum radeon_chips {
RADEON_QD,
RADEON_QE,
RADEON_QF,
- RADEON_QG
+ RADEON_QG,
+ RADEON_VE
};
@@ -71,6 +73,7 @@ static struct pci_device_id radeonfb_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QE},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QF},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_QG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_QG},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_RADEON_VE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_VE},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, radeonfb_pci_table);
@@ -639,6 +642,9 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
case PCI_DEVICE_ID_RADEON_QG:
strcpy(rinfo->name, "Radeon QG ");
break;
+ case PCI_DEVICE_ID_RADEON_VE:
+ strcpy(rinfo->name, "Radeon VE ");
+ break;
default:
return -ENODEV;
}
@@ -754,7 +760,7 @@ static int radeonfb_pci_register (struct pci_dev *pdev,
radeon_engine_init (rinfo);
}
- printk ("radeonfb: ATI Radeon %s %d MB\n", rinfo->ram_type,
+ printk ("radeonfb: ATI %s %d MB\n",rinfo->name,
(rinfo->video_ram/(1024*1024)));
return 0;