// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for SiS7019 Audio Accelerator
*
* Copyright (C) 2004-2007, David Dillow
* Written by David Dillow <dave@thedillows.org>
* Inspired by the Trident 4D-WaveDX/NX driver.
*
* All rights reserved.
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include "sis7019.h"
MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
MODULE_DESCRIPTION("SiS7019");
MODULE_LICENSE("GPL");
static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
static bool enable = 1;
static int codecs = 1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator.");
module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator.");
module_param(enable, bool, 0444);
MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator.");
module_param(codecs, int, 0444);
MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)");
static const struct pci_device_id snd_sis7019_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_sis7019_ids);
/* There are three timing modes for the voices.
*
* For both playback and capture, when the buffer is one or two periods long,
* we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt
* to let us know when the periods have ended.
*
* When performing playback with more than two periods per buffer, we set
* the "Stop Sample Offset" and tell the hardware to interrupt us when we
* reach it. We then update the offset and continue on until we are
* interrupted for the next period.
*
* Capture channels do not have a SSO, so we allocate a playback channel to
* use as a timer for the capture periods. We use the SSO on the playback
* channel to clock out virtual periods, and adjust the virtual period length
* to maintain synchronization. This algorithm came from the Trident driver.
*
* FIXME: It'd be nice to make use of some of the synth features in the
* hardware, but a woeful lack of documentation is a significant roadblock.
*/
struct voice {
u16 flags;
#define VOICE_IN_USE 1
#define VOICE_CAPTURE 2
#define VOICE_SSO_TIMING 4
#define VOICE_SYNC_TIMING 8
u16 sync_cso;
u16 period_size;
u16 buffer_size;
u16 sync_period_size;
u16 sync_buffer_size;
u32 sso;
u32 vperiod;
struct snd_pcm_substream *substream;
struct voice