#include <linux/smp_lock.h>
#include <linux/ac97_codec.h>
#include <linux/bitops.h>
+#include <linux/mutex.h>
+
#include <asm/uaccess.h>
#define DRIVER_VERSION "1.01"
static int strict_clocking;
static unsigned int clocking;
static int spdif_locked;
+static int ac97_quirk = AC97_TUNE_DEFAULT;
//#define DEBUG
//#define DEBUG2
PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4},
-
+ {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_AUDIO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE},
{0,}
};
struct i810_card *card; /* Card info */
/* single open lock mechanism, only used for recording */
- struct semaphore open_sem;
+ struct mutex open_mutex;
wait_queue_head_t open_wait;
/* file mode */
u16 pci_id_internal; /* used to access card_cap[] */
#ifdef CONFIG_PM
u16 pm_suspended;
- u32 pm_save_state[64/sizeof(u32)];
int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
#endif
/* soundcore stuff */
unsigned long ac97base_mmio_phys;
unsigned long iobase_mmio_phys;
- u_int8_t *ac97base_mmio;
- u_int8_t *iobase_mmio;
+ u_int8_t __iomem *ac97base_mmio;
+ u_int8_t __iomem *iobase_mmio;
int use_mmio;
#define CIV_TO_LVI(card, port, off) \
I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
+static struct ac97_quirk ac97_quirks[] __devinitdata = {
+ {
+ .vendor = 0x0e11,
+ .device = 0x00b8,
+ .name = "Compaq Evo D510C",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x00d8,
+ .name = "Dell Precision 530", /* AD1885 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x0126,
+ .name = "Dell Optiplex GX260", /* AD1981A */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x012d,
+ .name = "Dell Precision 450", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ { /* FIXME: which codec? */
+ .vendor = 0x103c,
+ .device = 0x00c3,
+ .name = "Hewlett-Packard onboard",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x12f1,
+ .name = "HP xw8200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x3008,
+ .name = "HP xw4200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x10f1,
+ .device = 0x2665,
+ .name = "Fujitsu-Siemens Celsius", /* AD1981? */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x10f1,
+ .device = 0x2885,
+ .name = "AMD64 Mobo", /* ALC650 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x110a,
+ .device = 0x0056,
+ .name = "Fujitsu-Siemens Scenic", /* AD1981? */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x11d4,
+ .device = 0x5375,
+ .name = "ADI AD1985 (discrete)",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1462,
+ .device = 0x5470,
+ .name = "MSI P4 ATX 645 Ultra",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1734,
+ .device = 0x0088,
+ .name = "Fujitsu-Siemens D1522", /* AD1981 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4856,
+ .name = "Intel D845WN (82801BA)",
+ .type = AC97_TUNE_SWAP_HP
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4d44,
+ .name = "Intel D850EMV2", /* AD1885 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4d56,
+ .name = "Intel ICH/AD1885",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x012d,
+ .name = "Dell Precision 450", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x3008,
+ .name = "HP xw4200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x12f1,
+ .name = "HP xw8200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ { } /* terminator */
+};
+
static struct i810_card *devs = NULL;
static int i810_open_mixdev(struct inode *inode, struct file *file);
dmabuf->rawbuf = rawbuf;
dmabuf->buforder = order;
- /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+ /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(rawbuf); page <= pend; page++)
SetPageReserved(page);
if (count < fragsize)
return;
+ /* if we are currently stopped, then our CIV is actually set to our
+ * *last* sg segment and we are ready to wrap to the next. However,
+ * if we set our LVI to the last sg segment, then it won't wrap to
+ * the next sg segment, it won't even get a start. So, instead, when
+ * we are stopped, we set both the LVI value and also we increment
+ * the CIV value to the next sg segment to be played so that when
+ * we call start, things will operate properly. Since the CIV can't
+ * be written to directly for this purpose, we set the LVI to CIV + 1
+ * temporarily. Once the engine has started we set the LVI to its
+ * final value.
+ */
if (!dmabuf->enable && dmabuf->ready) {
if (!(dmabuf->trigger & trigger))
return;
+ CIV_TO_LVI(state->card, port, 1);
+
start(state);
while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2))))
;
if (size > (PAGE_SIZE << dmabuf->buforder))
goto out;
ret = -EAGAIN;
- if (remap_page_range(vma, vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+ if (remap_pfn_range(vma, vma->vm_start,
+ virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
size, vma->vm_page_prot))
goto out;
dmabuf->mapped = 1;
state->card = card;
state->magic = I810_STATE_MAGIC;
init_waitqueue_head(&dmabuf->wait);
- init_MUTEX(&state->open_sem);
+ mutex_init(&state->open_mutex);
file->private_data = state;
dmabuf->trigger = 0;
card->ac97_codec[num_ac97] = codec;
}
+ /* tune up the primary codec */
+ ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
+
/* pick the minimum of channels supported by ICHx or codec(s) */
card->channels = (card->channels > total_channels)?total_channels:card->channels;
state->card = card;
state->magic = I810_STATE_MAGIC;
init_waitqueue_head(&dmabuf->wait);
- init_MUTEX(&state->open_sem);
+ mutex_init(&state->open_mutex);
dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
dmabuf->trigger = PCM_ENABLE_OUTPUT;
i810_set_spdif_output(state, -1, 0);
goto out_region2;
}
- if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
- goto out_pio;
- }
-
if (card->use_mmio) {
if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
}
/* initialize AC97 codec and register /dev/mixer */
- if (i810_ac97_init(card) <= 0) {
- free_irq(card->irq, card);
+ if (i810_ac97_init(card) <= 0)
goto out_iospace;
- }
pci_set_drvdata(pci_dev, card);
if(clocking == 0) {
if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
int i;
printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
- free_irq(card->irq, card);
for (i = 0; i < NR_AC97; i++)
if (card->ac97_codec[i] != NULL) {
unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
goto out_iospace;
}
+ if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
+ card_names[pci_id->driver_data], card)) {
+ printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
+ goto out_iospace;
+ }
+
+
card->initializing = 0;
return 0;
release_mem_region(card->ac97base_mmio_phys, 512);
release_mem_region(card->iobase_mmio_phys, 256);
}
-out_pio:
- release_region(card->iobase, 64);
-out_region2:
release_region(card->ac97base, 256);
+out_region2:
+ release_region(card->iobase, 64);
out_region1:
pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
card->channel, card->chandma);
}
#ifdef CONFIG_PM
-static int i810_pm_suspend(struct pci_dev *dev, u32 pm_state)
+static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
{
struct i810_card *card = pci_get_drvdata(dev);
struct i810_state *state;
}
}
}
- pci_save_state(dev,card->pm_save_state); /* XXX do we need this? */
+ pci_save_state(dev); /* XXX do we need this? */
pci_disable_device(dev); /* disable busmastering */
pci_set_power_state(dev,3); /* Zzz. */
int num_ac97,i=0;
struct i810_card *card=pci_get_drvdata(dev);
pci_enable_device(dev);
- pci_restore_state (dev,card->pm_save_state);
+ pci_restore_state (dev);
/* observation of a toshiba portege 3440ct suggests that the
hardware has to be more or less completely reinitialized from
}
#endif /* CONFIG_PM */
-MODULE_AUTHOR("");
+MODULE_AUTHOR("The Linux kernel team");
MODULE_DESCRIPTION("Intel 810 audio support");
MODULE_LICENSE("GPL");
-MODULE_PARM(ftsodell, "i");
-MODULE_PARM(clocking, "i");
-MODULE_PARM(strict_clocking, "i");
-MODULE_PARM(spdif_locked, "i");
+module_param(ftsodell, int, 0444);
+module_param(clocking, uint, 0444);
+module_param(strict_clocking, int, 0444);
+module_param(spdif_locked, int, 0444);
-#define I810_MODULE_NAME "intel810_audio"
+#define I810_MODULE_NAME "i810_audio"
static struct pci_driver i810_pci_driver = {
.name = I810_MODULE_NAME,
static int __init i810_init_module (void)
{
+ int retval;
+
printk(KERN_INFO "Intel 810 + AC97 Audio, version "
DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&i810_pci_driver)) {
- pci_unregister_driver(&i810_pci_driver);
- return -ENODEV;
- }
+ retval = pci_register_driver(&i810_pci_driver);
+ if (retval)
+ return retval;
+
if(ftsodell != 0) {
printk("i810_audio: ftsodell is now a deprecated option.\n");
}