patch-2.4.23 linux-2.4.23/drivers/sound/ali5455.c

Next file: linux-2.4.23/drivers/sound/cmpci.c
Previous file: linux-2.4.23/drivers/sound/ad1889.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/sound/ali5455.c linux-2.4.23/drivers/sound/ali5455.c
@@ -1,5 +1,5 @@
 /*
- *	ALI  ali5455 and friends ICH driver for Linux
+ *	Driver for ALI 5455  Audio PCI soundcard
  *	LEI HU <Lei_Hu@ali.com.tw>
  *
  *  Built from:
@@ -23,10 +23,7 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *
- *	ALi 5455 theory of operation
- *
- *	The chipset provides three DMA channels that talk to an AC97
+ *	The chipset provides five DMA channels that talk to an AC97
  *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
  *	you get 48Khz audio with basic volume and mixer controls. At the
  *	best you get rate adaption in the codec. We set the card up so
@@ -42,6 +39,13 @@
  *	esd working you need to use esd -r 48000 as it won't probe 48KHz
  *	by default. mpg123 can't handle 48Khz only audio so use xmms.
  *
+ *
+ *	Not everyone uses 48KHz. We know of no way to detect this reliably
+ *	and certainly not to get the right data. If your ali audio sounds
+ *	stupid you may need to investigate other speeds. According to Analog
+ *	they tend to use a 14.318MHz clock which gives you a base rate of
+ *	41194Hz.
+ *
  *	If you need to force a specific rate set the clocking= option
  *
  */
@@ -78,31 +82,45 @@
 
 static int strict_clocking = 0;
 static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
+#ifdef CONFIG_SOUND_ALI5455_CODECSPDIFOUT_PCMOUTSHARE
+static unsigned int codec_pcmout_share_spdif_locked = 48000;
+#else
+ static unsigned int codec_pcmout_share_spdif_locked = 0;
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CODECSPDIFOUT_CODECINDEPENDENTDMA
+static unsigned int codec_independent_spdif_locked = 48000;
+#else
+static unsigned int codec_independent_spdif_locked = 0;   
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_PCMOUTSHARE
+static unsigned int controller_pcmout_share_spdif_locked = 48000;
+#else
 static unsigned int controller_pcmout_share_spdif_locked = 0;
+#endif
+#ifdef CONFIG_SOUND_ALI5455_CONTROLLERSPDIFOUT_CONTROLLERINDEPENDENTDMA
+static unsigned int controller_independent_spdif_locked = 48000;
+#else
 static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING	1
-#define DAC_RUNNING	2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT	1
-#define ALI5455_FMT_STEREO	2
-#define ALI5455_FMT_MASK	3
+#endif
 
-#define SPDIF_ON	0x0004
-#define SURR_ON		0x0010
-#define CENTER_LFE_ON	0x0020
-#define VOL_MUTED	0x8000
+#define ADC_RUNNING			1
+#define DAC_RUNNING			2
+#define CONTROLLER_SPDIFOUT_RUNNING 	4
+#define CODEC_SPDIFOUT_RUNNING		8
+
+#define ALI5455_FMT_16BIT		1
+#define ALI5455_FMT_STEREO		2
+#define ALI5455_FMT_MASK		3
+
+#define SPDIF_ON			0x0004
+#define SURR_ON				0x0010
+#define CENTER_LFE_ON			0x0020
+#define VOL_MUTED			0x8000
 
+#define SPDIF_ENABLE_OUTPUT 		0x00000004
 
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* the 810's array of pointers to data buffers */
+#define ALI_SPDIF_OUT_CH_STATUS		0xbf
+/* the ali5455 's array of pointers to data buffers */
 
 struct sg_item {
 #define BUSADDR_MASK	0xFFFFFFFE
@@ -113,20 +131,21 @@
 	u32 control;
 };
 
