patch-2.4.0-test2 linux/drivers/sound/via82cxxx_audio.c
Next file: linux/drivers/sound/wavfront.c
Previous file: linux/drivers/sound/trident.c
Back to the patch index
Back to the overall index
- Lines: 614
- Date:
Tue Jun 20 07:52:36 2000
- Orig file:
v2.4.0-test1/linux/drivers/sound/via82cxxx_audio.c
- Orig date:
Tue May 23 15:31:35 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
@@ -6,12 +6,16 @@
* See the "COPYING" file distributed with this software for more info.
*
* For a list of known bugs (errata) and documentation,
- * see via82cxxx.txt in linux/Documentation/sound.
+ * see via-audio.pdf in linux/Documentation/DocBook.
+ * If this documentation does not exist, run "make pdfdocs".
+ * If "make pdfdocs" fails, obtain the documentation from
+ * the driver's Website at
+ * http://gtf.org/garzik/drivers/via82cxxx/
*
*/
-#define VIA_VERSION "1.1.6"
+#define VIA_VERSION "1.1.8"
#include <linux/config.h>
@@ -304,7 +308,7 @@
static struct pci_device_id via_pci_tbl[] __initdata = {
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, }
};
MODULE_DEVICE_TABLE(pci,via_pci_tbl);
@@ -325,12 +329,40 @@
*
*/
+/**
+ * via_chan_stop - Terminate DMA on specified PCM channel
+ * @iobase: PCI base address for SGD channel registers
+ *
+ * Terminate scatter-gather DMA operation for given
+ * channel (derived from @iobase), if DMA is active.
+ *
+ * Note that @iobase is not the PCI base address,
+ * but the PCI base address plus an offset to
+ * one of three PCM channels supported by the chip.
+ *
+ */
+
static inline void via_chan_stop (int iobase)
{
if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE)
outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL);
}
+
+/**
+ * via_chan_status_clear - Clear status flags on specified DMA channel
+ * @iobase: PCI base address for SGD channel registers
+ *
+ * Clear any pending status flags for the given
+ * DMA channel (derived from @iobase), if any
+ * flags are asserted.
+ *
+ * Note that @iobase is not the PCI base address,
+ * but the PCI base address plus an offset to
+ * one of three PCM channels supported by the chip.
+ *
+ */
+
static inline void via_chan_status_clear (int iobase)
{
u8 tmp = inb (iobase + VIA_PCM_STATUS);
@@ -339,12 +371,33 @@
outb (tmp, iobase + VIA_PCM_STATUS);
}
+
+/**
+ * sg_begin - Begin recording or playback on a PCM channel
+ * @chan: Channel for which DMA operation shall begin
+ *
+ * Start scatter-gather DMA for the given channel.
+ *
+ */
+
static inline void sg_begin (struct via_channel *chan)
{
outb (VIA_SGD_START, chan->iobase + VIA_PCM_CONTROL);
}
+/**
+ * via_chan_bufs_in_use - Number of buffers waiting to be consumed
+ * @chan: Channel for which DMA buffers will be counted
+ *
+ * Count the number of buffers waiting to be consumed. For a
+ * playback operation, this is the number of buffers which have
+ * yet to be sent to the DAC. For a recording operation, this
+ * is the number of buffers waiting to be consumed by software
+ * calling read() system call.
+ *
+ */
+
static inline int via_chan_bufs_in_use (struct via_channel *chan)
{
return atomic_read(&chan->next_buf) -
@@ -352,12 +405,31 @@
}
+/**
+ * via_chan_full - Check for no-free-buffers condition
+ * @chan: Channel for which DMA full condition will be checked
+ *
+ * Count the number of buffers waiting to be consumed, and return
+ * true (non-zero) if no buffers are available to be filled on the
+ * given DMA channel.
+ *
+ */
+
static inline int via_chan_full (struct via_channel *chan)
{
return (via_chan_bufs_in_use (chan) == VIA_DMA_BUFFERS);
}
+/**
+ * via_chan_empty - Check for no-buffers-in-use condition
+ * @chan: Channel for which DMA empty condition will be checked
+ *
+ * Count the number of buffers waiting to be consumed, and return
+ * true (non-zero) if no buffers are currently in use.
+ *
+ */
+
static inline int via_chan_empty (struct via_channel *chan)
{
return (atomic_read(&chan->next_buf) ==
@@ -372,6 +444,15 @@
*
*/
+
+/**
+ * via_stop_everything - Stop all audio operations
+ * @card: Private info for specified board
+ *
+ * Stops all DMA operations and interrupts, and clear
+ * any pending status bits resulting from those operations.
+ */
+
static void via_stop_everything (struct via_info *card)
{
DPRINTK ("ENTER\n");
@@ -402,6 +483,24 @@
}
+/**
+ * via_set_rate - Set PCM rate for given channel
+ * @card: Private info for specified board
+ * @rate: Desired PCM sample rate, in Khz
+ * @inhale_deeply: Boolean. If non-zero (true), the recording sample rate
+ * is set. If zero (false), the playback sample rate
+ * is set.
+ *
+ * Sets the PCM sample rate for a channel.
+ *
+ * Values for @rate are clamped to a range of 4000 Khz through 48000 Khz,
+ * due to hardware constraints.
+ *
+ * FIXME: @inhale_deeply argument is ignored, and %AC97_PCM_FRONT_DAC_RATE
+ * is the only rate which is really set. This needs to be fixed when
+ * recording support is added.
+ */
+
static int via_set_rate (struct via_info *card, unsigned rate, int inhale_deeply)
{
@@ -423,12 +522,32 @@
}
+/**
+ * via_set_adc_rate - Set PCM rate for recording channel
+ * @card: Private info for specified board
+ * @rate: Desired PCM sample rate, in Khz
+ *
+ * Sets the PCM sample rate for a recording channel.
+ *
+ * FIXME: @inhale_deeply argument to via_set_rate is ignored, and %AC97_PCM_FRONT_DAC_RATE
+ * is the only rate which is really set. Thus, this function will
+ * not work until via_set_rate is fixed.
+ */
+
static inline int via_set_adc_rate (struct via_info *card, int rate)
{
return via_set_rate (card, rate, 1);
}
+/**
+ * via_set_dac_rate - Set PCM rate for playback channel
+ * @card: Private info for specified board
+ * @rate: Desired PCM sample rate, in Khz
+ *
+ * Sets the PCM sample rate for a playback channel.
+ */
+
static inline int via_set_dac_rate (struct via_info *card, int rate)
{
return via_set_rate (card, rate, 0);
@@ -442,6 +561,27 @@
*
*/
+/**
+ * via_chan_init - Initialize PCM channel
+ * @card: Private audio chip info
+ * @chan: Channel to be initialized
+ * @chan_ofs: Offset from PCI address, which determines the
+ * set of SGD registers to use.
+ *
+ * Performs all the preparations necessary to begin
+ * using a PCM channel.
+ *
+ * Currently the preparations include allocating the
+ * scatter-gather DMA table and buffers, setting the
+ * PCM channel to a known state, and passing the
+ * address of the DMA table to the hardware.
+ *
+ * Note that special care is taken when passing the
+ * DMA table address to hardware, because it was found
+ * during driver development that the hardware did not
+ * always "take" the address.
+ */
+
static int via_chan_init (struct via_info *card,
struct via_channel *chan, long chan_ofs)
{
@@ -533,6 +673,20 @@
}
+/**
+ * via_chan_free - Release a PCM channel
+ * @card: Private audio chip info
+ * @chan: Channel to be released
+ *
+ * Performs all the functions necessary to clean up
+ * an initialized channel.
+ *
+ * Currently these functions include disabled any
+ * active DMA operations, setting the PCM channel
+ * back to a known state, and releasing any allocated
+ * sound buffers.
+ */
+
static void via_chan_free (struct via_info *card, struct via_channel *chan)
{
int i;
@@ -575,6 +729,22 @@
}
+/**
+ * via_chan_pcm_fmt - Update PCM channel settings
+ * @card: Private audio chip info
+ * @chan: Channel to be updated
+ * @reset: Boolean. If non-zero, channel will be reset
+ * to 8-bit mono mode.
+ *
+ * Stores the settings of the current PCM format,
+ * 8-bit or 16-bit, and mono/stereo, into the
+ * hardware settings for the specified channel.
+ * If @reset is non-zero, the channel is reset
+ * to 8-bit mono mode. Otherwise, the channel
+ * is set to the values stored in the channel
+ * information struct @chan.
+ */
+
static void via_chan_pcm_fmt (struct via_info *card,
struct via_channel *chan, int reset)
{
@@ -603,6 +773,14 @@
}
+/**
+ * via_chan_clear - Stop DMA channel operation, and reset pointers
+ * @chan: Channel to be cleared
+ *
+ * Call via_chan_stop to halt DMA operations, and then resets
+ * all software pointers which track DMA operation.
+ */
+
static void via_chan_clear (struct via_channel *chan)
{
via_chan_stop (chan->iobase);
@@ -612,6 +790,21 @@
}
+/**
+ * via_chan_set_speed - Set PCM sample rate for given channel
+ * @card: Private info for specified board
+ * @chan: Channel whose sample rate will be adjusted
+ * @val: New sample rate, in Khz
+ *
+ * Helper function for the %SNDCTL_DSP_SPEED ioctl. OSS semantics
+ * demand that all audio operations halt (if they are not already
+ * halted) when the %SNDCTL_DSP_SPEED is given.
+ *
+ * This function halts all audio operations for the given channel
+ * @chan, and then calls via_set_rate to set the audio hardware
+ * to the new rate.
+ */
+
static int via_chan_set_speed (struct via_info *card,
struct via_channel *chan, int val)
{
@@ -626,6 +819,21 @@
}
+/**
+ * via_chan_set_fmt - Set PCM sample size for given channel
+ * @card: Private info for specified board
+ * @chan: Channel whose sample size will be adjusted
+ * @val: New sample size, use the %AFMT_xxx constants
+ *
+ * Helper function for the %SNDCTL_DSP_SETFMT ioctl. OSS semantics
+ * demand that all audio operations halt (if they are not already
+ * halted) when the %SNDCTL_DSP_SETFMT is given.
+ *
+ * This function halts all audio operations for the given channel
+ * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
+ * to the new sample size, either 8-bit or 16-bit.
+ */
+
static int via_chan_set_fmt (struct via_info *card,
struct via_channel *chan, int val)
{
@@ -656,6 +864,21 @@
}
+/**
+ * via_chan_set_stereo - Enable or disable stereo for a DMA channel
+ * @card: Private info for specified board
+ * @chan: Channel whose stereo setting will be adjusted
+ * @val: New sample size, use the %AFMT_xxx constants
+ *
+ * Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls. OSS semantics
+ * demand that all audio operations halt (if they are not already
+ * halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given.
+ *
+ * This function halts all audio operations for the given channel
+ * @chan, and then calls via_chan_pcm_fmt to set the audio hardware
+ * to enable or disable stereo.
+ */
+
static int via_chan_set_stereo (struct via_info *card,
struct via_channel *chan, int val)
{
@@ -690,6 +913,14 @@
#if 0
+/**
+ * via_chan_dump_bufs - Display DMA table contents
+ * @chan: Channel whose DMA table will be displayed
+ *
+ * Debugging function which displays the contents of the
+ * scatter-gather DMA table for the given channel @chan.
+ */
+
static void via_chan_dump_bufs (struct via_channel *chan)
{
int i;
@@ -715,6 +946,15 @@
*
*/
+/**
+ * via_ac97_wait_idle - Wait until AC97 codec is not busy
+ * @card: Private info for specified board
+ *
+ * Sleep until the AC97 codec is no longer busy.
+ * Returns the final value read from the SGD
+ * register being polled.
+ */
+
static u8 via_ac97_wait_idle (struct via_info *card)
{
u8 tmp8;
@@ -740,6 +980,21 @@
}
+/**
+ * via_ac97_read_reg - Read AC97 standard register
+ * @codec: Pointer to generic AC97 codec info
+ * @reg: Index of AC97 register to be read
+ *
+ * Read the value of a single AC97 codec register,
+ * as defined by the Intel AC97 specification.
+ *
+ * Defines the standard AC97 read-register operation
+ * required by the kernel's ac97_codec interface.
+ *
+ * Returns the 16-bit value stored in the specified
+ * register.
+ */
+
static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg)
{
u32 data;
@@ -788,6 +1043,19 @@
}
+/**
+ * via_ac97_write_reg - Write AC97 standard register
+ * @codec: Pointer to generic AC97 codec info
+ * @reg: Index of AC97 register to be written
+ * @value: Value to be written to AC97 register
+ *
+ * Write the value of a single AC97 codec register,
+ * as defined by the Intel AC97 specification.
+ *
+ * Defines the standard AC97 write-register operation
+ * required by the kernel's ac97_codec interface.
+ */
+
static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value)
{
u32 data;
@@ -829,8 +1097,6 @@
DPRINTK ("ENTER\n");
- MOD_INC_USE_COUNT;
-
pci_for_each_dev(pdev) {
drvr = pci_dev_driver (pdev);
if (drvr == &via_driver) {
@@ -843,7 +1109,6 @@
}
DPRINTK ("EXIT, returning -ENODEV\n");
- MOD_DEC_USE_COUNT;
return -ENODEV;
match:
@@ -853,18 +1118,6 @@
return 0;
}
-
-static int via_mixer_release (struct inode *inode, struct file *file)
-{
- DPRINTK ("ENTER\n");
-
- MOD_DEC_USE_COUNT;
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -889,8 +1142,8 @@
static struct file_operations via_mixer_fops = {
+ owner: THIS_MODULE,
open: via_mixer_open,
- release: via_mixer_release,
llseek: via_llseek,
ioctl: via_mixer_ioctl,
};
@@ -971,9 +1224,11 @@
VIA_CR41_VRA | VIA_CR41_AC97_RESET);
udelay (100);
+#if 0 /* this breaks on K7M */
/* disable legacy stuff */
pci_write_config_byte (pdev, 0x42, 0x00);
udelay(10);
+#endif
/* route FM trap to IRQ, disable FM trap */
pci_write_config_byte (pdev, 0x48, 0x05);
@@ -1097,50 +1352,36 @@
struct via_info *card = dev_id;
struct via_channel *chan;
u8 status;
- int unhandled = 1;
- static long intcount = 0;
- assert (irq == card->pdev->irq);
-
- intcount++;
-
status = inb (card->baseaddr + 0x00);
if (status) {
assert (card->open_mode & FMODE_WRITE);
chan = &card->ch_out;
- unhandled = 0;
if (status & VIA_SGD_FLAG) {
assert ((status & VIA_SGD_EOL) == 0);
outb (VIA_SGD_FLAG, chan->iobase + 0x00);
- DPRINTK("FLAG intr, status=0x%02X, intcount=%ld\n",
- status, intcount);
+ DPRINTK("FLAG intr, status=0x%02X\n", status);
via_interrupt_write (chan);
}
if (status & VIA_SGD_EOL) {
assert ((status & VIA_SGD_FLAG) == 0);
outb (VIA_SGD_EOL, chan->iobase + 0x00);
- DPRINTK("EOL intr, status=0x%02X, intcount=%ld\n",
- status, intcount);
+ DPRINTK("EOL intr, status=0x%02X\n", status);
via_interrupt_write (chan);
}
if (status & VIA_SGD_STOPPED) {
outb (VIA_SGD_STOPPED, chan->iobase + 0x00);
- DPRINTK("STOPPED intr, status=0x%02X, intcount=%ld\n",
- status, intcount);
+ DPRINTK("STOPPED intr, status=0x%02X\n", status);
}
#if 0
via_chan_dump_bufs (&card->ch_out);
#endif
}
-
- if (unhandled)
- printk (KERN_WARNING PFX "unhandled interrupt, st=%02x, st32=%08x\n",
- status, inl (card->baseaddr + 0x84));
}
@@ -1229,6 +1470,7 @@
*/
static struct file_operations via_dsp_fops = {
+ owner: THIS_MODULE,
open: via_dsp_open,
release: via_dsp_release,
read: via_dsp_read,
@@ -1860,8 +2102,6 @@
DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode);
- MOD_INC_USE_COUNT;
-
if (file->f_mode & FMODE_READ) /* no input ATM */
goto err_out;
@@ -1951,7 +2191,6 @@
card->open_mode &= ~file->f_mode;
spin_unlock_irqrestore (&card->lock, flags);
err_out:
- MOD_DEC_USE_COUNT;
DPRINTK("ERROR EXIT, returning %d\n", rc);
return rc;
}
@@ -1981,7 +2220,6 @@
spin_unlock_irqrestore (&card->lock, flags);
wake_up (&card->open_wait);
- MOD_DEC_USE_COUNT;
DPRINTK("EXIT, returning 0\n");
return 0;
@@ -2331,6 +2569,7 @@
via_interrupt_cleanup (card);
via_card_cleanup_proc (card);
via_dsp_cleanup (card);
+ via_ac97_cleanup (card);
release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0));
@@ -2360,12 +2599,9 @@
int rc;
DPRINTK ("ENTER\n");
-
- MOD_INC_USE_COUNT;
rc = via_init_proc ();
if (rc) {
- MOD_DEC_USE_COUNT;
DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
@@ -2375,12 +2611,9 @@
if (rc == 0)
pci_unregister_driver (&via_driver);
via_cleanup_proc ();
- MOD_DEC_USE_COUNT;
DPRINTK ("EXIT, returning -ENODEV\n");
return -ENODEV;
}
-
- MOD_DEC_USE_COUNT;
DPRINTK ("EXIT, returning 0\n");
return 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)