## Automatically generated incremental diff
## From:   linux-2.2.16-pre7
## To:     linux-2.2.16-pre8
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.16-pre7/CREDITS linux/CREDITS
--- linux-2.2.16-pre7/CREDITS	Mon Dec  3 22:04:43 2001
+++ linux/CREDITS	Mon Dec  3 22:04:50 2001
@@ -1772,7 +1772,9 @@
 
 N: Paul Russell
 E: Paul.Russell@rustcorp.com.au
-W: http://www.rustcorp.com
+W: http://netfilter.filewatcher.org/ipchains
+W: http://www.samba.org/netfilter/ipchains
+W: http://netfilter.kernelnotes.org/ipchains
 D: Ruggedly handsome.
 D: Developed Generic IP Firewalling Chains with Michael Neuling.
 
@@ -2274,15 +2276,15 @@
 S: The Netherlands
 
 N: David Woodhouse
-E: David.Woodhouse@mvhi.com
-E: Dave@imladris.demon.co.uk
-D: Extensive ARCnet rewrite
-D: ARCnet COM20020, COM90xx IO-MAP drivers
-D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31)
-D: Contributed to NCPFS rewrite for 2.1.x dcache
-D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x
-S: 29, David Bull Way
-S: Milton, Cambridge. CB4 6DP
+E: dwmw2@infradead.org
+E: dwmw2@redhat.com
+D: ARCnet stuff, Applicom board driver, SO_BINDTODEVICE,
+D: some Alpha platform porting from 2.0, Memory Technology Devices,
+D: Acquire watchdog timer, PC speaker driver maintenance,
+D: various other stuff that annoyed me by not working.
+S: c/o Red Hat UK Limited
+S: 35-36 Cambridge Place
+S: Cambridge. CB2 1NS
 S: England
 
 N: Frank Xia
diff -urN linux-2.2.16-pre7/Documentation/Changes linux/Documentation/Changes
--- linux-2.2.16-pre7/Documentation/Changes	Tue Jan  4 10:12:10 2000
+++ linux/Documentation/Changes	Mon Dec  3 22:04:50 2001
@@ -264,7 +264,7 @@
 
    As of 2.1.102, the IP firewalling code has been replaced; ipfwadm
 will no longer work.  You need to obtain "ipchains," available from
-http://www.rustcorp.com/linux/ipchains/ , and use that instead of
+http://netfilter.filewatcher.org/ipchains/ , and use that instead of
 ipfwadm.
 
    To use masq forwarding you will need to obtain "ipmasqadm,"
@@ -718,8 +718,9 @@
 =========
 
 The 1.3.9 release:
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.gz
-ftp://ftp.rustcorp.com/ipchains/ipchains-1.3.9.tar.bz2
+http://netfilter.filewatcher.org/ipchains/ipchains-1.3.9.tar.bz2
+http://www.samba.org/netfilter/ipchains/ipchains-1.3.9.tar.bz2
+http://netfilter.kernelnotes.org/ipchains/ipchains-1.3.9.tar.bz2
 
 IP Masq Adm
 ===========
diff -urN linux-2.2.16-pre7/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.16-pre7/Documentation/Configure.help	Mon Dec  3 22:04:44 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:04:50 2001
@@ -2379,7 +2379,7 @@
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Also, you will need the ipchains tool (available on the WWW at
-  http://www.rustcorp.com/linux/ipchains/) to allow selective blocking
+  http://netfilter.kernelnotes.org/ipchains/) to allow selective blocking
   of Internet traffic based on type, origin and destination. 
   Note that the Linux firewall code has changed and the old program
   called ipfwadm won't work anymore. Please read the IPCHAINS-HOWTO.
@@ -10289,6 +10289,22 @@
   lspci -n and look for the PCI ID 5333:CA00. This driver 
   differs slightly from OSS/Free, so PLEASE READ
   Documentation/sound/sonicvibes.
+  
+Trident 4DWave DX/NX or SiS 7018 PCI Audio Core or ALi 5451
+CONFIG_SOUND_TRIDENT
+  Say Y or M if you have a PCI sound card utilizing the Trident
+  4DWave-DX/NX chipset or your mother board chipset has SiS 7018
+  built-in, or if you have an ALi 5451. The SiS 7018 PCI Audio Core
+  is embedded in SiS960 Super South Bridge and SiS540/630 Single
+  Chipset.
+
+  Use lspci -n to find out if your sound card or chipset uses
+  Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands
+  for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018.
+  PCI ID 10b9:5451 stands for ALi 5451.
+
+  This driver differs slightly from OSS/Free, so PLEASE READ the
+  comments at the beginning of driver/sound/trident.c
 
 Rockwell WaveArtist
 CONFIG_SOUND_WAVEARTIST
diff -urN linux-2.2.16-pre7/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.16-pre7/MAINTAINERS	Mon Dec  3 22:04:44 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:04:50 2001
@@ -433,7 +433,9 @@
 IP FIREWALL
 P:	Paul Russell
 M:	Paul.Russell@rustcorp.com.au
-W:	http://www.rustcorp.com/linux/ipchains
+W:	http://netfilter.filewatcher.org/ipchains
+W:	http://www.samba.org/netfilter/ipchains
+W:	http://netfilter.kernelnotes.org/ipchains
 S:	Supported
 
 IP MASQUERADING:
@@ -870,6 +872,13 @@
 L:	linux-net@vger.rutgers.edu
 L:	linux-tr@emissary.aus-etc.com
 S:	Maintained
+
+TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE/ALi 5451
+P:	Ollie Lho
+M:	ollie@sis.com.tw
+L:	linux-kernel@vger.rutgers.edu
+S:	Supported
+
 
 U14-34F SCSI DRIVER
 P:	Dario Ballabio
diff -urN linux-2.2.16-pre7/Makefile linux/Makefile
--- linux-2.2.16-pre7/Makefile	Mon Dec  3 22:04:44 2001
+++ linux/Makefile	Mon Dec  3 22:04:50 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 16
-EXTRAVERSION = pre7
+EXTRAVERSION = pre8
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.16-pre7/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- linux-2.2.16-pre7/drivers/block/ide-pci.c	Wed May  3 17:16:33 2000
+++ linux/drivers/block/ide-pci.c	Mon Dec  3 22:04:50 2001
@@ -24,6 +24,7 @@
 
 #include "ide.h"
 
+#define DEVID_450NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
 #define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
 #define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
 #define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
@@ -111,6 +112,8 @@
 #define INIT_CS5530     NULL
 #endif
 
+static int autodma_default = 0;
+
 typedef struct ide_pci_enablebit_s {
 	byte	reg;	/* byte pci reg holding the enable-bit */
 	byte	mask;	/* mask to isolate the enable-bit */
@@ -296,14 +299,12 @@
  */
 __initfunc(static void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d))
 {
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
+	unsigned int port, at_least_one_hwif_enabled = 0, pciirq = 0;
 	unsigned short pcicmd = 0, tried_config = 0;
 	byte tmp = 0;
 	ide_hwif_t *hwif, *mate = NULL;
+	int autodma = autodma_default;
 
-#ifdef CONFIG_IDEDMA_AUTO
-	autodma = 1;
-#endif
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
 		printk("%s: error accessing PCI regs\n", d->name);
@@ -443,6 +444,19 @@
 
 	if (!pci_present())
 		return;
+
+#ifdef CONFIG_IDEDMA_AUTO
+	autodma_default = 1;
+	for(dev = pci_devices; dev; dev=dev->next) {
+		devid.vid = dev->vendor;
+		devid.did = dev->device;
+		if (IDE_PCI_DEVID_EQ(devid, DEVID_450NX)) {
+			autodma_default = 0;
+			break;
+		}
+	}
+#endif
+
 	for(dev = pci_devices; dev; dev=dev->next) {
 		devid.vid = dev->vendor;
 		devid.did = dev->device;
diff -urN linux-2.2.16-pre7/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.2.16-pre7/drivers/cdrom/cdrom.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/cdrom/cdrom.c	Mon Dec  3 22:04:50 2001
@@ -208,11 +208,16 @@
   DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and
   dvd_do_auth passed uninitialized data to drive because init_cdrom_command
   did not clear a 0 sized buffer.
+
+  3.09 May 12, 2000 - Jens Axboe <axboe@suse.de>
+  -- Fix Video-CD on SCSI drives that don't support READ_CD command. In
+  that case switch block size and issue plain READ_10 again, then switch
+  back.
  
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 3.08"
-#define VERSION "Id: cdrom.c 3.08 2000/05/01"
+#define REVISION "Revision: 3.09"
+#define VERSION "Id: cdrom.c 3.09 2000/05/12"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -455,7 +460,7 @@
 	if ((cdi = cdrom_find_device(dev)) == NULL)
 		return -ENODEV;
 
-	if (fp->f_mode & FMODE_WRITE)
+	if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM))
 		return -EROFS;
 
 	/* if this was a O_NONBLOCK open and we should honor the flags,
@@ -1363,6 +1368,28 @@
 	return 0;
 }
 
+/*
+ * Specific READ_10 interface
+ */
+static int cdrom_read_cd(struct cdrom_device_info *cdi,
+			 struct cdrom_generic_command *cgc, int lba,
+			 int blocksize, int nblocks)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+
+	memset(&cgc->cmd, 0, sizeof(cgc->cmd));
+	cgc->cmd[0] = GPCMD_READ_10;
+	cgc->cmd[2] = (lba >> 24) & 0xff;
+	cgc->cmd[3] = (lba >> 16) & 0xff;
+	cgc->cmd[4] = (lba >>  8) & 0xff;
+	cgc->cmd[5] = lba & 0xff;
+	cgc->cmd[6] = (nblocks >> 16) & 0xff;
+	cgc->cmd[7] = (nblocks >>  8) & 0xff;
+	cgc->cmd[8] = nblocks & 0xff;
+	cgc->buflen = blocksize * nblocks;
+	return cdo->generic_packet(cdi, cgc);
+}
+
 /* very generic interface for reading the various types of blocks */
 static int cdrom_read_block(struct cdrom_device_info *cdi,
 			    struct cdrom_generic_command *cgc,
@@ -1779,6 +1806,34 @@
 	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
 }
 
+/*
+ * Required when we need to use READ_10 to issue other than 2048 block
+ * reads
+ */
+static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
+{
+	struct cdrom_device_ops *cdo = cdi->ops;
+	struct cdrom_generic_command cgc;
+	struct modesel_head mh;
+
+	memset(&mh, 0, sizeof(mh));
+	mh.block_desc_length = 0x08;
+	mh.block_length_med = (size >> 8) & 0xff;
+	mh.block_length_lo = size & 0xff;
+
+	memset(&cgc, 0, sizeof(cgc));
+	cgc.cmd[0] = 0x15;
+	cgc.cmd[1] = 1 << 4;
+	cgc.cmd[4] = 12;
+	cgc.buflen = sizeof(mh);
+	cgc.buffer = (char *) &mh;
+	mh.block_desc_length = 0x08;
+	mh.block_length_med = (size >> 8) & 0xff;
+	mh.block_length_lo = size & 0xff;
+
+	return cdo->generic_packet(cdi, &cgc);
+}
+
 static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
 		     unsigned long arg)
 {		
@@ -1820,8 +1875,20 @@
 		if (cgc.buffer == NULL)
 			return -ENOMEM;
 		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
-		if (!ret)
-			if (copy_to_user((char *)arg, cgc.buffer, blocksize))
+		if (ret) {
+			/*
+			 * SCSI-II devices are not required to support
+			 * READ_CD, so let's try switching block size
+			 */
+			/* FIXME: switch back again... */
+			if ((ret = cdrom_switch_blocksize(cdi, blocksize))) {
+				kfree(cgc.buffer);
+				return ret;
+			}
+			ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1);
+			ret |= cdrom_switch_blocksize(cdi, blocksize);
+		}
+		if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize))
 				ret = -EFAULT;
 		kfree(cgc.buffer);
 		return ret;
@@ -1858,8 +1925,7 @@
 		}
 
 		while (ra.nframes > 0) {
-			ret = cdrom_read_block(cdi, &cgc, lba, frames, 1,
-					       CD_FRAMESIZE_RAW);
+			ret = cdrom_read_block(cdi, &cgc, lba, frames, 1, CD_FRAMESIZE_RAW);
 			if (ret) break;
 			__copy_to_user(ra.buf, cgc.buffer,
 				       CD_FRAMESIZE_RAW * frames);
diff -urN linux-2.2.16-pre7/drivers/char/lp.c linux/drivers/char/lp.c
--- linux-2.2.16-pre7/drivers/char/lp.c	Tue Jan  4 10:12:14 2000
+++ linux/drivers/char/lp.c	Mon Dec  3 22:04:50 2001
@@ -202,7 +202,7 @@
 /* Test if the printer is not acking the strobe */
 #define	LP_NO_ACKING(status)	((status) & LP_PACK)
 /* Test if the printer has error conditions */
-#define LP_NO_ERROR(status)	((status) & LP_PERRORP)
+#define LP_NO_ERROR(minor, status)	((!(LP_F(minor) & LP_CAREFUL)) ? ((status) & LP_PERRORP) : (((status) & (LP_PERRORP|LP_POUTPA|LP_PSELECD)) == (LP_PERRORP|LP_PSELECD)))
 
 #undef LP_DEBUG
 #undef LP_READ_DEBUG
@@ -289,7 +289,7 @@
 		lp_yield(minor);
 
 		status = r_str(minor);
-		if (LP_NO_ERROR(status))
+		if (LP_NO_ERROR(minor, status))
 		{
 			if (LP_READY(status))
 				break;
diff -urN linux-2.2.16-pre7/drivers/char/random.c linux/drivers/char/random.c
--- linux-2.2.16-pre7/drivers/char/random.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/char/random.c	Mon Dec  3 22:04:50 2001
@@ -138,7 +138,7 @@
  * add_interrupt_randomness() uses the inter-interrupt timing as random
  * inputs to the entropy pool.  Note that not all interrupts are good
  * sources of randomness!  For example, the timer interrupts is not a
- * good choice, because the periodicity of the interrupts is to
+ * good choice, because the periodicity of the interrupts is too
  * regular, and hence predictable to an attacker.  Disk interrupts are
  * a better measure, since the timing of the disk interrupts are more
  * unpredictable.
diff -urN linux-2.2.16-pre7/drivers/net/acenic.c linux/drivers/net/acenic.c
--- linux-2.2.16-pre7/drivers/net/acenic.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/net/acenic.c	Mon Dec  3 22:04:50 2001
@@ -606,6 +606,7 @@
 MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
+#endif
 
 
 void __exit ace_module_cleanup(void)
@@ -695,7 +696,6 @@
 		root_dev = next;
 	}
 }
-#endif
 
 
 int __init ace_module_init(void)
diff -urN linux-2.2.16-pre7/drivers/net/hamachi.c linux/drivers/net/hamachi.c
--- linux-2.2.16-pre7/drivers/net/hamachi.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/net/hamachi.c	Mon Dec  3 22:04:50 2001
@@ -225,7 +225,7 @@
 
 
 #if (LINUX_VERSION_CODE >= 0x20100)