-/* an instance of the ali channel */
+/* An instance of the ali 5455 channel */
 #define SG_LEN 32
 struct ali_channel {
 	/* these sg guys should probably be allocated
 	   seperately as nocache. Must be 8 byte aligned */
 	struct sg_item sg[SG_LEN];	/* 32*8 */
-	u32 offset;		/* 4 */
-	u32 port;		/* 4 */
+	u32 offset;			/* 4 */
+	u32 port;			/* 4 */
 	u32 used;
 	u32 num;
 };
 
 /*
- * we have 3 seperate dma engines.  pcm in, pcm out, and mic.
+ * we have 5 seperate dma engines.  pcm in, pcm out, mc in, 
+ * codec independant DMA, and controller independant DMA
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
@@ -142,11 +161,11 @@
 	PRE##_CR =	0x##DIG##b		/* Control Register */				\
 }
 
-ENUM_ENGINE(OFF, 0);		/* Offsets */
-ENUM_ENGINE(PI, 4);		/* PCM In */
-ENUM_ENGINE(PO, 5);		/* PCM Out */
-ENUM_ENGINE(MC, 6);		/* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */
+ENUM_ENGINE(OFF, 0);			/* Offsets */
+ENUM_ENGINE(PI, 4);			/* PCM In */
+ENUM_ENGINE(PO, 5);			/* PCM Out */
+ENUM_ENGINE(MC, 6);			/* Mic In */
+ENUM_ENGINE(CODECSPDIFOUT, 7);		/* CODEC SPDIF OUT  */
 ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */
 ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */
 
@@ -171,7 +190,7 @@
 	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
 };
 
-// x-status register(x:pcm in ,pcm out, mic in,)
+/* x-status register(x:pcm in ,pcm out, mic in,codec independent DMA.controller independent DMA) */
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)	/* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)	/* buffer read/write complete and ioc set */
@@ -180,8 +199,7 @@
 #define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */	//not eqult intel
 #define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
 
-/* interrupts for the whole chip */// by interrupt status register finish
-
+/* interrupts for the whole chip */ 
 #define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */
 #define INT_SPDIFIN   (1<<22)
 #define INT_CODECSPDIFOUT   (1<<19)
@@ -193,13 +211,14 @@
 #define INT_GPIO    (1<<1)
 #define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
 
-#define DRIVER_VERSION "0.02ac"
+#define DRIVER_VERSION "0.03-ac"
 
 /* magic numbers to protect our data structures */
 #define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */
 #define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */
 #define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH			5	//I think 5 channel
+
+#define NR_HW_CH			5		/* I think 5 channel */
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
 #define NR_AC97		2
@@ -216,7 +235,7 @@
 	"ALI 5455"
 };
 
-static struct pci_device_id ali_pci_tbl[] __initdata = {
+static struct pci_device_id ali_pci_tbl[] __devinitdata = {
 	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
 	{0,}
@@ -267,12 +286,12 @@
 		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 consumed or been generated by dma machine */
+		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 consumed or been generated by dma machine */
 		unsigned total_bytes;	/* total bytes dmaed by hardware */
 
-		unsigned error;	/* number of over/underruns */
+		unsigned error;		/* number of over/underruns */
 		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
 
 		/* redundant, but makes calculations easier */
@@ -399,7 +418,11 @@
 }
 
 
-//add support  codec spdif out 
+/*
+ *	we use ALC650 which only support  48k sample rate, so we test firstly
+ *	spdifout 's sample rate validity 
+ */
+ 
 static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
 {
 	unsigned long id = 0L;
@@ -428,16 +451,13 @@
 
 /* ali_set_spdif_output
  * 
- *  Configure the S/PDIF output transmitter. When we turn on
- *  S/PDIF, we turn off the analog output. This may not be
- *  the right thing to do.
+ *  Configure the S/PDIF output transmitter.
  *
  *  Assumptions:
  *     The DSP sample rate must already be set to a supported
  *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
  */
-static void ali_set_spdif_output(struct ali_state *state, int slots,
-				 int rate)
+static void ali_set_spdif_output(struct ali_state *state, int slots, int rate)
 {
 	int vol;
 	int aud_reg;
@@ -453,8 +473,7 @@
 			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */
 			if (!(state->card->ac97_status & VOL_MUTED)) {
 				aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
-					     (aud_reg & ~VOL_MUTED));
+				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED));
 			}
 			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
 			return;
