^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Hewlett-Packard Harmony audio driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * This is a driver for the Harmony audio chipset found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * on the LASI ASIC of various early HP PA-RISC workstations.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2004, Kyle McMartin <kyle@{debian.org,parisc-linux.org}>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based on the previous Harmony incarnations by,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright 2000 (c) Linuxcare Canada, Alex deVries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright 2000-2003 (c) Helge Deller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Copyright 2001 (c) Matthieu Delahaye
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Copyright 2001 (c) Jean-Christophe Vaugeois
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Copyright 2003 (c) Laurent Canet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Copyright 2004 (c) Stuart Brady
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Notes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * - graveyard and silence buffers last for lifetime of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * the driver. playback and capture buffers are allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * per _open()/_close().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <sound/rawmidi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <sound/info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <asm/parisc-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #include "harmony.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) module_param(index, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) MODULE_PARM_DESC(index, "Index value for Harmony driver.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) module_param(id, charp, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) MODULE_PARM_DESC(id, "ID string for Harmony driver.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static const struct parisc_device_id snd_harmony_devtable[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* bushmaster / flounder */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* 712 / 715 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* pace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* outfield / coral II */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) { 0, }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) MODULE_DEVICE_TABLE(parisc, snd_harmony_devtable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define NAME "harmony"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define PFX NAME ": "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static const unsigned int snd_harmony_rates[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) 5512, 6615, 8000, 9600,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) 11025, 16000, 18900, 22050,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) 27428, 32000, 33075, 37800,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) 44100, 48000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static const unsigned int rate_bits[14] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) HARMONY_SR_5KHZ, HARMONY_SR_6KHZ, HARMONY_SR_8KHZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) HARMONY_SR_9KHZ, HARMONY_SR_11KHZ, HARMONY_SR_16KHZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) HARMONY_SR_18KHZ, HARMONY_SR_22KHZ, HARMONY_SR_27KHZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) HARMONY_SR_32KHZ, HARMONY_SR_33KHZ, HARMONY_SR_37KHZ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) HARMONY_SR_44KHZ, HARMONY_SR_48KHZ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static const struct snd_pcm_hw_constraint_list hw_constraint_rates = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) .count = ARRAY_SIZE(snd_harmony_rates),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) .list = snd_harmony_rates,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) .mask = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static inline unsigned long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) harmony_read(struct snd_harmony *h, unsigned r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return __raw_readl(h->iobase + r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) harmony_write(struct snd_harmony *h, unsigned r, unsigned long v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) __raw_writel(v, h->iobase + r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) harmony_wait_for_control(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) while (harmony_read(h, HARMONY_CNTL) & HARMONY_CNTL_C) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) harmony_reset(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) harmony_write(h, HARMONY_RESET, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) mdelay(50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) harmony_write(h, HARMONY_RESET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) harmony_disable_interrupts(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u32 dstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) dstatus = harmony_read(h, HARMONY_DSTATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) dstatus &= ~HARMONY_DSTATUS_IE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) harmony_write(h, HARMONY_DSTATUS, dstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) harmony_enable_interrupts(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) u32 dstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dstatus = harmony_read(h, HARMONY_DSTATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) dstatus |= HARMONY_DSTATUS_IE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) harmony_write(h, HARMONY_DSTATUS, dstatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) harmony_mute(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) spin_lock_irqsave(&h->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) harmony_write(h, HARMONY_GAINCTL, HARMONY_GAIN_SILENCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) spin_unlock_irqrestore(&h->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) harmony_unmute(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) spin_lock_irqsave(&h->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) harmony_write(h, HARMONY_GAINCTL, h->st.gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) spin_unlock_irqrestore(&h->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) harmony_set_control(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u32 ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) spin_lock_irqsave(&h->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) ctrl = (HARMONY_CNTL_C |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) (h->st.format << 6) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) (h->st.stereo << 5) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) (h->st.rate));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) harmony_write(h, HARMONY_CNTL, ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) spin_unlock_irqrestore(&h->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static irqreturn_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) snd_harmony_interrupt(int irq, void *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) u32 dstatus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct snd_harmony *h = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) harmony_disable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dstatus = harmony_read(h, HARMONY_DSTATUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (dstatus & HARMONY_DSTATUS_PN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (h->psubs && h->st.playing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) harmony_write(h, HARMONY_PNXTADD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) h->pbuf.addr + h->pbuf.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) h->stats.play_intr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) snd_pcm_period_elapsed(h->psubs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) h->stats.silence_intr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (dstatus & HARMONY_DSTATUS_RN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (h->csubs && h->st.capturing) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) h->cbuf.buf += h->cbuf.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) h->cbuf.buf %= h->cbuf.size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) harmony_write(h, HARMONY_RNXTADD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) h->cbuf.addr + h->cbuf.buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) h->stats.rec_intr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) snd_pcm_period_elapsed(h->csubs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) h->stats.graveyard_intr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) harmony_enable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static unsigned int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) snd_harmony_rate_bits(int rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) for (i = 0; i < ARRAY_SIZE(snd_harmony_rates); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (snd_harmony_rates[i] == rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return rate_bits[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return HARMONY_SR_44KHZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static const struct snd_pcm_hardware snd_harmony_playback =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) SNDRV_PCM_INFO_BLOCK_TRANSFER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) SNDRV_PCM_FMTBIT_A_LAW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) SNDRV_PCM_RATE_KNOT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .rate_min = 5512,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .rate_max = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .channels_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .buffer_bytes_max = MAX_BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) .period_bytes_min = BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .period_bytes_max = BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .periods_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .periods_max = MAX_BUFS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .fifo_size = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static const struct snd_pcm_hardware snd_harmony_capture =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) SNDRV_PCM_INFO_JOINT_DUPLEX | SNDRV_PCM_INFO_MMAP_VALID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) SNDRV_PCM_INFO_BLOCK_TRANSFER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .formats = (SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_MU_LAW |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) SNDRV_PCM_FMTBIT_A_LAW),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .rates = (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_48000 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) SNDRV_PCM_RATE_KNOT),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .rate_min = 5512,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .rate_max = 48000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .channels_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .channels_max = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .buffer_bytes_max = MAX_BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .period_bytes_min = BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .period_bytes_max = BUF_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .periods_min = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .periods_max = MAX_BUFS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .fifo_size = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) snd_harmony_playback_trigger(struct snd_pcm_substream *ss, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (h->st.capturing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) h->st.playing = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) harmony_write(h, HARMONY_PNXTADD, h->pbuf.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) harmony_unmute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) harmony_enable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) h->st.playing = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) harmony_mute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) harmony_disable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) snd_BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) snd_harmony_capture_trigger(struct snd_pcm_substream *ss, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (h->st.playing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) spin_lock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) case SNDRV_PCM_TRIGGER_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) h->st.capturing = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) harmony_write(h, HARMONY_RNXTADD, h->cbuf.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) harmony_unmute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) harmony_enable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) case SNDRV_PCM_TRIGGER_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) h->st.capturing = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) harmony_mute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) harmony_disable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) case SNDRV_PCM_TRIGGER_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) snd_BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) spin_unlock(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) snd_harmony_set_data_format(struct snd_harmony *h, int fmt, int force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) int o = h->st.format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) int n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) switch(fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) case SNDRV_PCM_FORMAT_S16_BE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) n = HARMONY_DF_16BIT_LINEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case SNDRV_PCM_FORMAT_A_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) n = HARMONY_DF_8BIT_ALAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) case SNDRV_PCM_FORMAT_MU_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) n = HARMONY_DF_8BIT_ULAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) n = HARMONY_DF_16BIT_LINEAR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (force || o != n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) snd_pcm_format_set_silence(fmt, h->sdma.area, SILENCE_BUFSZ /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) (snd_pcm_format_physical_width(fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) / 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) snd_harmony_playback_prepare(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (h->st.capturing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) h->pbuf.size = snd_pcm_lib_buffer_bytes(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) h->pbuf.count = snd_pcm_lib_period_bytes(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (h->pbuf.buf >= h->pbuf.size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) h->pbuf.buf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) h->st.playing = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) h->st.rate = snd_harmony_rate_bits(rt->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (rt->channels == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) h->st.stereo = HARMONY_SS_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) h->st.stereo = HARMONY_SS_MONO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) harmony_set_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) h->pbuf.addr = rt->dma_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) snd_harmony_capture_prepare(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (h->st.playing)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) h->cbuf.size = snd_pcm_lib_buffer_bytes(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) h->cbuf.count = snd_pcm_lib_period_bytes(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (h->cbuf.buf >= h->cbuf.size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) h->cbuf.buf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) h->st.capturing = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) h->st.rate = snd_harmony_rate_bits(rt->rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) h->st.format = snd_harmony_set_data_format(h, rt->format, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (rt->channels == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) h->st.stereo = HARMONY_SS_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) h->st.stereo = HARMONY_SS_MONO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) harmony_set_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) h->cbuf.addr = rt->dma_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static snd_pcm_uframes_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) snd_harmony_playback_pointer(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) unsigned long pcuradd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) unsigned long played;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (!(h->st.playing) || (h->psubs == NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if ((h->pbuf.addr == 0) || (h->pbuf.size == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pcuradd = harmony_read(h, HARMONY_PCURADD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) played = pcuradd - h->pbuf.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) #ifdef HARMONY_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) printk(KERN_DEBUG PFX "playback_pointer is 0x%lx-0x%lx = %d bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pcuradd, h->pbuf.addr, played);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (pcuradd > h->pbuf.addr + h->pbuf.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return bytes_to_frames(rt, played);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static snd_pcm_uframes_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) snd_harmony_capture_pointer(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) unsigned long rcuradd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) unsigned long caught;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (!(h->st.capturing) || (h->csubs == NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if ((h->cbuf.addr == 0) || (h->cbuf.size == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) rcuradd = harmony_read(h, HARMONY_RCURADD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) caught = rcuradd - h->cbuf.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) #ifdef HARMONY_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) printk(KERN_DEBUG PFX "capture_pointer is 0x%lx-0x%lx = %d bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) rcuradd, h->cbuf.addr, caught);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (rcuradd > h->cbuf.addr + h->cbuf.size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) return bytes_to_frames(rt, caught);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) snd_harmony_playback_open(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) h->psubs = ss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) rt->hw = snd_harmony_playback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) &hw_constraint_rates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) snd_harmony_capture_open(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) struct snd_pcm_runtime *rt = ss->runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) h->csubs = ss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) rt->hw = snd_harmony_capture;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) &hw_constraint_rates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) snd_harmony_playback_close(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) h->psubs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) snd_harmony_capture_close(struct snd_pcm_substream *ss)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) h->csubs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) snd_harmony_hw_params(struct snd_pcm_substream *ss,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) struct snd_pcm_hw_params *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) struct snd_harmony *h = snd_pcm_substream_chip(ss);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (h->dma.type == SNDRV_DMA_TYPE_CONTINUOUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) ss->runtime->dma_addr = __pa(ss->runtime->dma_area);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) static const struct snd_pcm_ops snd_harmony_playback_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) .open = snd_harmony_playback_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) .close = snd_harmony_playback_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) .hw_params = snd_harmony_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) .prepare = snd_harmony_playback_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) .trigger = snd_harmony_playback_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) .pointer = snd_harmony_playback_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) static const struct snd_pcm_ops snd_harmony_capture_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) .open = snd_harmony_capture_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) .close = snd_harmony_capture_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) .hw_params = snd_harmony_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) .prepare = snd_harmony_capture_prepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) .trigger = snd_harmony_capture_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) .pointer = snd_harmony_capture_pointer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) snd_harmony_pcm_init(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) struct snd_pcm *pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (snd_BUG_ON(!h))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) harmony_disable_interrupts(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) err = snd_pcm_new(h->card, "harmony", 0, 1, 1, &pcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) &snd_harmony_playback_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) &snd_harmony_capture_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) pcm->private_data = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) pcm->info_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) strcpy(pcm->name, "harmony");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) h->pcm = pcm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) h->psubs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) h->csubs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /* initialize graveyard buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) h->dma.type = SNDRV_DMA_TYPE_DEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) h->dma.dev = &h->dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) err = snd_dma_alloc_pages(h->dma.type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) h->dma.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) BUF_SIZE*GRAVEYARD_BUFS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) &h->gdma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) printk(KERN_ERR PFX "cannot allocate graveyard buffer!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) /* initialize silence buffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) err = snd_dma_alloc_pages(h->dma.type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) h->dma.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) BUF_SIZE*SILENCE_BUFS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) &h->sdma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) printk(KERN_ERR PFX "cannot allocate silence buffer!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) /* pre-allocate space for DMA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) snd_pcm_set_managed_buffer_all(pcm, h->dma.type, h->dma.dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) MAX_BUF_SIZE, MAX_BUF_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) h->st.format = snd_harmony_set_data_format(h,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) SNDRV_PCM_FORMAT_S16_BE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) snd_harmony_set_new_gain(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) harmony_wait_for_control(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) harmony_write(h, HARMONY_GAINCTL, h->st.gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) snd_harmony_mixercontrol_info(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) int mask = (kc->private_value >> 16) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) int left_shift = (kc->private_value) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) int right_shift = (kc->private_value >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) uinfo->count = left_shift == right_shift ? 1 : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) uinfo->value.integer.max = mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) snd_harmony_volume_get(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) struct snd_harmony *h = snd_kcontrol_chip(kc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) int shift_left = (kc->private_value) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) int shift_right = (kc->private_value >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) int mask = (kc->private_value >> 16) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) int invert = (kc->private_value >> 24) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) int left, right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) spin_lock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) left = (h->st.gain >> shift_left) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) right = (h->st.gain >> shift_right) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) if (invert) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) left = mask - left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) right = mask - right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) ucontrol->value.integer.value[0] = left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (shift_left != shift_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) ucontrol->value.integer.value[1] = right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) spin_unlock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) snd_harmony_volume_put(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) struct snd_harmony *h = snd_kcontrol_chip(kc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) int shift_left = (kc->private_value) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) int shift_right = (kc->private_value >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int mask = (kc->private_value >> 16) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) int invert = (kc->private_value >> 24) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) int left, right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int old_gain = h->st.gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) spin_lock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) left = ucontrol->value.integer.value[0] & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) if (invert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) left = mask - left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) h->st.gain &= ~( (mask << shift_left ) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) h->st.gain |= (left << shift_left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (shift_left != shift_right) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) right = ucontrol->value.integer.value[1] & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (invert)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) right = mask - right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) h->st.gain &= ~( (mask << shift_right) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) h->st.gain |= (right << shift_right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) snd_harmony_set_new_gain(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) spin_unlock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return h->st.gain != old_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) snd_harmony_captureroute_info(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) static const char * const texts[2] = { "Line", "Mic" };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) return snd_ctl_enum_info(uinfo, 1, 2, texts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) snd_harmony_captureroute_get(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) struct snd_harmony *h = snd_kcontrol_chip(kc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) spin_lock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) ucontrol->value.enumerated.item[0] = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) spin_unlock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) snd_harmony_captureroute_put(struct snd_kcontrol *kc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct snd_harmony *h = snd_kcontrol_chip(kc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) int old_gain = h->st.gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) spin_lock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) value = ucontrol->value.enumerated.item[0] & 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) h->st.gain &= ~HARMONY_GAIN_IS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) h->st.gain |= value << HARMONY_GAIN_IS_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) snd_harmony_set_new_gain(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) spin_unlock_irq(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) return h->st.gain != old_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) #define HARMONY_CONTROLS ARRAY_SIZE(snd_harmony_controls)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) #define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) .info = snd_harmony_mixercontrol_info, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) .private_value = ((left_shift) | ((right_shift) << 8) | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) ((mask) << 16) | ((invert) << 24)) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static const struct snd_kcontrol_new snd_harmony_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .name = "Input Route",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) .info = snd_harmony_captureroute_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) .get = snd_harmony_captureroute_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) .put = snd_harmony_captureroute_put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) HARMONY_GAIN_SE_SHIFT, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) HARMONY_GAIN_LE_SHIFT, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) HARMONY_GAIN_HE_SHIFT, 1, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) snd_harmony_mixer_reset(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) harmony_mute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) harmony_reset(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) h->st.gain = HARMONY_GAIN_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) harmony_unmute(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) snd_harmony_mixer_init(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) int idx, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (snd_BUG_ON(!h))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) card = h->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) strcpy(card->mixername, "Harmony Gain control interface");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) for (idx = 0; idx < HARMONY_CONTROLS; idx++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) err = snd_ctl_add(card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) snd_ctl_new1(&snd_harmony_controls[idx], h));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) snd_harmony_mixer_reset(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) snd_harmony_free(struct snd_harmony *h)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (h->gdma.addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) snd_dma_free_pages(&h->gdma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) if (h->sdma.addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) snd_dma_free_pages(&h->sdma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (h->irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) free_irq(h->irq, h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) iounmap(h->iobase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) kfree(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) snd_harmony_dev_free(struct snd_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) struct snd_harmony *h = dev->device_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) return snd_harmony_free(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) snd_harmony_create(struct snd_card *card,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) struct parisc_device *padev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) struct snd_harmony **rchip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) struct snd_harmony *h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) static const struct snd_device_ops ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) .dev_free = snd_harmony_dev_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) *rchip = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) h = kzalloc(sizeof(*h), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (h == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) h->hpa = padev->hpa.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) h->card = card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) h->dev = padev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) h->irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) h->iobase = ioremap(padev->hpa.start, HARMONY_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) if (h->iobase == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) printk(KERN_ERR PFX "unable to remap hpa 0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) (unsigned long)padev->hpa.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) err = request_irq(padev->irq, snd_harmony_interrupt, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) "harmony", h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) printk(KERN_ERR PFX "could not obtain interrupt %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) padev->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) h->irq = padev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) spin_lock_init(&h->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) spin_lock_init(&h->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) h, &ops)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) *rchip = h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) free_and_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) snd_harmony_free(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) snd_harmony_probe(struct parisc_device *padev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) struct snd_harmony *h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) err = snd_card_new(&padev->dev, index, id, THIS_MODULE, 0, &card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) err = snd_harmony_create(card, padev, &h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) err = snd_harmony_pcm_init(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) err = snd_harmony_mixer_init(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) strcpy(card->driver, "harmony");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) strcpy(card->shortname, "Harmony");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) sprintf(card->longname, "%s at 0x%lx, irq %i",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) card->shortname, h->hpa, h->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) err = snd_card_register(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) goto free_and_ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) parisc_set_drvdata(padev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) free_and_ret:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) snd_card_free(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) static int __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) snd_harmony_remove(struct parisc_device *padev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) snd_card_free(parisc_get_drvdata(padev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static struct parisc_driver snd_harmony_driver __refdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) .name = "harmony",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) .id_table = snd_harmony_devtable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) .probe = snd_harmony_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) .remove = __exit_p(snd_harmony_remove),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) static int __init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) alsa_harmony_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) return register_parisc_driver(&snd_harmony_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) static void __exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) alsa_harmony_fini(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) unregister_parisc_driver(&snd_harmony_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) MODULE_DESCRIPTION("Harmony sound driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) module_init(alsa_harmony_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) module_exit(alsa_harmony_fini);