-char kernel_version[] = UTS_RELEASE;
+static char kernel_version[] = UTS_RELEASE;
 #else
 #ifndef __alpha__
 #define ioremap vremap
diff -urN linux-2.2.16-pre7/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux-2.2.16-pre7/drivers/scsi/scsi.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/scsi/scsi.c	Mon Dec  3 22:04:51 2001
@@ -114,7 +114,6 @@
 #define BLIST_MAX5LUN	0x080
 #define BLIST_ISDISK	0x100
 #define BLIST_ISROM	0x200
-#define BLIST_GHOST	0x400
 
 /*
  * Data declarations.
@@ -307,13 +306,7 @@
 {"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
-{"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
-{"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
-{"AOpen","PD-2 DVD-520S","*", BLIST_GHOST},
-{"HITACHI","GF-1050","*", BLIST_GHOST},        /* Hitachi SCSI DVD-RAM */
 {"TOSHIBA","CDROM","*", BLIST_ISROM},
-{"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST},
-{"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST},
 {"MegaRAID", "LD", "*", BLIST_FORCELUN},
 /*
  * Must be at end of list...
@@ -677,8 +670,6 @@
   struct Scsi_Device_Template *sdtpnt;
   Scsi_Device * SDtail, *SDpnt=*SDpnt2;
   int bflags, type=-1;
-  static int ghost_channel=-1, ghost_dev=-1;
-  int org_lun = lun;
 
   SDpnt->host = shpnt;
   SDpnt->id = dev;
@@ -686,12 +677,6 @@
   SDpnt->channel = channel;
   SDpnt->online = TRUE;
 
-  if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) {
-    SDpnt->lun = 0;
-  } else {
-    ghost_channel = ghost_dev = -1;
-  }
-
   /* Some low level driver could use device->type (DB) */
   SDpnt->type = -1;
 
@@ -804,17 +789,6 @@
     scsi_result[1] |= 0x80;     /* removable */
   }
 
-  if (bflags & BLIST_GHOST) {
-    if ((ghost_channel == channel) && (ghost_dev == dev) && (org_lun == 1)) {
-      lun=1;
-    } else {
-      ghost_channel = channel;
-      ghost_dev = dev;
-      scsi_result[0] = TYPE_MOD;
-      scsi_result[1] |= 0x80;     /* removable */
-    }
-  }
-
   memcpy (SDpnt->vendor, scsi_result + 8, 8);
   memcpy (SDpnt->model, scsi_result + 16, 16);
   memcpy (SDpnt->rev, scsi_result + 32, 4);
@@ -999,15 +973,6 @@
    */
   if (bflags & BLIST_FORCELUN) {
     *max_dev_lun = 8;
-    return 1;
-  }
-
-  /*
-   * If this device is Ghosted, scan upto two luns. (It physically only
-   * has one). -- REW
-   */
-  if (bflags & BLIST_GHOST) {
-    *max_dev_lun = 2;
     return 1;
   }
 
diff -urN linux-2.2.16-pre7/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- linux-2.2.16-pre7/drivers/scsi/sg.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/scsi/sg.c	Mon Dec  3 22:04:51 2001
@@ -16,8 +16,8 @@
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.37 (20000504)";
- static int sg_version_num = 20137; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.1.38 (20000527)";
+ static int sg_version_num = 20138; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -35,7 +35,7 @@
  *          # echo "scsi dump 1" > /proc/scsi/scsi 
  *        To dump the state of sg's data structures get the 'sg_debug'
  *        program from the utilities and enter:
- *          # sg_debug /dev/sga 
+ *          # sg_debug /dev/sg0 
  *        or any valid sg device name. The state of _all_ sg devices
  *        will be sent to the console and the log.
  *
@@ -127,6 +127,7 @@
     Sg_scatter_hold data;       /* hold buffer, perhaps scatter list */
     struct sg_header header;    /* scsi command+info, see <scsi/sg.h> */
     char res_used;              /* 1 -> using reserve buffer, 0 -> not ... */
+    char done;                  /* 0->before bh, 1->before read, 2->read */
 } Sg_request; /* 72 bytes long on i386 */
 
 typedef struct sg_fd /* holds the state of a file descriptor */
@@ -186,7 +187,7 @@
 static void sg_low_free(char * buff, int size, int mem_src);
 static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
-static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
+static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp);
 static int sg_res_in_use(const Sg_fd * sfp);
@@ -319,13 +320,13 @@
         copy_from_user(&hdr, buf, size_sg_header);
         req_pack_id = hdr.pack_id;
     }