@@ -486,7 +505,7 @@
 		ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
 
 		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
+		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF; /* ALC650 don't support VRA */
 		ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
 
 		aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
@@ -508,8 +527,6 @@
 			aud_reg = ali_ac97_get(codec, 0x6a);
 			ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
 		}
-		/* Mute the analog output */
-		/* Should this only mute the PCM volume??? */
 	}
 }
 
@@ -517,13 +534,6 @@
  *
  *  Configure the codec's multi-channel DACs
  *
- *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
- *
- *  What about the ICH? We currently configure it using the
- *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
- *  does that imply that we want the ICH set to support
- *  these channels?
- *  
  *  TODO:
  *    vailidate that the codec really supports these DACs
  *    before turning them on. 
@@ -556,8 +566,7 @@
 }
 
 /* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_state *state,
-				     unsigned int rate)
+static unsigned int ali_set_dac_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 new_rate;
@@ -594,8 +603,7 @@
 }
 
 /* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_state *state,
-				     unsigned int rate)
+static unsigned int ali_set_adc_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	u32 new_rate;
@@ -632,11 +640,10 @@
 }
 
 /* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
-					       unsigned int rate)
+static unsigned int ali_set_codecspdifout_rate(struct ali_state *state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-
+	
 	if (!(state->card->ac97_features & 0x0001)) {
 		dmabuf->rate = clocking;
 		return clocking;
@@ -652,8 +659,7 @@
 }
 
 /* set  controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
-				  unsigned int rate)
+static void ali_set_spdifout_rate(struct ali_state *state, unsigned int rate)
 {
 	unsigned char ch_st_sel;
 	unsigned short status_rate;
@@ -729,7 +735,9 @@
 	data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
 	if (inw(port_picb) == 0)
 		data -= 2048;
-
+	/* It is  hardware  bug  when read port 's PICB ==0 */
+	if ( inw(port_picb) == 0 )
+		data -= 2048;  
 	return data;
 }
 
@@ -745,6 +753,8 @@
 	udelay(1);
 
 	outb(0, card->iobase + PI_CR);
+ 
+	// wait for the card to acknowledge shutdown
 	while (inb(card->iobase + PI_CR) != 0);
 
 	// now clear any latent interrupt bits (like the halt bit)
@@ -771,10 +781,8 @@
 		outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
 		if (state->card->channel[0].used == 1)
 			outl(1, state->card->iobase + ALI_DMACR);	// DMA CONTROL REGISTRER
-		udelay(100);
 		if (state->card->channel[2].used == 1)
 			outl((1 << 2), state->card->iobase + ALI_DMACR);	//DMA CONTROL REGISTER
-		udelay(100);
 	}
 }
 
@@ -965,7 +973,7 @@
 static int prog_dmabuf(struct ali_state *state, unsigned rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_channel *c = NULL;
+	struct ali_channel *c = NULL ;
 	struct sg_item *sg;
 	unsigned long flags;
 	int ret;
@@ -1248,9 +1256,7 @@
 	}
 }
 
-static inline int ali_get_free_write_space(struct
-					   ali_state
-					   *state)
+static inline int ali_get_free_write_space(struct ali_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int free;
@@ -1267,9 +1273,7 @@
 	return (free);
 }
 
