patch-2.3.99-pre2 linux/drivers/sound/trident.c
Next file: linux/drivers/sound/trident.h
Previous file: linux/drivers/sound/sb_common.c
Back to the patch index
Back to the overall index
- Lines: 368
- Date:
Thu Mar 16 11:18:35 2000
- Orig file:
v2.3.99-pre1/linux/drivers/sound/trident.c
- Orig date:
Tue Mar 7 14:32:26 2000
diff -u --recursive --new-file v2.3.99-pre1/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
@@ -29,6 +29,10 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* History
+ * 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
@@ -62,14 +66,14 @@
*
* 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 partially, need channel binding to test)
+ * 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
- * new pci device driver interface for 2.4 kernel
+ * "Channel Binding" ioctl extension (done)
+ * new pci device driver interface for 2.4 kernel (done)
*/
-
+
#include <linux/module.h>
#include <linux/version.h>
#include <linux/string.h>
@@ -92,7 +96,7 @@
#include "trident.h"
-#define DRIVER_VERSION "0.13"
+#define DRIVER_VERSION "0.14"
/* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
@@ -107,8 +111,14 @@
#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 };
@@ -126,7 +136,7 @@
"SiS 7018 PCI Audio"
};
-static struct pci_device_id trident_pci_tbl [] __devinitdata = {
+static struct pci_device_id trident_pci_tbl [] __initdata = {
{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, TRIDENT_4D_DX},
{PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX,
@@ -256,6 +266,19 @@
u32 irq;
};
+/* table to map from CHANNELMASK to channel attribute for SiS 7018 */
+static u16 mask2attr [] =
+{
+ PCM_LR, PCM_LR, SURR_LR, CENTER_LFE,
+ HSET, MIC, MODEM_LINE1, MODEM_LINE2,
+ I2S_LR, SPDIF_LR
+};
+/* table to map from channel attribute to CHANNELMASK for SiS 7018 */
+static int attr2mask [] = {
+ DSP_BIND_MODEM1, DSP_BIND_MODEM2, DSP_BIND_FRONT, DSP_BIND_HANDSET,
+ DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF
+};
+
static struct trident_card *devs = NULL;
static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
@@ -596,11 +619,7 @@
channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
channel->eso -= 1;
- if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
- /* FIXME: channel attributes are configured by ioctls, but it is not
- implemented so just set to ZERO for the moment */
- channel->attribute = 0;
- } else {
+ if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
channel->attribute = 0;
}
@@ -660,12 +679,7 @@
channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
channel->eso -= 1;
- if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
- /* FIXME: channel attributes are configured by ioctls, but it is not
- implemented so just set to 0x8a80 for the moment, record from PCM L/R
- input and mono = (left + right + 1)/2*/
- channel->attribute = 0x8A80;
- } else {
+ if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
channel->attribute = 0;
}
@@ -1577,7 +1591,8 @@
return 0;
case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP, (int *)arg);
+ return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,
+ (int *)arg);
case SNDCTL_DSP_GETTRIGGER:
val = 0;
@@ -1656,6 +1671,28 @@
return put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?
AFMT_S16_LE : AFMT_U8, (int *)arg);
+ case SNDCTL_DSP_GETCHANNELMASK:
+ return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE,
+ (int *)arg);
+
+ case SNDCTL_DSP_BIND_CHANNEL:
+ if (state->card->pci_id != PCI_DEVICE_ID_SI_7018)
+ return -EINVAL;
+
+ get_user_ret(val, (int *)arg, -EFAULT);
+ if (val == DSP_BIND_QUERY) {
+ val = dmabuf->channel->attribute | 0x3c00;
+ val = attr2mask[val >> 8];
+ } else {
+ dmabuf->ready = 0;
+ if (file->f_mode & FMODE_READ)
+ dmabuf->channel->attribute = (CHANNEL_REC|SRC_ENABLE);
+ if (file->f_mode & FMODE_WRITE)
+ dmabuf->channel->attribute = (CHANNEL_SPC_PB|SRC_ENABLE);
+ dmabuf->channel->attribute |= mask2attr[ffs(val)];
+ }
+ return put_user(val, (int *)arg);
+
case SNDCTL_DSP_MAPINBUF:
case SNDCTL_DSP_MAPOUTBUF:
case SNDCTL_DSP_SETSYNCRO:
@@ -1673,6 +1710,7 @@
int minor = MINOR(inode->i_rdev);
struct trident_card *card = devs;
struct trident_state *state = NULL;
+ struct dmabuf *dmabuf = NULL;
/* find an avaiable virtual channel (instance of /dev/dsp) */
while (card != NULL) {
@@ -1683,6 +1721,7 @@
if (state == NULL)
return -ENOMEM;
memset(state, 0, sizeof(struct trident_state));
+ dmabuf = &state->dmabuf;
goto found_virt;
}
}
@@ -1694,7 +1733,7 @@
found_virt:
/* found a free virtual channel, allocate hardware channels */
- if ((state->dmabuf.channel = trident_alloc_pcm_channel(card)) == NULL) {
+ if ((dmabuf->channel = trident_alloc_pcm_channel(card)) == NULL) {
kfree (card->states[i]);
card->states[i] = NULL;;
return -ENODEV;
@@ -1704,7 +1743,7 @@
state->virt = i;
state->card = card;
state->magic = TRIDENT_STATE_MAGIC;
- init_waitqueue_head(&state->dmabuf.wait);
+ init_waitqueue_head(&dmabuf->wait);
init_MUTEX(&state->open_sem);
file->private_data = state;
@@ -1714,24 +1753,34 @@
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) {
- state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
- if ((minor & 0xf) == SND_DEV_DSP16)
- state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
- state->dmabuf.ossfragshift = 0;
- state->dmabuf.ossmaxfrags = 0;
- state->dmabuf.subdivision = 0;
+ 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) {
/* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample,
to be dealed with in trident_set_adc_rate() ?? */
- state->dmabuf.fmt &= ~TRIDENT_FMT_MASK;
- if ((minor & 0xf) == SND_DEV_DSP16)
- state->dmabuf.fmt |= TRIDENT_FMT_16BIT;
- state->dmabuf.ossfragshift = 0;
- state->dmabuf.ossmaxfrags = 0;
- state->dmabuf.subdivision = 0;
+ 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);
}
@@ -1860,7 +1909,7 @@
address = SI_AC97_READ;
mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
if (codec->id)
- mask |= SI_AC97_SECONDARY;
+ mask |= SI_AC97_SECONDARY;
busy = SI_AC97_BUSY_READ;
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
@@ -1873,7 +1922,7 @@
else
address = NX_ACR2_AC97_R_PRIMARY;
mask = NX_AC97_BUSY_READ;
- busy = 0x0c00;
+ busy = NX_AC97_BUSY_READ | NX_AC97_BUSY_DATA;
break;
}
@@ -1953,9 +2002,13 @@
case PCI_DEVICE_ID_SI_7018:
/* disable AC97 GPIO interrupt */
outl(0x00, TRID_REG(card, SI_AC97_GPIO));
- /* stop AC97 cold reset process */
- outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL));
- ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
+ /* 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:
@@ -1972,7 +2025,7 @@
for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
- return -1;
+ return -ENOMEM;
memset(codec, 0, sizeof(struct ac97_codec));
/* initialize some basic codec information, other fields will be filled
@@ -2004,7 +2057,7 @@
/* 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 __devinit trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
unsigned long iobase;
struct trident_card *card;
@@ -2012,19 +2065,19 @@
if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) {
printk(KERN_ERR "trident: architecture does not support"
" 30bit PCI busmaster DMA\n");
- return -1;
+ return -ENODEV;
}
iobase = pci_dev->resource[0].start;
if (check_region(iobase, 256)) {
printk(KERN_ERR "trident: can't allocate I/O space at 0x%4.4lx\n",
iobase);
- return -1;
+ return -ENODEV;
}
if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
printk(KERN_ERR "trident: out of memory\n");
- return -1;
+ return -ENOMEM;
}
memset(card, 0, sizeof(*card));
@@ -2054,7 +2107,7 @@
printk(KERN_ERR "trident: unable to allocate irq %d\n", card->irq);
release_region(card->iobase, 256);
kfree(card);
- return 0;
+ return -ENODEV;
}
/* register /dev/dsp */
if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
@@ -2062,7 +2115,7 @@
release_region(iobase, 256);
free_irq(card->irq, card);
kfree(card);
- return -1;
+ return -ENODEV;
}
/* initilize AC97 codec and register /dev/mixer */
if (trident_ac97_init(card) <= 0) {
@@ -2070,7 +2123,7 @@
release_region(iobase, 256);
free_irq(card->irq, card);
kfree(card);
- return -1;
+ return -ENODEV;
}
outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
@@ -2083,7 +2136,7 @@
return 0;
}
-static void __devexit trident_remove(struct pci_dev *pci_dev)
+static void __exit trident_remove(struct pci_dev *pci_dev)
{
int i;
struct trident_card *card = pci_dev->driver_data;
@@ -2120,15 +2173,22 @@
static int __init trident_init_module (void)
{
+ 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");
- return pci_module_init (&trident_pci_driver);
+ if (!pci_register_driver(&trident_pci_driver)) {
+ pci_unregister_driver(&trident_pci_driver);
+ return -ENODEV;
+ }
+ return 0;
}
static void __exit trident_cleanup_module (void)
{
- pci_unregister_driver (&trident_pci_driver);
+ pci_unregister_driver(&trident_pci_driver);
}
module_init(trident_init_module);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)