-    srp = sg_get_request(sfp, req_pack_id);
+    srp = sg_get_rq_mark(sfp, req_pack_id);
     if (! srp) { /* now wait on packet to arrive */
         if (filp->f_flags & O_NONBLOCK)
             return -EAGAIN;
         res = 0;  /* following is a macro that beats race condition */
         __wait_event_interruptible(sfp->read_wait, 
-                                   (srp = sg_get_request(sfp, req_pack_id)),
+                                   (srp = sg_get_rq_mark(sfp, req_pack_id)),
                                    res);
         if (res)
             return res; /* -ERESTARTSYS because signal hit process */
@@ -533,7 +534,7 @@
         if (result) return result;
         srp = sfp->headrp;
         while (srp) {
-            if (! srp->my_cmdp) {
+            if (1 == srp->done) {
                 __put_user(srp->header.pack_id, (int *)arg);
                 return 0;
             }
@@ -545,7 +546,7 @@
         srp = sfp->headrp;
         val = 0;
         while (srp) {
-            if (! srp->my_cmdp)
+            if (1 == srp->done)
                 ++val;
             srp = srp->nextrp;
         }
@@ -673,7 +674,7 @@
     poll_wait(filp, &sfp->read_wait, wait);
     srp = sfp->headrp;
     while (srp) {   /* if any read waiting, flag it */
-        if (! (res || srp->my_cmdp))
+        if ((0 == res) && (1 == srp->done))
             res = POLLIN | POLLRDNORM;
         ++count;
         srp = srp->nextrp;
@@ -753,6 +754,7 @@
     srp->data.buffer = SCpnt->buffer;
     sg_clr_scpnt(SCpnt);
     srp->my_cmdp = NULL;
+    srp->done = 1;
 
     SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n", 
                 dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
@@ -885,9 +887,9 @@
     dev = MINOR(sdp->i_rdev);
 
     if (part_of)
-        printk(" >>> device=%d(sg%c), ", dev, 'a' + dev);
+        printk(" >>> device=%d (sg%d), ", dev, dev);
     else
-        printk("sg_debug: device=%d(sg%c), ", dev, 'a' + dev);
+        printk("sg_debug: device=%d (sg%d), ", dev, dev);
     printk("scsi%d chan=%d id=%d lun=%d  em=%d\n", sdp->device->host->host_no,
            sdp->device->channel, sdp->device->id, sdp->device->lun,
            sdp->device->host->hostt->emulated);
@@ -929,7 +931,8 @@
                        srp->header.pack_id, srp->my_cmdp->bufflen, 
                        srp->my_cmdp->use_sg);
             else
-                printk("to_read: pack_id=%d, bufflen=%d, use_sg=%d\n",
+                printk("%s: pack_id=%d, bufflen=%d, use_sg=%d\n",
+                   ((1 == srp->done) ? "to_read" : "prior"),
                    srp->header.pack_id, srp->data.bufflen, srp->data.use_sg);
             if (! srp->parentfp)
                 printk(">> request has NULL parent pointer ???\n");
@@ -966,9 +969,9 @@
         case TYPE_WORM:
         case TYPE_TAPE: break;
         default:
-        printk("Detected scsi generic sg%c at scsi%d,"
+        printk("Detected scsi generic sg%d at scsi%d,"
                 " channel %d, id %d, lun %d\n",
-               'a'+sg_template.dev_noticed,
+               sg_template.dev_noticed,
                scsidp->host->host_no, scsidp->channel, 
                scsidp->id, scsidp->lun);
     }
@@ -1438,15 +1441,17 @@
     srp->res_used = 0;
 }
 
-static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
+static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id)
 {
     Sg_request * resp = NULL;
 
     resp = sfp->headrp;
     while (resp) {
-        if ((! resp->my_cmdp) && 
-            ((-1 == pack_id) || (resp->header.pack_id == pack_id)))
+        if ((1 == resp->done) && 
+            ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+            resp->done = 2;
             return resp;
+        }
         resp = resp->nextrp;
     }
     return resp;
@@ -1575,7 +1580,7 @@
 /* Need to stop sg_command_done() playing with this list during this loop */
         while (srp) {
             tsrp = srp->nextrp;
-            if (! srp->my_cmdp)
+            if (srp->done)
                 sg_finish_rem_req(srp, NULL, 0);
             else
                 ++dirty;
diff -urN linux-2.2.16-pre7/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- linux-2.2.16-pre7/drivers/scsi/sr.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/scsi/sr.c	Mon Dec  3 22:04:51 2001
@@ -23,6 +23,9 @@
  *       Modified by Jens Axboe <axboe@image.dk> - Uniform sr_packet()
  *       interface, capabilities probe additions, ioctl cleanups, etc.
  *
+ *	Modified by Jens Axboe <axboe@suse.de> - support DVD-RAM
+ *	transparently and loose the GHOST hack
+ *
  */
 
 #include <linux/module.h>
@@ -562,11 +565,14 @@
 	}
 	switch (SCpnt->request.cmd) {
 	case WRITE:
-		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-		goto repeat;
+		if (!scsi_CDs[dev].device->writeable) {
+			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+			goto repeat;
+		}
+		cmd[0] = WRITE_10;
 		break;
 	case READ:
-		cmd[0] = READ_6;
+		cmd[0] = READ_10;
 		break;
 	default:
 		panic("Unknown sr command %d\n", SCpnt->request.cmd);
@@ -740,36 +746,19 @@
 	if (scsi_CDs[dev].sector_size == 512)
 		realcount = realcount << 2;
 
-	/*
-	 * Note: The scsi standard says that READ_6 is *optional*, while
-	 * READ_10 is mandatory.   Thus there is no point in using
-	 * READ_6.
-	 */
-	if (scsi_CDs[dev].ten) {
-		if (realcount > 0xffff) {
-			realcount = 0xffff;
-			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-		}
-		cmd[0] += READ_10 - READ_6;
-		cmd[2] = (unsigned char) (block >> 24) & 0xff;
-		cmd[3] = (unsigned char) (block >> 16) & 0xff;
-		cmd[4] = (unsigned char) (block >> 8) & 0xff;
-		cmd[5] = (unsigned char) block & 0xff;
-		cmd[6] = cmd[9] = 0;
-		cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
-		cmd[8] = (unsigned char) realcount & 0xff;
-	} else {
-		if (realcount > 0xff) {
-			realcount = 0xff;
-			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-		}
-		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-		cmd[3] = (unsigned char) block & 0xff;
-		cmd[4] = (unsigned char) realcount;
-		cmd[5] = 0;
+	if (realcount > 0xffff) {
+		realcount = 0xffff;
+		this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
 	}
 
+	cmd[2] = (unsigned char) (block >> 24) & 0xff;
+	cmd[3] = (unsigned char) (block >> 16) & 0xff;
+	cmd[4] = (unsigned char) (block >> 8) & 0xff;
+	cmd[5] = (unsigned char) block & 0xff;
+	cmd[6] = cmd[9] = 0;
+	cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
+	cmd[8] = (unsigned char) realcount & 0xff;
+
 #ifdef DEBUG
 	{
 		int i;
@@ -968,6 +957,7 @@
 		""
 	};
 
+	scsi_CDs[i].device->writeable = 0;
 	spin_lock_irq(&io_request_lock);
 	buffer = (unsigned char *) scsi_malloc(512);
 	spin_unlock_irq(&io_request_lock);
@@ -991,10 +981,11 @@
 	scsi_CDs[i].readcd_known = 1;
 	scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01;
 	/* print some capability bits */
-	printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n", i,
+	printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", i,
 	       ((buffer[n + 14] << 8) + buffer[n + 15]) / 176,
 	       scsi_CDs[i].cdi.speed,
 	       buffer[n + 3] & 0x01 ? "writer " : "",	/* CD Writer */
+	       buffer[n + 3] & 0x20 ? "dvd-ram " : "",
 	       buffer[n + 2] & 0x02 ? "cd/rw " : "",	/* can read rewriteable */
 	       buffer[n + 4] & 0x20 ? "xa/form2 " : "",		/* can read xa/from2 */
 	       buffer[n + 5] & 0x01 ? "cdda " : "",	/* can read audio data */
@@ -1005,9 +996,12 @@
 	if ((buffer[n + 2] & 0x8) == 0)
 		/* not a DVD drive */
 		scsi_CDs[i].cdi.mask |= CDC_DVD;
-	if ((buffer[n + 3] & 0x20) == 0)
+	if ((buffer[n + 3] & 0x20) == 0) {
 		/* can't write DVD-RAM media */
 		scsi_CDs[i].cdi.mask |= CDC_DVD_RAM;
+	} else {
+		scsi_CDs[i].device->writeable = 1;
+	}
 	if ((buffer[n + 3] & 0x10) == 0)
 		/* can't write DVD-R media */
 		scsi_CDs[i].cdi.mask |= CDC_DVD_R;
@@ -1030,7 +1024,6 @@
 		scsi_CDs[i].cdi.mask |= CDC_SELECT_DISC;
 	/*else    I don't think it can close its tray
 		scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */
-
 
 	scsi_free(buffer, 512);
 }
diff -urN linux-2.2.16-pre7/drivers/sound/Config.in linux/drivers/sound/Config.in
--- linux-2.2.16-pre7/drivers/sound/Config.in	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/Config.in	Mon Dec  3 22:04:51 2001
@@ -40,8 +40,10 @@
 dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 
 if [ "$CONFIG_VISWS" = "y" ]; then
-    dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
+    dep_tristate ' Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
 fi
+
+dep_tristate 'Trident 4DWave DX/NX or SiS 7018 PCI Audio Core or ALi 5451' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
 
 dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
 if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
diff -urN linux-2.2.16-pre7/drivers/sound/Makefile linux/drivers/sound/Makefile
--- linux-2.2.16-pre7/drivers/sound/Makefile	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/Makefile	Mon Dec  3 22:04:51 2001
@@ -87,6 +87,7 @@
 obj-$(CONFIG_SOUND_ICH)		+= i810_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
+obj-$(CONFIG_SOUND_TRIDENT)     += trident.o ac97_codec.o
 
 # Declare multi-part drivers.
 
diff -urN linux-2.2.16-pre7/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- linux-2.2.16-pre7/drivers/sound/ac97_codec.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/ac97_codec.c	Mon Dec  3 22:04:51 2001
@@ -21,7 +21,7 @@
  *
  * History
  * v0.4 Mar 15 2000 Ollie Lho
- *	dual codec support verified with 4 channel output
+ *	dual codecs support verified with 4 channels output
  * v0.3 Feb 22 2000 Ollie Lho
  *	bug fix for record mask setting
  * v0.2 Feb 10 2000 Ollie Lho
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/bitops.h>
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
 
@@ -70,6 +71,7 @@
 	{0x83847605, "SigmaTel STAC9704"      , NULL},
 	{0x83847608, "SigmaTel STAC9708"      , NULL},
 	{0x83847609, "SigmaTel STAC9721/23"   , sigmatel_init},
+	{0x54524106, "TriTech TR28026"        , NULL},
 	{0x54524108, "TriTech TR28028"        , NULL},
 	{0x574D4C00, "Wolfson WM9704"         , NULL},
 	{0x00000000, NULL, NULL}
@@ -329,6 +331,11 @@
 
 	/* else, write the first set in the mask as the
 	   output */	
+	/* clear out current set value first (AC97 supports only 1 input!) */
+	val = (1 << ac97_rm2oss[codec->codec_read(codec, AC97_RECORD_SELECT) & 0x07]);
+	if (mask != val)
+	    mask &= ~val;
+       
 	val = ffs(mask); 
 	val = ac97_oss_rm[val-1];
 	val |= val << 8;  /* set both channels */
@@ -417,6 +424,7 @@
 		switch (_IOC_NR(cmd)) {
 		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 			if (!codec->recmask_io) return -EINVAL;
+			if (!val) return 0;
 			if (!(val &= codec->record_sources)) return -EINVAL;
 
 			codec->recmask_io(codec, 0, val);
@@ -442,6 +450,7 @@
 {
 	int len = 0, cap, extid, val, id1, id2;
 	struct ac97_codec *codec;
+	int is_ac97_20 = 0;
 
 	if ((codec = data) == NULL)
 		return -ENODEV;
@@ -455,6 +464,7 @@
 	extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
 	len += sprintf (page+len, "AC97 Version     : %s\n",
 			extid ? "2.0 or later" : "1.0");
+	if (extid) is_ac97_20 = 1;
 
 	cap = codec->codec_read(codec, AC97_RESET);
 	len += sprintf (page+len, "Capabilities     :%s%s%s%s%s%s\n",
@@ -493,6 +503,7 @@
 			val & 0x0100 ? "MIC2" : "MIC1",
 			val & 0x0080 ? "on" : "off");
 
+	extid = codec->codec_read(codec, AC97_EXTENDED_ID);
 	cap = extid;
 	len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
 			cap & 0x0001 ? " -var rate PCM audio-" : "",
@@ -502,6 +513,10 @@
 			cap & 0x0080 ? " -PCM surround DAC-" : "",
 			cap & 0x0100 ? " -PCM LFE DAC-" : "",
 			cap & 0x0200 ? " -slot/DAC mappings-" : "");
+	if (is_ac97_20) {
+		len += sprintf (page+len, "Front DAC rate   : %d\n",
+				codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE));
+	}
 
 	return len;
 }
diff -urN linux-2.2.16-pre7/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux-2.2.16-pre7/drivers/sound/i810_audio.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/i810_audio.c	Mon Dec  3 22:04:51 2001
@@ -401,8 +401,8 @@
 	i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
 	
 	/* Load the rate and read the effective rate */
-	i810_ac97_set(codec, AC97_PCM_LR_ADC_RATE, rate);
-	rp=i810_ac97_get(codec, AC97_PCM_LR_ADC_RATE);
+	i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
+	rp=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
 	
 //	printk("ADC rate set to %d Returned %d\n", 
 //		rate, (int)rp);
diff -urN linux-2.2.16-pre7/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- linux-2.2.16-pre7/drivers/sound/sound_core.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/sound_core.c	Mon Dec  3 22:04:51 2001
@@ -58,6 +58,9 @@
 #ifdef CONFIG_SOUND_MAESTRO
 extern int init_maestro(void);
 #endif
+#ifdef CONFIG_SOUND_TRIDENT
+extern int init_trident(void);
+#endif
 #ifdef CONFIG_SOUND_ICH
 extern int i810_probe(void);
 #endif
@@ -421,6 +424,9 @@
 #endif
 #ifdef CONFIG_SOUND_MAESTRO
 	init_maestro();
+#endif
+#ifdef CONFIG_SOUND_TRIDENT
+	init_trident();
 #endif
 #ifdef CONFIG_SOUND_MSNDCLAS
 	msnd_classic_init();
diff -urN linux-2.2.16-pre7/drivers/sound/trident.c linux/drivers/sound/trident.c
--- linux-2.2.16-pre7/drivers/sound/trident.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/trident.c	Mon Dec  3 22:04:51 2001
@@ -0,0 +1,2504 @@
+/*
+ *
+ *	Trident 4D-Wave/SiS 7018 OSS driver for Linux 2.2.x
+ *
+ *	Driver: Alan Cox <alan@redhat.com>
+ *
+ *  Built from:
+ *	Low level code: <audio@tridentmicro.com> from ALSA
+ *	Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *	Extended by: Zach Brown <zab@redhat.com>  
+ *
+ *  Hacked up by:
+ *	Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *	Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
+ *
+ *
+ *	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.
+ *
+ *  History
+ *  v0.14.5 June 3 2000 Ollie Lho
+ *  	Misc bug fix from the Net
+ *	Backported from 2.4.0-test1 to 2.2.16 (Eric Brombaugh)
+ *  v0.14.4 May 20 2000 Aaron Holtzman
+ *  	Fix kfree'd memory access in release
+ *  	Fix race in open while looking for a free virtual channel slot
+ *  	remove open_wait wq (which appears to be unused)
+ *  v0.14.3 May 10 2000 Ollie Lho
+ *	fixed a small bug in trident_update_ptr, xmms 1.0.1 no longer uses 100% CPU
+ *  v0.14.2 Mar 29 2000 Ching Ling Lee
+ *	Add clear to silence advance in trident_update_ptr 
+ *	fix invalid data of the end of the sound
+ *  v0.14.1 Mar 24 2000 Ching Ling Lee
+ *	ALi 5451 support added, playback and recording O.K.
+ *	ALi 5451 originally developed and structured based on sonicvibes, and
+ *	suggested to merge into this file by Alan Cox.
+ *  v0.14 Mar 15 2000 Ollie Lho
+ *	5.1 channel output support with channel binding. What's the Matrix ?
+ *  v0.13.1 Mar 10 2000 Ollie Lho
+ *	few minor bugs on dual codec support, needs more testing
+ *  v0.13 Mar 03 2000 Ollie Lho
+ *	new pci_* for 2.4 kernel, back ported to 2.2
+ *  v0.12 Feb 23 2000 Ollie Lho
+ *	Preliminary Recording support
+ *  v0.11.2 Feb 19 2000 Ollie Lho
+ *	removed incomplete full-dulplex support
+ *  v0.11.1 Jan 28 2000 Ollie Lho
+ *	small bug in setting sample rate for 4d-nx (reported by Aaron)
+ *  v0.11 Jan 27 2000 Ollie Lho
+ *	DMA bug, scheduler latency, second try
+ *  v0.10 Jan 24 2000 Ollie Lho
+ *	DMA bug fixed, found kernel scheduling problem
+ *  v0.09 Jan 20 2000 Ollie Lho
+ *	Clean up of channel register access routine (prepare for channel binding)
+ *  v0.08 Jan 14 2000 Ollie Lho
+ *	Isolation of AC97 codec code
+ *  v0.07 Jan 13 2000 Ollie Lho
+ *	Get rid of ugly old low level access routines (e.g. CHRegs.lp****)
+ *  v0.06 Jan 11 2000 Ollie Lho
+ *	Preliminary support for dual (more ?) AC97 codecs
+ *  v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
+ *	adapt to 2.3.x new __setup/__init call
+ *  v0.04 Dec 31 1999 Ollie Lho
+ *	Multiple Open, using Middle Loop Interrupt to smooth playback
+ *  v0.03 Dec 24 1999 Ollie Lho
+ *	mem leak in prog_dmabuf and dealloc_dmabuf removed
+ *  v0.02 Dec 15 1999 Ollie Lho
+ *	SiS 7018 support added, playback O.K.
+ *  v0.01 Alan Cox et. al.
+ *	Initial Release in kernel 2.3.30, does not work
+ * 
+ *  ToDo
+ *	Clean up of low level channel register access code. (done)
+ *	Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
+ *	Dual AC97 codecs support (done)
+ *	Recording support (done)
+ *	Mmap support
+ *	"Channel Binding" ioctl extension (done)
+ *	new pci device driver interface for 2.4 kernel (done)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <asm/spinlock.h>
+#include <linux/ac97_codec.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <linux/bitops.h>
+
+#include "trident.h"
+
+#define DRIVER_VERSION "0.14.5"
+
+/* magic numbers to protect our data structures */
+#define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
+#define TRIDENT_STATE_MAGIC	0x63657373 /* "cess" */
+
+#define TRIDENT_DMA_MASK	0x3fffffff /* DMA buffer mask for pci_alloc_consist */
+
+#define NR_HW_CH		32
+
+/* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
+   have 2 SDATA_IN lines (currently) */
+#define NR_AC97		2
+
+/* minor number of /dev/dspW */
+#define SND_DEV_DSP8	3
+
+/* minor number of /dev/dspW */
+#define SND_DEV_DSP16	5 
+
+/* minor number of /dev/swmodem (temporary, experimental) */
+#define SND_DEV_SWMODEM	7
+
+static const unsigned sample_size[] = { 1, 2, 2, 4 };
+static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+
+static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
+
+struct pci_audio_info {
+	u16 vendor;
+	u16 device;
+	char *name;
+};
+
+static struct pci_audio_info pci_audio_devices[] = {
+	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX, "Trident 4DWave DX"},
+	{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX, "Trident 4DWave NX"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"},
+	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5451, "ALi Audio Accelerator"}
+};
+
+/* "software" or virtual channel, an instance of opened /dev/dsp */
+struct trident_state {
+	unsigned int magic;
+	struct trident_card *card;	/* Card info */
+
+	/* file mode */
+	mode_t open_mode;
+
+	/* virtual channel number */
+	int virt;
+
+	struct dmabuf {
+		/* wave sample stuff */
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* hardware channel */
+		struct trident_channel *channel;
+
+		/* OSS buffer management stuff */
+		void *rawbuf;
+
+		unsigned buforder;
+		unsigned numfrag;
+		unsigned fragshift;
+
+		/* our buffer acts like a circular ring */
+		unsigned hwptr;		/* where dma last started, updated by update_ptr */
+		unsigned swptr;		/* where driver last clear/filled, updated by read/write */
+		int count;		/* bytes to be comsumed or been generated by dma machine */
+		unsigned total_bytes;	/* total bytes dmaed by hardware */
+
+		unsigned error;		/* number of over/underruns */
+		struct wait_queue *wait;	/* put process on wait queue when no more space in buffer */
+
+		/* redundant, but makes calculations easier */
+		unsigned fragsize;
+		unsigned dmasize;
+		unsigned fragsamples;
+
+		/* OSS stuff */
+		unsigned mapped:1;
+		unsigned ready:1;
+		unsigned endcleared:1;
+		unsigned update_flag;
+		unsigned ossfragshift;
+		int ossmaxfrags;
+		unsigned subdivision;
+	} dmabuf;
+};
+
+/* hardware channels */
+struct trident_channel {
+	int  num;	/* channel number */
+	u32 lba;	/* Loop Begine Address, where dma buffer starts */
+	u32 eso;	/* End Sample Offset, wehre dma buffer ends (in the unit of samples) */
+	u32 delta;	/* delta value, sample rate / 48k for playback, 48k/sample rate for recording */
+	u16 attribute;	/* control where PCM data go and come  */
+	u16 fm_vol;
+	u32 control;	/* signed/unsigned, 8/16 bits, mono/stereo */
+};
+
+struct trident_pcm_bank_address {
+	u32 start;
+	u32 stop;
+	u32 aint;
+	u32 aint_en;
+};
+static struct trident_pcm_bank_address bank_a_addrs =
+{
+	T4D_START_A,
+	T4D_STOP_A,
+	T4D_AINT_A,
+	T4D_AINTEN_A
+};
+static struct trident_pcm_bank_address bank_b_addrs =
+{
+	T4D_START_B,
+	T4D_STOP_B,
+	T4D_AINT_B,
+	T4D_AINTEN_B
+};
+struct trident_pcm_bank {
+	/* register addresses to control bank operations */
+	struct trident_pcm_bank_address *addresses;
+	/* each bank has 32 channels */
+	u32 bitmap; /* channel allocation bitmap */
+	struct trident_channel channels[32];
+};
+
+struct trident_card {
+	unsigned int magic;
+
+	/* We keep trident cards in a linked list */
+	struct trident_card *next;
+
+	/* single open lock mechanism, only used for recording */
+	struct semaphore open_sem;
+
+	/* The trident has a certain amount of cross channel interaction
+	   so we use a single per card lock */
+	spinlock_t lock;
+
+	/* PCI device stuff */
+	struct pci_audio_info *pci_info;
+	struct pci_dev * pci_dev;
+	u16 pci_id;
+	u8 revision;
+
+	/* soundcore stuff */
+	int dev_audio;
+
+	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	struct ac97_codec *ac97_codec[NR_AC97];
+	struct trident_pcm_bank banks[NR_BANKS];
+	struct trident_state *states[NR_HW_CH];
+
+	/* hardware resources */
+	unsigned long iobase;
+	u32 irq;
+	
+	/* Function support */
+	struct trident_channel *(*alloc_pcm_channel)(struct trident_card *);
+	struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *);
+	void (*free_pcm_channel)(struct trident_card *, int chan);
+	void (*address_interrupt)(struct trident_card *);
+};
+
+static struct trident_card *devs = NULL;
+
+static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
+static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg);
+
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
+
+static int trident_open_mixdev(struct inode *inode, struct file *file);
+static int trident_release_mixdev(struct inode *inode, struct file *file);
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg);
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin);
+
+static int trident_enable_loop_interrupts(struct trident_card * card)
+{
+	u32 global_control;
+
+	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
+
+	switch (card->pci_id)
+	{
+	case PCI_DEVICE_ID_SI_7018:
+		global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN);
+		break;
+	case PCI_DEVICE_ID_ALI_5451:
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		global_control |= (ENDLP_IE | MIDLP_IE);
+		break;
+	default:
+		return FALSE;
+	}
+
+	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+	printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
+	       global_control);
+#endif
+	return (TRUE);
+}
+
+static int trident_disable_loop_interrupts(struct trident_card * card)
+{
+	u32 global_control;
+
+	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
+	global_control &= ~(ENDLP_IE | MIDLP_IE);
+	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
+
+#ifdef DEBUG
+	printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
+	       global_control);
+#endif
+	return (TRUE);
+}
+
+static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint_en;
+
+	reg = inl(TRID_REG(card, addr));
+	reg |= mask;
+	outl(reg, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_AINTEN_B));
+	printk("trident: enabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint_en;
+	
+	reg = inl(TRID_REG(card, addr));
+	reg &= ~mask;
+	outl(reg, TRID_REG(card, addr));
+	
+	/* Ack the channel in case the interrupt was set before we disable it. */
+	outl(mask, TRID_REG(card, bank->addresses->aint));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_AINTEN_B));
+	printk("trident: disabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static void trident_start_voice(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 addr = bank->addresses->start;
+
+#ifdef DEBUG
+	u32 reg;
+#endif
+
+	outl(mask, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_START_B));
+	printk("trident: start voice on channel %d, START_B  = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static void trident_stop_voice(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 addr = bank->addresses->stop;
+
+#ifdef DEBUG
+	u32 reg;
+#endif
+
+	outl(mask, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_STOP_B));
+	printk("trident: stop voice on channel %d,  STOP_B  = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static u32 trident_get_interrupt_mask (struct trident_card * card, unsigned int channel)
+{
+	struct trident_pcm_bank *bank = &card->banks[channel];
+	u32 addr = bank->addresses->aint;
+	return inl(TRID_REG(card, addr));
+}
+
+static int trident_check_channel_interrupt(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	u32 reg = trident_get_interrupt_mask (card, channel >> 5);
+
+#ifdef DEBUG
+	if (reg & mask)
+		printk("trident: channel %d has interrupt, AINT_B = 0x%08x\n",
+		       channel, reg);
+#endif
+	return (reg & mask) ? TRUE : FALSE;
+}
+
+static void trident_ack_channel_interrupt(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint;
+
+	reg = inl(TRID_REG(card, addr));
+	reg &= mask;
+	outl(reg, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_AINT_B));
+	printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card)
+{
+	struct trident_pcm_bank *bank;
+	int idx;
+
+	bank = &card->banks[BANK_B];
+
+	for (idx = 31; idx >= 0; idx--) {
+		if (!(bank->bitmap & (1 << idx))) {
+			struct trident_channel *channel = &bank->channels[idx];
+			bank->bitmap |= 1 << idx;
+			channel->num = idx + 32;
+			return channel;
+		}
+	}
+
+	/* no more free channels avaliable */
+	printk(KERN_ERR "trident: no more channels available on Bank B.\n");
+	return NULL;
+}
+
+static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card)
+{
+	struct trident_pcm_bank *bank;
+	int idx;
+
+	bank = &card->banks[BANK_A];
+
+	for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST ; idx++) {
+		if (!(bank->bitmap & (1 << idx))) {
+			struct trident_channel *channel = &bank->channels[idx];
+			bank->bitmap |= 1 << idx;
+			channel->num = idx;
+			return channel;
+		}
+	}
+
+	/* no more free channels avaliable */
+	printk(KERN_ERR "trident: no more channels available on Bank B.\n");
+	return NULL;
+}
+
+static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card)
+{
+	struct trident_pcm_bank *bank;
+	int idx = ALI_PCM_IN_CHANNEL;
+
+	bank = &card->banks[BANK_A];
+	
+	if (!(bank->bitmap & (1 << idx))) {
+		struct trident_channel *channel = &bank->channels[idx];
+		bank->bitmap |= 1 << idx;
+		channel->num = idx;
+		return channel;
+	}
+	return NULL;
+}
+
+
+static void trident_free_pcm_channel(struct trident_card *card, int channel)
+{
+	int bank;
+
+	if (channel < 31 || channel > 63)
+		return;
+
+	bank = channel >> 5;
+	channel = channel & 0x1f;
+
+	card->banks[bank].bitmap &= ~(1 << (channel));
+}
+
+static void ali_free_pcm_channel(struct trident_card *card, int channel)
+{
+	int bank;
+
+	if (channel > 31)
+		return;
+
+	bank = channel >> 5;
+	channel = channel & 0x1f;
+
+	card->banks[bank].bitmap &= ~(1 << (channel));
+}
+
+
+/* called with spin lock held */
+
+static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel)
+{
+	int i;
+
+	if (channel > 63)
+		return FALSE;
+
+	/* select hardware channel to write */
+	outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
+
+	/* Output the channel registers, but don't write register
+	   three to an ALI chip. */
+	for (i = 0; i < CHANNEL_REGS; i++) {
+		if (i == 3 && card->pci_id == PCI_DEVICE_ID_ALI_5451)
+			continue;
+		outl(data[i], TRID_REG(card, CHANNEL_START + 4*i));
+	}
+	return TRUE;
+}
+
+/* called with spin lock held */
+static int trident_write_voice_regs(struct trident_state *state)
+{
+	unsigned int data[CHANNEL_REGS + 1];
+	struct trident_channel *channel;
+
+	channel = state->dmabuf.channel;
+
+	data[1] = channel->lba;
+	data[4] = channel->control;
+
+	switch (state->card->pci_id)
+	{
+	case PCI_DEVICE_ID_ALI_5451:
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = 0;
+		break;	
+	case PCI_DEVICE_ID_SI_7018:
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff);
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = channel->fm_vol & 0xffff;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		data[0] = (channel->delta << 24);
+		data[2] = ((channel->delta << 16) & 0xff000000) | (channel->eso & 0x00ffffff);
+		data[3] = channel->fm_vol & 0xffff;
+		break;
+	default:
+		return FALSE;
+	}
+
+	return trident_load_channel_registers(state->card, data, channel->num);
+}
+
+static int compute_rate_play(u32 rate)
+{
+	int delta;
+	/* We special case 44100 and 8000 since rounding with the equation
+	   does not give us an accurate enough value. For 11025 and 22050
+	   the equation gives us the best answer. All other frequencies will
+	   also use the equation. JDW */
+	if (rate == 44100)
+		delta = 0xeb3;
+	else if (rate == 8000)
+		delta = 0x2ab;
+	else if (rate == 48000)
+		delta = 0x1000;
+	else
+		delta = (((rate << 12) + rate) / 48000) & 0x0000ffff;
+	return delta;
+}
+
+static int compute_rate_rec(u32 rate)
+{
+	int delta;
+
+	if (rate == 44100)
+		delta = 0x116a;
+	else if (rate == 8000)
+		delta = 0x6000;
+	else if (rate == 48000)
+		delta = 0x1000;
+	else
+		delta = ((48000 << 12) / rate) & 0x0000ffff;
+
+	return delta;
+}
+/* set playback sample rate */
+static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate)
+{	
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 4000)
+		rate = 4000;
+
+	dmabuf->rate = rate;
+	dmabuf->channel->delta = compute_rate_play(rate);
+
+	trident_write_voice_regs(state);
+
+#ifdef DEBUG
+	printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
+#endif
+
+	return rate;
+}
+
+/* set recording sample rate */
+static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 4000)
+		rate = 4000;
+
+	dmabuf->rate = rate;
+	dmabuf->channel->delta = compute_rate_rec(rate);
+
+	trident_write_voice_regs(state);
+
+#ifdef DEBUG
+	printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
+#endif
+	return rate;
+}
+
+/* prepare channel attributes for playback */ 
+static void trident_play_setup(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct trident_channel *channel = dmabuf->channel;
+
+	channel->lba = virt_to_bus(dmabuf->rawbuf);
+	channel->delta = compute_rate_play(dmabuf->rate);
+
+	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+	channel->eso -= 1;
+
+	if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
+		channel->attribute = 0;
+	}
+
+	channel->fm_vol = 0x0;
+	
+	channel->control = CHANNEL_LOOP;
+	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
+		/* 16-bits */
+		channel->control |= CHANNEL_16BITS;
+		/* signed */
+		channel->control |= CHANNEL_SIGNED;
+	}
+	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
+		/* stereo */
+		channel->control |= CHANNEL_STEREO;
+#ifdef DEBUG
+	printk("trident: trident_play_setup, LBA = 0x%08x, "
+	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	       channel->lba, channel->delta, channel->eso, channel->control);
+#endif
+	trident_write_voice_regs(state);
+}
+
+/* prepare channel attributes for recording */
+static void trident_rec_setup(struct trident_state *state)
+{
+	u16 w;
+	struct trident_card *card = state->card;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	struct trident_channel *channel = dmabuf->channel;
+
+	/* Enable AC-97 ADC (capture) */
+	switch (card->pci_id) 
+	{
+	case PCI_DEVICE_ID_ALI_5451:
+	case PCI_DEVICE_ID_SI_7018:
+		/* for 7018, the ac97 is always in playback/record (duplex) mode */
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		/* enable and set record channel */
+		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		w = inw(TRID_REG(card, T4D_MISCINT));
+		outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
+		/* enable and set record channel */
+		outb(0x80 | channel->num, TRID_REG(card, T4D_REC_CH));
+		break;
+	default:
+		return;
+	}
+
+	channel->lba = virt_to_bus(dmabuf->rawbuf);
+	channel->delta = compute_rate_rec(dmabuf->rate);
+
+	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+	channel->eso -= 1;
+
+	if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
+		channel->attribute = 0;
+	}
+
+	channel->fm_vol = 0x0;
+	
+	channel->control = CHANNEL_LOOP;
+	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
+		/* 16-bits */
+		channel->control |= CHANNEL_16BITS;
+		/* signed */
+		channel->control |= CHANNEL_SIGNED;
+	}
+	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
+		/* stereo */
+		channel->control |= CHANNEL_STEREO;
+#ifdef DEBUG
+	printk("trident: trident_rec_setup, LBA = 0x%08x, "
+	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	       channel->lba, channel->delta, channel->eso, channel->control);
+#endif
+	trident_write_voice_regs(state);
+}
+
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+   called with spinlock held! */
+extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 cso;
+
+	if (!dmabuf->enable)
+		return 0;
+
+	outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR));
+
+	switch (state->card->pci_id) 
+	{
+	case PCI_DEVICE_ID_ALI_5451:
+	case PCI_DEVICE_ID_SI_7018:
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		/* 16 bits ESO, CSO for 7018 and DX */
+		cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2));
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		/* 24 bits ESO, CSO for NX */
+		cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
+		break;
+	default:
+		return 0;
+	}
+
+#ifdef DEBUG
+	printk("trident: trident_get_dma_addr: chip reported channel: %d, "
+	       "cso = 0x%04x\n",
+	       dmabuf->channel->num, cso);
+#endif
+	/* ESO and CSO are in units of Samples, convert to byte offset */
+	cso <<= sample_shift[dmabuf->fmt];
+
+	return (cso % dmabuf->dmasize);
+}
+
+/* Stop recording (lock held) */
+extern __inline__ void __stop_adc(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
+
+	dmabuf->enable &= ~ADC_RUNNING;
+	trident_stop_voice(card, chan_num);
+	trident_disable_voice_irq(card, chan_num);
+}
+
+static void stop_adc(struct trident_state *state)
+{
+	struct trident_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void start_adc(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) {
+		dmabuf->enable |= ADC_RUNNING;
+		trident_enable_voice_irq(card, chan_num);
+		trident_start_voice(card, chan_num);
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* stop playback (lock held) */
+extern __inline__ void __stop_dac(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
+
+	dmabuf->enable &= ~DAC_RUNNING;
+	trident_stop_voice(card, chan_num);
+	trident_disable_voice_irq(card, chan_num);
+}
+
+static void stop_dac(struct trident_state *state)
+{
+	struct trident_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_dac(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}	
+
+static void start_dac(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
+		dmabuf->enable |= DAC_RUNNING;
+		trident_enable_voice_irq(card, chan_num);
+		trident_start_voice(card, chan_num);
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+#define DMABUF_MINORDER 1
+
+/* allocate DMA buffer, playback and recording buffer should be allocated seperately */
+static int alloc_dmabuf(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	void *rawbuf;
+	int order;
+	unsigned long map, mapend;
+
+	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
+	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+		if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+			break;
+	if (!rawbuf)
+		return -ENOMEM;
+
+#ifdef DEBUG
+	printk("trident: allocated %ld (order = %d) bytes at %p\n",
+	       PAGE_SIZE << order, order, rawbuf);
+#endif
+
+	/* for 4DWave and 7018, there are only 30 (31) siginifcan bits for Loop Begin Address
+	   (LBA) which limits the address space to 1 (2) GB, bad T^2 design */
+	if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~0x3fffffff) {
+		printk(KERN_ERR "trident: DMA buffer beyond 1 GB; "
+		       "bus address = 0x%lx, size = %ld\n",
+		       virt_to_bus(rawbuf), PAGE_SIZE << order);
+		free_pages((unsigned long)rawbuf, order);
+		return -ENOMEM;
+	}
+	dmabuf->ready  = dmabuf->mapped = 0;
+	dmabuf->rawbuf = rawbuf;
+	dmabuf->buforder = order;
+	
+	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+	mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+	for (map = MAP_NR(rawbuf); map <= mapend; map++)
+		set_bit(PG_reserved, &mem_map[map].flags);
+
+	return 0;
+}
+
+/* free DMA buffer */
+static void dealloc_dmabuf(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long map, mapend;
+
+	if (dmabuf->rawbuf) {
+		/* undo marking the pages as reserved */
+		mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+		for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
+			clear_bit(PG_reserved, &mem_map[map].flags);
+		free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder);
+	}
+	dmabuf->rawbuf = NULL;
+	dmabuf->mapped = dmabuf->ready = 0;
+}
+
+static int prog_dmabuf(struct trident_state *state, unsigned rec)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned bytepersec;
+	unsigned bufsize;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	dmabuf->hwptr = dmabuf->swptr = dmabuf->total_bytes = 0;
+	dmabuf->count = dmabuf->error = 0;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* allocate DMA buffer if not allocated yet */
+	if (!dmabuf->rawbuf)
+		if ((ret = alloc_dmabuf(state)))
+			return ret;
+
+	/* FIXME: figure out all this OSS fragment stuff */
+	bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
+	bufsize = PAGE_SIZE << dmabuf->buforder;
+	if (dmabuf->ossfragshift) {
+		if ((1000 << dmabuf->ossfragshift) < bytepersec)
+			dmabuf->fragshift = ld2(bytepersec/1000);
+		else
+			dmabuf->fragshift = dmabuf->ossfragshift;
+	} else {
+		/* lets hand out reasonable big ass buffers by default */
+		dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+	}
+	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
+		dmabuf->fragshift--;
+		dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	}
+	dmabuf->fragsize = 1 << dmabuf->fragshift;
+	if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
+		dmabuf->numfrag = dmabuf->ossmaxfrags;
+	dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
+	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
+
+	memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
+	       dmabuf->dmasize);
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	if (rec) {
+		trident_rec_setup(state);
+	} else {
+		trident_play_setup(state);
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* set the ready flag for the dma buffer */
+	dmabuf->ready = 1;
+
+#ifdef DEBUG
+	printk("trident: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, "
+	       "fragsize = %d dmasize = %d\n",
+	       dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
+	       dmabuf->fragsize, dmabuf->dmasize);
+#endif
+
+	return 0;
+}
+
+/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.
+   |------------|------------|   or   |xxxxxxxxxxxx|------------|   or   |xxxxxxxxxxxx|xxxxxxxxxxxx|
+   but we almost always get this
+   |xxxxxx------|------------|   or   |xxxxxxxxxxxx|xxxxx-------|
+   so we have to clear the tail space to "silence"
+   |xxxxxx000000|------------|   or   |xxxxxxxxxxxx|xxxxxx000000|
+*/
+static void trident_clear_tail(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned swptr;
+	unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
+	unsigned int len;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	swptr = dmabuf->swptr;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
+		return;
+
+	if (swptr < dmabuf->dmasize/2)
+		len = dmabuf->dmasize/2 - swptr;
+	else
+		len = dmabuf->dmasize - swptr;
+
+	memset(dmabuf->rawbuf + swptr, silence, len);
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	dmabuf->swptr += len;
+	dmabuf->count += len;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* restart the dma machine in case it is halted */
+	start_dac(state);
+}
+
+static int drain_dac(struct trident_state *state, int nonblock)
+{
+	struct wait_queue wait = {current, NULL};
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+
+	if (dmabuf->mapped || !dmabuf->ready)
+		return 0;
+
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
+		   every time to make the process really go to sleep */
+		current->state = TASK_INTERRUPTIBLE;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (count <= 0)
+			break;
+
+		if (signal_pending(current))
+			break;
+
+		if (nonblock) {
+			remove_wait_queue(&dmabuf->wait, &wait);
+			current->state = TASK_RUNNING;
+			return -EBUSY;
+		}
+
+		/* No matter how much data left in the buffer, we have to wait untill
+		   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+		tmo >>= sample_shift[dmabuf->fmt];
+		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+			printk(KERN_ERR "trident: drain_dac, dma timeout?\n");
+			break;
+		}
+	}
+	remove_wait_queue(&dmabuf->wait, &wait);
+	current->state = TASK_RUNNING;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	return 0;
+}
+
+/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
+static void trident_update_ptr(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned hwptr, swptr;
+	int clear_cnt = 0;
+	int diff;
+	unsigned char silence;
+	unsigned half_dmasize;
+
+	/* update hardware pointer */
+	hwptr = trident_get_dma_addr(state);
+	diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+	dmabuf->hwptr = hwptr;
+	dmabuf->total_bytes += diff;
+
+	/* error handling and process wake up for ADC */
+	if (dmabuf->enable == ADC_RUNNING) {
+		if (dmabuf->mapped) {
+			dmabuf->count -= diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			dmabuf->count += diff;
+
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_adc(state);
+				dmabuf->error++;
+			}
+			else if (!dmabuf->endcleared) {
+				swptr = dmabuf->swptr;
+				silence = (dmabuf->fmt & TRIDENT_FMT_16BIT ? 0 : 0x80);
+				if (dmabuf->update_flag & ALI_ADDRESS_INT_UPDATE) {
+					/* We must clear end data of 1/2 dmabuf if needed.
+					   According to 1/2 algorithm of Address Engine Interrupt,
+					   check the validation of the data of half dmasize. */
+					half_dmasize = dmabuf->dmasize / 2;
+					if ((diff = hwptr - half_dmasize) < 0 )
+						diff = hwptr;
+					if ((dmabuf->count + diff) < half_dmasize) {
+						//there is invalid data in the end of half buffer
+						if ((clear_cnt = half_dmasize - swptr) < 0)
+							clear_cnt += half_dmasize;
+						//clear the invalid data
+						memset (dmabuf->rawbuf + swptr,
+							silence, clear_cnt);
+
+						dmabuf->endcleared = 1;
+					}
+				} else if (dmabuf->count < (signed) dmabuf->fragsize) {
+					clear_cnt = dmabuf->fragsize;
+					if ((swptr + clear_cnt) > dmabuf->dmasize)
+						clear_cnt = dmabuf->dmasize - swptr;
+					memset (dmabuf->rawbuf + swptr, silence, clear_cnt);
+					dmabuf->endcleared = 1;
+				}
+			}
+			/* trident_update_ptr is called by interrupt handler or by process via
+			   ioctl/poll, we only wake up the waiting process when we have more
+			   than 1/2 buffer of data to process (always true for interrupt handler) */
+			if (dmabuf->count > (signed)dmabuf->dmasize/2)
+				wake_up(&dmabuf->wait);
+		}
+	}
+
+	/* error handling and process wake up for DAC */
+	if (dmabuf->enable == DAC_RUNNING) {
+		if (dmabuf->mapped) {
+			dmabuf->count += diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			dmabuf->count -= diff;
+
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_dac(state);
+				dmabuf->error++;
+			}
+			/* trident_update_ptr is called by interrupt handler or by process via
+			   ioctl/poll, we only wake up the waiting process when we have more
+			   than 1/2 buffer free (always true for interrupt handler) */
+			if (dmabuf->count < (signed)dmabuf->dmasize/2)
+				wake_up(&dmabuf->wait);
+		}
+	}
+	dmabuf->update_flag &= ~ALI_ADDRESS_INT_UPDATE;
+}
+
+static void trident_address_interrupt(struct trident_card *card)
+{
+	int i;
+	struct trident_state *state;
+	
+	/* Update the pointers for all channels we are running. */
+	/* FIXME: should read interrupt status only once */
+	for (i = 0; i < NR_HW_CH; i++) {
+		if (trident_check_channel_interrupt(card, 63 - i)) {
+			trident_ack_channel_interrupt(card, 63 - i);
+			if ((state = card->states[i]) != NULL) {
+				trident_update_ptr(state);
+			} else {
+				printk("trident: spurious channel irq %d.\n",
+				       63 - i);
+				trident_stop_voice(card, 63 - i);
+				trident_disable_voice_irq(card, 63 - i);
+			}
+		}
+	}
+}
+
+static void ali_address_interrupt(struct trident_card *card)
+{
+	int i;
+	u32 mask = trident_get_interrupt_mask (card, BANK_A);
+
+#ifdef DEBUG
+	/* Sanity check to make sure that every state has a channel
+	   and vice versa. */
+	u32 done = 0;
+	unsigned ns = 0;
+	unsigned nc = 0;
+	for (i = 0; i < NR_HW_CH; i++) {
+		if (card->banks[BANK_A].bitmap & (1<<i))
+			nc ++;
+
+		if (card->states[i]) {
+			u32 bit = 1 << card->states[i]->dmabuf.channel->num;
+			if (bit & done) 
+				printk (KERN_ERR "trident: channel allocated to two states\n");
+			ns++;
+
+			done |= bit;
+		}
+	}
+	if (ns != nc) 
+		printk (KERN_ERR "trident: number of states != number of channels\n");
+#endif
+
+	for (i = 0; mask && i < NR_HW_CH; i++) {			
+		struct trident_state *state = card->states[i];
+		if (!state)
+			continue;
+
+		trident_ack_channel_interrupt(card, state->dmabuf.channel->num);
+		mask &= ~ (1<<state->dmabuf.channel->num);
+		state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
+		trident_update_ptr(state);
+	}
+
+	if (mask) 
+		for (i = 0; i < NR_HW_CH; i++)
+			if (mask & (1<<i)) {
+				printk("ali: spurious channel irq %d.\n", i);
+				trident_stop_voice(card, i);
+				trident_disable_voice_irq(card, i);
+			}
+
+}
+
+static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct trident_card *card = (struct trident_card *)dev_id;
+	u32 event;
+
+	spin_lock(&card->lock);
+	event = inl(TRID_REG(card, T4D_MISCINT));
+
+#ifdef DEBUG
+	printk("trident: trident_interrupt called, MISCINT = 0x%08x\n", event);
+#endif
+
+	if (event & ADDRESS_IRQ) {
+		card->address_interrupt(card);
+	}
+
+	/* manually clear interrupt status, bad hardware design, blame T^2 */
+	outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+	     TRID_REG(card, T4D_MISCINT));
+	spin_unlock(&card->lock);
+}
+
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
+   the user's buffer.  it is filled by the dma machine and drained by this loop. */
+static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+#ifdef DEBUG
+	printk("trident: trident_read called, count = %d\n", count);
+#endif
+
+	VALIDATE_STATE(state);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)
+		outl(inl(TRID_REG (state->card, ALI_GLOBAL_CONTROL)) | ALI_PCM_IN_ENABLE,
+		     TRID_REG (state->card, ALI_GLOBAL_CONTROL));
+
+	while (count > 0) {
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->count > (signed) dmabuf->dmasize) {
+			/* buffer overrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr, make process flush the buffer */
+			dmabuf->count = dmabuf->dmasize;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count < cnt)
+			cnt = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/* buffer is empty, start the dma machine and wait for data to be
+			   recorded */
+			start_adc(state);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret) ret = -EAGAIN;
+				return ret;
+			}
+			/* No matter how much space left in the buffer, we have to wait untill
+			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer overrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "trident: recording schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
+#endif
+				/* a buffer overrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have space to record */
+			}
+			if (signal_pending(current)) {
+				ret = ret ? ret : -ERESTARTSYS;
+				return ret;
+			}
+			continue;
+		}
+
+		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
+			if (!ret) ret = -EFAULT;
+			return ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		dmabuf->swptr = swptr;
+		dmabuf->count -= cnt;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_adc(state);
+	}
+	return ret;
+}
+
+/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
+   the soundcard.  it is drained by the dma machine and filled by this loop. */
+static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret;
+	unsigned long flags;
+	unsigned swptr;
+	int cnt;
+
+#ifdef DEBUG
+	printk("trident: trident_write called, count = %d\n", count);
+#endif
+
+	VALIDATE_STATE(state);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (dmabuf->mapped)
+		return -ENXIO;
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+		return ret;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	ret = 0;
+
+	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)
+		if (dmabuf->channel->num == ALI_PCM_IN_CHANNEL)
+			outl ( inl (TRID_REG (state->card, ALI_GLOBAL_CONTROL)) &
+			       ALI_PCM_IN_DISABLE, TRID_REG (state->card, ALI_GLOBAL_CONTROL));
+
+	while (count > 0) {
+		spin_lock_irqsave(&state->card->lock, flags);
+		if (dmabuf->count < 0) {
+			/* buffer underrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr */
+			dmabuf->count = 0;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count + cnt > dmabuf->dmasize)
+			cnt = dmabuf->dmasize - dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			unsigned long tmo;
+			/* buffer is full, start the dma machine and wait for data to be
+			   played */
+			start_dac(state);
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret) ret = -EAGAIN;
+				return ret;
+			}
+			/* No matter how much data left in the buffer, we have to wait untill
+			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when
+			   the interrupt is serviced correctly and the process is waked up by
+			   ISR ON TIME. Another is when timeout is expired, which means that
+			   either interrupt is NOT serviced correctly (pending interrupt) or it
+			   is TOO LATE for the process to be scheduled to run (scheduler latency)
+			   which results in a (potential) buffer underrun. And worse, there is
+			   NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "trident: playback schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
+#endif
+				/* a buffer underrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have data to play */
+			}
+			if (signal_pending(current)) {
+				if (!ret) ret = -ERESTARTSYS;
+				return ret;
+			}
+			continue;
+		}
+		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+			if (!ret) ret = -EFAULT;
+			return ret;
+		}
+
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		dmabuf->swptr = swptr;
+		dmabuf->count += cnt;
+		dmabuf->endcleared = 0;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		start_dac(state);
+	}
+	return ret;
+}
+
+/* No kernel lock - we have our own spinlock */
+static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	VALIDATE_STATE(state);
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &dmabuf->wait, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &dmabuf->wait, wait);
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	trident_update_ptr(state);
+	if (file->f_mode & FMODE_READ) {
+		if (dmabuf->count >= (signed)dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (signed)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	return mask;
+}
+
+static int trident_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int ret;
+	unsigned long size;
+
+	VALIDATE_STATE(state);
+	if (vma->vm_flags & VM_WRITE) {
+		if ((ret = prog_dmabuf(state, 0)) != 0)
+			return ret;
+	} else if (vma->vm_flags & VM_READ) {
+		if ((ret = prog_dmabuf(state, 1)) != 0)
+			return ret;
+	} else 
+		return -EINVAL;
+
+
+	if (vma->vm_offset != 0)
+		return -EINVAL;
+	size = vma->vm_end - vma->vm_start;
+	if (size > (PAGE_SIZE << dmabuf->buforder))
+		return -EINVAL;
+	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+			     size, vma->vm_page_prot))
+		return -EAGAIN;
+	dmabuf->mapped = 1;
+
+	return 0;
+}
+
+static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	unsigned long flags;
+	audio_buf_info abinfo;
+	count_info cinfo;
+	int val, mapped, ret;
+
+	VALIDATE_STATE(state);
+	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
+		((file->f_mode & FMODE_READ) && dmabuf->mapped);
+#ifdef DEBUG
+	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
+	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
+#endif
+
+	switch (cmd) 
+	{
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		/* FIXME: spin_lock ? */
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(state);
+			synchronize_irq();
+			dmabuf->ready = 0;
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(state);
+			synchronize_irq();
+			dmabuf->ready = 0;
+			dmabuf->swptr = dmabuf->hwptr = 0;
+			dmabuf->count = dmabuf->total_bytes = 0;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_dac(state, file->f_flags & O_NONBLOCK);
+		return 0;
+
+	case SNDCTL_DSP_SPEED: /* set smaple rate */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				trident_set_dac_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				trident_set_adc_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+		}
+		return put_user(dmabuf->rate, (int *)arg);
+
+	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(state);
+			dmabuf->ready = 0;
+			if (val)
+				dmabuf->fmt |= TRIDENT_FMT_STEREO;
+			else
+				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+		}
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(state);
+			dmabuf->ready = 0;
+			if (val)
+				dmabuf->fmt |= TRIDENT_FMT_STEREO;
+			else
+				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if ((val = prog_dmabuf(state, 0)))
+				return val;
+			return put_user(dmabuf->fragsize, (int *)arg);
+		}
+		if (file->f_mode & FMODE_READ) {
+			if ((val = prog_dmabuf(state, 1)))
+				return val;
+			return put_user(dmabuf->fragsize, (int *)arg);
+		}
+
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+		return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT: /* Select sample format */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+				if (val == AFMT_S16_LE)
+					dmabuf->fmt |= TRIDENT_FMT_16BIT;
+				else
+					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				if (val == AFMT_S16_LE)
+					dmabuf->fmt |= TRIDENT_FMT_16BIT;
+				else
+					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;
+			}
+		}
+		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+				AFMT_S16_LE : AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				dmabuf->ready = 0;
+				if (val >= 2)
+					dmabuf->fmt |= TRIDENT_FMT_STEREO;
+				else
+					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				dmabuf->ready = 0;
+				if (val >= 2)
+					dmabuf->fmt |= TRIDENT_FMT_STEREO;
+				else
+					dmabuf->fmt &= ~TRIDENT_FMT_STEREO;
+			}
+		}
+		return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+				(int *)arg);
+
+	case SNDCTL_DSP_POST:
+		/* FIXME: the same as RESET ?? */
+		return 0;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		if (dmabuf->subdivision)
+			return -EINVAL;
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		dmabuf->subdivision = val;
+		return 0;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		dmabuf->ossfragshift = val & 0xffff;
+		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
+		if (dmabuf->ossfragshift < 4)
+			dmabuf->ossfragshift = 4;
+		if (dmabuf->ossfragshift > 15)
+			dmabuf->ossfragshift = 15;
+		if (dmabuf->ossmaxfrags < 4)
+			dmabuf->ossmaxfrags = 4;
+
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->dmasize - dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		abinfo.fragsize = dmabuf->fragsize;
+		abinfo.bytes = dmabuf->count;
+		abinfo.fragstotal = dmabuf->numfrag;
+		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, 
+			    (int *)arg);
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & FMODE_READ && dmabuf->enable)
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+					return ret;
+				start_adc(state);
+			} else
+				stop_adc(state);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+					return ret;
+				start_dac(state);
+			} else
+				stop_dac(state);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		cinfo.bytes = dmabuf->total_bytes;
+		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
+		cinfo.ptr = dmabuf->hwptr;
+		if (dmabuf->mapped)
+			dmabuf->count &= dmabuf->fragsize-1;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return -EINVAL;
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		val = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return put_user(val, (int *)arg);
+
+	case SOUND_PCM_READ_RATE:
+		return put_user(dmabuf->rate, (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+		return put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+				(int *)arg);
+
+	case SOUND_PCM_READ_BITS:
+		return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
+				AFMT_S16_LE : AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+		
+	}
+	return -EINVAL;
+}
+
+static int trident_open(struct inode *inode, struct file *file)
+{
+	int i = 0;
+	int minor = MINOR(inode->i_rdev);
+	struct trident_card *card = devs;
+	struct trident_state *state = NULL;
+	struct dmabuf *dmabuf = NULL;
+
+	MOD_INC_USE_COUNT;
+	/* find an avaiable virtual channel (instance of /dev/dsp) */
+	while (card != NULL) {
+		down(&card->open_sem);
+		for (i = 0; i < NR_HW_CH; i++) {
+			if (card->states[i] == NULL) {
+				state = card->states[i] = (struct trident_state *)
+					kmalloc(sizeof(struct trident_state), GFP_KERNEL);
+				if (state == NULL) {
+					MOD_DEC_USE_COUNT;
+					return -ENOMEM;
+				}
+				memset(state, 0, sizeof(struct trident_state));
+				dmabuf = &state->dmabuf;
+				goto found_virt;
+			}
+		}
+		up(&card->open_sem);
+		card = card->next;
+	}
+	/* no more virtual channel avaiable */
+	if (!state) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+ found_virt:
+	/* found a free virtual channel, allocate hardware channels */
+	if(file->f_mode & FMODE_READ)
+		dmabuf->channel = card->alloc_rec_pcm_channel(card);
+	else
+		dmabuf->channel = card->alloc_pcm_channel(card);
+		
+	if (dmabuf->channel == NULL) {
+		kfree (card->states[i]);
+		card->states[i] = NULL;
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	/* initialize the virtual channel */
+	state->virt = i;
+	state->card = card;
+	state->magic = TRIDENT_STATE_MAGIC;
+	init_waitqueue(&dmabuf->wait);
+	file->private_data = state;
+
+	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
+	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
+	   /dev/dspW will accept 16-bits sample */
+	if (file->f_mode & FMODE_WRITE) {
+		dmabuf->fmt &= ~TRIDENT_FMT_MASK;
+		if ((minor & 0x0f) == SND_DEV_DSP16)
+			dmabuf->fmt |= TRIDENT_FMT_16BIT;
+		dmabuf->ossfragshift = 0;
+		dmabuf->ossmaxfrags  = 0;
+		dmabuf->subdivision  = 0;
+		if (card->pci_id == PCI_DEVICE_ID_SI_7018) {
+			/* set default channel attribute to normal playback */
+			dmabuf->channel->attribute = CHANNEL_PB;
+		}
+		trident_set_dac_rate(state, 8000);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+			card->states[ALI_PCM_IN_CHANNEL] = state;
+			card->states[i] = NULL;
+			state->virt = ALI_PCM_IN_CHANNEL;
+		}
+		/* FIXME: Trident 4d can only record in signed 16-bits stereo, 48kHz sample,
+		   to be dealed with in trident_set_adc_rate() ?? */
+		dmabuf->fmt &= ~TRIDENT_FMT_MASK;
+		if ((minor & 0x0f) == SND_DEV_DSP16)
+			dmabuf->fmt |= TRIDENT_FMT_16BIT;
+		dmabuf->ossfragshift = 0;
+		dmabuf->ossmaxfrags  = 0;
+		dmabuf->subdivision  = 0;
+		if (card->pci_id == PCI_DEVICE_ID_SI_7018) {
+			/* set default channel attribute to 0x8a80, record from
+			   PCM L/R FIFO and mono = (left + right + 1)/2*/
+			dmabuf->channel->attribute =
+				(CHANNEL_REC|PCM_LR|MONO_MIX);
+		}
+		trident_set_adc_rate(state, 8000);
+	}
+
+	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	up(&card->open_sem);
+
+#ifdef DEBUG
+       printk(KERN_ERR "trident: open virtual channel %d, hard channel %d\n", 
+              state->virt, dmabuf->channel->num);
+#endif
+
+	return 0;
+}
+
+static int trident_release(struct inode *inode, struct file *file)
+{
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct trident_card *card = state->card;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	VALIDATE_STATE(state);
+
+	if (file->f_mode & FMODE_WRITE) {
+		trident_clear_tail(state);
+		drain_dac(state, file->f_flags & O_NONBLOCK);
+	}
+
+	/* stop DMA state machine and free DMA buffers/channels */
+	down(&card->open_sem);
+
+	if (file->f_mode & FMODE_WRITE) {
+		stop_dac(state);
+		dealloc_dmabuf(state);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+	}
+	if (file->f_mode & FMODE_READ) {
+		stop_adc(state);
+		dealloc_dmabuf(state);
+		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+	}
+
+	card->states[state->virt] = NULL;
+	kfree(state);
+
+	/* we're covered by the open_sem */
+	up(&card->open_sem);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static /*const*/ struct file_operations trident_audio_fops = {
+	llseek:		trident_llseek,
+	read:		trident_read,
+	write:		trident_write,
+	poll:		trident_poll,
+	ioctl:		trident_ioctl,
+	mmap:		trident_mmap,
+	open:		trident_open,
+	release:	trident_release,
+};
+
+/* trident specific AC97 functions */
+/* Write AC97 codec registers */
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask, busy;
+	unsigned short count  = 0xffff;
+	unsigned long flags;
+	u32 data;
+
+	data = ((u32) val) << 16;
+
+	switch (card->pci_id)
+	{
+	default:
+	case PCI_DEVICE_ID_SI_7018:
+		address = SI_AC97_WRITE;
+		mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+		if (codec->id)
+			mask |= SI_AC97_SECONDARY;
+		busy = SI_AC97_BUSY_WRITE;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		address = DX_ACR0_AC97_W;
+		mask = busy = DX_AC97_BUSY_WRITE;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		address = NX_ACR1_AC97_W;
+		mask = NX_AC97_BUSY_WRITE;
+		if (codec->id)
+			mask |= NX_AC97_WRITE_SECONDARY;
+		busy = NX_AC97_BUSY_WRITE;
+		break;
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+	do {
+		if ((inw(TRID_REG(card, address)) & busy) == 0)
+			break;
+	} while (count--);
+
+
+	data |= (mask | (reg & AC97_REG_ADDR));
+
+	if (count == 0) {
+		printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
+		spin_unlock_irqrestore(&card->lock, flags);
+		return;
+	}
+
+	outl(data, TRID_REG(card, address));
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* Read AC97 codec registers */
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask, busy;
+	unsigned short count = 0xffff;
+	unsigned long flags;
+	u32 data;
+
+	switch (card->pci_id)
+	{
+	default:
+	case PCI_DEVICE_ID_SI_7018:
+		address = SI_AC97_READ;
+		mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+		if (codec->id)
+			mask |= SI_AC97_SECONDARY;
+		busy = SI_AC97_BUSY_READ;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		address = DX_ACR1_AC97_R;
+		mask = busy = DX_AC97_BUSY_READ;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		if (codec->id)
+			address = NX_ACR3_AC97_R_SECONDARY;
+		else
+			address = NX_ACR2_AC97_R_PRIMARY;
+		mask = NX_AC97_BUSY_READ;
+		busy = NX_AC97_BUSY_READ | NX_AC97_BUSY_DATA;
+		break;
+	}
+
+	data = (mask | (reg & AC97_REG_ADDR));
+
+	spin_lock_irqsave(&card->lock, flags);
+	outl(data, TRID_REG(card, address));
+	do {
+		data = inl(TRID_REG(card, address));
+		if ((data & busy) == 0)
+			break;
+	} while (count--);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	if (count == 0) {
+		printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
+		data = 0;
+	}
+	return ((u16) (data >> 16));
+}
+
+/* Write AC97 codec registers for ALi*/
+static void ali_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask;
+	unsigned int wCount1 = 0xffff;
+	unsigned int wCount2= 0xffff;
+	unsigned long chk1, chk2;
+	unsigned long flags;
+	u32 data;
+
+	data = ((u32) val) << 16;
+
+	address = ALI_AC97_WRITE;
+	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
+	if (codec->id)
+		mask |= ALI_AC97_SECONDARY;
+	if (card->revision == 0x02)
+		mask |= ALI_AC97_WRITE_MIXER_REGISTER;
+		
+	spin_lock_irqsave(&card->lock, flags);
+	while (wCount1--) {
+		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_WRITE) == 0) {
+			data |= (mask | (reg & AC97_REG_ADDR));
+			
+			chk1 = inl(TRID_REG(card,  ALI_STIMER));
+			chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			while (wCount2-- && (chk1 == chk2))
+				chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			if (wCount2 == 0) {
+				spin_unlock_irqrestore(&card->lock, flags);
+				return;
+			}
+			outl(data, TRID_REG(card, address));	//write!
+			spin_unlock_irqrestore(&card->lock, flags);
+			return;	//success
+		}
+		inw(TRID_REG(card, address));	//wait a read cycle
+	}
+
+	printk(KERN_ERR "ali: AC97 CODEC write timed out.\n");
+	spin_unlock_irqrestore(&card->lock, flags);
+	return;
+}
+
+/* Read AC97 codec registers for ALi*/
+static u16 ali_ac97_get(struct ac97_codec *codec, u8 reg)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask;
+        unsigned int wCount1 = 0xffff;
+        unsigned int wCount2= 0xffff;
+        unsigned long chk1, chk2;
+	unsigned long flags;
+	u32 data;
+
+	address = ALI_AC97_READ;
+	if (card->revision == 0x02) {
+		address = ALI_AC97_WRITE;
+		mask &= ALI_AC97_READ_MIXER_REGISTER;
+	}
+	mask = ALI_AC97_READ_ACTION | ALI_AC97_AUDIO_BUSY;
+	if (codec->id)
+		mask |= ALI_AC97_SECONDARY;
+
+	spin_lock_irqsave(&card->lock, flags);
+	data = (mask | (reg & AC97_REG_ADDR));
+	while (wCount1--) {
+		if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
+			chk1 = inl(TRID_REG(card,  ALI_STIMER));
+			chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			while (wCount2-- && (chk1 == chk2))
+				chk2 = inl(TRID_REG(card,  ALI_STIMER));
+			if (wCount2 == 0) {
+				printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
+				spin_unlock_irqrestore(&card->lock, flags);
+				return 0;
+			}
+			outl(data, TRID_REG(card, address));	//read!
+			wCount2 = 0xffff;
+			while (wCount2--) {
+				if ((inw(TRID_REG(card, address)) & ALI_AC97_BUSY_READ) == 0) {
+					data = inl(TRID_REG(card, address));
+					spin_unlock_irqrestore(&card->lock, flags);
+					return ((u16) (data >> 16));
+				}
+			}
+		}
+		inw(TRID_REG(card, address));	//wait a read cycle
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+	printk(KERN_ERR "ali: AC97 CODEC read timed out.\n");
+	return 0;
+}
+
+/* OSS /dev/mixer file operation methods */
+static int trident_open_mixdev(struct inode *inode, struct file *file)
+{
+	int i;
+	int minor = MINOR(inode->i_rdev);
+	struct trident_card *card = devs;
+
+	MOD_INC_USE_COUNT;
+	for (card = devs; card != NULL; card = card->next)
+		for (i = 0; i < NR_AC97; i++)
+			if (card->ac97_codec[i] != NULL &&
+			    card->ac97_codec[i]->dev_mixer == minor)
+				goto match;
+
+	if (!card) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+ match:
+	file->private_data = card->ac97_codec[i];
+
+
+	return 0;
+}
+
+static int trident_release_mixdev(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations trident_mixer_fops = {
+	llseek:		trident_llseek,
+	ioctl:		trident_ioctl_mixdev,
+	open:		trident_open_mixdev,
+	release:	trident_release_mixdev,
+};
+
+/* AC97 codec initialisation. */
+static int __init trident_ac97_init(struct trident_card *card)
+{
+	int num_ac97 = 0;
+	int ready_2nd = 0;
+	struct ac97_codec *codec;
+
+	/* initialize controller side of AC link, and find out if secondary codes
+	   really exist */
+	switch (card->pci_id)
+	{
+	case PCI_DEVICE_ID_ALI_5451:
+		outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL));
+		ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); 
+		ready_2nd &= SI_AC97_SECONDARY_READY;
+		break;
+	case PCI_DEVICE_ID_SI_7018:
+		/* disable AC97 GPIO interrupt */
+		outl(0x00, TRID_REG(card, SI_AC97_GPIO));
+		/* when power up the AC link is in cold reset mode so stop it */
+		outl(PCMOUT|SURROUT|CENTEROUT|LFEOUT|SECONDARY_ID,
+		     TRID_REG(card, SI_SERIAL_INTF_CTRL));
+		/* it take a long time to recover from a cold reset (especially when you have
+		   more than one codec) */
+		udelay(2000);
+		ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
+		ready_2nd &= SI_AC97_SECONDARY_READY;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		/* playback on */
+		outl(DX_AC97_PLAYBACK, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		/* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
+		outl(NX_AC97_PCM_OUTPUT, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+		ready_2nd = inl(TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+		ready_2nd &= NX_AC97_SECONDARY_READY;
+		break;
+	}
+
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		memset(codec, 0, sizeof(struct ac97_codec));
+
+		/* initialize some basic codec information, other fields will be filled
+		   in ac97_probe_codec */
+		codec->private_data = card;
+		codec->id = num_ac97;
+
+		if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+			codec->codec_read = ali_ac97_get;
+			codec->codec_write = ali_ac97_set;
+		}
+		else {
+			codec->codec_read = trident_ac97_get;
+			codec->codec_write = trident_ac97_set;
+		}
+	
+		if (ac97_probe_codec(codec) == 0)
+			break;
+
+		if ((codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+			printk(KERN_ERR "trident: couldn't register mixer!\n");
+			kfree(codec);
+			break;
+		}
+
+		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;
+	}
+
+	return num_ac97;
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
+   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+static int __init trident_install(struct pci_dev *pci_dev, struct pci_audio_info *pci_info)
+{
+	u16 w;
+	unsigned long iobase;
+	struct trident_card *card;
+
+
+	iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+	if (check_region(iobase, 256)) {
+		printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
+		       iobase);
+		return -ENODEV;
+	}
+
+	/* just to be sure that IO space and bus master is on */
+	pci_set_master(pci_dev);
+	pci_read_config_word(pci_dev, PCI_COMMAND, &w);
+	w |= PCI_COMMAND_IO|PCI_COMMAND_MASTER;
+	pci_write_config_word(pci_dev, PCI_COMMAND, w);
+
+	if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "trident: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(*card));
+
+	card->iobase = iobase;
+	card->pci_info = pci_info;
+	card->pci_id = pci_info->device;
+	card->irq = pci_dev->irq;
+	card->next = devs;
+	card->magic = TRIDENT_CARD_MAGIC;
+	card->banks[BANK_A].addresses = &bank_a_addrs;
+	card->banks[BANK_A].bitmap = 0UL;
+	card->banks[BANK_B].addresses = &bank_b_addrs;
+	card->banks[BANK_B].bitmap = 0UL;
+	card->open_sem = MUTEX;
+	spin_lock_init(&card->lock);
+	devs = card;
+
+	printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
+	       card->pci_info->name, card->iobase, card->irq);
+
+	if(card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+		card->alloc_pcm_channel = ali_alloc_pcm_channel;
+		card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
+		card->free_pcm_channel = ali_free_pcm_channel;
+		card->address_interrupt = ali_address_interrupt;
+	}
+	else {
+		card->alloc_pcm_channel = trident_alloc_pcm_channel;
+		card->alloc_rec_pcm_channel = trident_alloc_pcm_channel;
+		card->free_pcm_channel = trident_free_pcm_channel;
+		card->address_interrupt = trident_address_interrupt;
+	}
+
+	/* claim our iospace and irq */
+	request_region(card->iobase, 256, card->pci_info->name);
+	if (request_irq(card->irq, &trident_interrupt, SA_SHIRQ, card->pci_info->name, card)) {
+		printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq);
+		release_region(card->iobase, 256);
+		kfree(card);
+		return -ENODEV;
+	}
+	/* register /dev/dsp */
+	if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "trident: couldn't register DSP device!\n");
+		release_region(iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+	/* initilize AC97 codec and register /dev/mixer */
+	if (trident_ac97_init(card) <= 0) {
+		unregister_sound_dsp(card->dev_audio);
+		release_region(iobase, 256);
+		free_irq(card->irq, card);
+		kfree(card);
+		return -ENODEV;
+	}
+	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
+
+	if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
+		/* edited by HMSEO for GT sound */
+#ifdef CONFIG_ALPHA_NAUTILUS
+		ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL);
+		trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL,
+				  ac97_data | ALI_EAPD_POWER_DOWN);
+#endif
+		/* edited by HMSEO for GT sound*/
+	}
+
+	/* Enable Address Engine Interrupts */
+	trident_enable_loop_interrupts(card);
+
+	return 1;
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+int init_trident(void)
+#endif
+ {
+	struct pci_dev *pcidev = NULL;
+	int foundone = 0;
+ 	int i;
+ 
+	if (!pci_present())   /* No PCI bus in this machine! */
+		return -ENODEV;
+ 
+	printk(KERN_INFO "Trident 4DWave/SiS 7018 PCI Audio, version "
+	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
+ 
+	for (i = 0; i < sizeof (pci_audio_devices); i++) {
+		pcidev = NULL;
+		while ((pcidev = pci_find_device(pci_audio_devices[i].vendor,
+						 pci_audio_devices[i].device,
+						 pcidev)) != NULL) {
+			foundone += trident_install(pcidev, pci_audio_devices + i);
+ 		}
+	}
+ 
+	if (!foundone)
+		return -ENODEV;
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee");
+MODULE_DESCRIPTION("Trident 4DWave/SiS 7018/ALi 5451 PCI Audio Driver");
+
+void cleanup_module(void)
+#else
+void cleanup_trident(void)
+#endif
+{
+	while (devs != NULL) {
+		int i;
+		/* Kill interrupts, and SP/DIF */
+		trident_disable_loop_interrupts(devs);
+ 
+		/* free hardware resources */
+		free_irq(devs->irq, devs);
+		release_region(devs->iobase, 256);
+ 
+		/* unregister audio devices */
+		for (i = 0; i < NR_AC97; i++)
+			if (devs->ac97_codec[i] != NULL) {
+				unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer);
+				kfree (devs->ac97_codec[i]);
+			}
+		unregister_sound_dsp(devs->dev_audio);
+ 
+		kfree(devs);
+		devs = devs->next;
+	}
+}
+
diff -urN linux-2.2.16-pre7/drivers/sound/trident.h linux/drivers/sound/trident.h
--- linux-2.2.16-pre7/drivers/sound/trident.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/trident.h	Mon Dec  3 22:04:51 2001
@@ -0,0 +1,289 @@
+#ifndef __TRID4DWAVE_H
+#define __TRID4DWAVE_H
+
+/*
+ *  audio@tridentmicro.com
+ *  Fri Feb 19 15:55:28 MST 1999
+ *  Definitions for Trident 4DWave DX/NX chips
+ *
+ *
+ *   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.
+ *
+ */
+
+/* PCI vendor and device ID */ 
+#ifndef PCI_VENDOR_ID_TRIDENT
+#define PCI_VENDOR_ID_TRIDENT		0x1023
+#endif
+
+#ifndef PCI_VENDOR_ID_SI
+#define PCI_VENDOR_ID_SI			0x0139
+#endif
+
+#ifndef PCI_VENDOR_ID_ALI
+#define PCI_VENDOR_ID_ALI			0x10b9
+#endif
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
+#endif
+
+#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX
+#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX	0x2001
+#endif
+
+#ifndef PCI_DEVICE_ID_SI_7018
+#define PCI_DEVICE_ID_SI_7018		0x7018
+#endif
+
+#ifndef PCI_DEVICE_ID_ALI_5451
+#define PCI_DEVICE_ID_ALI_5451		0x5451
+#endif
+
+#ifndef FALSE
+#define FALSE 		0
+#define TRUE  		1
+#endif
+
+#define CHANNEL_REGS	5
+#define CHANNEL_START	0xe0   // The first bytes of the contiguous register space.
+
+#define BANK_A 		0
+#define BANK_B 		1
+#define NR_BANKS		2
+
+#define TRIDENT_FMT_STEREO     0x01
+#define TRIDENT_FMT_16BIT      0x02
+#define TRIDENT_FMT_MASK       0x03
+
+#define DAC_RUNNING	0x01
+#define ADC_RUNNING	0x02
+
+/* Register Addresses */
+
+/* operational registers common to DX, NX, 7018 */
+enum trident_op_registers {
+	T4D_REC_CH	= 0x70,
+	T4D_START_A     = 0x80, T4D_STOP_A      = 0x84,
+	T4D_DLY_A       = 0x88, T4D_SIGN_CSO_A  = 0x8c,
+	T4D_CSPF_A      = 0x90, T4D_CEBC_A      = 0x94,
+	T4D_AINT_A      = 0x98, T4D_EINT_A	= 0x9c,
+	T4D_LFO_GC_CIR	= 0xa0, T4D_AINTEN_A    = 0xa4,
+	T4D_MUSICVOL_WAVEVOL = 0xa8, T4D_SBDELTA_DELTA_R = 0xac,
+	T4D_MISCINT	= 0xb0, T4D_START_B     = 0xb4,
+	T4D_STOP_B      = 0xb8, T4D_CSPF_B	= 0xbc,
+	T4D_SBBL_SBCL	= 0xc0, T4D_SBCTRL_SBE2R_SBDD    = 0xc4,
+	T4D_STIMER	= 0xc8, T4D_LFO_B_I2S_DELTA      = 0xcc,
+	T4D_AINT_B	= 0xd8, T4D_AINTEN_B    = 0xdc
+};
+
+enum ali_op_registers {
+	ALI_GLOBAL_CONTROL	= 0xd4,
+	ALI_STIMER		= 0xc8
+};
+
+enum ali_global_control_bit {
+	ALI_PCM_IN_ENABLE	= 0x80000000,
+	ALI_PCM_IN_DISABLE	= 0x7fffffff
+};
+
+enum ali_pcm_in_channel_num {
+	ALI_PCM_IN_CHANNEL	= 31
+};
+
+enum ali_pcm_out_channel_num {
+	ALI_PCM_OUT_CHANNEL_FIRST = 1,
+	ALI_PCM_OUT_CHANNEL_LAST = 30
+};
+
+enum ali_ac97_power_control_bit {
+	ALI_EAPD_POWER_DOWN	= 0x8000
+};
+
+enum ali_update_ptr_flags {
+	ALI_ADDRESS_INT_UPDATE	= 0x01
+};
+
+/* S/PDIF Operational Registers for 4D-NX */
+enum nx_spdif_registers {
+	NX_SPCTRL_SPCSO	= 0x24, NX_SPLBA = 0x28,
+	NX_SPESO	= 0x2c, NX_SPCSTATUS = 0x64
+};
+
+/* OP registers to access each hardware channel */
+enum channel_registers {
+	CH_DX_CSO_ALPHA_FMS = 0xe0, CH_DX_ESO_DELTA = 0xe8,
+	CH_DX_FMC_RVOL_CVOL = 0xec,
+	CH_NX_DELTA_CSO     = 0xe0, CH_NX_DELTA_ESO = 0xe8,
+	CH_NX_ALPHA_FMS_FMC_RVOL_CVOL = 0xec,
+	CH_LBA              = 0xe4,
+	CH_GVSEL_PAN_VOL_CTRL_EC      = 0xf0
+};
+
+/* registers to read/write/control AC97 codec */
+enum dx_ac97_registers {
+	DX_ACR0_AC97_W        = 0x40, DX_ACR1_AC97_R = 0x44,
+	DX_ACR2_AC97_COM_STAT = 0x48
+};
+
+enum nx_ac97_registers {
+	NX_ACR0_AC97_COM_STAT  = 0x40, NX_ACR1_AC97_W           = 0x44,
+	NX_ACR2_AC97_R_PRIMARY = 0x48, NX_ACR3_AC97_R_SECONDARY	= 0x4c
+};
+
+enum si_ac97_registers {
+	SI_AC97_WRITE       = 0x40, SI_AC97_READ = 0x44,
+	SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c
+};
+
+enum ali_ac97_registers {
+	ALI_AC97_WRITE       = 0x40, ALI_AC97_READ = 0x44
+};
+
+/* Bit mask for operational registers */
+#define AC97_REG_ADDR      0x000000ff
+
+enum ali_ac97_bits {
+	ALI_AC97_BUSY_WRITE = 0x8000, ALI_AC97_BUSY_READ = 0x8000,
+	ALI_AC97_WRITE_ACTION = 0x8000, ALI_AC97_READ_ACTION = 0x8000,
+	ALI_AC97_AUDIO_BUSY = 0x4000, ALI_AC97_SECONDARY  = 0x0080,
+	ALI_AC97_READ_MIXER_REGISTER = 0xfeff,
+	ALI_AC97_WRITE_MIXER_REGISTER = 0x0100
+};
+
+enum sis7018_ac97_bits {
+	SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000,
+	SI_AC97_AUDIO_BUSY = 0x4000, SI_AC97_MODEM_BUSY = 0x2000,
+	SI_AC97_SECONDARY  = 0x0080
+};
+
+enum trident_dx_ac97_bits {
+	DX_AC97_BUSY_WRITE = 0x8000, DX_AC97_BUSY_READ = 0x8000,
+	DX_AC97_READY      = 0x0010, DX_AC97_RECORD    = 0x0008,
+	DX_AC97_PLAYBACK   = 0x0002
+};
+
+enum trident_nx_ac97_bits {
+	/* ACR1-3 */
+	NX_AC97_BUSY_WRITE = 0x0800, NX_AC97_BUSY_READ = 0x0800,
+	NX_AC97_BUSY_DATA  = 0x0400, NX_AC97_WRITE_SECONDARY = 0x0100,
+	/* ACR0 */
+	NX_AC97_SECONDARY_READY = 0x0040, NX_AC97_SECONDARY_RECORD = 0x0020,
+	NX_AC97_SURROUND_OUTPUT = 0x0010,
+	NX_AC97_PRIMARY_READY   = 0x0008, NX_AC97_PRIMARY_RECORD   = 0x0004,
+	NX_AC97_PCM_OUTPUT      = 0x0002,
+	NX_AC97_WARM_RESET      = 0x0001
+};
+
+enum serial_intf_ctrl_bits {
+	WARM_REST   = 0x00000001, COLD_RESET  = 0x00000002,
+	I2S_CLOCK   = 0x00000004, PCM_SEC_AC97= 0x00000008,
+	AC97_DBL_RATE = 0x00000010, SPDIF_EN  = 0x00000020,
+	I2S_OUTPUT_EN = 0x00000040, I2S_INPUT_EN = 0x00000080,
+	PCMIN       = 0x00000100, LINE1IN     = 0x00000200,
+	MICIN       = 0x00000400, LINE2IN     = 0x00000800,
+	HEAD_SET_IN = 0x00001000, GPIOIN      = 0x00002000,
+	/* 7018 spec says id = 01 but the demo board routed to 10 
+	   SECONDARY_ID= 0x00004000, */
+	SECONDARY_ID= 0x00004000,
+	PCMOUT      = 0x00010000, SURROUT     = 0x00020000,
+	CENTEROUT   = 0x00040000, LFEOUT      = 0x00080000,
+	LINE1OUT    = 0x00100000, LINE2OUT    = 0x00200000,
+	GPIOOUT     = 0x00400000,
+	SI_AC97_PRIMARY_READY   = 0x01000000,
+	SI_AC97_SECONDARY_READY = 0x02000000,
+};
+
+enum global_control_bits {
+	CHANNLE_IDX = 0x0000003f, PB_RESET    = 0x00000100,
+	PAUSE_ENG   = 0x00000200,
+	OVERRUN_IE  = 0x00000400, UNDERRUN_IE = 0x00000800,
+	ENDLP_IE    = 0x00001000, MIDLP_IE    = 0x00002000,
+	ETOG_IE     = 0x00004000,
+	EDROP_IE    = 0x00008000, BANK_B_EN   = 0x00010000
+};
+
+enum channel_control_bits {
+	CHANNEL_LOOP   = 0x00001000, CHANNEL_SIGNED = 0x00002000,
+	CHANNEL_STEREO = 0x00004000, CHANNEL_16BITS = 0x00008000,
+};
+
+enum channel_attribute {
+	/* playback/record select */
+	CHANNEL_PB     = 0x0000, CHANNEL_SPC_PB = 0x4000,
+	CHANNEL_REC    = 0x8000, CHANNEL_REC_PB = 0xc000,
+	/* playback destination/record source select */
+	MODEM_LINE1    = 0x0000, MODEM_LINE2    = 0x0400,
+	PCM_LR         = 0x0800, HSET           = 0x0c00,
+	I2S_LR         = 0x1000, CENTER_LFE     = 0x1400,
+	SURR_LR        = 0x1800, SPDIF_LR       = 0x1c00,
+	MIC            = 0x1400,
+	/* mist stuff */
+	MONO_LEFT      = 0x0000, MONO_RIGHT     = 0x0100,
+	MONO_MIX       = 0x0200, SRC_ENABLE     = 0x0080,
+};
+
+enum miscint_bits {
+	PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
+	SB_IRQ          = 0x00000004, MPU401_IRQ      = 0x00000008,
+	OPL3_IRQ        = 0x00000010, ADDRESS_IRQ     = 0x00000020,
+	ENVELOPE_IRQ    = 0x00000040, ST_IRQ          = 0x00000080,
+	PB_UNDERRUN     = 0x00000100, REC_OVERRUN     = 0x00000200,
+	MIXER_UNDERFLOW = 0x00000400, MIXER_OVERFLOW  = 0x00000800,
+	ST_TARGET_REACHED = 0x00008000, PB_24K_MODE   = 0x00010000, 
+	ST_IRQ_EN       = 0x00800000, ACGPIO_IRQ      = 0x01000000
+};
+
+#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
+
+#define VALIDATE_MAGIC(FOO,MAG)				\
+({						  \
+	if (!(FOO) || (FOO)->magic != MAG) { \
+		printk(invalid_magic,__FUNCTION__);	       \
+		return -ENXIO;			  \
+	}					  \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+
+ 
+extern __inline__ unsigned ld2(unsigned int x)
+{
+	unsigned r = 0;
+	
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
+
+#endif /* __TRID4DWAVE_H */
+
diff -urN linux-2.2.16-pre7/drivers/sound/ymf_sb.c linux/drivers/sound/ymf_sb.c
--- linux-2.2.16-pre7/drivers/sound/ymf_sb.c	Mon Dec  3 22:04:44 2001
+++ linux/drivers/sound/ymf_sb.c	Mon Dec  3 22:04:51 2001
@@ -14,8 +14,31 @@
     * OPL3-compatible FM synthesizer
     * MPU-401 compatible "external" MIDI interface
 
-  Because of hardware specification, only 4 cards on a machine can 
-  be handled. This driver supports 4 cards with one driver.
+  -------------------------------------------------------------------------
+
+  Revision history
+
+   Tue May 14 19:00:00 2000   0.0.1
+   * initial release
+
+   Tue May 16 19:29:29 2000   0.0.2
+
+   * add a little delays for reset devices.
+   * fixed addressing bug.
+
+   Sun May 21 15:14:37 2000   0.0.3
+
+   * Add 'master_vol' module parameter to change 'PCM out Vol' of AC'97.
+   * remove native UART401 support. External MIDI port should be supported 
+     by sb_midi driver.
+   * add support for SPDIF OUT. Module parameter 'spdif_out' is now available.
+
+   Wed May 31 00:13:57 2000   0.0.4
+
+   * remove entries in Hwmcode.h. Now YMF744 / YMF754 sets instructions 
+     in 724hwmcode.h.
+   * fixed wrong legacy_io setting on YMF744/YMF754 .
+
  */
 
 #include <linux/module.h>
@@ -35,7 +58,6 @@
 #include "ac97.h"
 
 #include "724hwmcode.h"
-#include "Hwmcode.h"
 
 #undef YMF_DEBUG
 #define SUPPORT_UART401_MIDI 1
@@ -201,7 +223,7 @@
 
 #define PFX		"ymf_sb: "
 
-#define YMFSB_VERSION	"0.0.3"
+#define YMFSB_VERSION	"0.0.4"
 #define YMFSB_CARD_NAME	"YMF7xx Legacy Audio driver " YMFSB_VERSION
 
 #ifdef SUPPORT_UART401_MIDI
@@ -262,7 +284,6 @@
 
 	if (ymfbase[cards]==NULL) return 0;
 
-	/* printk(KERN_INFO PFX "readRegWord(%p)\n",ymfbase[cards]+adr/2); */
 	return readw(ymfbase[cards]+adr/2);
 }
 
@@ -326,7 +347,7 @@
 {
 	u8 tmp8;
 
-	pci_read_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8);
+	pci_read_config_byte( pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8 );
 	if ( tmp8 & 0x03 ) {
 		pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc);
 		mdelay(YMFSB_RESET_DELAY);
@@ -344,7 +365,7 @@
 static int setupLegacyIO( struct pci_dev *pcidev )
 {
 	int v;
-	int sbio=0x220,mpuio=0x330,oplio=0x388,dma=0;
+	int sbio=0, mpuio=0, oplio=0,dma=0;
 
 	switch(sb_data[cards].io_base) {
 	case 0x220:
@@ -437,12 +458,11 @@
 	case PCI_DEVICE_ID_YMF754:
 		v = 0x8800;
 		pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v);
-#ifdef YMF_DEBUG
-		printk(PFX "ELEGCTRL: 0x%x\n",v);
+		pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, opl3_data[cards].io_base);
+		pci_write_config_word(pcidev, YMFSB_PCIR_SBADR,  sb_data[cards].io_base);
+#ifdef SUPPORT_UART401_MIDI
+		pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, mpu_data[cards].io_base);
 #endif
-		pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, oplio);
-		pci_write_config_word(pcidev, YMFSB_PCIR_SBADR,  sbio);
-		pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, mpuio);
 		break;
 
 	default:
@@ -502,14 +522,14 @@
 	val = readRegWord( YMFSB_GLOBALCTRL );
 	writeRegWord( YMFSB_GLOBALCTRL, (val&~0x0007) );
 
+	/* setup DSP instruction code */
+	for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
+	  writeRegDWord( YMFSB_DSPINSTRAM+i, DspInst[i>>2] );
+	}
+
 	switch( pcidev->device ) {
 	case PCI_DEVICE_ID_YMF724:
 	case PCI_DEVICE_ID_YMF740:
-		/* setup DSP instruction code */
-		for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
-			writeRegDWord( YMFSB_DSPINSTRAM+i, DspInst[i>>2] );
-		}
-
 		/* setup Control instruction code */
 		for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
 			writeRegDWord( YMFSB_CTRLINSTRAM+i, CntrlInst[i>>2] );
@@ -518,11 +538,8 @@
 
 	case PCI_DEVICE_ID_YMF724F:
 	case PCI_DEVICE_ID_YMF740C:
-		/* setup DSP instruction code */
-		for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
-			writeRegDWord( YMFSB_DSPINSTRAM+i, DspInst[i>>2] );
-		}
-
+	case PCI_DEVICE_ID_YMF744:
+	case PCI_DEVICE_ID_YMF754:
 		/* setup Control instruction code */
 	
 		for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