-static inline int ali_get_available_read_data(struct
-					      ali_state
-					      *state)
+static inline int ali_get_available_read_data(struct ali_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int avail;
@@ -1288,12 +1292,12 @@
 
 static int drain_dac(struct ali_state *state, int signals_allowed)
 {
-
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
 	unsigned long tmo;
 	int count;
+
 	if (!dmabuf->ready)
 		return 0;
 	if (dmabuf->mapped) {
@@ -1302,11 +1306,11 @@
 	}
 	add_wait_queue(&dmabuf->wait, &wait);
 	for (;;) {
-
 		spin_lock_irqsave(&state->card->lock, flags);
 		ali_update_ptr(state);
 		count = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+
 		if (count <= 0)
 			break;
 		/* 
@@ -1355,7 +1359,6 @@
 
 static int drain_spdifout(struct ali_state *state, int signals_allowed)
 {
-
 	DECLARE_WAITQUEUE(wait, current);
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned long flags;
@@ -1548,7 +1551,6 @@
 {
 	struct ali_card *card = (struct ali_card *) dev_id;
 	u32 status;
-	u16 status2;
 
 	spin_lock(&card->lock);
 	status = inl(card->iobase + ALI_INTERRUPTSR);
@@ -1557,19 +1559,8 @@
 		return;		/* not for us */
 	}
 
-	if (codec_independent_spdif_locked > 0) {
-		if (globel == 0) {
-			globel += 1;
-			status2 = inw(card->iobase + 0x76);
-			outw(status2 | 0x000c, card->iobase + 0x76);
-		} else {
-			if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-				ali_channel_interrupt(card);
-		}
-	} else {
-		if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-			ali_channel_interrupt(card);
-	}
+	if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
+		ali_channel_interrupt(card);
 
 	/* clear 'em */
 	outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
@@ -1580,8 +1571,7 @@
    waiting to be copied to the user's buffer.  It is filled by the dma
    machine and drained by this loop. */
 
-static ssize_t ali_read(struct file *file, char *buffer,
-			size_t count, loff_t * ppos)
+static ssize_t ali_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct ali_card *card = state ? state->card : 0;
@@ -1721,8 +1711,7 @@
 
 /* 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 ali_write(struct file *file,
-			 const char *buffer, size_t count, loff_t * ppos)
+static ssize_t ali_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct ali_card *card = state ? state->card : 0;
@@ -1908,8 +1897,7 @@
 }
 
 /* No kernel lock - we have our own spinlock */
-static unsigned int ali_poll(struct file *file, struct poll_table_struct
-			     *wait)
+static unsigned int ali_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct ali_state *state = (struct ali_state *) file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
@@ -2014,8 +2002,7 @@
 		}
 		if (c != NULL) {
 			outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]),
-			     state->card->iobase + c->port + OFF_BDBAR);
+			outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
 			outb(0, state->card->iobase + c->port + OFF_CIV);
 			outb(0, state->card->iobase + c->port + OFF_LVI);
 		}
@@ -2990,7 +2977,6 @@
 {
 	struct ali_card *card = dev->private_data;
 	int count1 = 100;
-	unsigned long flags;
 	char val;
 	unsigned short int count;
 
@@ -3660,12 +3646,17 @@
 MODULE_PARM(codec_independent_spdif_locked, "i");
 MODULE_PARM(controller_pcmout_share_spdif_locked, "i");
 MODULE_PARM(controller_independent_spdif_locked, "i");
+
 #define ALI5455_MODULE_NAME "ali5455"
+
 static struct pci_driver ali_pci_driver = {
-	name:ALI5455_MODULE_NAME, id_table:ali_pci_tbl, probe:ali_probe,
-	    remove:__devexit_p(ali_remove),
+	name:			ALI5455_MODULE_NAME, 
+	id_table:		ali_pci_tbl, 
+	probe:			ali_probe,
+	remove:			__devexit_p(ali_remove),
 #ifdef CONFIG_PM
-	suspend:ali_pm_suspend, resume:ali_pm_resume,
+	suspend:		ali_pm_suspend, 
+	resume:			ali_pm_resume,
 #endif				/* CONFIG_PM */
 };
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)