@@ -530,19 +547,6 @@
 		}
 		break;
 
-	case PCI_DEVICE_ID_YMF744:
-	case PCI_DEVICE_ID_YMF754:
-		/* setup DSP instruction code */
-		for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
-			writeRegDWord( YMFSB_DSPINSTRAM+i, gdwDSPCode[i>>2] );
-		}
-
-		/* setup Control instruction code */
-
-		for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
-			writeRegDWord( YMFSB_CTRLINSTRAM+i, gdwCtrl1eCode[i>>2] );
-		}
-		break;
 	default:
 		return -1;
 	}
@@ -634,9 +638,6 @@
 
 static void __init ymf7xxsb_attach_sb(struct address_info *hw_config)
 {
-#ifdef SUPPORT_UART401_MIDI
-//	hw_config->driver_use_1 |= SB_NO_MIDI;
-#endif
 	if(!sb_dsp_init(hw_config))
 		hw_config->slots[0] = -1;
 }
@@ -649,7 +650,6 @@
 		       hw_config->io_base);
 		return 0;
 	}
-//	return sb_dsp_detect(hw_config, 0, 0);
 	return sb_dsp_detect(hw_config, SB_PCI_YAMAHA, 0);
 }
 
@@ -822,7 +822,7 @@
 	return;
 }
 
-int __init init_ymf7xxsb_module(void)
+static int __init init_ymf7xxsb_module(void)
 {
 	if ( master_vol < 0 ) master_vol  = 50;
 	if ( master_vol > 100 ) master_vol = 100;
diff -urN linux-2.2.16-pre7/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h
--- linux-2.2.16-pre7/include/linux/ac97_codec.h	Mon Dec  3 22:04:45 2001
+++ linux/include/linux/ac97_codec.h	Mon Dec  3 22:04:51 2001
@@ -32,7 +32,7 @@
 #define AC97_PCM_FRONT_DAC_RATE   0x002C       /* PCM Front DAC Rate */
 #define AC97_PCM_SURR_DAC_RATE    0x002E       /* PCM Surround DAC Rate */
 #define AC97_PCM_LFE_DAC_RATE     0x0030       /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_ADC_RATE      0x0032       /* PCM LR ADC Rate */
+#define AC97_PCM_LR_DAC_RATE      0x0032       /* PCM LR DAC Rate */
 #define AC97_PCM_MIC_ADC_RATE     0x0034       /* PCM MIC ADC Rate */
 #define AC97_CENTER_LFE_MASTER    0x0036       /* Center + LFE Master Volume */
 #define AC97_SURROUND_MASTER      0x0038       /* Surround (Rear) Master Volume */
@@ -133,7 +133,7 @@
 	SOUND_MASK_LINE1| SOUND_MASK_LINE|\
 	SOUND_MASK_PHONEIN)
 
-#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
+#define supported_mixer(CODEC,FOO) ((CODEC)->supported_mixers & (1<<FOO) )
 
 struct ac97_codec {
 	/* AC97 controller connected with */
diff -urN linux-2.2.16-pre7/include/linux/cdrom.h linux/include/linux/cdrom.h
--- linux-2.2.16-pre7/include/linux/cdrom.h	Mon Dec  3 22:04:45 2001
+++ linux/include/linux/cdrom.h	Mon Dec  3 22:04:51 2001
@@ -266,6 +266,15 @@
 
 #define CDROM_PACKET_SIZE	12
 
+/*
+ * These are for 2.3/4 only, but lets have them in 2.2 as well so that
+ * apps don't need to check for versions.
+ */
+#define CGC_DATA_UNKNOWN	0
+#define CGC_DATA_WRITE		1
+#define CGC_DATA_READ		2
+#define CGC_DATA_NONE		3
+
 /* for CDROM_PACKET_COMMAND ioctl */
 struct cdrom_generic_command
 {
@@ -274,6 +283,7 @@
 	unsigned int 		buflen;
 	int			stat;
 	struct request_sense	*sense;
+	unsigned char		data_direction;
 	void			*reserved[3];
 };
 
@@ -471,16 +481,11 @@
 /* This seems to be a SCSI specific CD-ROM opcode 
  * to play data at track/index */
 #define GPCMD_PLAYAUDIO_TI		    0x48
-
-/* Is this really used by anything?  I couldn't find these...*/
-#if 0
-/* MMC2/MTFuji Opcodes */
-#define ERASE			0x2c
-#define READ_BUFFER		0x3c
-#endif
-
-
-
+/*
+ * From MS Media Status Notification Support Specification. For
+ * older drives only.
+ */
+#define GPCMD_GET_MEDIA_STATUS		    0xda
 
 /* Mode page codes for mode sense/set */
 #define GPMODE_R_W_ERROR_PAGE		0x01
@@ -986,6 +991,22 @@
 	__u8 subhdr2;
 	__u8 subhdr3;
 } __attribute__((packed)) write_param_page;
+
+struct modesel_head
+{
+	__u8	reserved1;
+	__u8	medium;
+	__u8	reserved2;
+	__u8	block_desc_length;
+	__u8	density;
+	__u8	number_of_blocks_hi;
+	__u8	number_of_blocks_med;
+	__u8	number_of_blocks_lo;
+	__u8	reserved3;
+	__u8	block_length_hi;
+	__u8	block_length_med;
+	__u8	block_length_lo;
+};
 
 typedef struct {
 	__u16 report_key_length;
diff -urN linux-2.2.16-pre7/include/scsi/sg.h linux/include/scsi/sg.h
--- linux-2.2.16-pre7/include/scsi/sg.h	Mon Dec  3 22:04:45 2001
+++ linux/include/scsi/sg.h	Mon Dec  3 22:04:51 2001
@@ -11,10 +11,13 @@
 2.x extensions to driver:
 *       Copyright (C) 1998 - 2000 Douglas Gilbert
 
-    Version: 2.1.37 (20000504)
+    Version: 2.1.38 (20000527)
     This version for 2.2.x series kernels
     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
 
+    Changes since 2.1.37 (20000504)
+        - fine tune state machine to stop read() race
+        - switch to numeric device description (e.g. sg0 instead of sga)
     Changes since 2.1.36 (991008)
         - fix 0 length scatter gather requests + alignment
         - activate SG_SCSI_RESET ioctl() [to work needs mid level changes]
@@ -45,9 +48,9 @@
        2.1.32            2.2.8 and 2.2.9
        2.1.34            2.2.10 to 2.2.13
        2.1.36            2.2.14 and 2.2.15
-       2.1.37            2.2.16
-       3.0.13            optional version 3 sg driver for 2.2 series
-       3.1.13            2.3.99-pre5, version 3 sg driver for 2.3 series
+       2.1.38            2.2.16
+       3.0.15            optional version 3 sg driver for 2.2 series
+       3.1.15            late 2.3 series approaching 2.4
 
     New features and changes:
         - per file descriptor (fd) write-read sequencing
diff -urN linux-2.2.16-pre7/kernel/kmod.c linux/kernel/kmod.c
--- linux-2.2.16-pre7/kernel/kmod.c	Mon Dec  3 22:04:45 2001
+++ linux/kernel/kmod.c	Mon Dec  3 22:04:51 2001
@@ -44,6 +44,7 @@
 	dput(fs->pwd);
 	fs->root = dget(init_task.fs->root);
 	fs->pwd = dget(init_task.fs->pwd);
+	fs->umask = 0022;
 
 	unlock_kernel();
 }
diff -urN linux-2.2.16-pre7/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- linux-2.2.16-pre7/net/ipv4/ipconfig.c	Mon Dec  3 22:04:45 2001
+++ linux/net/ipv4/ipconfig.c	Mon Dec  3 22:04:51 2001
@@ -1158,7 +1158,9 @@
 	/*
 	 * Record which protocol was actually used.
 	 */
+#ifdef IPCONFIG_DYNAMIC
 	ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP);
+#endif
 
 #ifndef IPCONFIG_SILENT
 	/*
diff -urN linux-2.2.16-pre7/net/ipv4/proc.c linux/net/ipv4/proc.c
--- linux-2.2.16-pre7/net/ipv4/proc.c	Wed May  3 17:16:53 2000
+++ linux/net/ipv4/proc.c	Mon Dec  3 22:04:51 2001
@@ -134,7 +134,7 @@
 	if(timer_active == 0)
 		timer_expires = jiffies;
 	sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu",
 		i, src, srcp, dest, destp, sp->state, 
 		(tw_bucket ?
 		 0 :
diff -urN linux-2.2.16-pre7/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- linux-2.2.16-pre7/net/ipv4/tcp_output.c	Wed May  3 17:16:53 2000
+++ linux/net/ipv4/tcp_output.c	Mon Dec  3 22:04:51 2001
@@ -596,6 +596,7 @@
 	   (skb->len < (cur_mss >> 1)) &&
 	   (skb->next != tp->send_head) &&
 	   (skb->next != (struct sk_buff *)&sk->write_queue) &&
+	   (skb->next != tp->retrans_head) &&
 	   (sysctl_tcp_retrans_collapse != 0))
 		tcp_retrans_try_collapse(sk, skb, cur_mss);
 
